-
[HackCTF] Register Write-up표튜터와 함께하는 Pwnable/HackCTF Write-up 2019. 5. 26. 20:07
이번에 풀어볼 문제는 64bit에서 진행되는 Register이다.
또하나 교훈을 얻게되는 문제였다!!
* Thanks to Py0zz1 *
이 문제도 역시 NX와 Partial RELRO를 가지고 있다.
그러므로 stack, heap, .data 영역에 실행권한이 없으면서
Got Overwrite가 가능하다는 것을 알 수 있다.
문제를 실행시켜보도록 하겠다.
RAX, RDI... 등의 register에 값을 입력하는 것으로 보이는
Code가 보여진다. 또한 한 바퀴를 돌고나니까
다시 RAX부터 register 값을 입력받고 있었다.
이번에는 IDA를 이용하여 코드를 보도록 하자!!
< main >
main 함수의 경우 5초의 alarm 함수가 진행되었으며
build 함수를 호출하고 있는 것을 알 수 있었다.
< build >
build 함수의 경우 signal 함수가 호출되었으며
시그널 번호는 14번이며 이 14번 시그널을
handler(신호 핸들러)에서 처리하도록 되어있었다. 14번 시그널은
SIGALRM으로 알람에 의해 발생되는 시그널이다.
쉽게 말해서 14번 시그널 SIGARLM이 발생하면
신호핸들러인 handler가 동작한다는 의미이다.
< handler >
handler는 다시 exec_syscall_obj를 호출하고 있었으며
그러므로 main에 있는 알람 함수가 동작하면서 5초 뒤에
14번 시그널이 발생될 것이고 그 말은 즉, 5초 뒤에
handler가 동작하여 exec_syscall_obj가 진행된다는 의미가 된다.
< exec_syscall_obj >
이 함수에서는 syscall을 호출하고 있었다.
또한 build 함수에서는 get_obj를 호출하고 있었는데
< get_obj >
아까 우리가 보았던 register 이름들이 출력되었고
get_ll를 호출하고 있는 것으로 보아 입력을 받는 부분이 있을 것이다.
< get_ll >
해당 함수에는 get_inp가 호출되었고 인자로 넘겨진
nptr을 atol함수를 이용하여 문자열을 long형 정수로 바꿔주고 있었다.
< get_inp >
마지막으로 get_inp를 보니 역시 예상했던대로 입력을 받고 있었다.
다시 build를 보면 while문의 조건으로 validate_syscall_obj가 있고
종결조건인 validate_syscall_obj의 리턴값이 거짓이면 raise함수가
14번 시그널을 실행 중인 프로그램에게 보내게된다. 그러므로
프로그램이 시작되고 5초 후에 alarm 함수로 인해 14번 시그널이
발생되고 syscall을 진행할 수 있게되며 다음 while문이 진행될 때
validate_syscall_obj가 거짓이 되면 다시 raise 함수로 인해
14번 시그널이 발생하게되는 로직이다. 이 점을 잘 이용해야한다.
< validate_syscall_obj >
build 함수의 모습을 어셈블리어 코드로 보게되면
validate_syscall_obj 함수의 실행 다음을 보면 jne로 비교해서
다르면 build+155로 jmp한다. 만약 같아서 다음으로 넘어가면 raise를
호출하게되고 build+38로 jmp해서 다시 입력을 받는다. 만약 위에서 처럼
달라서 build+155로 뛰더라도 다시 build+156에서 jmp를 만나서
build + 38로 뛰게되어있다. 결국 계속 입력을 받는다는 의미이다..
차이점은 raise 함수를 실행하냐 마느냐 이다.
test eax, eax의 의미는 함수의 return값이 저장되는 eax를
비교하여 그 값이 0인지 아닌지를 확인하는 것이다.
test는 두 값을 AND 연산하며 연산결과를 따로 저장하지 않는다.
대신 FLAG Register에 그 흔적을 남기게 된다. 값이 0인경우 ZF = 1이 된다.
참고 : https://p3ace.tistory.com/41
그렇다면 여기까지 진행했을 때 이 문제는 특정 메모리 leak을
할 필요가 없이 64bit syscall table을 보고 우리가 필요한 함수들을
syscall 해주면 될 것임을 알 수 있다. 그러면 간단하게 풀 수 있다.
Payload는 다음과 같이 구성하게 된다.
read 함수를 호출하기 위해 rax, rdi를 0으로 진행하고
고정주소영역의 버퍼를 rsi값으로 준다. 우리는 고정주소영역에
"/bin/sh\x00"을 저장할 것이기 때문에 rdx로 "/bin/sh\x00"의 길이
8을 줄 것이다. 그 다음으로는 "/bin/sh"을 실행하기위해 execute 함수를
호출할 것이다. 그러므로 rax는 59, rdi는 "/bin/sh\x00"이 저장된
고정주소 영역 나머지는 Null로 채워주면 쉘이 따질 것이다.
나는 고정주소 영역으로 .data영역을 사용하였다.
< Payload >
주의할 점은 해당 Payload대로 Syscall을 하기전에
alarm 함수를 유의해야한다. 5초 이후에 알람 시그널(14)를
전송하기 때문에 Syscall이 일어나려면 시간을 잘 맞춰주어야한다.
나는 시간을 맞춰주기위해서 sleep(3)을 사용하였다.
* 또한 이렇게 반복되는 Payload의 경우 가독성을 위해 함수화하자 *
위의 Payload대로 진행을 하게되면~
짜잔~ FLAG를 볼 수 있었다!! 문제를 풀 때는 항상 함수들을 꼼꼼히 보도록하자!!
참고 : https://www.ibm.com/support/knowledgecenter/ko/ssw_ibm_i_73/rtref/raise.htm
http://forum.falinux.com/zbxe/index.php?document_srl=413254&mid=C_LIB
반응형'표튜터와 함께하는 Pwnable > HackCTF Write-up' 카테고리의 다른 글
[HackCTF] Basic_FSB Write-up (0) 2019.06.11 [HackCTF] World Best Encryption Tool Write-up (0) 2019.06.10 [HackCTF] Yes or no Write-up (2) 2019.05.26 [HackCTF] RTC Write-up (1) 2019.05.10 [HackCTF] SysROP Write-up (0) 2019.05.07 댓글