info func 명령으로 함수 목록을 봤을 때 main함수 말고 별 다른 함수 목록이 안보여서 main 함수의 어셈을 보면 다음과 같다.
0x6d30(27952)만큼의 크기에 gets함수로 입력을 받고있다.
gets함수가 끝난 main+96에 bp를 걸고 값을 입력하면 파일을 실행할 때 출력하는 buf 주소와 입력한 값이 들어간 주소가 동일함을 확인할 수 있다.
따라서 입력값에 쉘코드를 넣고 (27952(buf크기) - 쉘코드 길이) + 8(RET까지 거리)만큼 입력값을 채우고 buf의 주소를 받아서 넣으면 문제를 RET에 쉘코드가 들어간 buf주소가 들어가 쉘을 딸 수 있을 것 같다. 이를 파이썬 익스코드를 작성하고 실행하면 다음과 같이 쉘을 딸 수 있다.
Hack CTF pwnable 분야 이전 문제들에 대한 롸업은 Project H4C 게시판에 있다.
파일 명령어로 확인해보면 64비트 리눅스 실행파일임을 확인할 수 있다.
파일을 실행하면 문자열을 입력받고, Hello 입력받은 문자열 의 형태로 출력하고 있다 .
checksec로 확인해보면 NX보호기법이 적용되어 있다.
info func로 함수 정보를 보면 다음과 같다.
execve 함수가 사용됨을 확인할 수 있고, main함수 말고, callMeMaybe 함수도 있는것을 확인할 수 있다.
main함수와 callMeMaybe 함수의 어셈 코드를 확인하면 다음과 같다.
main 함수에서 0x110(272)만큼의 공간을 할당하고, scanf함수로 입력을 받고 있고, callMeMaybe함수에서 execve 함수를 실행하고 있다. main함수의 입력받는 부분에서 bof를 발생시켜 callMeMaybe함수를 실행시킬 수 있을 것 같다. 입력값으로 272(buffer) + 8(SFP)를 채우고 ret에 callMeMaybe함수의 주소를 넣으면 될 것 같다.
from pwn import *
p = remote("ctf.j0n9hyun.xyz", 3004)
pay = "A"*280
pay += p64(0x0000000000400606)
p.sendline(pay)
p.interactive()
RTL은 Retuen Address 영역에 공유 라이브러리 함수의 주소로 변경해 해당 함수를 호출하는 방식이다. 이 기법을 통해 NX 보호기법을 우회할 수 있다.
공유 라이브러리는 컴파일을 할때 링커가 실행 파일에 사용할 공유 라이브러리를 표시하면 그 라이브러리에 있는 컴파일 된 코드를 가져와 사용한다. 리눅스는 기본적으로 공유 라이브러리가 있으면 그것과 링크를 시키고, 없으면 정적 라이브러리로 링크 작업을 한다.
인텔 x86 시스템, 리눅스 커널에서는 Cdecl 호출 규약을 사용한다. 이 호출 규약은 함수의 인자값을 stack에 저장하며 오른쪽에서 왼쪽 순서로 스택에 저장한다. 함수의 반환 값은 EAX 레지스터에 저장된다. 사용된 스택 정리는 해당 함수를 호출한 함수가 정리한다.
다음과 같이 스택에 저장된 vlun 함수의 인자값들을 확인할 수 있다. vlun함수 실행전인 main+35에 breakpoint를 걸고 esp를 확인했다.
vuln 함수의 어셈 코드를 보면 다음과 같다.
push ebp로 main 함수에서 사용하던 호출 프레임을 스택에 저장한다. 이전 함수에서 사용하던 호출 프레임은 ebp 레지스터에 저장되어 있다. mov ebp, esp로 vlun 함수에서 사용할 새 호출 프레임이 ebp레지스터에 초기화 된다. ebp 레지스터를 통해 main 함수에서 전달된 인자값을 사용할 수 있다.
DWORD PTR [ebp+*] 영역으로 각각의 인자값을 확인할 수 있다.
ret2libc 기법 사용시 인자값을 전달하려면 Return Address의 4바이트 뒤에 인자 값을 전달해야 한다.
다음과 같이 코드를 작성하고 컴파일 하여 Return to Shellcode를 확인할 수 있다.