문제분석 & 풀이
코드 분석
1. printit() : 출력문 출력
2. crap, *call, buf[] 선언
3. call에 printit()의 주소를 넣는다.
4. fgets()로 사용자에게 48바이트만큼 입력값을 받는다.
5. setreuid()로 level18의 권한으로 변경
6. call()을 실행함으로써 printit() 실행
이전 문제와 유사한 코드이다. 하지만 셸을 실행하는 함수인 shell()이 존재하지 않는다.
따라서 level16과 같은 방식으로는 문제를 해결 할 수 없다.
그렇다면 어떻게 해결 할 수 있을까?
RTL 공격기법을 이용하면 해결 할 수 있다. RTL을 활용하기 위해서는 system(), "/bin/sh" 등의 주소를 구해야하는 번거로움이 있다.
더 쉽게 풀기 위해서 번거로운 작업을 한 번에 해결할 수 있는 다른 방법이 있다.
eggshell을 이용하는 방법이다. (eggshell 관련해서는 아래 링크의 level11, level12번 글을 참고하면 도움이 될 것이다!)
2022.01.21 - [Wargame/ftz] - [ftz] level11 (Buffer Overflow)
eggshell을 이용하면 환경변수 영역에 셸코드가 적재되고 그 주소를 출력해준다.
그 주소를 call 영역에 덮어씌우면 call() 실행 시, 셸코드가 실행되어 level18의 셸을 얻어낼 수 있다.
스택 구조 분석을 위해 attackme를 복사해서 GDB로 분석했다.
level16와 똑같이 0x38(56)바이트 만큼의 공간을 할당하고 있으며, call의 위치는 [ebp-16]이다.
스택 구조가 이전 문제와 동일하다.
위 내용대로 페이로드를 미리 구성하면 다음과 같다.
"A"*40+[셸코드 주소]
셸코드를 적재하고 주소를 구하면 페이로드를 완성 할 수 있다.
eggshell을 이용하여 셸코드를 적재하고 주소를 구했다.
셸코드 주소는 0xbffff2c2이다.
셸코드 주소를 구했으니 페이로드를 완성해보자.
"A"*40+"\xc2\xf2\xff\xbf"
(python -c 'print "A"*40+"\xc2\xf2\xff\xbf"';cat) | ./attackme
완성한 페이로드를 그대로 실행해보자.