這題跟 yench 討論
至少省下我一個小時突破盲點 XD
上學期辛苦開程式安全終於感覺有回饋了 QQ
這題是考 format string vulnerability
執行程式要我們輸入帳密
打開 ida pro 很容易就知道帳密多少
輸入 guest / guest123 以後成功登入
接著有三個功能可以選擇:
== 0CTF Login System ==
1. Show Profile
2. Login as User
3. Logout
=======================
Your choice:
但其實還有一個隱藏功能 4
必須讓自己的身分變成 normal 才能觸發
功能 4 是登入成 root 的功能
裡面有兩個很明顯的 printf(buf)
所以首先我們要讓自己的身份從 guest 變成 normal
pseudo code 大概長這樣:
char user[256];
int64 mode;
...
if ( choice == 4 && !mode)
root_login()
Login as User 利用 scanf("%256s", user)
取得 user
乍看之下是剛好 但是 scanf("%s")
的特性會在字串結尾補上 \00
因此會有 off-by-one 的問題
因此只要輸入長度 256 的 user
即可讓身份變為 normal
進入 root_login()
以後的行為如下:
readn(user, 256);
pw = md5(readn(pw, 256));
if (user == "root" && pw == "0ops{secret_MD5}")
cat_flag();
printf(user);
puts("login failed.");
...
/* 2 chances */
...
exit(1);
登入失敗會用 printf(user)
印出使用者名稱
一個非常明顯的 Format String
我一開始以為 binary 中的 0ops{secret md5} 是被替換掉的
真實環境會放真的 md5 ... 只要 leak 出密碼就過了
後來試一下才發現那個字串真的就是那樣 = =
md5 的結果是 hex string 的形式
所以不可能滿足條件 XD
由於最後會用 exit(1)
結束程式
沒辦法透過改 ret address 去控制程式
所以很直覺的會想改 exit()
的 GOT
但是寫完 exploit 才發現這題的 GOT 竟然是 read-only XDDD
不確定是因為 PIE 的緣故或是有開啟其他保護機制
乍看之下無技可施了
正當我在嘗試研究 memcpy()
內部的是不是有可以利用的同時
yench 提醒我能不能改 printf()
的 rbp 去控制程式
結果是沒辦法~ 因為 printf()
最後沒有 leave
但是這讓我想起去年 HITCON 的某一題
是利用 sprinf()
任意改值造成 overflow 的二次利用
果然這題也是類似的做法
由於實際發生 Format String 是在 printf 內部的 vprintf()
因此可以將 printf()
的 return address 給改掉
有兩次 printf()
可以利用
因此只要第一次 leak 出 libc base 以及 stack base
第二次可以做 rop 攻擊
改 ret 跳到 pop rdi
再到 system()
就拿到這題的 shell 了~
exploit: login.py
flag: 0ctf{login_success_and_welcome_back}