Yes or no 문제를 해결해보겠다.
이번에 주어지는 파일은 zip 파일이다. 파일이 한 개가 아닌가 보다.
우선 checksec부터 해보자.
쉘 코드만 사용하지 못하도록 되어 있다.
다음, 바이너리를 까 보자.
보니 main함수에서 gets함수를 실행시키는 것이 목표인 듯하다. 그렇다면 gdb로 디버깅하면서 34번째 줄의 if문을 만족하도록 v10값을 찾으면 문제를 풀 수 있을 것이다.
main+237줄에서 gets를 호출할 수 있도록 하는 조건인 cmp가 있는 것을 알 수 있다.
따라서 저 부분에 break를 걸고 v10에 임의의 값을 집어넣어 run을 해보겠다.
이 바이너리는 64bit 기반이므로 rax값은 곧 eax값이다. 여기서 [rbp-0x8]에 들어있는 값과 eax의 값을 비교하므로 입력해야 하는 값은 eax 값인 0x960000이다. 10진수로 넣어야 하므로 0x960000=9830400 (10)을 입력하면 gets함수를 호출할 수 있다.
gets 함수가 실행되면서 입력을 받도록 되어 있다. 자, 이제 풀이 방법을 떠올려보자.
우선 기본적으로 RTL을 생각해볼 수 있다. ASLR도 안 걸려 있고 NX bit만 걸려 있어서 더욱 확신했다.
제일 만만한 got는 printf의 got이므로 got에 들어 있는 printf의 실제 주소를 system함수의 주소로 바꾼 다음, "/bin/sh"문자열이 있는 위치를 찾으면 될 것이다.
기본 gdb에서 `find &system,+99999999, "/bin/sh"`라고 입력하면 "/bin/sh"의 주소가 나온다.
저 주소를 기억해두자.
system 함수의 주소는 이렇게 찾으면 된다.
system : 0x7ffff7a52390
binsh : 0x7ffff7b99d57
64bit payload를 위한 gadget도 찾아주었다. system을 호출하기 위해서는 pop rdi ; ret 가젯이 필요하므로 0x400883을 가져오겠다.
자 그럼 이제 페이로드를 작성해보자. 구성은 s (18byte) + SFP(8byte) + p64(pop rdi)+p64(binsh)+p64(system) 이다.
exploit code를 간단히 적어보았다.
실행시켜보면....!
어? 왜 flag가 안 따이지? 이상하다......ㅠ
깊은 고민을 하였는데, 내가 가장 기본적인 실수를 하고 있었다. 바로 libc의 base 주소는 remote 서버 프로그램이 실행될 때마다 바뀐다는 것을.....
따라서 내가 구한 system과 binsh 주소는 로컬에서만 동작하며, remote에서는 이것을 동적으로 찾아줘야 한다.
지금까지 ROP나 memory leak 문제를 어려워하였고, 함수 호출 규약에 대해 잘 몰랐기 때문에 발생하는 문제였다.
나의 블로그의 Hacking/Pwnable 주제에 쉽게 오해할 만한 것들을 한번 정리해서 실수를 바로잡을 것이다.
독자분들은 Pwnable을 공부하실 때 32bit, 64bit 함수 호출 규약과 레지스터에 대해 꼭 자세히 공부하시길 바란다.
내가 직접 작성하는 Write-up이 필요한 이유가 바로 이런 오해와 진실을 바로잡기 위해서이고, 공부하는 분들에게 조금이나마 도움이 되었으면 좋겠기 때문이다.
아무튼, 다시 문제를 풀어보자.
--------------------------------------------------------------------------------------------------------
1. Memory leak을 통한 exploit
gets함수를 호출하기 위해 9830400을 입력하고 puts의 주소와 libc_base와의 offset을 구해 직접 libc_base를 구한다.
1. puts 주소 구하기 -> puts의 offset 구하기 -> puts 주소에서 offset을 빼 libc_base를 구하기
그 다음, system과 binsh의 offset을 구한다. libc_base에 더해 실제 주소를 가져오기 위함이다.
2. system과 binsh offset 구하기 -> libc_base에 각각의 offset 더해 system과 binsh 실제 주소 구하기
그럼, payload를 구성해보자. puts는 인자가 하나이므로 pop rdi를 gadget으로 사용하면 된다.
system과 binsh의 offset은 pwntools로 구해도 되지만, libc-database를 사용하여 직접 구하였다.
처음 STEP 1으로 1번과 2번 계획을 완수하고, main을 다시 호출한 다음, STEP 2로 system("/bin/sh")을 호출하였다.
exploit code는 다음과 같다.
제발....돼라....!!!!
flag가 출력되었다!!!!!!
'Hacking > HackCTF' 카테고리의 다른 글
HackCTF g++ pwn Write-up (0) | 2020.01.07 |
---|---|
HackCTF RTL_World Write-up (0) | 2020.01.06 |
HackCTF BOF_PIE Write-up (0) | 2020.01.06 |
HackCTF offset Write-up (0) | 2019.12.29 |
HackCTF Simple_Overflow_ver_2 Write-up (0) | 2019.12.23 |