올 초에 열렸던 SwampCTF 2018의 return 문제 라이트업입니다.

바이너리를 바로 열면
main()함수에서 바로 doBattle() 함수를 실행한다.
--

doBattle() 함수를 보면 buf에 50바이트를 입력는다.
하지만 buf는 ebp-38(0x26)바이트에 위치하므로 doBattle()함수의 리턴 어드레스를 덮을 수 있다.
---1

그런데 9번째 줄을 보면 ret(리턴어드레스)가 locret_8048595보다 크면 안 된다.

slayTheBeast()라는 함수가 있다.
이 함수는 flag.txt를 읽어준다.

---2

doBattle()함수에서 ret를 &slayTheBeast()로 덮으면 되는데, 이 함수의 주소가 locret_8048595보다 위에있다. 따라서 그냥 덮어 쓸 수가 없다.
slay-the-beast
(0x080485DB는 0x08048595보다 크다.)

그래서 생각해 낸 방법은 다음과 같다.
doBattle()함수 리턴어드레스 부분에 ret 명령어 코드 조각을 넣고, 그 다음에 slayTheBeast() 함수의 주소를 넣는다.
함수 에필로그의 ret는

pop eip
jmp eip

의 의미를 갖고 있기 때문에 ret 명령어를 실행하면 esp가 가르키고 있는 주소의 명령어를 실행한다.

dummy 42 byte + &ret + &slayTheBeast()
ret 명령어 주소는 0x08048372에 있는 것을 사용하도록 한다.

-retn

위에서 Hex-ray로도 확인 한 것 처럼 slayTheBeast() 함수의 주소는 0x080485db이다.
-slayTheBeast

아래는 익스플로잇이다.
ex

result