이번에도 항상 그래왔듯
ls -alF
로 파일목록을 확인합니다.
접근 가능한 파일 중 col.c를 까보면 다음과 같은 코드가 나옵니다.
#include <stdio.h>
#include <string.h>
unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){
int* ip = (int*)p; // 매개변수를 정수형 포인터로 변환한 값을 ip변수에 저장
int i;
int res=0;
for(i=0; i<5; i++){
res += ip[i]; // int형이라 4byte씩 5번에 걸쳐 res에 값을 더해줌
}
return res; // 4byte씩 넘겨받은 값을 반환
}
int main(int argc, char* argv[]){
if(argc<2){ // 전달받은 매개변수가 없으면 다음을 출력
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] )){ // hashcode와 check_password의 반환 값이 같은지 비교
system("/bin/cat flag");
return 0;
}
else
printf("wrong passcode.\n"); // 반환값과 hashcode가 다를 경우 출력
return 0;
}
코드를 확인하면 매개변수로 받은 값을 check_password()에 넘겨나온 반환값을 passcode와 비교하여 플래그를 뱉어내는 코드입니다.
check_password()를 분석해보면 20byte로 받은 매개변수를 4byte씩 쪼개서 res라는 반환값을 담을 변수에 더해주는 코드라는 것을 알 수 있습니다. 따라서 4byte 길이의 16진수 5개의 합이 0x21DD09EC되는 payload를 작성해주면 됩니다.
먼저 5개의 값이 거의 같아야 계산하기 편함으로 5로 나눠줍니다.(여기서 결과값을 16진수로하면 "~.CCC…"가 되기 때문에 10진수로 결과를 뽑아주세요!)
그리고 소수점을 제거하면 0x6C5CEC8
이 나오고 제거한 소수점을 여기에 더해주면 0x6C5CECC
이 나옵니다. 따라서 페이로드를 구성하자면 0x6C5CEC8
4개와 0x6C5CECC
1개로 구성할 수 있겠죠?
∴ ./col $(python -c 'print "\xc8\xce\xc5\x06"*4+"\xcc\xce\xc5\x06"')
왜 이렇게 적는지 모르겠는 분들을 위해 설명을 드리자면 \x
의 경우엔 16진수를 나타내는 이스케이프 문이고, 그 뒤에 각각 c8, ce, c5, 06은 06/C5/CE/C8
를 리틀 엔디언 방식에 따라 뒤에서부터 2자리씩 넣어준겁니다.(이 부분에 대해서는 어셈블리어를 하다보면 이해하는데 도움이 될 것입니다.)