본문으로 바로가기

[pwnable.kr] collision 풀이, write-up

category Wargame/pwnable.kr 2018. 11. 1. 21:50

pwnable.kr --- collision



ssh col@pwnable.kr 2222 (passwd: guest)로 접속하면 collsion 문제를 만날 수 있다.


windows 환경의 cmd로 접속한것이 아니라 xshell5를 통해 접속했다.


windows 환경의 cmd로 접속하려면, ssh col@pwnable.kr -p2222 이와 같이 접속 해야한다.



우선 현재 디렉터리에 어떤 파일이 있는지 확인해보자.





우리는 flag를 알아야 하는데 현재 id가 col이기 때문에 flag를 볼 수 있는 권한이 없다.


col이라는 실행파일이 존재하고, setuid가 col_pwn의 권한으로 걸려있다.


col elf 파일을 통해 col_pwn의 권한을 얻고 flag를 보면 될것 같은 느낌이 든다.


col.c를 가지고 col elf 파일을 만들었을 확률이 높으므로 col.c를 분석해보자.





unsigned long type의 hashcode 변수를 생성한다.



1
unsigned long hashcode = 0x21DD09EC;                                                
cs



check_password 함수를 정의한다.


파라미터를 int 형으로 형 변환 후 4 byte씩 5번 읽어들여 res에 더한다.



1
2
3
4
5
6
7
8
9
unsigned long check_password(const char *p){                                        
    int *ip = (int *)p;
    int i;
    int res=0;
    for(i=0; i<5; i++){
        res += ip[i];
    }
    return res;
}
cs



인자가 없으면 ("usage : %s [passcode]\n", argv[0])을 출력하고 종료한다.



1
2
3
4
if(argc<2){
        printf("usage : %s [passcode]\n", argv[0]);                                    
        return 0;
}
cs



첫 번째 인자의 길이가 20 byte가 아니면 "passcode length should be 20 bytes\n"를 출력하고 종료한다.



1
2
3
4
if(strlen(argv[1]) != 20) {
    printf("passcode length should be 20 bytes\n");                                    
    return 0;
}
cs



hashcode와 check_password(argv[1])의 길이가 같으면 flag를 보여준다.



1
2
3
4
if(hashcode == check_password(argv[1])){                                            
        system("/bin/cat flag");
        return 0;
}
cs



hashcode와 check_password(argv[1])의 길이가 다르면 "wrong passcode.\n"을 출력하고 종료한다.



1
2
3
else
        printf("wrong passcode.\n");                                                
return 0;
cs




col 프로그램은 인자 하나가 반드시 있어야하고, 길이는 20 byte 이다.


첫 번째 인자가 check_password() 함수를 지나서 return 된 값이 hashcode와 같아야 한다.


int 형 포인터로 형 변환을 했기 때문에 배열을 통해 접근하면 4 byte씩 읽어들인다.


첫 번째 인자는 20 byte의 문자열이고, 이것을 int 형 포인터로 접근한 뒤 4 byte 씩 5 번 접근한다.


처음에 unsinged long hashcode의 MSB를 신경써야하나? 하고 생각했지만, MSB가 양수이기 때문에 우리가 res 값을 음수로 만들 필요가 없다.


hashcode 값이 0x80000000 이상(MSB = 1)이라면, 정상적인 long 타입은 음수로 인식되지만, unsigned long 타입이면 양수로 인식되기 때문에 어려움이 있는데 다행이 이번 문제는 양수(MSB = 0)라서 unsigned type이 굳이 문제 되지 않는다.


0x21DD09EC를 5로 나누면 몫은 0x06C5CEC8이고 나머지는 4이다.

0x06C5CEC8을 4번 더하고 0x06C5CECC를 한번 더하면 hashcode 값과 같아진다.


또한 우리는 little-endian 방식을 사용하고 있기 때문에 스크립트립트를 little-endian에 맞춰 작성해야한다.