level12
- 소스코드의 11 행에서 gets 함수를 사용하므로 길이체크를 하지않아 Buffer Overflow 취약점이 발생한다.
- str 배열의 길이가 (256 + 8) 이며 sfp 사이즈(4바이트)를 더한 268바이트를 payload 로 전송하게되면 RET 값을 변조할 수 있다.
- aslr 보호기법으로 인해 str 배열에 shellcode 를 삽입할 수 없어서 환경변수에 삽입하고 RET 주소에 쉘코드가 포함된 환경변수의 주소로 변조함으로써 결론적으로 프로그램의 흐름을 제어하고 level13(3093) 권한의 쉘을 획득하였다.
1. #include <stdio.h>
2. #include <stdlib.h>
3. #include <unistd.h>
4.
5. int main( void )
6. {
7. char str[256];
8.
9. setreuid( 3093, 3093 );
10. printf( "문장을 입력하세요.\n" );
11. gets( str );
12. printf( "%s\n", str );
13. }
14.
15.
- FTZ LEVEL11 와 동일하게 소스코드를 통해 프로그램의 흐름을 대략적으로 파악(정적분석)한 뒤 프로그램을 실행(동적분석) 시켜보며 분석 할 것이다.
- setuid 가 설정되어 있으면 gdb 가 동작하지 않기 떄문에 tmp 디렉토리에 cp 명령을 이용하여 복사한다.
- attackme 소스코드를 보면 FTZ LEVEL11 과 거의 동일하며 strcpy 함수 대신 gets 함수를 사용한다는 차이점이 있다.
- 또한, FTZ LEVEL11 에서는 FSB(Format String Bug) 취약점이 있었지만 FTZ LEVEL12 에서는 Format String이 명시되어 있다.
- gets 함수도 strcpy 함수와 동일하게 길이 값을 체크하지 않아 Buffer Overflow 취약점이 발생한다.
- gdb 에 attackme 프로그램을 올린 뒤, disassemble main(disas main 가능) 명령을 통해 main 함수(Entry Point, EP) 를 disassemble 하고, ret(main+88) 에 BreakPoint(BP) 를 건다.
- FTZ LEVEL11 에서는 argv[1] 을 사용하여 인자를 받았지만, LEVEL12 에서는 gets 함수를 사용하기 때문에 입출력 리다이렉션 연산자("<" or ">") 를 이용하여 인자를 넘겨야 한다.
- 필자는 파이썬을 이용해 출력을 payload 파일에 저장했다.
- 왜냐하면, gdb 에서도 입출력 연산자의 사용이 가능하기 때문에 paylaod 를 다시 작성하는 반복작업을 최소화하기 위해 사용했다.
- payload 는 FTZ LEVEL11 와 동일하게 str 변수가 256 바이트니까 268바이트를 덮으면 ret 주소가 나올것이라 가정하고 A * 268 과 B * 4 를 출력했다.
- 예상한것과 같이 ret 주소 위치에 BBBB 로 덮혀있다. 이제 페이로드만 작성하면 되지만 FTZ LEVEL11 와 동일하게 aslr 이 걸려있으므로 환경변수에 쉘코드를 올리고 ret 주소를 쉘코드가 위치한 환경변수 주소로 덮어쓰면 된다.
- 또한, bash 에서 주소값 \xff 를 쓰면 \xff (null) 로 바뀌는 버그가 있어서 bash2 프로세스에서 작업을 진행했다.
1. #include <stdio.h>
2.
3. int main(int argc, char *argv[]) {
4. printf("Addr : %p\n", getenv(argv[1]));
5. return 0;
6. }
7.
8.
- 위 프로그램은 필자가 등록한 쉘코드의 환경변수 위치를 찾아주는 프로그램이다.
- gdb 를 이용해 확인해보면 \x90(NOP) + ShellCode 가 위치한것을 알 수 있다.
python -c 'print "A"*268 + "\x1f\xfc\xff\xbf"' > payload
(cat payload;cat) | ./attackme
- ;cat 을 붙이는 이유는 gets 함수의 인자를 stdin으로 입력한 것들을 pipe 를 통해 넘겨줄때 EOF 가 붙기 때문이다.
- 즉, exploit 을 정상적으로 작성해서 shell 을 실행시키더라도 EOF 를 만나 종료되어 버린다.
- 따라서 cat 이나 echo 등을 이용할때 뒤에 ;cat 을 붙이면 cat 의 작동이 끝나기 전까지 EOF 가 나오지 않는다.