728x90
#include <stdio.h>
#include <string.h>
unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){ //p로 argv[1]이 들어온다.
int* ip = (int*)p; //argv[1]를 char*에서 int*로 바꾼다.
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){ // ./col 비번
printf("usage : %s [passcode]\n", argv[0]);
return 0;
}
if(strlen(argv[1]) != 20){ //비번이 20byte여야함
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;
}
hashcode == check_password(argv[1])이면 통과이다.
아래는 check_password의 정의이다.
unsigned long check_password(const char* p){ //p로 argv[1]이 들어온다.
int* ip = (int*)p; //argv[1]를 char*에서 int*로 바꾼다.
int i;
int res=0;
for(i=0; i<5; i++){
res += ip[i];
}
return res;
}
위 코드를 아래와 같이 나타냈다.
p가 가리키는 문자열은 문제 조건에 의해 20byte(4byte*5)이다. 따라서 p[0]p[1]p[2]p[3]이 ip[0]이 된다.
그냥 포인터의 자료형은 메모리를 읽을 때 내가 이 메모리(바이트)를 이 자료형으로 인식할게! 라는 뜻이다. 결국 메모리에는 다 바이트로 저장되니까(0x61 이런형식으로) char*는 0x61을 a로 읽는 것이다. int는 32bit 환경에서 4byte이니까 0x61626364자체를 int*는 하나의 정수로 보겠다고 해서 이해하는 것이고..
아무튼 res=ip[0]+..+ip[4]이고 ip[i]들은 0x1213159764 뭐 이런 꼴이다. 그래서 저런꼴 5개 더해서 0x21DD09EC와 같게하면 된다.
여기서 알아낸 것
꼭 pwntools 안써도 바이트 보낼 수 있다!
./col `python -c 'print "쉘코드"'`
그래서 얘를 5조각으로 자르자
0x6C5CEC8*4+0x6C5CECC로 나눠서 보내자. (사실 순서는 상관없다.)
b"\xC8\xCE\xC5\x06"*4+b"\xCC\xCE\xC5\x06" 로 보내자
따라서 ./col `python -c 'print b"\xC8\xCE\xC5\x06"*4+b"\xCC\xCE\xC5\x06"'`로 보내면된다.
그럼 잘 나온다. 끝.
'Linux Exploitation > Wargame' 카테고리의 다른 글
[드림핵(Dreamhack)] tcache_dup (0) | 2023.06.27 |
---|---|
[드림핵(Dreamhack)] uaf_overwrite (0) | 2023.06.20 |
[Pwnable.kr] fd (0) | 2023.06.03 |
[Pwnable.kr] bof (0) | 2023.06.03 |
[ROP 시리즈 (4)] 드림핵(Dreamhack) - rop (0) | 2023.04.21 |