pwnable.kr - collision

securitykss·2022년 11월 10일
0

pwn-wargame

목록 보기
2/6
post-thumbnail

1. Description

flag를 알아보자!

2. Check

C code

#include <stdio.h>
#include <string.h>
unsigned long hashcode = 0x21DD09EC;
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;
}

int main(int argc, char* argv[]){
        if(argc<2){
                printf("usage : %s [passcode]\n", argv[0]);
                return 0;
        }
        if(strlen(argv[1]) != 20){
                printf("passcode length should be 20 bytes\n");
                return 0;
        }

        if(hashcode == check_password( argv[1] )){
                system("/bin/cat flag");
                return 0;
        }
        else
                printf("wrong passcode.\n");
        return 0;
}

unsigned long hashcode = 0x21DD09EC;

전역변수로 부호가 없는 long타입 hashcode가 선언되어 있다.

check_password(const char* p):

상수 char*, 즉, 문자열을 가져온다.

int* ip = (int*)p;

char *p(int*) 을 통해서 형변환을 해준다.


예를 들어 20bytes의 문자열을 가져 오게 되면, char[0] ~ char[19]까지를

int[0] ~ int[3]으로 변하게 된다.(int는 4bytes로 저장하기 때문)


그 후 * ip 에 넣는다.

for(i=0; i<5; i++) { res += ip[i];}

위에서 값이 할당된 ip 배열을 ,ip[0] ~ ip[4]까지 더해서 res에 넣는다.

그후 res값을 리턴

main(int argc, char* argv[])

if(argc<2) { ... }

인자가 1개 이하이면, 종료된다. 즉, 실행파일 제외 따로 넘겨받는 인자가 없으면 종료.

if(strlen(argv[1] != 20) { ... }

넘겨받은 인자의 길이가 20bytes가 아니라면 종료.

if(hashcode == check_password(argv[1]) { ... }

system("/bin/cat flag"); 가 있는 것을 보아 이 조건문에 충족해야 답을 얻을 수 있다.

위에서 전역변수로 선언된 hashcode와 check_password(argv[1])이 같아야 된다.

argv[1]에 어떤 값, 즉 인자로 어떤 값을 넘겨줘야 할까?

3. Design

인자값, 즉 argv[1]이 20bytes의 길이이여야한다.

check_password에서 20bytes 길이의 문자열 p를 인자로 넘겨 받고,

int타입의 포인터로 변환되어서 1 x 20 = 4 x 5, 즉 p는 5개의 배열로 ip에 저장된다.

그리고 배열 ip[0] ~ ip[4]까지 더한 후, 반환한다.

반환된 값은 hashcode와 비교하여 같으면, 답을 얻어낼 수 있다.

4. Exploit

4-1. how?

hashcode = 0x21DD09EC = 568134124,

이 값을 5로 나누면, 몫은 113626824, 나머지는 4가 된다.

즉, ip[0] ~ ip[3]까지 113626824, 16진수로 0x06C5CEC8,

ip[4]에 113626828, 16진수로 0x06C5CECC를 넣는다.

이렇게 되면, 20bytes를 넘게 되는거 아닌가요?

python 인터프리터를 이용해서 값을 넣어주자

'$(python -c)'

./col $(python -c 'print "\xc8\xce\xc5\x06"* 4 + "\xcc\xce\xc5\x06"')

여기서 두 개씩 거꾸로 넣는 이유는 리틀엔디안 방식으로 저장되기 때문이다.

4-2. result

flag를 얻어 냈다.

Reference

http://pwnable.kr/play.php (문제 출처)
https://icmp-ycdi.tistory.com/49 (참고)

profile
보안 공부를 하는 학생입니다.

0개의 댓글