문제에 MD5 hash collision을 사용하라고 나와있어서 이에 대해 알아보았다.
MD5는 128비트 암호화 해시 함수이다. 임의의 길이의 메시지를 입력받아 128비트짜리 고정 길이의 출력값을 낸다. 알고리즘은 사진으로 대체하고 설명은 생략하였다.
(출처 - 위키백과)
이 MD5는 암호화 결함이 발견되어 더 이상 암호화에 사용되지 않는다. 서로 다른 값을 넣었는데도 해시값이 똑같이 나오는 충돌이 발생하기 때문이다.
문제 서버에 접속했을 때 col, col.c, flag 파일이 있어서 col.c 파일을 열어보았다. 코드는 다음과 같다.
#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;
}
메인 함수를 분석해보면 인자로 argc와 argv를 받는데, argv[1]은 20바이트여야 한다.
또한 hashcode와 argv[1]을 인자로 하여 실행한 check_password 함수의 실행값이 같을 때, flag를 확인할 수 있다.
이 때 입력한 argv[1]을 인자로 하여 check_password 함수가 실행되는데 check_password는 입력값을 다섯 번 더하는 실행을 한다. 따라서 원래 hashcode의 값을 5로 나누어 입력해야 한다.
0x21DD09EC를 5로 나누면 나누어 떨어지지 않기 때문에 0x6C5CEC8 * 4 + 0x6C5CECC로 입력해준다. (little endian 방법으로 입력해주어야 한다.)
daddy! I just managed to create a hash collision :) 플래그를 확인할 수 있다.
bof 파일과 bof.c 파일을 다운받아 문제풀이를 해야 한다.
bof.c 파일을 먼저 확인했다.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
char overflowme[32];
printf("overflow me : ");
gets(overflowme); // smash me!
if(key == 0xcafebabe){
system("/bin/sh");
}
else{
printf("Nah..\n");
}
}
int main(int argc, char* argv[]){
func(0xdeadbeef);
return 0;
}
먼저 메인함수를 보면 인자를 전달받지만 func 함수에는 이미 정해진 인자값이 들어가 있다.
0xdeadbeef를 인자로 하여 func 함수를 실행시키는데, func 함수는 overflowerme라는 배열에 32바이트를 할당하고 이를 버퍼에 저장한다. 여기서 bof를 발생시키면 /bin/sh를 실행시킬 수 있다.
bof를 발생시키기 위해 0xdeadbeef와 overfloweme 사이의 거리가 얼마인지 알아본다.
확인해 보면 lea eax, [ebp-0x2c]
, DWORD PTR [ebp+0x8], 0xcafebabe
에서 각각의 위치를 알 수 있고 총 52byte가 차이난다는 것을 확인할 수 있다.
따라서 52byte의 더미값과 4byte의 cafebabe를 입력해주면 된다.
daddy, I just pwned a buFFer :) flag를 확인할 수 있다.
flag 파일만 있고 실행시켜봤더니 permission denied가 떴다.
chmod 명령어로 권한을 바꾸어 실행시켜 보았다.
I will malloc() and strcpy the flag there. take it. 이라는 문자열을 확인할 수 있다.
문제에 packed 된 파일이라고 나와있으므로 이를 unpacking 하기 위해 파일의 정보를 살펴본다. unpaking은 처음 해보는 것이라서 인터넷을 참고하였다.
ghex를 통해 알아보니 UPX라는 값이 보인다. 이는 압축 방법 중 하나로 이를 unpacking 해주면 파일을 분석할 수 있다.
아래 링크에서 upx를 설치했다.
upx -d 명령어를 사용한다.
위와 같이 unpaking 된 것을 확인할 수 있다.
flag의 주소가 0x6c2070임을 알았다.
gdb의 x/xg 명령어는 메모리 주소에서부터 long 형식의 데이터를 16진수로 표시하라는 의미이다. 즉 x/xg 0x6c2070은 0x6c2070의 데이터를 64비트로 나타내라는 의미이다.
x/s 명령어는 메모리의 내용을 문자열로 나타내라는 의미이다.
따라서 gdb를 통해 UPX...? sounds like a delivery service :) flag를 확인할 수 있다.