pwnable.kr (mistake)

c0wb3ll ㅣ 2020. 12. 6. 23:03

pwnable.kr (mistake)

 

 

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

문제 이름이 mistake이다. 무엇을 실수했을까?

우선 flag 획득 조건을 보자.

if(!strncmp(pw_buf, pw_buf2, PW_LEN)){
        printf("Password OK\n");
        system("/bin/cat flag\n");
    }

pw_buf와 pw_buf2의 값이 같으면 flag를 읽어준다.

flag 획득 조건을 확인했으니 이제 무슨 실수를 했는지 찾아보자.

    if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
        printf("can't open password %d\n", fd);
        return 0;
    }

소스코드 중 위 if문에 실수가 존재한다.

바로 연산자 우선 순위의 문제인데 < 연산자가 = 연산자보다 우선순위가 높기 때문에 < 연산을 마친 후 fd에는 연산을 마친 값이 들어가게 된다.

과정을 순서대로 적어보면 아래와 같다.

  1. password파일을 읽어온다.
    • read() 의 반환 값
    • 성공 시 : 읽어온 바이트 수
    • 실패 시 : -1
  2. password가 존재하면 반환 값은 읽어온 바이트 수이기 때문에 양수 반환
  3. 0미만이 아니기 때문에 false값인 0반환
  4. fd는 0의 값을 가짐

그럼 fd가 0의 값을 가지면 무슨 문제가 일어나냐?

if(!(len=read(fd,pw_buf,PW_LEN) > 0)){
        printf("read error\n");
        close(fd);
        return 0;        
    }

이 부분에서도 같은 실수가 있는데 이 때 read(fd, pw_buf, PW_LEN) 에서 fd가 0이면 read함수는 stdio로 작동하여 pw_buf에 원하는 값을 우리가 입력시켜 줄 수 있다.

char pw_buf2[PW_LEN+1];
    printf("input password : ");
    scanf("%10s", pw_buf2);

그럼 그 이후 pw_buf와 같은지 확인하기 위해 pw_buf2에 우리가 입력을 할 수 있는데 여기서 인증에 필요한 pw_buf와 pw_buf2를 모두 우리가 입력시킬 수 있다.

    xor(pw_buf2, 10);

다만 pw_buf2에 입력한 값은 xor을 한번 돌리기 때문에 pw_buf에 입력한 값에 xor한 값을 pw_buf2에 입력해주면 되겠다.

 

 

Reference

http://ehpub.co.kr/리눅스-시스템-프로그래밍-3-3-read-write/

https://dojang.io/mod/page/view.php?id=188