본문 바로가기

pwnable.kr/Toddler's Bottle

collision

[소스코드]

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

 

[해석]

-main 함수: argv[1] 값으로 20bytes만큼의 인자를 받아 이를 check_password 함수의 인자로 주고, check_password의 리턴값이 hashcode(0x21DD09EC)와 일치하면 flag를 출력해주는 코드이다.

-check_password 함수: 문자열 p를 int 포인터형으로 변환한다. 이 결과 문자열 p는 4byte 단위로 끊어져서 int 포인터형인 ip에 저장된다. 그 후 for문을 이용하여 ip[0], ip[1], ip[2], ip[3], ip[4]를 합한 결과를 res에 저장한 후 이 res를 리턴해준다.

 

따라서, 우리는 argv[1]로 20bytes로 구성된 문자열을 보낸 뒤, 이 20bytes를 4bytes로 끊은 것들의 합이 0x21DD09EC가 되게 하면 될 것이다.

 

1st try)

0x21DD09EC - 0x4 = 0x21DD09E8

따라서 나는 argv[1] 값으로 '0x1(4bytes)*4'와 '0x21DD09E8(4bytes)'을 줄 것이다.

그래서 인자값을 이렇게 줬더니 다음과 같은 메세지를 받는다.(little-endian 방식으로 인자를 주었다)

아마 0x00000001을 그냥 x01로 인지해 1바이트로 처리하여 다음과 같은 오류 메세지가 뜬 것 같다.

그래서 궁금해서 0x00000001을 몇 바이트로 인지하는지 궁금하여 찾아낸 결과

0x00000001*19를 16바이트로 인지한다는 걸 알 수 있었다..(? 왜지..?)

python에서 인지한 길이는 4인데 말이다..

왜 이런 현상이 일어나는지 모르겠지만, 어쨌든 이 방법은 쓰지 못 할 것 같다. 

 

2nd try)

0x21DD09EC / 0x5 = 0x06C5CEC8이다. 0x06C5CEC8는 4bytes로 처리될테니 1st try에서와 같은 문제가 나타나지 않을 것이다.

이때 0x21DD09EC(568,134,124)는 5의 배수가 아니므로 5로 나누었을 때 나머지가 4가 된다.

따라서 나는 인수로 "0x06C5CEC8*4 + 0x06C5CECC(=0x0x06C5CEC8+0x4)"를 줄 것이다.

그 결과 flag를 획득한 것을 알 수 있다.

 

1st try에서 왜 저런 결과가 나왔는지는 찾아봐야 할 것 같다.

'pwnable.kr > Toddler's Bottle' 카테고리의 다른 글

random  (0) 2023.08.04
passcode  (0) 2023.08.03
flag  (0) 2023.08.03
bof  (1) 2023.06.14
fd  (0) 2023.06.14