渗透测试前四天笔记

第一天

人工智能正在深刻改变网络安全领域。2026年将是AI辅助安全的重要发展年份,大模型在代码分析、漏洞复现、Exploit编写等方面展现出强大能力。Claude Code、GPT-4、Gemini等AI工具已经成为安全研究人员的得力助手。对于安全研究人员而言,积极拥抱AI技术,利用AI辅助安全测试将是未来发展的重要趋势。

必备工具与环境配置

搭建良好的学习和研究环境是安全渗透的基础。以下是推荐的开发环境配置:

Python环境推荐使用Python 3.10版本,配合PyCharm或VS Code进行开发。建议使用Conda创建虚拟环境,这样可以同时管理多个Python版本,避免版本冲突。虚拟环境就像容器一样,可以为每个项目创建独立的依赖环境。

Java环境推荐安装JDK 1.8和JDK 17两个版本。JDK 1.8是许多企业应用的基础,而JDK 17在模块化方面有较大改进,对Java反序列化漏洞的利用有一定限制。IDEA是Java开发的首选IDE,配合Maven可以很好地管理项目依赖。

PHP环境推荐使用phpstudy进行快速部署,PHPStorm或VS Code配合Xdebug进行调试。Xdebug的配置需要修改php.ini文件,添加如下配置:

复制代码
[Xdebug]
xdebug.mode = debug
xdebug.start_with_request = yes
zend_extension=D:/phpstudy_pro/Extensions/php/php7.3.4nts/ext/php_xdebug-3.1.6-7.3-vc15-nts-x86_64.dll

对于底层C语言代码的调试,推荐使用pwndbg插件,这是一个功能强大的GDB调试器。前端JavaScript调试在逆向分析过程中也非常重要,需要掌握浏览器开发者工具的使用。

Linux环境推荐使用Ubuntu 22.04,配合Nginx、MySQL、PHP-FPM构建LNMP环境。源码安装和APT安装各有优劣,源码安装便于调试底层代码,而APT安装更为便捷。

LNMP XAMP WAMP 等等 L(linux) N(nginx) M(mysql)P(PHP) W(windows)

ubuntu安装nginx以及php的部署关键步骤

1.安装依赖包

复制代码
apt-get install gcc
apt-get install libpcre3 libpcre3-dev
apt-get install zlib1g zlib1g-devsudo 
apt-get install openssl sudo 
apt-get install libssl-dev

2.安装nginx

复制代码
cd /usr/local

mkdir nginx

cd nginx

tar -xvf nginx-1.22.1.tar.gz

3.编译nginxkennefg

复制代码
/usr/local/nginx/nginx-1.21.6
# 执行命令

./configure
这里也可以不用改 不更改会安装在默认位置通常是/usr/local/下
      
./configure --prefix=/home/centos/nginx(这里是改变了安装位置) --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module

# 执行make命令

make

# 执行make install命令

make install

php源码级别调试可能遇到的问题

fpm进程出现问题

可以选择kill也可以选择重新启动

第二天

4.1 HTTPS通信流程

HTTPS的安全性建立在多层加密机制之上。当用户访问HTTPS网站时,首先进行DNS解析获取服务器IP,然后通过TCP三次握手建立连接,接着是SSL/TLS握手过程,最后才是HTTP请求和响应。

TLS握手的关键步骤包括:

1.Client Hello:客户端发送TLS版本号、随机数、支持的加密算法套件等信息

2.Server Hello:服务器确认使用的TLS版本号,返回自己的随机数和选择的加密算法

3.证书交换:服务器发送由CA签发的数字证书,包含服务器公钥

4.密钥协商:客户端验证证书后,生成对称加密密钥,用服务器公钥加密后发送

5.握手完成:后续通信使用协商的对称密钥进行加密

4.2 加密算法与安全性

HTTPS使用混合加密方案:非对称加密(如RSA)用于安全地传递对称加密密钥,对称加密(如AES)用于实际数据加密,SHA384等哈希算法用于数据完整性校验。

RSA非对称加密的安全性基于大数分解难题,目前2048位及以上的密钥被认为是安全的。AES对称加密理论上不可破解(仅在密钥安全的前提下)。这种设计既保证了安全性,又解决了非对称加密效率低的问题。

4.3 TLS流量解密原理

课程提出了几个深入的问题供思考:

问题一:Wireshark如何自动解密TLS流量?

需要获取TLS握手过程中的关键信息,包括TLS版本号、Client Random、Server Random以及协商的对称密钥。Wireshark可以通过这些信息计算出最终的加密密钥,从而解密TLS流量。

问题二:中间人能否无条件解密TLS流量?

正常情况下不能。因为中间人无法获取服务器私钥,无法完成证书验证,也就无法解密客户端生成的对称密钥。这是HTTPS设计的核心安全保证。

问题三:Burpsuite作为中间人如何解密HTTPS流量?

Burpsuite能够解密HTTPS流量是因为用户安装了Burpsuite的CA证书。此时Burpsuite可以伪造服务器证书,与客户端和服务器分别建立TLS连接,从而解密所有流量。这就是为什么在测试环境需要导入Burpsuite证书的原因。

五、实验:PHP源码调试

课程最后介绍了使用Docker容器进行PHP源码调试的实验。实验目标是找到一个密码,其SHA256哈希值等于指定的哈希值。

实验步骤如下:

1.使用他人分享的PHP 8.1源码环境镜像启动Docker容器

2.下载PHP源码并编译

3.使用VSCode通过SSH连接到容器内的Ubuntu系统

4.安装C/C++扩展插件

5.在目标函数处设置断点

6.逐步调试,寻找匹配的密码

Web通信原理与HTTPS安全机制

HTTP/HTTPS通信流程

理解Web通信原理是安全研究的基础。当用户访问一个HTTPS网站时,整个通信流程包括以下几个关键步骤:

首先是DNS解析,将域名转换为服务器的IP地址。其次是TCP三次握手,建立可靠的连接。然后是SSL/TLS握手过程,协商加密算法并交换密钥。SSL握手完成后,客户端会生成一个对称加密密钥,用服务器的公钥加密后发送给服务器。之后所有的通信都使用这个对称加密密钥进行加密,确保数据传输的安全性。

HTTPS的安全性建立在非对称加密和对称加密的结合之上。非对称加密(如RSA)用于安全地传递对称加密密钥,而对称加密(如AES)用于实际的数据加密,因为对称加密的效率更高。这种设计既保证了安全性,又保证了通信效率。

服务器会将包含公钥的数字证书发送给客户端,证书由CA(证书颁发机构)签发。客户端使用CA的公钥验证证书的真实性,确保服务器的身份没有被冒充。这就是为什么HTTPS能够防止中间人攻击的原因。

TLS流量解密原理

安全研究中经常需要解密TLS流量进行分析。Wireshark可以通过以下方式解密TLS流量:

在TLS握手过程中,客户端和服务器会交换两个随机数(Client Random和Server Random),再加上协商的对称密钥,就会生成最终的加密密钥。如果能够在握手阶段获取到这些信息,就可以解密后续的TLS通信流量。

Burpsuite作为中间人代理,可以解密HTTPS流量,但这需要用户信任Burpsuite的CA证书。当Burpsuite作为中间人时,它会伪造服务器的证书,客户端如果信任了这个证书,Burpsuite就可以解密所有流量。这就是为什么在测试环境需要安装Burpsuite证书的原因。

需要注意的是,在正常的网络环境下,如果没有用户配合(即用户没有安装中间人证书),中间人攻击是无法解密的。这正是HTTPS设计的初衷------即使通信被截获,攻击者也无法获取明文内容。

第三天

php伪协议讲解

PHP Filter伪协议在CTF中的高级利用技巧

在CTF比赛和实际渗透测试中,PHP的filter伪协议是一个强大而灵活的工具。许多参赛者和安全研究人员对filter的理解停留在基础层面,仅仅知道可以使用它来读取文件的Base64编码内容。然而,filter协议的功能远不止于此,它提供了丰富的数据转换和过滤能力,在复杂的CTF题目中往往能发挥关键作用。本文将从原理出发,深入讲解filter协议的各种高级利用技巧,帮助读者在比赛中快速识别和利用这类考点。

一、PHP Filter协议基础

1.1 Filter协议概述

PHP的filter伪协议是PHP内核内置的一个数据处理机制,它允许对数据进行实时的过滤、转换和编码操作。使用filter协议时,需要通过php://前缀指定协议类型,然后通过/分隔符指定使用的过滤器链。filter协议既可以用于读取数据(read模式),也可以用于写入数据(write模式),这使得它在文件包含、数据处理等场景中有着广泛的应用。

Filter协议的基本语法格式为:

复制代码
php://filter/[read|write]=过滤器1|过滤器2|.../resource=目标资源

其中,readwrite分别指定过滤操作的方向,可以串联多个过滤器形成过滤器链,resource指定要处理的目标资源,可以是文件路径也可以是特殊的流(如php://input)。

1.2 常用过滤器分类

PHP内置了三大类过滤器,分别是字符串过滤器、转换过滤器和压缩过滤器。字符串过滤器主要处理字符串的格式转换,如string.strip_tags用于去除XML/HTML标签,string.rot13用于ROT13加密。转换过滤器包括Base64编解码(convert.base64-encodeconvert.base64-decode)、URL编解码、quoted-printable编解码等。压缩过滤器则用于处理gzip和bzip2压缩数据。

在CTF中最常用的过滤器组合是Base64编码器和字符串过滤器,它们的巧妙组合可以绕过各种代码执行限制,实现getshell目标。理解这些过滤器的底层原理是灵活运用的前提。

二、"死亡Exit"绕过技术详解

2.1 问题的提出

在实际的Web应用和CTF题目中,开发者为了防止配置文件或缓存文件被直接执行,经常会在文件开头添加<?php exit; ?>这样的终止代码。假设存在如下代码:

复制代码
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

这段代码看似允许用户控制写入的文件名和内容,但由于exit语句的存在,即使写入了一句话木马,PHP在执行该文件时也会立即退出,无法真正执行恶意代码。这种防御机制被称为"死亡Exit",是CTF中常见的考点之一。

要利用这个"后门",我们面临两个挑战:第一,如何绕过exit语句;第二,如何让写入的内容被PHP解析执行。Filter协议为我们提供了绕过这两个限制的可能。

2.2 Base64解码绕过的原理

Base64是一种基于64个可打印字符来表示二进制数据的编码方式。在Base64编码表中,使用的字符包括0-9的数字、a-z的小写字母、A-Z的大写字母,以及加号(+)和斜杠(/),共64个字符。这意味着Base64编码后的字符串只包含这64个合法字符,其他所有字符在解码时都会被忽略。

PHP的base64_decode函数在解码Base64字符串时,会自动跳过所有非Base64合法字符。假设我们有一个字符串<?php exit; ?>,其中<?;>空格都是非法字符,解码器会跳过这些字符,只保留phpexit这几个字符。

考虑以下代码片段:

复制代码
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

如果我们直接传入txt=<?php eval($_POST[123]); ?>,由于exit的存在,代码无法执行。但如果我们利用filter协议,指定write=convert.base64-decode,写入的内容会先经过Base64解码。

Base64解码的规则是每4个字符一组进行解码。如果我们传入的Base64字符串是phpexita,其中phpexit7个字符加上1个填充字符a共8个字符,刚好可以被正常解码为PHP代码。而<?php exit; ?>中的非法字符会被跳过,剩下的phpexita能够正常解码。

2.3 完整的利用链

要实现"死亡Exit"的绕过,完整的利用步骤如下:

首先,确定目标文件的内容结构。假设$content<?php exit; ?>加上用户可控的$txt内容。

其次,使用filter协议指定Base64解码过滤器。请求URL应该类似:

复制代码
?filename=php://filter/write=convert.base64-decode/resource=shell.php&txt=经过Base64编码的PHP代码

在CTF比赛中,payload通常是先将要写入的PHP代码进行Base64编码,然后作为txt参数的值传入。PHP在写入文件前,会先对txt的内容进行Base64解码,此时<?php exit; ?>中的非法字符被跳过,剩下的phpexita(或其他有效字符组合)被正常解码,而后面真正的PHP代码也被还原。

这种利用方式的关键在于:巧妙利用Base64解码特性,让exit语句在解码过程中"消失",同时保留后续的有效代码。

2.4 实战示例

以下是一个典型的利用场景,假设目标代码存在文件写入功能:

复制代码
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

构造的利用请求如下:

复制代码
POST /write.php
filename=php://filter/write=convert.base64-decode/resource=shell.php
txt=PD9waHAgcGhwaW5mbygpOw==  // 这是"<?php phpinfo(); ?>"的Base64编码

当这个请求被处理时,txt参数的内容会先被Base64解码,然后与<?php exit; ?>拼接,最后写入shell.php。由于Base64解码的特性,解码后的内容实际上是phpexit<?php phpinfo(); ?>exit语句被有效字符包围无法正常执行,后面的phpinfo()代码得以保留并可以执行。

三、字符串过滤器的高级利用

3.1 string.strip_tags过滤器

string.strip_tags过滤器是另一个在CTF中非常有用的工具。它可以去除字符串中的XML和HTML标签,模拟PHP内置的strip_tags()函数。这个过滤器在处理包含标签的数据时非常有用。

考虑以下代码:

复制代码
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

<?php exit; ?>实际上是一个XML标签(虽然不是标准的XML格式),因此可以使用string.strip_tags将其去除。请求URL类似:

复制代码
?filename=php://filter/write=string.strip_tags/resource=shell.php

执行后,<?php exit; ?>会被完全去除,只剩下用户传入的内容。但这种方法有一个问题:如果我们传入的也是PHP代码,同样会被strip_tags去除,导致无法写入有效代码。

3.2 过滤器链组合技巧

为了解决上述问题,可以使用过滤器链组合多个过滤器。filter协议支持将多个过滤器串联使用,形成处理流水线。一个经典的组合是:string.strip_tags|convert.base64-decode

这种组合的工作流程是:首先使用string.strip_tags去除<?php exit; ?>标签,然后使用convert.base64-decode对后面的内容进行解码。这两个操作按顺序执行,最终达到绕过死亡Exit的目的。

请求URL格式如下:

复制代码
?filename=php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php

但需要注意,过滤器链的顺序非常重要。如果顺序错误,可能无法达到预期效果。在实际比赛中,需要根据题目代码的具体逻辑来调整过滤器的顺序。

3.3 strip_tags与Base64的组合应用

string.strip_tags过滤器的另一个应用场景是处理用户输入中可能包含的恶意标签。在某些情况下,目标系统可能对输入内容进行HTML过滤,此时可以使用Base64编码配合strip_tags来绕过。

具体思路是:首先将恶意PHP代码进行Base64编码,然后在请求中使用过滤器链convert.base64-decode|string.strip_tags。Base64解码后,如果存在任何残留的标签字符,strip_tags会将其去除,只保留有效的PHP代码。

这种组合在处理复杂过滤逻辑时特别有用,能够绕过多种输入验证机制。

四、convert.iconv过滤器的高级技巧

4.1 iconv过滤器简介

convert.iconv.*是PHP filter协议中功能最强大的转换过滤器之一。它支持各种字符编码之间的转换,如UCS-2、UCS-4、UTF-8、UTF-16、UTF-32、ISO-10646-UCS-BOM等。在CTF比赛中,这个过滤器经常出现在大型赛事的高难度题目中。

iconv过滤器的基本语法是convert.iconv.编码1/编码2convert.iconv.编码1.编码2,表示将数据从编码1转换为编码2。常见的编码组合包括convert.iconv.UCS-4.UCS-4BEconvert.iconv.UTF-16.UTF-32等。

4.2 利用编码转换绕过限制

在某些情况下,目标系统可能对特定字符或字符串进行过滤,直接写入代码会被拦截。此时可以利用字符编码转换的特性,将代码转换为特殊的编码格式,在运行时由PHP自动解码执行。

例如,假设系统禁止写入字符串eval,我们可以将代码转换为UCS-4编码后写入。PHP在执行文件时,会按照文件保存的编码进行解码,如果编码处理得当,可以绕过某些字符串过滤检测。

一个典型的利用方式是利用不同编码之间的字节长度差异。某些编码(如UCS-4)使用4字节表示一个字符,而其他编码(如UTF-8)使用变长字节。通过精心构造编码转换,可以实现特殊的绕过效果。

4.3 iconv在CTF中的应用实例

在大型CTF赛事中,iconv过滤器经常与其他过滤器组合使用,形成复杂的利用链。一个常见的题目模式是:目标代码对输入进行多种过滤,要求参赛者找到一种编码组合,使得处理后的代码能够绕过所有过滤并正常执行。

例如,可能的过滤器链如下:

复制代码
php://filter/convert.iconv.UCS-4.UCS-4BE|convert.base64-encode/resource=...

这个过滤器链先将数据转换为UCS-4大端编码,然后进行Base64编码。在某些场景下,这种双重编码可以绕过特定的安全检测。

理解iconv过滤器需要对字符编码有深入了解,建议读者系统学习Unicode编码原理和各种字符集的特点,这是解决相关题目的基础。

五、一句话木马与Webshell技术演进

5.1 一句话木马的原理

一句话木马是一种极简的Webshell,通常只有一行代码,却能实现完整的命令执行功能。最经典的一句话木马格式如下:

复制代码
<?php @eval($_POST[cmd]); ?>

这行代码的含义是:接收POST参数cmd的值,将其作为PHP代码执行。攻击者通过向服务器发送POST请求,可以在目标服务器上执行任意PHP代码,从而获取服务器权限。

与传统的"大马"(功能完整的Webshell,通常几十KB甚至更大)相比,一句话木马具有以下优势:体积小(通常只有几十字节)、特征少(难以被安全软件识别)、灵活度高(可以根据需要进行各种变形)。

5.2 Webshell技术发展历程

Webshell技术的发展经历了几个重要阶段。早期的Webshell功能全面,可以查看全盘文件、修改任意文件、删除任意文件、上传文件等,但体积过大(如著名的aspspy.aspx、phpspy.php、jspSpy.jsp等),特征明显,容易被安全软件检测和清除。

随着安全软件的发展,大马的生存空间被压缩。一句话木马因其简洁性成为主流,但单一的一句话木马功能有限,通常需要配合其他工具(如中国菜刀、蚁剑、冰蝎等)使用。这些工具提供了图形化界面,可以方便地管理一句话木马,执行文件管理、命令执行、数据库操作等功能。

现代Webshell还会进行各种变形和加密,以绕过WAF(Web应用防火墙)和安全软件的检测。常见的变形技术包括:变量替换、字符串编码、函数回调、匿名函数等。

5.3 结合Filter协议写入Webshell

在CTF比赛中,经常需要利用文件写入功能来植入Webshell。结合filter协议可以绕过各种限制,成功写入一句话木马。

以之前的代码为例:

复制代码
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

构造的payload如下:

复制代码
filename=php://filter/write=convert.base64-decode/resource=shell.php
txt=PD9waHAgQGV2YWwoJF9QT1NbY21kXSk7  // "<?php @eval($_POST[cmd]); ?>"的Base64编码

当这个payload被处理时,Base64解码器会跳过<?php exit; ?>中的非法字符,解码后的内容成为有效的PHP一句话木马,可以被蚁剑、冰蝎等工具连接使用。

六、综合利用与实战技巧

6.1 过滤器链的设计原则

在实际CTF题目中,过滤器链的设计往往需要根据题目给出的代码进行针对性分析。设计有效的过滤器链需要遵循以下原则:

首先,理解目标代码的过滤逻辑。如果目标使用exit阻止代码执行,考虑使用Base64解码或strip_tags去除;如果目标过滤特定字符串,考虑使用编码转换改变字符串表现形式。

其次,注意过滤器的作用顺序。filter协议中的过滤器按照从左到右的顺序执行,每个过滤器的输出作为下一个过滤器的输入。顺序错误可能导致利用失败。

最后,考虑过滤器的兼容性。某些过滤器组合可能不兼容,或者在特定PHP版本下表现不同。在实际测试中,需要根据目标环境调整过滤器配置。

6.2 常见的过滤器组合

在CTF比赛中,以下几种过滤器组合较为常见:

Base64解码绕过 :使用convert.base64-decode配合resource参数,绕过死亡Exit限制。

字符串过滤 :使用string.strip_tags去除XML/HTML标签,适用于处理包含标签的内容。

编码转换 :使用convert.iconv.*进行字符编码转换,可以绕过某些基于字符串匹配的过滤。

多过滤器组合 :如string.strip_tags|convert.base64-decode,先去除标签再解码,组合利用多种过滤特性。

第四天

文件包含与Phar协议

文件包含漏洞和PHP伪协议的高级利用技巧。文件包含漏洞作为Web应用安全中最危险的漏洞类型之一,长期占据OWASP Top 10的重要位置。而PHP独特的伪协议机制为漏洞利用提供了丰富的攻击面,特别是filter协议和phar协议,在CTF比赛和实际渗透测试中都是必考知识点。

二、Phar文件包含漏洞深度分析

2.1 Phar文件结构解析

Phar(PHP Archive)是PHP内置的归档格式,类似于Java的JAR文件,用于将多个PHP文件打包成一个可执行文件。理解Phar的文件结构是掌握相关漏洞利用的基础。Phar文件由四个核心部分组成:stub(存根部分)、manifest(元数据区域)、contents(文件内容区域)和signature(签名部分)。

Stub是Phar文件的入口点,必须包含__HALT_COMPILER()函数调用,用于标识这是一个Phar文件。manifest区域存储了归档内各文件的元数据信息,包括文件名、压缩方式、文件大小等关键信息。contents区域存放实际的文件内容,可以包含任意类型的文件。signature用于对整个Phar文件进行完整性校验。

Phar归档支持三种打包格式:原生的Phar格式、Tar格式和Zip格式。这三种格式各有特点,其中Zip格式因其与操作系统工具的兼容性,在实际利用中最为常见。值得注意的是,PHP的phar协议能够自动识别这三种格式,这意味着攻击者可以使用普通的Zip压缩工具创建包含恶意代码的归档文件。

2.2 Phar协议识别机制

Phar协议的一个核心特性是它不依赖文件扩展名来识别归档格式,而是通过检测文件内容开头的Magic Bytes(魔数)来判断文件类型。这种设计为攻击者提供了极大的便利:可以将包含恶意代码的Zip文件重命名为图片格式(如.jpg),绕过基于扩展名的上传限制,然后仍然能够通过phar协议正常访问其中的PHP文件。

具体来说,当使用include('phar://test.jpg/shell.php')这样的语句时,PHP内核的处理流程如下:首先,phar_wrapper_open_url函数会解析URL,分离出归档文件名(test.jpg)和内部文件路径(shell.php);接着,phar_detect_phar_format函数会读取test.jpg文件的头部数据,检测其中的Magic Bytes;由于Zip文件的Magic Bytes是PK\x03\x04(PK是Phil Katz的缩写,Zip格式的创始人),PHP会识别出这是一个Zip格式的归档;最后,phar_parse_zipfile函数会解析Zip的中央目录结构,构建manifest哈希表,从而定位并读取shell.php的内容。

这种识别机制的本质是:phar协议将任何具有有效归档结构的文件都视为Phar归档,而不管它的扩展名是什么。这与compile_file钩子形成了鲜明对比------compile_file钩子会检查文件名是否包含.phar扩展名,只有直接包含.phar文件的请求才会触发Phar处理逻辑。

2.3 源码级调用链分析

从PHP内核源码的角度来看,phar协议的完整调用链涉及多个核心函数和数据结构的协作。当用户代码执行include('phar://1.jpg/2.php')时,PHP的Zend Engine会首先调用zend_include_or_eval函数处理包含操作。该函数会通过PHP Streams层调用php_stream_open_wrapper函数,指定phar://协议前缀。

Streams层会查找注册的phar_stream_wrapper,并调用phar_wrapper_open_url函数进行URL解析。phar_parse_url函数负责分离归档文件名和内部文件路径,将URL解析为arch(归档路径)和entry(内部文件路径)两部分。随后,phar_open_from_filename函数会打开归档文件,phar_detect_phar_format函数根据Magic Bytes检测文件格式。

对于Zip格式的文件,phar_parse_zipfile函数会执行以下操作:定位Zip文件末尾的中央目录记录(End of Central Directory),解析中央目录中的每个文件条目,构建manifest哈希表。manifest哈希表以文件名为键,以phar_entry_info结构为值,存储了每个文件在归档中的位置、压缩后大小、解压后大小等关键信息。

当需要读取内部文件内容时,phar_get_entry_data函数会在manifest中查找对应的条目,获取文件的位置偏移量。php_stream_alloc函数会创建一个php_stream结构,其ops指针指向phar_ops函数表,abstract指针指向phar_entry_info结构。最终,phar_stream_read函数负责从归档中读取指定文件的内容,返回纯PHP源码字符串给Zend Compiler进行编译执行。

2.4 关键数据结构详解

理解Phar机制需要掌握几个核心数据结构的含义和作用。php_stream结构是PHP Streams系统的基本抽象,包含ops函数指针表和abstract私有数据域。在Phar上下文中,abstract指针指向phar_entry_info结构,存储了当前操作的归档内文件信息。

phar_entry_info结构定义了归档内每个文件的元信息,包括fp_pos(文件在归档中的偏移位置)、uncompressed_size(解压后大小)、compressed_size(压缩后大小)、flags(标志位)和filename(文件名)等字段。这个结构是定位和读取归档内文件的关键。

phar_archive_data结构表示一个完整的Phar归档,包含fp文件句柄指针、manifest哈希表、is_zip/is_tar标志位以及可选的metadata元数据。manifest哈希表是归档的"目录",通过它可以快速查找任意文件的信息。

这三个数据结构形成了Phar系统的核心骨架:phar_archive_data表示整个归档,manifest中的每个条目是phar_entry_info,每个phar_entry_info通过php_stream结构对外提供读取接口。三者协作完成了从归档文件到可执行代码的完整转换过程。

三、PHP Filter协议高级技巧

3.1 Filter协议基础与应用场景

PHP的filter伪协议是PHP内核内置的数据处理机制,通过php://前缀进行调用。filter协议支持多种过滤器(Filter),可以对数据进行实时的过滤、转换和编码操作。filter协议既可以用于读取数据(read模式),也可以用于写入数据(write模式),这使其在文件包含和数据处理场景中具有极高的灵活性。

Filter协议的基本语法格式为php://filter/[read|write]=过滤器1|过滤器2|.../resource=目标资源。其中read和write分别指定过滤操作的方向,过滤器可以串联形成处理链,resource指定要处理的目标资源,可以是文件路径也可以是特殊的流(如php://input)。

在CTF比赛中,filter协议最常见的用途是利用Base64编码读取任意文件的源代码,绕过后缀名限制执行PHP代码。典型的用法是file=php://filter/read=convert.base64-encode/resource=index.php,这条语句会将index.php的内容进行Base64编码后返回,避免了直接读取文件内容时可能触发的后缀名限制。

3.2 "死亡Exit"绕过技术详解

在实际的Web应用和CTF题目中,开发者经常会在配置文件或缓存文件的开头添加<?php exit; ?>语句,以防止这些文件被直接访问时执行恶意代码。这种防御机制被称为"死亡Exit",是代码审计中常见的防护手段。

考虑以下代码:

复制代码
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

这段代码看似允许用户控制写入的文件名和内容,但由于exit语句的存在,即使成功写入一句话木马,PHP在执行该文件时也会立即退出,无法真正执行恶意代码。要利用这个"后门",需要解决两个挑战:如何绕过exit语句,以及如何让写入的内容被PHP解析执行。

Base64解码提供了绕过死亡Exit的可能。Base64编码只使用64个可打印字符(0-9、a-z、A-Z、+、/),PHP的base64_decode函数在解码时会自动跳过所有非Base64合法字符。<?php exit; ?>中的<?;>和空格都是非法字符,会被解码器忽略,只剩下phpexit这几个字符。

巧妙之处在于Base64的解码规则是每4个字符一组。phpexit共7个字符,需要补充1个填充字符(如"a")构成8个字符才能正常解码。因此,可以构造如下利用链:

复制代码
filename=php://filter/write=convert.base64-decode/resource=shell.php&txt=经过Base64编码的一句话木马

执行时,txt参数的内容会先经过Base64解码,<?php exit; ?>中的非法字符被跳过,解码后的phpexita(或其他有效字符组合)无法构成有效的exit语句,后续的一句话木马代码得以保留。

3.3 String.strip_tags过滤器

string.strip_tags过滤器可以去除字符串中的XML和HTML标签,模拟PHP内置的strip_tags函数。由于<?php exit; ?>在形式上类似于XML标签,可以使用strip_tags将其去除。请求格式为?filename=php://filter/write=string.strip_tags/resource=shell.php

然而,这种方法有一个明显的问题:strip_tags不仅会去除exit标签,还会去除用户传入的PHP代码中的标签,导致无法写入有效代码。解决方案是使用过滤器链组合,先用strip_tags去除exit,再用Base64解码还原代码:

复制代码
php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php

过滤器链的工作流程是:首先执行string.strip_tags去除<?php exit; ?>标签,然后执行convert.base64-decode将编码后的webshell还原。这种组合利用既去除了死亡Exit,又保留了有效的PHP代码,是CTF中绕过内容过滤的经典技巧。

3.4 Filter过滤器分类总结

PHP filter协议提供了三大类过滤器,各有不同的用途。字符串过滤器包括string.strip_tags(去除XML/HTML标签)、string.rot13(ROT13加密)、string.toupper(转为大写)等,主要用于字符串格式转换。转换过滤器包括convert.base64-encode和convert.base64-decode(Base64编解码)、convert.quoted-printable-encode和convert.quoted-printable-decode(引用可打印编码)、convert.iconv.*(字符编码转换)等,用于各种编码转换操作。压缩过滤器用于处理gzip和bzip2压缩数据。

在CTF比赛中,Base64编解码和字符串过滤是最常用的组合,而convert.iconv过滤器则出现在大型赛事的高难度题目中。理解这些过滤器的工作原理是灵活运用的前提。

四、文件包含实战技巧

4.1 phpinfo+LFI条件竞争利用

当目标网站同时存在phpinfo页面和文件包含漏洞时,可以利用phpinfo页面的特性实现getshell。phpinfo页面会显示所有请求信息,包括文件上传的临时文件路径。PHP处理文件上传时,会将上传的文件存储在临时目录(如/tmp),文件名类似phpXXXXXX的形式。

利用条件竞争getshell的流程需要理解几个关键原理。首先,临时文件在phpinfo页面加载完毕后才会被删除。其次,phpinfo页面会将所有数据都打印出来,包括HTTP头信息。第三,PHP默认的输出缓冲区大小为4096字节,每次向socket连接返回4096个字节。

条件竞争的具体步骤如下:

第一步,发送包含webshell的上传数据包给phpinfo页面,同时在HTTP头中填充大量垃圾数据,延长phpinfo页面的加载时间。

第二步,使用原生socket连接,每次读取4096个字节。一旦读取到的数据中包含临时文件名,立即发送第二个请求包含该临时文件。

第三步,利用时间差,在临时文件被删除前完成包含。

写入webshell的payload建议使用一次性写入的方式:

复制代码
<?php file_put_contents('/tmp/sky', '<?php eval($_REQUEST[sky]);?>');?>

这样一旦包含成功,就会在tmp目录下留下永久的webshell,后续利用更加便捷。

4.2 LFI+PHP7崩溃利用技术

当目标不存在phpinfo页面时,上述方法将失效。此时可以利用PHP7的一个特性------string.strip_tags过滤器导致的段错误(Segment Fault)。当使用如下请求时:

复制代码
http://ip/index.php?file=php://filter/string.strip_tags=/etc/passwd

PHP在执行过程中会出现Segment Fault。在此期间,如果同时上传文件,临时文件将不会被删除,而是保留在tmp目录中。

利用步骤包括:发送包含webshell的上传请求,同时触发strip_tags过滤器导致PHP崩溃;利用目录遍历漏洞列举tmp目录,找到临时文件名;包含临时文件执行webshell。

这种方法不需要phpinfo页面,利用条件更加宽松。关键在于利用PHP的过滤器导致进程崩溃,而临时文件的清理机制在进程正常退出时才会执行。

4.3 文件包含漏洞综合分析

文件包含漏洞的本质是应用程序使用用户可控的参数作为包含文件的路径。当include函数包含的文件路径可控时,攻击者可以让服务器执行任意PHP代码。常见的存在漏洞的代码模式包括:

复制代码
$file = $_GET['file'];
include($file);
相关推荐
妄汐霜3 小时前
小白学习笔记(MySQL基础中其他知识)
笔记·学习·mysql
一个响当当的名号3 小时前
lectrue1 关系模型和代数
笔记
GLDbalala3 小时前
GPU PRO 4 - 5.1 An Aspect-Based Engine Architecture 笔记
笔记
小裕哥略帅3 小时前
PMP学习笔记--过程
笔记·学习
ocean'3 小时前
渗透笔记总结
笔记
ljt27249606614 小时前
Flutter笔记--Isolate
笔记·flutter
weixin_440730504 小时前
02测试基础知识笔记
笔记
就叫飞六吧4 小时前
Jenkins 流水线全流程实战笔记
笔记·servlet·jenkins
别了,李亚普诺夫4 小时前
运算放大器的参数、选型与应用-学习笔记
笔记·学习