bootsect.S解読に引き続き、今度はsetup.Sの解読をしていこうと思うです。
bootsect.Sの解読は、其の壱〜其の六まで約2週間ほどかかったので、
多分setup.Sもそれくらいかかりそうです(多分それ以上かかりそう...)。
まぁ、実際Linuxの最初のプロセス(initだっけ?)が立ち上がるまでには、
まだまだ遠い道のりですので、まったりと歩いて行こうと思うです。
では、setup.S解読、スタート!
start: jmp trampoline
とりあえず、いろいろとありますが、bootsect.Sからジャンプしてきての最初の処理は、start:から始まります。
んで、いきなしジャーーンプ! ジャンプ先はtrampolineですね。
trampoline: call start_of_setup .space 1024 # End of setup header #####################################################
はい、きました、trampolineです。ずいぶん長い距離をジャンプしましたが、足は折れませんでしたか?
そうですか、では続けましょう。
ジャンプしてきて早々ですが、さらにcall命令でstart_of_setupを呼び出されてます。
ちなみに、ここに、意味ありげにも「End of setup header」なんて書かれてあります。
?
では、続けましょう。
start_of_setup: # Bootlin depends on this being done early movw $0x01500, %ax movb $0x81, %dl int $0x13
http://www.delorie.com/djgpp/doc/rbinter/id/45/6.html
GET DISK TYPEというBIOSを利用しています。でもこれ意味分からないのですよね。
いや、やってることは分かるんですけど、なんでこれを呼んでいるのかが分からない。
0x81ということは、「1000 0001」ということですよね。7ビット目じゃないのでハードディスクでもない。
このあとも%alを参照してないので、何がしたかったのが分からないのです。
まぁご丁寧にもコメントが書かれてあるので何かしらの意味があるのでしょう。
#ifdef SAFE_RESET_DISK_CONTROLLER # Reset the disk controller. movw $0x0000, %ax movb $0x80, %dl int $0x13 #endif
http://www.delorie.com/djgpp/doc/rbinter/id/11/6.html
これはお馴染のBIOSですね。フロッピーディスクドライブをリセットします。
# Set %ds = %cs, we know that SETUPSEG = %cs at this point movw %cs, %ax # aka SETUPSEG movw %ax, %ds # Check signature at end of setup cmpw $SIG1, setup_sig1 jne bad_sig cmpw $SIG2, setup_sig2 jne bad_sig jmp good_sig1
まぁコメントを読めば分かります。SETUPSEGを%csと%dsにいれてます(というか%csには始めから入ってます)。
ちなみにSETUPSEGは0x9020ですぜ。すなわち、setup.Sのアドレスです。
#define SIG1 0xAA55 #define SIG2 0x5A5A
ソースの最初の方に上記のように定義されています。
そして、setup_sig1とsetup_sig2は、ソースのいちばん下の方に
setup_sig1: .word SIG1 setup_sig2: .word SIG2
と定義されています。ここで通常のアプリケーションプログラマならば、「はぁ?」って感じです。
だって、cmpw命令は確実にイコールになりますから。んでも、setup.Sでは必ずしもイコールになるとは、
限りません! なぜなら、setup.Sがすべてメモリに読み込まれたとは限らないからです。
だからこそ、setup_sig1、setup_sig2がソースコードの一番最後に置かれてあるわけです。
つまり、ここでは、setup.Sがすべてメモリに読み込まれているかどうかを判定しているわけです。
ちなみに、例えすべて読み込まれていなくて、bad_sigへジャンプしたとしても、bootsect.Sを検索して、
再度コピーしてくるような処理をやっているみたいです。
まぁそれはそれとして、正常に読み込みが完了してたとして、話を進めます。
good_sig1: jmp good_sig
good_sig1へジャンプすると、そのままgood_sigへ進みます。
good_sig: movw %cs, %ax # aka SETUPSEG subw $DELTA_INITSEG, %ax # aka INITSEG movw %ax, %ds # Check if an old loader tries to load a big-kernel testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel? jz loader_ok # No, no danger for old loaders. cmpb $0, %cs:type_of_loader # Do we have a loader that # can deal with us? jnz loader_ok # Yes, continue. pushw %cs # No, we have an old loader, popw %ds # die. lea loader_panic_mess, %si call prtstr jmp no_sig_loop
SETUPSEGは0x9020ですね。DELTA_INITSEGは、ソースの上の方で定義されていますが、0x0020です。
よって%dsは0x9000となります。
# flags, unused bits must be zero (RFU) bit within loadflags loadflags: LOADED_HIGH = 1 # If set, the kernel is loaded high
LOADED_HIGHはソースの途中で定義されています。1ですね。
そして、%cs:loadflagsはそのままLOADED_HIGHの位置を示しています。
つまり、これは、イコールとなります。ということは、test命令(つまりand命令)を行うと、
0000 00001 and 0000 00001 = 0000 00001 となります。つまりZFフラグが1となります。
ZFフラグが1だとjz命令はジャンプします。よってloader_okへ飛びます。
これが失敗してジャンプしなかった場合は、さらに%cs:type_of_loaderが0かどうかを比較しています。
つまり、ここまででやっていたのは、setup.Sが本当にメモリに読み込まれたかどうかを検査していたわけです。
ちなみに、このcmp命令でもジャンプできなかった場合は、no_sig_loopへと飛びます。
no_sig_loop: hlt jmp no_sig_loop
予想通りの無限ループとなります。まぁここに処理がくることはありえないということでしょう。
ちなみに、hlt命令は、CPUを休ませる命令らしいです。
さてさて、かなり時間があいちゃいましたが、やめたわけではないです。
とりあえず前回は、setup.Sがちゃんとメモリに読み込まれたかどうかを判断するプログラムでした。
んで、今日ですが、setup.Sがちゃんとメモリに読み込まれてことが確認できたら、
次は、いよいよちゃんとしたsetup.Sの処理です(もちろんこれまでもちゃんとした処理ですけどね)。
んで、bootsect.Sってのは、全体としては、ただフロッピーに入ってるデータを、
すべてメモリへ読み込んでいるだけです。
ぶっちゃけた話、bootsect.SなんてのはLinuxのおまけみたいなものです。
だいたいフロッピー起動じゃなかったら実行さえされないかもしれないのですから。
言うなれば、コンピュータでいうキーボードやマウスみたいなもので、
いくらでも「かえ」がきくわけです。(でもキーボードは絶対必要ですけどね)
実際LILOやSYSLINUXといった、bootsect.Sに変わるものがいくらでもあるわけです。
しかしsetup.Sから先のコードは間違いなくちゃんとしたLinuxです。
さて、ではOSが起動して真っ先にしなければならない処理とはなんでしょうか。
それは、物理メモリの量を確認することです。
loader_ok: # Get memory size (extended mem, kB) xorl %eax, %eax movl %eax, (0x1e0) #ifndef STANDARD_MEMORY_BIOS_CALL movb %al, (E820NR) ....(コメント省略).... #define SMAP 0x534d4150 meme820: xorl %ebx, %ebx # continuation counter movw $E820MAP, %di # point into the whitelist # so we can have the bios # directly write into it. jmpe820: movl $0x0000e820, %eax # e820, upper word zeroed movl $SMAP, %edx # ascii 'SMAP' movl $20, %ecx # size of the e820rec pushw %ds # data record. popw %es int $0x15 # make the call jc bail820 # fall to e801 if it fails
意味がわからーーーーん。
プロテクトモードでもないのに、なんでいきなりeaxがでてきてんだよー。
メモリを調べるためのBIOSサービスは以下です。
http://www.delorie.com/djgpp/doc/rbinter/id/50/17.html
BIOSサービスのメモリマップ取得を呼び出しています。
なんかこれ、新しいBIOSらしくて、eaxやebxやecxやedxなんかにも入れないといけないようです。
ってかリアルモードなのにeaxとか使っていいの?
%dsをスタックを経由して%esにいれてますが、%dsは0x9000です。
%es:%diへ取得したデータが格納されるらしいので、それを指定しているのでしょう。
cmpl $SMAP, %eax # check the return is `SMAP' jne bail820 # fall to e801 if it fails # cmpl $1, 16(%di) # is this usable memory? # jne again820 # If this is usable memory, we save it by simply advancing %di by # sizeof(e820rec). # good820: movb (E820NR), %al # up to 32 entries cmpb $E820MAX, %al jnl bail820 incb (E820NR) movw %di, %ax addw $20, %ax movw %ax, %di again820: cmpl $0, %ebx # check to see if jne jmpe820 # %ebx is set to EOF bail820:
ここではメモリのサイズ取得が成功したのかを検査しているようです。
とりあえず%eaxがSMAPならば成功らしいので、ジャンプしません。
%es:%diには取得したデータが入るので、それが1じゃないならジャンプします。ジャンプすると、ebxを0にして
再びメモリのサイズ取得をします。なんで何回もよびだしているかというと、
このBIOSは、1度の呼び出しでメモリ空間のエントリを返します。つまり、すべてのエントリをゲットするまで
呼び出し続けなければなりません。(そのへんはBIOSの説明のところを読めばわかるかと)
again820へジャンプしなかったら、最後のエントリが読み込まれたとして終了となり、bail820へ飛びます。
meme801: stc # fix to work around buggy xorw %cx,%cx # BIOSes which dont clear/set xorw %dx,%dx # carry on pass/error of # e801h memory size call # or merely pass cx,dx though # without changing them. movw $0xe801, %ax int $0x15 jc mem88 cmpw $0x0, %cx # Kludge to handle BIOSes jne e801usecxdx # which report their extended cmpw $0x0, %dx # memory in AX/BX rather than jne e801usecxdx # CX/DX. The spec I have read movw %ax, %cx # seems to indicate AX/BX movw %bx, %dx # are more reasonable anyway... e801usecxdx: andl $0xffff, %edx # clear sign extend shll $6, %edx # and go from 64k to 1k chunks movl %edx, (0x1e0) # store extended memory size andl $0xffff, %ecx # clear sign extend addl %ecx, (0x1e0) # and add lower memory into # total size.
さて、ここでもメモリのサイズを取得しています(笑)。
さっきも取得したやんかー。意味わからんわー。
実は、メモリサイズを管理するということはOSにとってはかなり大事なことらしくて、
一度取得したくらいじゃ、信用できないらしいです。なので、考えうるすべての方法で取得してみて、
それらの総合的な結果から、サイズを決定するらしいです。
http://www.delorie.com/djgpp/doc/rbinter/id/48/17.html
おなじみ、BIOSです。
このBIOSはeax,ebxというようなもんは使わないようです。
ちなみに、最初のメモリサイズ取得BIOSは、4GB以上のメモリも取得できるという
32ビットCPUの能力の150%を発揮させるすごいBIOSです。
そんなことだからeaxなんていうリアルモードではありえないレジスタを使ってるんでしょう。
しかし、今回のBOISはさっきのとはちょっと質が落ち、最高4GBのメモリサイズしか取得できません。
つまりもしメモリが4GB以上あったとしても(4GBのメモリなんてうらやましい限りですけどね)
4GBまでしか確認できないBIOSなのです。
つーか、4GB以上のメモリを積んでるPCなんてこの世にあるの?
まぁそんなスーパーコンピュータみたいなPCにもLinuxは対応しているわけです。
でも現在の普通のPCだったらせいぜい128MBとか256MBとか512MBとかなので、この4GB以下のBIOSで十分なわけです。
# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or # 64mb, depending on the bios) in ax. mem88: #endif movb $0x88, %ah int $0x15 movw %ax, (2)
http://www.delorie.com/djgpp/doc/rbinter/id/37/15.html
んで、4GB以上のメモリにも対応しているLinuxですが、64MB以下のコンピュータにも対応しているのです。
もうLinuxはなんでもありのようです(笑)。
要するに、3つのBIOSを使って、どのくらい物理メモリを持ったコンピュータなのかを判断しているわけです。
んで、ご丁寧にも3回も物理メモリのサイズを調べあげたsetup.Sですが、
もちろん調べあげたデータをメモリ空間に保存しておかなければなりません。
とりあえず最後に調べた64MB以下のデータは、
上記のプログラム「movw %ax, (2)」から90002Hに保存されたことが分かります。
んじゃ、4GB以下を調べるmeme801の結果はどこに保存されたのかというと、ソースを見てみればわかりますが、
1e0に書き込んでいるのが分かります。つまり901E0Hに保存しているわけです。
ちなみにこの2つのBIOS結果保存先は、bootsect.Sが置かれている場所ですね。
bootsect.Sは90000Hから90200Hまでに書き込まれています。
よって見事に上書きしています。まぁbootsect.Sはもう処理が終了していて、いらないので、
メモリ再利用ということで上書きしているのだろうと思います。
そして、もっとも優秀なメモリサイズ取得BIOSであるmeme820の結果はどこに保存しているのかというと
分かりません(笑)。どこにしてんの?
ただE820NRといういかにもあやしげな数値が使われているので、おそらく
この値がコンパイル時とかに別の値に変貌するのでしょう。
でも正確な値が分からんので、もういいです(笑)。
だいたい4GB以上のメモリ用に書かれたソースなんて読んでるだけで腹立ってきます(笑)。
# Set the keyboard repeat rate to the max movw $0x0305, %ax xorw %bx, %bx int $0x16
一応物理メモリのサイズは分かったということで、次は一転して、
キーボードのリピートレートの設定です。
http://www.delorie.com/djgpp/doc/rbinter/id/66/17.html
最初リピートレートの意味が分からなかったのですが、調べてみたらどうやら
「キーを押し続けたときの繰り返しスピード」のことらしいです。
つまり「キーを押し続けたときのカーソルキーなどの移動の速さ」とかでしょう。
んでALレジスタやBXレジスタをみてみると、このキーボードのリピートレートを最大にしてるみたいです。
つまり、むっちゃカーソルキーを速くするように設定しているということでしょう。
# Check for video adapter and its parameters and allow the # user to browse video modes. call video # NOTE: we need %ds pointing # to bootsector
で、サブルーチンvideoを呼び出しています。
はい、サブルーチンvideoですけどね。これ実はsetup.Sにはないんですよね。
んで、どこにあるかというと、setup.Sと同じディレクトリにあるvideo.Sというソースの中にあるわけです。
そのvideo.Sが相当ながいソースコードで、マジ意味不明なんですけど。
どうやら90000Hから始まる32バイトに
カーソル位置やページ番号やなにやかかにやらの情報を格納する関数らしいのです。
もうね、こんなvideo.Sなんて読んでられないんですよ。だってぱっとみ2000行くらいあるんだもん。
なので、飛ばします(笑)。いや飛ばしても多分setup.Sのコードは解読できるはずなので。
というか、video.S解読ということで、
またどこかでやろかなと(こんな面白くなさそうなところは多分一生やんないと思いますけど^^;)。
ということで、飛ばし決定!(笑)。
作ってみました。というか、改良してみました(笑)
http://ruffnex.oc.to/kenji/socket/synk4.c
[kenji@localhost kenji]$ gcc -Wall -o synk4 synk4.c [kenji@localhost kenji]$ su Passwd:(rootになる) [root@localhost kenji]# ./synk4 222.222.222.222 127.0.0.1 1000 2000 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 2004 The Regents of the University of California. All Rights Reserved. LapTime:0000(ms), SendPacket:75553 LapTime:1000(ms), SendPacket:150398 LapTime:2000(ms), SendPacket:227103 ..... [Ctrl + C] Signal Caught. Exiting Cleanly. [root@localhost kenji]#
とすることで自らのPCへSYNパケットを連続送信。
あとはuptimeコマンドやxloadコマンドを使ってPCの負荷率を調べると、
どんどんと負荷がかかっていくのが分かります。
元ネタプログラムは↓です。
http://www.packetstormsecurity.com/Exploit_Code_Archive/synk4.c
最近rawsocket関連のプログラム組んでなかったので、良い練習になりました。
バグとかみつけたら、知らせてくれるとうれしいです。
以下のレジストリにプログラムを登録しておくとWindows起動時にプログラムを実行してくれる
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
他にもありそうだけど、とりあえずこれだけ覚えよう。
Peeking into Password Edit '& Internet Explorer - Super Password Spy++
http://www.codeguru.com/Cpp/I-N/ieprogram/security/article.php/c4387
パスワード閲覧ソフトの解説サイト(英語)
DLLを注入することでIEのパスワードも閲覧できるようにしてる。
ソースコードがあるので、みてみると面白いです。
MessagerSpy++ for MSN Messenger/Windows Messager
http://www.codeguru.com/Cpp/misc/misc/msn/article.php/c3901
マイクロソフトのメッセンジャーのログを取得するプログラム?
メッセンジャー自体よく知らないので読んでませんけど、
興味がある人はソースコード読んでみてください。
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dns/dns/dnsquery.asp
こんな便利な関数があったなんて…。
これ使ったら、わざわざDNSクライアント書いてサーバから取得してこなくても、
メールアドレスからメールサーバアドレスへの変換ができるじゃないか。
あぁ、DNSクライアント作成の努力が…。
わけ分からんいろいろなネットワークインターフェースを取得したかったらGetIfTable関数がお勧め。
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/iphlp/iphlp/getiftable.asp
http://homepage2.nifty.com/spw/tips/GetIfTable.html
netstatの「-e」オプションなんかはこれを使っているみたい。
追記:
他にもGetTcpTable、GetUdpTableなどが存在する模様。
その辺の勉強兼ねてnetstat作成中〜。
シンプルなパッカー(プロテクター)の作成(英語)
http://sandsprite.com/CodeStuff/Build_your_own_executable_crypter.html
デバイスドライバ関連のソース満載です。
http://www.hxdef.org/knowhow.php
他にも、APIフックやヒープBOFについての記事がいろいろと。
やっぱり、英語圏の方がレベル高い記事が多いよー(;'д`)。
まず、以下からVMPlayerをダウンロードします。Windows版とLinux版が用意されていますので、環境に合わせてダウンロードしてください。私はWindows環境で仮想環境を構築したかったので、Windows版をダウンロードしました。
http://www.vmware.com/download/player/
http://download3.vmware.com/software/vmplayer/VMware-player-1.0.0-18587.exe
ダウンロードしたら、さっそくインストール!
次に、QEMUをダウンロードします。現在の最新版はQemuInstall-0.7.2.exe。
http://free.oszoo.org/ftp/qemu/win32/release/
QEMUをインストールしたら、コマンドプロンプトから以下のように入力します。
C:\Program Files\Qemu>qemu-img.exe create -f vmdk WindowsXPPro.vmdk 5G Formating 'WindowsXPPro.vmdk', fmt=vmdk, size=2097152 kB
仮想マシンにWinXPProをインストールしたかったので、WindowsXPPro.vmdkとなっていますが、もし別のOSをインストールしたい場合は、適当に変更してください。最後の「5G」のところは割り当てるHDのサイズのようですので、ここも適当に変更してください。そして、さらに以下のファイルを新しく作成します。
http://kenjinet.s26.xrea.com/WindowsXPPro.vmx
そして、WindowsXPPro.vmxとWindowsXPPro.vmdkを同じフォルダに入れ、WindowsXPProのインストールCD(DVD)をCDドライブに挿入し、VMware Playerを起動し、WindowsXPPro.vmxを読み込みます。あとは、VMware Playerの中で勝手に進むので、通常のインストールと同様に進めてください。
これで仮想環境構築だぁー、わーい。
参考にしたサイトを以下に書いときます。最後に、情報をくれたWillさんに感謝〜m(_ _)m
http://johnbokma.com/mexit/2005/10/26/vmware-player-windows-xp.html(英語)
http://yamashita.dyndns.org/blog/343
http://blog.livedoor.jp/hakin/archives/50168211.html
http://mayoi.net/archives/2005/11/01-1715.php
http://blog.yasaka.com/archives/2005/10/vmware_playervi.html
Hooking the kernel directly
http://www.codeproject.com/useritems/soviet_direct_hooking.asp
TCP/IPを利用しているプロセス情報を視覚的に表示する
http://codezine.jp/a/article.aspx?aid=101
画像からASCIIアートを自動生成する
何かすごい面白そうなものを発見。
http://www.eeye.com/html/resources/downloads/other/index.html
eEye BootRoot eEye BootRoot is a project presented at Black Hat USA 2005 by researchers Derek Soeder and Ryan Permeh, as an exploration of technology that custom boot sector code can use to subvert the Windows kernel as it loads. The eEye BootRootKit is a boot sector-based NDIS backdoor that demonstrates the implementation of this technology.
eEye BootRootは、カスタムブートセクタのコードがWindowsカーネルを落とすために使用することができるテクニックの調査として、Derek SoederとRyan PermehによりBlack Hat USA 2005で発表されたプロジェクトです。eEye BootRootKitは、このテクニックの実行を示すブートセクタベースのNDISバックドアです。(以上、exciteに頼り切った翻訳^^;)。
readme.txtを読むと、INT 13hをフックしてどうたらこうたらと英文で書いてあって全然分からん(笑)。おまけにソースコードはMASMだったり。私はNASMの方好ききなんですけど…。フロッピー起動でNTOSKRNL.EXEを書き換えるあたりがなかなか面白そうで、早速試してみたいのだけど、適当な実験機が見つからないので、仮想マシンで。と思うのだけど、インストールしてあるVMってフロッピー読み込みに対応してたかな? ということでちょっとウェイト状態。
詳しいことが分からんから余計に気になる…。それにBlack Hat USAも行きたい…。
ハッキングが無料でできるサイト
Hack This Site(http://www.hackthissite.org/)
まずhttp://www.hackthissite.org/user/create/からユーザ登録を行って、
左上のログインフォームからログインして、
ログインフォーム以下にあるchallengesコンテンツからはじめることができます。
とりあえずは、Basic Web(↓)から始めるのがお勧め
http://www.hackthissite.org/missions/basic/
ユーザ登録は、基本的にメールアドレスだけでOKです。
とりあえず、Basic Web(http://www.hackthissite.org/missions/basic/)をやってみました。レベル5くらいまでなら、HTMLとJavaScriptとほんの少しのひらめきだけで進めます。その以降はUNIXやサーバサイドプログラムの知識が必要になってきますが…。よって、とりあえずはレベル5までの内容をダイジェストで。
level1 - ヒントはないがとても簡単な問題。このページのHTMLを参照すれば、入力フォームの上にパスワードが書いてある。まぁ作成者が「馬鹿なテスト」と呼ぶだけあって、こんなものをテストにする必要はないということだろうか。
level2 - 開発者のサムは、パスワード認証のためのスクリプトを書いたが、肝心のパスワードファイルをアップロードするのを忘れてしまった。ということで、この認証を突破しろ、という問題。とりあえず、適当なパスワードを入れてみると、「ファイルがありません」といってスクリプトエラーとなる。この問題はちょっとひらめきが必要だが、要するにサーバ側のPHPスクリプトはフォームにデータを入力していると、それと比較しようとして、ファイルを参照しにいき、そこでエラーになるのだろう、と推測できれば勝ち。
level3 - 開発者サムは今度はちゃんとパスワードファイルをアップロードしたらしい。しかし、それでもまだひどい脆弱性があるので、それを攻略しろとのこと。これもものすごい簡単。HTMLを見たら、なんかそのアップロードしたパスワードファイルの名前をフォームのhiddenで渡しているみたい。だから、そのパスワードファイルのURLをブラウザに入力すれば、パスワードが表示される。
level4 - 開発者サムは忘れっぽいので、パスワードもすぐに忘れてしまう。だから、忘れても大丈夫なように自分のメールアドレスにだけ送信してくれるパスワード取得ボタンを作成したようだ。それでこの脆弱性をつくのが今回の問題。といってもHTMLを見れば、パスワード送信先のメールアドレスがフォームから渡されているのが分かる。だからここを自分のメールアドレスに変更したデータを送ってやればOK。方法はいろいろあるが、IEなら、アドレスバーで利用できるJavascriptで「javascript:void(document.forms[1].to.value="test@test.com");void(document.forms[1].submit());」という感じが一番手っ取り早い。
level5 - level4とかなり似ているが、少し改良が加えられており、Referrerでも識別するようになっている。なので、他のページからフォーム情報を投稿することはできないようになっているが、アドレスバーで利用できるjavascriptは普通に通過できため、この手法でlevel5も攻略可能。
いよいよレベル6ですが、WEB系の開発者なら多分問題なく進めます。というか、このくらいは簡単に解いてもらわないと、WEB系アプリのセキュリティホールが多発することになりそう…(^^;。というわけで、後半戦スタート!
level6 - 開発者サムはついに暗号化スクリプトを作成したらしい。それで、その暗号化スクリプトは「平文→暗号文」の変換プログラムは公開されている。そして、パスワードを暗号化したものが「6e5gjf>l」であることが分かっている。これで、変換プログラムを利用して暗号化アルゴリズムを特定し、パスワードを調べろ、とのこと。アルゴリズム自体はとても簡単。何度か変換プログラムを利用してみるとアルゴリズムが見えてくる。とりあえず「aaaaaa」や「11223344」などをやってみると良い。
level7 - やっと少しハッキングっぽい内容(笑)。とりあえず、calコマンドを実行してくれる入力ボックスが存在する。そして、開発者サムは、次のレベルへのパスワードが書かれてあるファイルを、同じディレクトリ内に「よく分からないあいまいな(bscurely)」名前で保存している。どうやら入力ボックスからはcalコマンドの引数を入れられるらしいが、こんなあからさまなターゲットは他にはない。calコマンドと同時に実行させたいプログラムはもちろんlsコマンドなので、それぞれのコマンドを「;」で区切れば、そのままファイル一覧が取得できる。すると「k1kh31b1n55h.php」というよく分からないファイルがあるので、それにアクセスするとパスワードゲット。
level8 - 次はサムの娘のステファニーが作った、ファイル操作プログラムの脆弱性を利用する問題。今回の題材はSSI(.shtml)。よってSSIの知識が必要になってくる。SSIでいったいどういったことが可能になるのかというと、http://www.openspc2.org/reibun/SSI/←こういうことができるようだ。このページを読んでいくと、「exec cmd」で任意のコマンドを実行させることができるようだ。というわけで、試しに「<!--#exec cmd="ls" -->」を送ってみるとtmpディレクトリ内のファイルが列挙できる。それで、肝心のパスワードファイルはどこにあるのかというと、tmpディレクトリよりひとつ下のディレクトリに存在することが問題文に書かれてある。よって「ls ../」をコマンドとして送ってやれば、パスワードファイル「au12ha39vc.php」が見える。これにアクセスして見事パスワードゲット。
level9 - 今回はかなりlevel8と似ており、とても簡単な問題。level8の動作を理解していれば数秒でクリアできる。level8の脆弱性を利用して取得できるのは、level8のパスワードだけか? もちろん違う。任意のコードを実行できるというのなら、level9のパスワードだって可能。level9のパスワードファイルは「/var/www/hackthissite.org/html/missions/basic/9/」に存在することが問題文に書かれてあるので、そこに移動してlsコマンドを実行するようなものを「exec cmd」へ渡せばよい。するとlevel9のディレクトリ以下に「p91e283zc3.php」が見えるので、それにアクセスしてパスワードゲット。
level10 - いよいよ最終レベル。cookieの問題。どうやら最終レベルのスクリプトは、cookieを取得して、そのデータから閲覧の許可、非許可を出すスクリプトらしい。とりあえず適当なパスワードを入力して試してみると、「You are not authorized to view this page」(あんたこのページを見る許可がないよ)と怒られてしまう。そして、その状態でブラウザが持っているcookieを調べると「level11_authorized=no」というcookieがwww.hackthissite.orgからブラウザに与えられているのが分かる。つまり、この「level11_authorized=no」を「level11_authorized=yes」に変更して、このページへアクセスすればよいというわけだ。この問題、攻略方法はいろいろあるが、IEならば、level5で使用したテクニックを使うことができる。アドレスバーでのjavascriptでクッキー情報を書き換えて、このページをリロードするだけでよい。また、cookieファイルを直接いじってもよいだろう。ブラウザによってはcookieを直接変更する機能を持っているものもあるかもしれないので、その場合はその機能を利用してもよいし、その気になれば、cookieを変更したデータを送信するクライアントプログラムをCなりPerlなりで自作してもよい(これは実際にlevel5で私がやろうとしたことだが…)。無事攻略できたら「Congratulations, you have successfully completed every basic level!」というテキストが表示される(これだけですか…(汗))。そんなこんなでBasic Webの攻略は終了。お疲れ様でした。
Uncle Arnold's Local Band Review
http://www.hackthissite.org/missions/playlevel/1/ (依頼)
http://www.hackthissite.org/missions/realistic/1/ (ターゲットサイト)
バンドのレビューサイトのハッキング。投票数によってランキングが作成されており、「Imposing Republic」というバンドが1位となっている。そして、依頼主の好きなバンドは最下位の「Raging Inferno」。フォームから頑張って投票しようにも、最大で5までしか投票できないため、1位にさせることは難しい。よって依頼主の依頼は、この「Raging Inferno」というバンドをどうにかして1位に仕立て上げてほしいとのこと。とりあえずこのWEBページのHTMLを調べると、投票用のフォームデータがPOSTで渡されていないのが分かる。
<form action="vote.php"> <input type="hidden" name="PHPSESSID" value="********" /> <input type="hidden" name="id" value="5"> <select name="vote"> <option value=1>1 <option value=2>2 <option value=3>3 <option value=4>4 <option value=5>5 </select> <input type="submit" value="vote!"></form>
見ての通り、GETでフォームデータが渡されていることが分かるので、つまり仮に投票数5で投票した場合、「vote.php?PHPSESSID=********&id=0&vote=5」というような感じで、.phpファイルへデータが渡されることが推測できる。よって、投票数(vote)の部分を「99」などに変更してアクセスしてみると、無事攻略完了となる。Perl(PHP)とHTMLの知識を持っていれば、簡単に攻略することができる。
Peace Poetry: HACKED
http://www.hackthissite.org/missions/playlevel/3/ (依頼)
http://www.hackthissite.org/missions/realistic/3/ (ターゲットサイト)
どこかのハッキンググループに、自分のサイトのトップページを書き換えられて困っている依頼者。よって、そのハッキンググループと同じ手法を使って、トップページを元に戻してほしいというのが今回の問題。これは気づかないとちょっと難しいかもしれないのだが、HTML見ると、一番最後の行に「Note to the webmaster This website has been hacked, but not totally destroyed. The old website is still up. I simply copied the old index.html file to oldindex.html and remade this one. Sorry about the inconvenience.」というコメントアウトされている一文が見つかる。これによって、元々のindex.htmlは、現在はoldindex.htmlというファイルで保存されていることが分かる。よって、oldindex.htmlへアクセスする。すると、依頼者のサイトのトップページ(ハックされる前のトップページ)を閲覧することができる。
さて、このページの脆弱性を利用して、index.htmlを元々のoldindex.htmlに戻すわけだが、注目すべきなのは、readpoem.phpとsubmitpoems.phpの2つ。submitpoems.phpはユーザが気に入った詩を投稿できるシステムで、サーバ側にファイルが保存される。一方readpoem.phpはサーバに保存されたファイルを閲覧することができるシステムだ。というわけで、どうにかして、「submitpoems.php」を使ってindex.htmlを書き換えることができないか、ということ。
まぁここまで分かればあとは簡単。ファイル名を「index.html」として、oldindex.htmlのHTMLデータを投稿すればよいだけ。ただし、これだけだとなぜか失敗する。ここでちょっとしたひらめきが必要となる。投稿される詩のファイルとindex.htmlファイルは同じディレクトリには存在しないのではないか? これを推測できれば勝ち。投稿するファイル名を「../index.html」として攻略完了。
Chicago American Nazi Party
http://www.hackthissite.org/missions/playlevel/2/
http://www.hackthissite.org/missions/realistic/2/
今度は人種差別を推奨するグループのサイトのハッキング。まずは、HTMLを調べる。すると、一番下に
<a href="update.php"><font color="#000000">update</font></a>
という一行があるので、ここ(update.php)にアクセス。するとログイン画面が表示される。このログイン画面は一見普通で何も問題ないように思えるけれど、実はSQL injection攻撃が可能。というわけで、送信フォームから適当に「' or 'a'='a」という感じのデータを送ってやればOK。SQL injectionの仕組みを知っていればかなり容易な問題だけれど、知らないならば、まず解けない。ちなみに私もSQL injectionについては基本的なことしか知らなかったりする(笑)。
ToxiCo Industrial Chemicals
http://www.hackthissite.org/missions/playlevel/6/
http://www.hackthissite.org/missions/realistic/6/
今回は暗号解読に関する問題。こういう解読系の問題は、知識よりもむしろ数学的な能力の方が必要かもしれない。「.296.294.255.268.313.278.311.270.290. (省略) 282.268.320.287.320.270」という暗号文があり、これを解読することが今回の問題。これだけの情報で「さあ、解け!」と言われるとかなり難しいのだが、ちゃんと暗号化に使用したスクリプト(encryption.php)も公開されているので問題ない。
というわけで、さっそく暗号化アルゴリズムを解読していく。まず「テキスト『A』」、「パスワード『』(未入力)」で暗号化を施すと、暗号文は「.1.35.29」となった。つまり、「A」=「.1.35.29」ということだが、もう一度同じ値(「テキスト『A』」、「パスワード『』(未入力)」)で試すと、今度は「.45.-3.23」となった。つまり、同じ平文なのに、暗号文は変化するアルゴリズムであることが分かる。こういう場合、2つの暗号文の共通点を探すことが解決の糸口となる場合が多い。「.1.35.29」と「.45.-3.23」の共通点。それは、加算するとどちらも「65」になるということ。「1 + 35 + 29 = 65」、「45 + (-3) + 23 = 65」。そして、「A」のASCIIコードは0x41(65)。簡単だ。
次にパスワードの動作を見てみる。「テキスト『A』」、「パスワード『B』」で暗号化を施すと、「.16.31.84」となる。つまり「16 + 31 + 84 = 131」。「A」は65のはずなのに、131になっている。では、次は「テキスト『A』」、「パスワード『C』」で暗号化を施す。すると「.63.63.6」。つまり「63 + 63 + 6 = 132」。パスワードを「B」から「C」へ変更することで、「A」の暗号文が「131」から「132」になった。
これらから言えることは、「A(65) + B(66) = 131」、「A(65) + C(67) = 132」ということ。つまり、パスワードに入力したデータは、平文のそれぞれ1文字に加算される。では、パスワードを2文字以上にしたらどうだろうか。試しに「テキスト『A』」、「パスワード『BB』」とすると、「.87.35.75」。「87 + 35 + 75 = 197」。「197 - A(65) = 132」。「132 = B(66) + B(66)」。ということは、パスワードが複数の場合は、それらの値がすべて平文に加算されることになる。なんともややこしいアルゴリズムだが、一応これで解読プログラムは作成できる。
http://ruffnex.oc.to/kenji/src/decrypt.cpp
VC++.NETでコンパイル確認。行き当たりばったりで書いたのでソースコードは結構適当だったりします。このプログラムを実行して作成されたtest.txtを読んでいくと、復号化されたテキストがパスワードの合計値762のところで見つかる。これで無事解読完了。解読できたテキストを依頼主に送れば、無事この問題解決となる。
久しぶりの「Hack This Site!攻略」です。最近、忙しさのあまりすっかり忘れていましたが、暇なときにこつこつと、やっていくことにします。
What's Right For America
http://www.hackthissite.org/missions/playlevel/7/
http://www.hackthissite.org/missions/realistic/7/
今回のターゲットはここ。まず最初に注意すべきなのはshowimages.phpというスクリプトが使われていること。このスクリプトは、どうやら、アドレスのクエリ(?以降の文字列)にファイル名を渡して、そのファイルを整形して表示しているらしいことが分かる。そして、表示されている画像が置かれているフォルダ。つまり、images(/missions/realistic/7/images/)フォルダだが、このフォルダは直接アクセスすることで内容が分かるようになっている。それで、直接アクセスすると、adminというディレクトリが存在しているのが分かる。どうやら、この中に重要なデータが入ってそうだが、残念ながら、このディレクトリにはパスワード制限がかけられている。というわけで、このパスワード制限を突破するのが、今回の課題となる。
まず、利用すべきなのはshowimages.phpスクリプト。これを使えばadminディレクトリの中を見れそうだが、いったい何のファイルを見るのか。それはもちろん、.htaccessファイルだろう。adminディレクトリのアクセス制限は、.htaccessファイルが行っていると仮定して、そのファイルをのぞくことにする。つまり「/missions/realistic/7/showimages.php?file=images/admin/.htaccess」という感じでアクセスする。すると以下のようなテキストがHTMLに出力される。
<center><a href="AuthName "Administration Access> <img src="AuthName "Administration Access width=100></a> <a href="AuthType Basic"> <img src="AuthType Basic" width=100></a> <a href="AuthUserFile /var/www/hackthissite.org/ html/missions/realistic/7/images/admin/.htpasswd"> <img src="AuthUserFile /var/www/hackthissite.org/ html/missions/realistic/7/images/admin/.htpasswd" width=100></a> <a href="require valid-user"> <img src="require valid-user" width=100></a> <a href=""><img src="" width=100></a> </center></font> </td></tr></table>
どうやら.htaccessファイルが整形されて表示されたようだ。というわけで、これをよく読んでみると、.htpasswdファイルが存在することが分かる。なので「/missions/realistic/7/showimages.php?file=images/admin/.htpasswd」にアクセス。すると、「administrator:aH0qcQOVz7e0s」というデータが得られる。これで、とりあえずハッキングは終了。
ただし、.htpasswdファイルに書かれてあるパスワードはcrypt関数で暗号化されてあるので、このまま入力しても認証は突破できない。本当のパスワードを得るためには、これをパスワードクラックしなければならない。
crypt関数の暗号化アルゴリズムについては興味がある方は「crypt() アルゴリズム解析」(http://ruffnex.oc.to/kenji/xrea/crypt.txt)を参照してもらいたいが、これを知らなくても、PerlやC言語でcrypt関数を使えれば簡単にクラック可能。これで、無事、攻略完了となる。