문제의 힌트를 보면 바로 소스코드를 보여준다. char형 배열을 두개 선언해주고, 40크기의 문자열을 표준 입력(키보드)로부터 입력받는다.
이때 배열은 둘 다 10바이트인데 40바이트를 입력받으니, buf에 입력을 받아도 버퍼 오버플로우를 이용하여 buf2의 값을 임의로 수정할 수 있을 것이라 생각된다.
if문을 살펴보면, go와 buf2의 문자열을 앞 2글자만 비교하는데 즉 buf2에 go라는 문자열을 입력시키면 if문 안으로 진입할 수 있다. if문 안에서는 uid를 3010(level10의 권한)으로 변경시킨 상태에서 bash쉘을 띄운다. 즉, if문 안으로 들어가기만 하면 level10의 권한으로 쉘을 실행할 수 있는 것.
/usr/bin/bof 파일은 디버거를 할 수 없으므로, 동일 코드를 level9/tmp에 작성하기로 한다.
>를 이용하여 비교적 편하게 코드를 옮겨 적었다.
gcc로 컴파일을 하고, gdb로 디버깅을 실행한다.
set disassembly-flavor intel : intel 식으로 어셈블리 출력
disas main : main 함수부분 디스어셈블하여 출력
우리가 살펴봐야 할 부분은 다음과 같다.
1. fgets(buf, 40, stdin);
2. strncmp(buf2, "go", 2);
함수를 호출할 때, 인자는 오른쪽에서부터 스택에 쌓인다. 그렇기 때문에 fgets()의 경우, stdin, 40, buf의 순으로 스택에 들어오게 된다.
디스어셈블 된 코드에서 main+41을 확인하면 다음과 같이 40이 스택에 들어간 것을 알 수 있다. 그렇기 때문에 그 다음 줄인 main+43에 있는 ebp-40이 buf의 주소가 될 것이다.
이번에는 strncmp를 살펴보자. main+58을 보면, 2가 스택에 들어간 것을 알 수 있다. 그렇기에 순차적으로 들어간다면, main+65에 있는 ebp-24가 buf2의 주소가 된다.
buf와 buf2의 정확한 주소는 모르지만, 대략적으로 다음과 같이 스택에 저장되어있다는 것은 알 수 있다. 두 배열 간 거리는 16바이트이다.
buf2에 "go"를 입력하기 위해서는 buf에 16바이트를 입력하고, 17바이트째부터 "go"를 입력해야 한다. 정확하게 입력하기 위해 파이썬 스크립트를 사용하기로 한다.
(python -c 'print "A"*16 + "go"'; cat) | /usr/bin/bof
간단히, A를 16번 나열하고 그 끝에 "go"를 붙인 문자열을 출력하고 이어서 해당 명령으로 인한 결과를 출력한다. (;cat의 역할) 그리고 |(파이프)를 통해 이 입력을 /usr/bin/bof라는 파일을 실행시키고 나서 넘긴다.
실행을 하면 다음과 같이 배쉬 쉘이 뜨고, level10권한으로 쉘이 돌아가는 것을 확인할 수 있다. 항상 그렇듯, my-pass 명령어로 패스워드를 확인하면 된다.
'Write-Up > FTZ' 카테고리의 다른 글
FTZ: Level11 (0) | 2019.11.13 |
---|---|
FTZ: Level 10 - writeup 수정중 (해결완료) (0) | 2019.11.12 |
FTZ: Level 8 (0) | 2019.09.26 |
FTZ: Level 7 (0) | 2019.09.26 |
FTZ: Level6 (0) | 2019.09.26 |