'Security > Wargame' 카테고리의 다른 글
[Write-Up/Pwnable.kr] Toddler’s Bottle - bof (0) | 2015.07.11 |
---|---|
[Write-Up/Pwnable.kr] Toddler’s Bottle - fd (0) | 2015.07.09 |
[Write-Up/Pwnable.kr] Toddler’s Bottle - random (0) | 2015.07.08 |
Daddy told me about cool MD5 hash collision today.
I wanna do something like that too!
ssh col@pwnable.kr -p2222 (pw:guest)
GNU bash (version 4.3.11)
col@ubuntu:~$ ls -al
total 32
drwxr-x--- 4 root col 4096 Aug 20 2014 .
dr-xr-xr-x 48 root root 4096 Jul 12 05:20 ..
d--------- 2 root root 4096 Jun 12 2014 .bash_history
-r-sr-x--- 1 col2 col 7341 Jun 11 2014 col
-rw-r--r-- 1 root root 555 Jun 12 2014 col.c
-r--r----- 1 col2 col2 52 Jun 11 2014 flag
dr-xr-xr-x 2 root root 4096 Aug 20 2014 .irssi
#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;
}
이 문제는 Hash Collision의 기초 원리에 대해 이해하고 있냐에 대하여 묻는 문제이다.argv[1]
에 넣은 값이 check_password
라는 함수를 거치면서 가공되고, 그 리턴 값이 0x21DD09EC
가 되면 flag값이 나오는 듯 하다.
여기서 주목해야 할 부분은 총 세 부분, 크게는 두 부분이다.
가장 먼저, 문제의 입력 값 제한이다.
if(strlen(argv[1]) != 20){
printf("passcode length should be 20 bytes\n");
return 0;
}
이 문제에서는 입력 값을 char형으로 20Byte를 받고 있다는 것을 알 수 있다.
다음으로 살펴볼 곳은 연산부분이다.
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;
}
이 부분을 보면 왜 입력 값을 char형 20Byte를 받는지 알 수 있다.
우선, int* ip = (int*)p;
를 이용하여 문자열 배열을 강제로 정수 배열로 형변환을 하는 것에 주목하자, 만일 이 코드가 컴파일 된 환경에서의 int형 크기가 WORD형이라고 가정할 시, 아래의 for(i=0; i<5; i++);
와 함께 쓰여, 총 20Byte를 가리키게 된다는 것을 알 수 있다.
그렇다면 대략적인 틀이 잡혔다. 총 20바이트의 문자열을 4바이트 단위로 끊어, 정수형으로 강제 형변환한 뒤, res
라는 변수에 더하게 된다. 결국, 디버깅까지도 필요 없는, 단순 코드 분석 문제라는 것이다.
그럼 우리가 argv[1]
에는 무엇을 넣어주어야 할까? 다시 코드로 돌아가서 다음 부분들을 살펴보자.
unsigned long hashcode = 0x21DD09EC;
if(hashcode == check_password( argv[1] ))
좋다, 이제 풀이를 위한 모든 재료가 모였다. 이제 적절하게 요리해보자. 간단하게 0x21DD09EC
를 통째로 5로 나눈 뒤, 그 값을 반복해서 5번 입력해주되, 소수점 손실만 보정해주면 될 듯 하다. 자, 계산기를 꺼내 계산하자.
0x21DD09EC를 5로 나눈 몫 : 0x6C5CEC8
0x21DD09EC를 5로 나눈 나머지 : 0x4
이제 공격코드를 도출해낼 수 있다. 그 모습은 다음과 같다.
`python -c 'print "\xc8\xce\xc5\x06"*4+"\xcc\xce\xc5\x06"'`
col@ubuntu:~$ ./col `python -c 'print "\xc8\xce\xc5\x06"*4+"\xcc\xce\xc5\x06"'`
daddy! I just managed to create a hash collision :)
[Write-Up/Pwnable.kr] Toddler’s Bottle - bof (0) | 2015.07.11 |
---|---|
[Write-Up/Pwnable.kr] Toddler’s Bottle - fd (0) | 2015.07.09 |
[Write-Up/Pwnable.kr] Toddler’s Bottle - random (0) | 2015.07.08 |
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |