DongDD's IT

[pwnable.kr] mistake 본문

Wargame/pwnable.kr

[pwnable.kr] mistake

DongDD 2018. 6. 14. 16:46

[pwnable.kr] mistake



Problem




모든 사람들이 실수한다고 적혀있었다. 심각하게 생각하지말고 화려한 해킹 기술이 필요하지는 않다고 되어있었다.

hint로는 연산자 우선순위가 주어져있었고 ssh를 통해 접속해 확인해보았다.



먼저 ssh를 통해 접속해보니 password 파일과 mistake 실행 파일, mistake.c 소스 코드 파일과 flag 파일이 있었다.

소스 코드를 확인해보았다.


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
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <fcntl.h>
 
#define PW_LEN 10
#define XORKEY 1
 
void xor(char* s, int len){
        int i;
        for(i=0; i<len; i++){
                s[i] ^= XORKEY;
        }
}
 
int main(int argc, char* argv[]){
 
        int fd;
        if(fd=open("/home/mistake/password",O_RDONLY,0400< 0){
                printf("can't open password %d\n", fd);
                return 0;
        }
 
        printf("do not bruteforce...\n");
        sleep(time(0)%20);
 
        char pw_buf[PW_LEN+1];
        int len;
        if(!(len=read(fd,pw_buf,PW_LEN) > 0)){
                printf("read error\n");
                close(fd);
                return 0;
        }
 
        char pw_buf2[PW_LEN+1];
        printf("input password : ");
        scanf("%10s", pw_buf2);
 
        // xor your input
        xor(pw_buf2, 10);
 
        if(!strncmp(pw_buf, pw_buf2, PW_LEN)){
                printf("Password OK\n");
                system("/bin/cat flag\n");
        }
        else{
                printf("Wrong Password\n");
        }
 
        close(fd);
        return 0;
}
 
cs

먼저 main에서 open을 통해 password 파일을 열어주게 되어있었다.

그리고 설정된 fd를 통해 pw_buf에 PW_LEN 만큼 read를 해준다.

그 후에 pw_buf2를 stdin을 통해 입력을 받고 xor함수를 거친다.

xor() 함수를 거친 후 pw_buf와 pw_buf2를 PW_LEN만큼 비교 하여 같다면 "Password OK"라는 message와 함께 flag를 cat하는 system() 함수를 실행하게 된다.

xor() 함수에서는 string으로 받은 인자와 len을 이용해 len만큼 for문을 돌며 각 string 문자를 XORKEY(1)와 xor해준다.


Solution


이 문제의 hint인 연산자 우선순위를 생각해보면 쉽게 해결할 수 있는 문제이다.

연산자 우선순위를 모른다고 하더라도 프로그램을 실행해보면 문제를 어떻게 풀어야하는 지는 알 수 있게 되어있었다.



먼저 프로그램을 실행해보면 "do not bruteforce..." 이 후에 아무런 메시지도 뜨지 않는 것을 볼 수 있다.

10글자를 입력하게 되면 그 후에 "input password : "가 출력되고 이 후에 다시 입력을 받게 되는 모습을 볼 수 있다.

즉, 이것을 통해 추론할 수 있는 점은 어떠한 오류로 인해 fd가 stdin으로 설정되어 read에서 stdin으로 입력을 받고 그 이후에 다시 scanf를 통해 stdin으로 받는 다는 것이다.

그렇다면 왜 fd가 stdin(0)으로 설정되는지 확인해보았다.



기본적으로 '=' 보다는 '<'의 연산자 우선순위가 높게 설정되어 있다. 그렇기 때문에 open을 통해 불러온 file descriptor를 fd에 넣은 후 0보다 작은 지 비교하는 것이 아닌 open을 통해 불러온 file descriptor를 0과 비교해 작은 지에 대한 여부(true, false)를 fd에 넣게 된다. 

기본적인 file descriptor 0(stdin), 1(stdout), 2(stderr)를 제외하고 open을 하게되면 3이라는 fd를 얻게 되는데 이것을 0과 비교해 (3 < 0)이므로 false(0)을 fd에 넣어 fd가 stdin으로 설정되게 되는 것이다.

원래 의도대로 작성하려면 "(fd = open("/home/mistake/password",O_RDONLY,0400)) < 0"과 같이 비교문을 작성해주어야 open하지 못했을 때 error 메시지를 출력할 수 있게 된다.


연산자 우선순위 오류로 생긴 버그를 이용해 특정 문자 10개를 입력하고 이 값을 각각 'xor 1'하여 나오는 결과를 두번째 scanf로 넣어주게 되면 flag를 얻을 수 있게 되어있다.







**************     Answer & Flag     **************



직접 실행


mistake를 실행시키고 처음 입력에 10글자("0000000000")를 입력한 후 두번째 입력에서 xor된 10글자("1111111111")를 입력하면 flag를 획득할 수 있다.



Python SSH code(pwntool)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
 
= ssh(user="mistake",host="pwnable.kr", port=2222,password="guest")
 
p1 = p.process(executable="/home/mistake/mistake")
 
print p1.recv()
 
= "1111111111"
p1.send(s)
s1 =""
for i in range(len(s)):
    s1 += chr(ord(s[i])^1)
 
p1.send(s1)
 
print p1.recv()
 
cs




Flag : Mommy, the operator priority always confuses me :(



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

[pwnable.kr] coin1  (0) 2018.06.26
[pwnable.kr] shellshock  (0) 2018.06.18
[pwnable.kr] leg  (0) 2018.06.10
[pwnable.kr] input  (0) 2018.04.19
[pwnable.kr] random  (0) 2018.04.02
Comments