記事説明
CTF初めて1週間の主がPicoCTFのEasyをbeginnerむけに書いている記事です。CTFのwriteupではCTF常識が前提になっている記事が多く無知すぎてよくわからなかったので書くことにしました。至らぬところ等あると思いますのでご指摘いただけると嬉しいです。 #picoCTFbeginner※補足
ほかの方のformat string 0 picoCTF writeupを見ると全く違う解き方をされている方がおられました。当記事は作問者が意図した解き方ではない可能性があるのでご注意ください。作問者の意図したであろう解き方の解説記事は下記になります。
事前知識
SIGSEGV
プログラムがメモリに対して不正なアクセスを試みたときに発生するシグナル。 具体的には無効なメモリアドレスの参照、配列の範囲外アクセスなどが含まれる。char型
c言語で文字列をあらわされるときに使う型。 charは1文字ごとに区切り、文字列を配列として認識する。例
char c = "a" //cは1文字の配列["a"]
char c[32] //cは32文字以下で配列
c = "abc" //cは["a","b","c"]
関数の意味
printf("\n%s\n", flag)
変数flagに格納されている値を表示fgets(flag, FLAGSIZE, f);
変数flagにf【file】の内容をFLAGSIZE【64】の字数だけ代入する。signal(SIGSEGV, sigsegv_handler);
指定されたシグナルに対してシグナルハンドラを設定する関数。 SIGSEGV発生時にsigsegv_handlerを実行する。flag獲得条件
format-string-0.c
void sigsegv_handler(int sig) {
printf("\n%s\n", flag);
fflush(stdout);
exit(1);
}
int on_menu(char *burger, char *menu[], int count) {
for (int i = 0; i < count; i++) {
if (strcmp(burger, menu[i]) == 0)
return 1;
}
return 0;
}
//-中略-
int main(int argc, char **argv){
FILE *f = fopen("flag.txt", "r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
exit(0);
}
fgets(flag, FLAGSIZE, f);
signal(SIGSEGV, sigsegv_handler);
gid_t gid = getegid();
setresgid(gid, gid, gid);
serve_patrick();
return 0;
}
プログラムが不正なメモリアクセスを行わせて、sigsegv_handler()を実行する。
そうするとprintf("\n%s\n", flag)されて、フラグが表示される。
コード概要
format-string-0.c
void serve_patrick() {
printf("%s %s\n%s\n%s %s\n%s",
"Welcome to our newly-opened burger place Pico 'n Patty!",
"Can you help the picky customers find their favorite burger?",
"Here comes the first customer Patrick who wants a giant bite.",
"Please choose from the following burgers:",
"Breakf@st_Burger, Gr%114d_Cheese, Bac0n_D3luxe",
"Enter your recommendation: ");
fflush(stdout);
char choice1[BUFSIZE];
scanf("%s", choice1);
char *menu1[3] = {"Breakf@st_Burger", "Gr%114d_Cheese", "Bac0n_D3luxe"};
if (!on_menu(choice1, menu1, 3)) {
printf("%s", "There is no such burger yet!\n");
fflush(stdout);
} else {
int count = printf(choice1);
if (count > 2 * BUFSIZE) {
serve_bob();
} else {
printf("%s\n%s\n",
"Patrick is still hungry!",
"Try to serve him something of larger size!");
fflush(stdout);
}
}
}
format-string-0.c
//上記から抜粋。
char choice1[BUFSIZE];
//入力される値をBUFSIZE【32】以下で定義。
scanf("%s", choice1);
//入力された値をchoce1に代入。
choise1が32文字以下で定義されているため、32bite以上の文字列を入力すると配列の範囲外アクセスが発生します。その結果SIGSEGVが発生してflag獲得条件を満たします。
答え
cmd
Welcome to our newly-opened burger place Pico 'n Patty! Can you help the picky customers find their favorite burger?
Here comes the first customer Patrick who wants a giant bite.
Please choose from the following burgers: Breakf@st_Burger, Gr%114d_Cheese, Bac0n_D3luxe
Enter your recommendation: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
There is no such burger yet!
picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_dc0f36c4}