0xl4ughCTF và mình đã quá chủ quan.

Mình cứ nghĩ giải này nó kiểu dễ dễ nhưng nó bruh thật đấy :V Member team mình nghỉ Tết hết roài nên chơi một mình thoai :<

Web1:  Micro



Bài này mình được cho source, xem qua cấu trúc thư mục trước đã


index.php

<?php

error_reporting(0);
function Check_Admin($input)
{
    $input=iconv('UTF-8', 'US-ASCII//TRANSLIT', $input);   // Just to Normalize the string to UTF-8
    if(preg_match("/admin/i",$input))
    {
        return true;
    }
    else
    {
        return false;
    }
}

function send_to_api($data)
{
    $api_url = 'http://127.0.0.1:5000/login';
    $options = [
        'http' => [
            'method' => 'POST',
            'header' => 'Content-Type: application/x-www-form-urlencoded',
            'content' => $data,
        ],
    ];
    var_dump($options);
    $context = stream_context_create($options);
    $result = file_get_contents($api_url, false, $context);
    var_dump(file_get_contents($api_url, false, $context));
   
    if ($result !== false)
    {
        echo "Response from Flask app: $result";
    }
    else
    {
        echo "Failed to communicate with Flask app.";
    }
}
if(isset($_POST['login-submit']))
{
    if(!empty($_POST['username'])&&!empty($_POST['password']))
    {
        $username=$_POST['username'];
        $password=md5($_POST['password']);
        echo $username;
        if(Check_Admin($username) && $_SERVER["REMOTE_ADDR"]!==127.0.0.1)
        {
            die("Admin Login allowed from localhost only : )");
        }
        else
        {  
            var_dump(file_get_contents("php://input"));
            send_to_api(file_get_contents("php://input"));

        }  
    }
    else
    {
        echo "<script>alert('Please Fill All Fields')</script>";
    }
}
?>

app.py

from flask import Flask, request
import mysql.connector, hashlib

app = Flask(__name__)

# MySQL connection configuration
mysql_host = "localhost"
mysql_user = "root"
mysql_password = "root"
mysql_db = "ctf"

def authenticate_user(username, password):
    try:
        conn = mysql.connector.connect(
            host=mysql_host,
            user=mysql_user,
            password=mysql_password,
            database=mysql_db
        )

        cursor = conn.cursor()
        print(f"[username]:{username}")
        query = "SELECT * FROM users WHERE username = %s AND password = %s"

        cursor.execute(query,(username,password))
        # query log
        print(f"[query]:{cursor.statement}")

        result = cursor.fetchone()
        print(f"[result]:{result}")
       
        cursor.close()
        conn.close()

        return result  
    except mysql.connector.Error as error:
        print("Error while connecting to MySQL", error)
        return None

@app.route('/login', methods=['POST'])
def handle_request():
    try:
        username = request.form.get('username')
        print(username)
        password = hashlib.md5(request.form.get('password').encode()).hexdigest()
        # Authenticate user
        user_data = authenticate_user(username, password)

        if user_data:
            return "0xL4ugh{Test_Flag}"  
        else:
            return "Invalid credentials"  
    except:
        return "internal error happened"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)


Mình đã có đặt khá nhiều breakpoint nhưng ngại sửa nên mong mn thông cảm V:
Cơ bản ở đây chúng ta chỉ cần bypass username làm sao cho nó vượt qua hàm check mà mysql vẫn hiểu rằng là admin.
Payload của mình sẽ như sau.



Mọi người có thể thấy php sẽ parse last parameter, tức là giá trị đi vô hàm check sẽ là test -> bypass hàm check
Tuy nhiên python lại parse first parameter nên khi cho vô query mysql thì là admin -> nhận flag thành công :D





Nhận xét

Bài đăng phổ biến từ blog này

KMACTF và nỗi buồn éo làm được gì cả T__T