wargame/dreamhack

[시스템 해킹] Return Address Overwrite 문제 풀이

seungwon9201 2024. 10. 31. 13:28

다운로드 받은 문제파일에서 rao.c의 코드를 vi 명령어로 확인해 보자.

rao.c

여기서 주목해서 봐야 할 부분은 buf 부분과 scanf부분이다. 

버퍼는 [0x28]만큼 제한하고 있지만 인풋값을 받아서 출력하는 scanf함수는 버퍼의 양만큼 따로 제한하지 않았다. 

여기서 버퍼 오버플로우가 가능하다는 점을 파악할 수 있다. 

또한 get_shell로 쉘 코드를 실행시킬 수 있다는 점까지 확인 가능하다

 

실제로 코드를 실행하고 입력값을 넣은 결과 버퍼의 크기만큼 벗어난 값을 넣어준다면 이렇게  에러가 발생하게 된다.

 

즉, flag를 얻기 위해선 버퍼오버플로우를 이용하여 에러메시지가 발생하는 것을 get_shell함수가 실행하는 것으로 바꿔야 한다. 다시 말해, 리턴값의 주소를 get_shell의 주소로 바꿔줘야 한다. 

 

그럼 get_shell의 주소를 알아야 한다.

get_shell의 주소 : 0x4006aa

gdb를 사용하여 get_shell의 주소를 파악해 보자. 

 

자 그럼 get_shell의 주소도 확인했으니 버퍼 오버플로우를 발생시키고 그것의 리턴주소를 0x4006aa로 바꿔주면 flag값이 나올 것이다. 

 

단, 버퍼의 크기(0x28, 40바이트)만 넘겨서 공격을 해선 안된다.

 

버퍼의 크기만 채우면 그냥 버퍼의 범위를 벗어났을 뿐이지 프로그램의 실행에 영향을 주진 못한다. 즉, 리턴 주소를 바꿔서 프로그램의 실행에 영향을 줘야 한다. 또한 버퍼 뒤에 있는 rbp와 리턴 주소를 덮어쓰지 않으면 프로그램은 원래 설정된 주소로 돌아가게 된다. 

 

정리하자면 버퍼와 그 뒤에 있는 rbp와 리턴 주소를 덮을 만한 페이로드를 만들어야 한다. 

 

그럼 gdb를 사용해서 확인해 보자.

여기서 sub rsp, 0x30에서 보이듯이 버퍼의 크기는 48바이트라는 걸 확인할 수 있고, push rbp를 통해서 rbp가 8바이트 크기로 저장된다.

즉, 48 + 8바이트를 채워야 리턴주소에 도달하여 프로그램의 흐름을 바꿀 수 있다.

 

그럼 pwntools로 코드를 만들어보자. 

이렇게 코드를 짜주면

이렇게 flag값을 얻을 수 있다.