[Pwnable.kr Prob] collision

코코·2023년 1월 27일
0

Pwnable.kr

목록 보기
4/10

Pwnable.kr 두 번째 문제 풀이

Pwnable.kr의 두 번째 문제이다..!
이해가 안가서 결국 다른 블로그를 한 번 참고하여 풀게되었다ㅠㅠㅠㅠ 갈 길이 너무 멀다😭

우선 ssh를 통해 문제 서버에 접속한다..

바이너리 파일을 실행시켜보면, 사용법에 ./col [passcode] 라는 문구를 출력한다.
다시 ./col 0000으로 실행시켜보면, 이번에는 passcode의 길이가 20bytes여야한다고 알려준다.
이번에는 ./col 00001111222233334444를 넣고 실행시키면 "wrong passcode" 라는 문자열을 출력한다.


바로 소스코드를 살펴보자!
#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;                                                 
}                                                                 

소스코드는 위와 같다..
우선 프로그램 실행 시 같이 입력되는 20btyes의 문자열을 argv[1]에 들어간다.(argv[0]는 바이너리 파일의 실행경로)
그 후 argc를 통해 argv[1]이 있는지 확인하고, 그 다음 strlen을 통해 문자열의 길이가 20인지 확인한 후 check_password 함수로 넘어간다!


해당 함수부터가 진짜 분석해야 할 부분 !! check_password 함수만 다시 보자...

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

argv[1](사용자의 입력값)을 char* p에 넣는다. 그러면 사용자가 입력한 문자열의 주소가 p에 저장될 것이다..
그 후에는 (int 포인터)로 형변환하여, ip에 넣어준다. 즉, p의 주소가 ip에 들어가는 것이다.
아래의 for문을 통해 ip를 배열로 가져오므로 4byte씩 잘라서 가져올 것이다..


사실 이 부분은 잘 이해가 안가서 직접 printf로 출력해봤다..

unsigned long check_password(const char* p){
        // 상수형 포인터 char *p 이므로, p에는 주소값이 저장되어있음
        // 00001111222233334444의 주소가 저장되어있음
        // 그냥 p는 주소값
        printf("p's addr : %p\n", p);
        int* ip = (int*)p;
        printf("ip's addr : %p\n", ip);
        int i; // for문 반복문 변수로 신경 x
        int res=0; // return value                      
        for(i=0; i<5; i++){
                printf("[*] %d : %d\n", i, ip[i]);
                printf("[+] ip[%d]'s addr : %p\n", i, &ip[i]);
                res += ip[i];                                     
        }                                                         
        return res;                                               
}     

결과는 위와 같다.. ip[0], ip[1] ... 의 주소가 4byte씩 커지는 것을 확인할 수 있고, 문자열도 4자리씩 끊겨서 출력된다.
ip[0]의 값은 808464432인데 이를 Hex값으로 바꾸면, 0x30303030(0000의 아스키코드 값을 이어 붙임)이 나오게 된다.

그리고 ip[0] ~ ip[4]를 모두 더한 값이 0x21DD09EC가 나와야 한다.
해당 값을 5로 나누게 되면, (0x6C5CEC8 * 4) + 0x6C5CECC 인데, 해당 값을 2byte씩 끊어서 int형으로 변환한 후 chr 함수를 호출하여 값을 만들어서 넣어주면 되지만 편하게 pwntools를 사용하려한다...


pwntools의 ssh 함수와 process 함수를 활용하자! pwntools의 공식 홈페이지 주소는 아래와 같다. https://docs.pwntools.com/en/stable/index.html

pwntools의 공식 홈피이지에서 ssh 함수 사용방법을 살펴본다.
우선 ssh에 접속하기위해 user, host, port, password를 사용하려한다. ssh 접속 후에는 process 함수를 이용하여 해당 바이너리 파일을 실행시켜줄 것이다!


또한 process 함수를 통해 argv 인자를 전달하는 방법도 살펴보자.
argv의 경우 list 형태로 전달해주면 되는듯 싶다.(List of arguments to pass to the spawned process.)

그럼 위의 내용을 토대로 Exploit 스크립트를 작성해보자!

from pwn import *

payload = p32(0x6C5CEC8) * 4 + p32(0x6C5CECC)
# p = remote('./col', argv=payload)
argvs = ['/home/col/col', payload]

p = ssh("[user]", "[host]", port=[port번호], password=[패스워드])
p1 = p.process(executable='/home/col/col', argv=argvs)

p1.interactive()

참고로 interactive해야하는 것은 p1이다!
Flag 획득 !! "daddy! I just managed to create a hash collision :)"


😂

화이팅!!!






※ 참고 사이트
pwntools argv : https://oz1ng019.tistory.com/31

profile
화이팅!

0개의 댓글