#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;
}
① : 문자배열은 단위가 1바이트 정수배열은 단위가 4바이트이다. 따라서 이렇게 형변환을 하면 문자배열이 4자리씩 끊어서 들어가게 된다.
② : 아래에서 총 20문자를 받았으므로 이 함수는 문자 20바이트를 정수 4바이트 단위로 잘라서 총 값을 더해 결과를 반환하는 함수이다.
③ : 그렇게 해서 입력받은 값이 위의 hashcode변수와 같으면 플래그를 출력해준다.
여기까지만 보면 좀 복잡해보인다. 하지만 perl이 출동한다면 어떨까!
P!
E!
R!
L!
꿀잼
해공예를 보면 perl명령어를 사용하는 방법이 나와있다.
++ 해쉬코드는 unsigned로 선언되어있기 때문에 -hashcode = hashcode 크.. 이 정도면 ㄹㅇ 다 알려줌
우선 적당한 문자 하나를 4개 쓴다. 여기서 적당하게란 4개의 바이트에 0이 하나도 없는걸 말한다.
해쉬코드가 언사인드 변수이므로 121DD09EC, 221DD09EC . . 를 해쉬코드로 놓고 해도 같은 결과가 나온다.
-> 8바이트짜리 unsigned 변수이므로 0xFFFFFFFF + 0x1 = 0x0임. 최댓값을 넘어가면 0으로 돌아오므로 9번째 비트부터는 의미가 없음
그냥 적당하게 121DD09EC를 놓고 했다.
그리고 AAAA = 0x41414141이므로 4개를 입력하면 0x41414141 x 4 = 105050504이다.
121DD09EC - 105050504 = 1CD804E8 마지막 바이트에 저거만 입력해주면 끝난다.
따라서 payload는
./col $( perl -e 'print "AAAA" x 4 . "\xe8\x04\xd8\x1c"' ) 가 된다!
'write-up > pwnable.kr' 카테고리의 다른 글
[toddler's bottle] random (0) | 2018.11.30 |
---|---|
[toddler's bottle] passcode (0) | 2018.11.30 |
[toddler's bottle] flag (0) | 2018.11.30 |
[toddler's bottle] bof (0) | 2018.11.30 |
[toddler's bottle] fd (0) | 2018.11.29 |