seccamp (mini) in Akita 2018 に参加した話【訂正版】
seccamp (mini) in Akitaに参加しました。
セキュリティキャンプ2週間前から爆速でアセンブラを勉強しましたが、
当日の講義でアセンブラの知識はあまり使いませんでした。
午前のバイナリエクスプロイトの講義で使用したC言語の脆弱性プログラムです。
当日の講義ではほとんど理解できなかったため、
クラスのガチプロにいろいろと聞きました。
以下は、聞いたことをそのまま書かせていただきました。
>>>VUL1>>> #include <stdbool.h> #include <stdio.h> typedef struct { char name[100]; bool is_admin; } Profile; int main() { Profile profile = {0, false}; printf("Enter your name: "); scanf("%s", profile.name); printf("Are you admin? "); getchar(); char c = getchar(); if (c == 'y' && profile.is_admin) { puts("Goooooooooooooood!!! You are hacker!!!!"); exit(0); } else { puts("Hi, noob."); exit(0); } }
vul1は構造体の目盛りの確保に仕方について。
Profileはchar name[100]の後にすぐis_adminのメモリを確保する。
つまり、name[100] (つまり101番目)とやると、is_adminの場所を参照してしまう。
scanfは文字列の長さをいちいちチェックしない。
そこで、Enter your name:のところで101文字打ってあげて(101文字目ではname[100]に'\0'が入り結局falseになる)、name[100]を参照させ、is_adminの値を書き換えてしまえばよい。
>>>VUL2>>> #include <stdio.h> typedef struct { char name[16], age; } person; person alan = {"Alan Turing", 12}; void check_age(char age) { if(alan.age != age) { printf("You don't cheating me. Haha.\n"); exit(1); } } int main(void) { int age = 0; printf("Hello\n"); printf("Enter your age>"); scanf("%d", &age); check_age(age); if(age >= 18) { printf("I allow %s to drink!\n", alan.name); return 0; } printf("Sorry, you cannot drink.\n"); return 0; }
vul2はキャストについて。
intとcharは格納できる値の範囲が違う。
charの範囲を超えた値を入れたint型変数をcharにキャストすると、
値がおかしなことになる。
intは4byte、charは1byteの型。
だから、int ->charのキャストはint型変数の後ろ1byteがcharに代入される。
int型の0xdeadbeefはcharにキャストすると、
後ろの1byte分が0x0cであれば何でもよい。
0xaaaaaa0c
0x1237890c
0x0a0b0c0c
だから268(0x0000010c)を打てばよい
(ただし12(0x0000000c)は18以上では無いため今回のコードでは、はずれ)
>>>VUL3>>> #include <stdio.h> #include <stdlib.h> int randarr[3] = {0}; int next_rand = 0; void init_arr(void) { for(int i = 0; i < 3; i++) { randarr[i] = rand(); } next_rand = rand(); } int main(void) { int n = 0; srand(time(NULL)); init_arr(); printf("can you guess me?"); for(int i = 3; i; i--) { printf("you can see number log. enter number(1-3) rest(%d)>", i); scanf("%d", &n); printf("%d\n", randarr[n]); } printf("enter guess number >"); scanf("%d", &n); if(next_rand == n) { printf("You are hacker!\n"); } else { printf("oh no."); } }
vul3はグローバル変数のメモリの確保の仕方について。
next_randはrandarr[3]と参照すれば、next_randの値が見れる。
だから3打って上げれば、next_randの値が見れる。
したがって、3と打ってあげれば、
next_randの数字が出てくるのでそれを打てばよい。
>>>VUL4>>> #include <stdio.h> void exec_shell(void) { printf("hacked!\n"); } int main(void) { char input[256] = ""; printf("this is a simple echo program - enter text and hack this!\n"); printf("hint: main = %p, exec_shell = %p, input[256] = %p\n", main, exec_shell, input); for(;;) { if(!gets(input)) return 0; puts(input); } }
vul4はスクリプト言語やらなんやらを使った覚えがあるが詳しいことは知らん!!