문제 코드
#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] )){
setregid(getegid(), getegid());
system("/bin/cat flag");
return 0;
}
else
printf("wrong passcode.\n");
return 0;
}취약한 코드 분석
if(hashcode == check_password( argv[1] )){
setregid(getegid(), getegid());
system("/bin/cat flag");
return 0;
}위 코드에서 조건문을 실행시켰을 경우 system("/bin/cat flag"); 해당 명령어를 통해서 flag를 탈취할 수 있는 것을 알 수 있었다.
해당 조건문의 hashcode는 0x21DD09EC였으며, argv[1] 즉 첫 번째 인자 값을 check_password라는 함수에 넣어서 hashcode와 비교하는 문제였다. 따라서 check_password라는 함수에 역연산을 하는 함수를 만들어서 hashcode 값을 넣으면 입력값에 넣을 값을 알 수 있다.
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;
}ip[0] =주소
ip[1]= 주소
…
이므로 결국 hashcode /5한 값을 *5번 곱하면 되지만 hashcode를 계산기에 넣어보면 5의 배수가 아니므로, /5를 하는 과정에서 반올림을 하게 된다. 따라서 “0x6C6CEC8” * 4 + “0x6C5CECC” 이렇게 넣어줘야 합니다.
exploit
./col `python2 -c 'print "\xC8\xCE\xC5\x06"*4+"\xCC\xCE\xC5\x06"'`삽질 내용
char * p가 1byte이고 int * ip 가 8byte 인 것은 알았지만 hashcode가 5번 덧셈 연산이 이뤄져서 만들어진 것인데, 5개의 연산이 전부 다르면 어떻게 찾지라는 의문을 가졌다.
하지만 if hashcode==check_password(argv[1])이 함수만 통과하면 된다는 사실을 코드를 계속 반복적으로 해석하다 보니 알게 되었으며, 따라서 hashcode/5라고 hashcode가 5의 배수는 아니므로 이로 인해 생기는 차이는 추가적인 +으로 해결하려고 하였다. 또한 20자 문제는 \xC8이거 자체가 1자인데, 나는 C를 입력값 한 자로만 생각하고 있었다. 위 문제는 ascii 코드를 떠올리고 풀릴 수 있었다.