Kali Linux与DVWA靶场实战:手把手复现SQL注入漏洞攻击

发布时间:2026/7/10 14:59:03

Kali Linux与DVWA靶场实战:手把手复现SQL注入漏洞攻击 1. 项目概述从“安装”到“实战”的跨越很多刚接触网络安全的朋友拿到Kali Linux和DVWA靶场后第一步往往是照着教程“安装成功”然后对着界面发愣不知道下一步该干什么。这就像你拿到了一套顶级厨具和新鲜食材却只会开火不知道如何炒出一盘菜。今天我们就来彻底改变这个状态。我们的目标不是“安装DVWA”而是“利用DVWA在Kali上亲手、完整地复现一次经典的SQL注入漏洞攻击”。这个过程是从一个旁观者变成一个实践者的关键一步。你会清晰地看到一个看似简单的输入框背后是如何因为程序员的疏忽导致整个数据库大门洞开的。这不仅是为了完成一个实验更是为了在你的脑子里建立起对“漏洞”最直观、最肌肉记忆的理解。SQL注入SQL Injection作为OWASP Top 10的常客原理其实不复杂就是攻击者通过构造特殊的输入欺骗后端程序让其把用户输入的数据当作SQL代码的一部分去执行。DVWADamn Vulnerable Web Application则是一个故意设计得漏洞百出的PHP/MySQL应用是我们安全学习者的“沙盒”。在Kali Linux这个渗透测试标准环境中运行它能给我们提供一个最贴近实战的隔离实验场。通过这次手把手的复现你将掌握漏洞环境的搭建、漏洞原理的验证、攻击手法的实操以及修复思路的溯源形成一个完整的学习闭环。2. 环境准备与靶场部署打造专属漏洞实验室2.1 Kali Linux基础环境确认在开始之前确保你的Kali Linux处于一个“干净”且“联网”的备战状态。我个人的习惯是在开展任何实验前先做三件事更新源、升级系统、安装必备服务。打开终端依次执行sudo apt update sudo apt full-upgrade -y这个过程可能会花费一些时间但它能确保你系统中的所有工具都是最新的避免因为版本问题导致一些莫名其妙的问题。接下来我们需要Kali扮演一个Web服务器的角色来运行DVWA因此需要安装LAMPLinux, Apache, MySQL, PHP套件。虽然Kali自带了Apache和PHP但为了环境完整我们可以使用一个集成命令来安装MySQL现在是MariaDB并确保所有组件就绪sudo apt install -y mariadb-server mariadb-client php php-mysql libapache2-mod-php安装完成后启动Apache和MariaDB服务并设置开机自启sudo systemctl start apache2 sudo systemctl start mariadb sudo systemctl enable apache2 sudo systemctl enable mariadb此时在浏览器访问http://127.0.0.1或http://localhost你应该能看到Apache的默认欢迎页面。这证明你的Web服务已经跑起来了。注意Kali Linux默认以root用户运行这在生产环境中是极度危险的但在我们的本地靶场环境中为了方便可以暂时接受。但在未来学习其他服务配置时务必建立正确的权限观念。2.2 DVWA靶场的下载与配置DVWA的部署是核心步骤很多教程只告诉你怎么做却不解释为什么这里我们把每一步背后的意图讲清楚。首先我们进入Apache的网站根目录。在Kali上通常是/var/www/html/。我们将在这里直接部署DVWA。cd /var/www/html/接着使用git克隆DVWA的源代码。如果系统提示未安装git使用sudo apt install -y git安装。sudo git clone https://github.com/digininja/DVWA.git克隆完成后你会看到一个DVWA文件夹。这里有一个关键操作修改文件所有权。Apache服务进程通常以www-data用户身份运行需要能够读写这个目录下的某些文件比如上传目录、配置文件。执行sudo chown -R www-data:www-data DVWA/ sudo chmod -R 755 DVWA/chown命令将DVWA目录及其下所有文件的所有者和所属组都改为www-data。chmod 755则设置了权限所有者可读可写可执行同组用户和其他用户可读可执行。这为Web应用正常运行提供了必要的权限基础。接下来是配置数据库。DVWA需要一个MySQL数据库来存储数据。我们使用MariaDB的命令行客户端来操作sudo mysql -u root进入MySQL命令行后依次执行以下SQL语句来创建数据库、用户并授权CREATE DATABASE dvwa; CREATE USER dvwalocalhost IDENTIFIED BY pssw0rd; GRANT ALL PRIVILEGES ON dvwa.* TO dvwalocalhost; FLUSH PRIVILEGES; EXIT;这里我们创建了一个名为dvwa的数据库一个用户名为dvwa、密码为pssw0rd的本地用户并将dvwa数据库的所有权限授予了这个用户。FLUSH PRIVILEGES;命令是让权限更改立即生效。最后复制DVWA的配置文件模板并对其进行编辑cd DVWA/config/ sudo cp config.inc.php.dist config.inc.php sudo nano config.inc.php在nano编辑器中找到以下关键行并进行修改确保它们与上面数据库配置一致$_DVWA[ db_server ] 127.0.0.1; $_DVWA[ db_database ] dvwa; $_DVWA[ db_user ] dvwa; $_DVWA[ db_password ] pssw0rd;还有一个极其重要的配置是$_DVWA[ default_security_level ]。它默认为impossible这意味着所有漏洞防护都是最高级别不利于我们学习攻击。务必将其修改为low$_DVWA[ default_security_level ] low;保存并退出编辑器在nano中CtrlX然后按Y确认再按Enter保存。2.3 访问靶场与初始化设置现在打开浏览器访问http://127.0.0.1/DVWA/。首次访问时你会看到一个红色的“Setup / Reset Database”按钮。点击它。这个操作会执行DVWA自带的初始化脚本在dvwa数据库中创建所需的数据表并插入一些测试数据如用户账号。如果一切顺利页面会提示“Setup Successful”。此时使用页面上的默认凭证登录用户名admin密码password登录成功后在左侧菜单找到“DVWA Security”选项。在这里你可以看到当前的安全等级是“Low”。这正是我们需要的。如果显示其他等级请手动将其设置为“Low”。这个设置决定了后端代码对用户输入的过滤和检查严格程度。“Low”级别意味着几乎没有防护非常适合我们进行漏洞原理的学习和复现。至此你的专属漏洞实验室已经搭建完毕。这不仅仅是安装更是理解了每一个配置项的意义为后续的实战打下了坚实的基础。3. SQL注入漏洞原理深度解析3.1 从一段代码理解漏洞根源在DVWA的“SQL Injection”关卡我们面对的是一个简单的用户ID查询功能。前端是一个输入框让我们猜猜后端代码Low安全级别下可能是什么样子。它很可能类似下面这段PHP代码$id $_GET[id]; // 直接从URL参数获取用户输入未经任何处理 $query SELECT first_name, last_name FROM users WHERE user_id $id; $result mysqli_query($connection, $query);这段代码的逻辑非常直接获取用户输入的id拼接到SQL查询字符串中然后执行。问题就出在这个“拼接”上。在编程中代码SQL语句和数据用户输入的id应该是分离的。但这里它们被粗暴地混合在了一起。想象一下如果用户输入的不是一个数字如1而是一段精心构造的字符串1 OR 11。那么拼接后的SQL语句会变成SELECT first_name, last_name FROM users WHERE user_id 1 OR 11WHERE子句的含义完全改变了。它不再寻找user_id等于‘1’的记录而是寻找user_id1或者11的记录。在逻辑上11这个条件永远为真True。因此整个WHERE条件就变成了True OR True如果user_id1存在或者False OR True最终结果永远是True。这意味着这条查询语句将返回users表中的所有记录。这就是SQL注入最经典的“永真式”攻击。它利用了程序将用户输入原样代入代码执行层的缺陷使得攻击者能够突破原有的查询逻辑操纵数据库执行非预期的命令。3.2 漏洞的危害等级与攻击意图一次成功的SQL注入所能造成的危害远不止“看到所有用户名单”这么简单。它的危害是阶梯式的取决于数据库的权限、后端代码的逻辑以及攻击者的技巧信息泄露Information Disclosure这是最基本的一层正如我们上面复现的可以绕过条件查询 dump 出整张表的数据包括用户名、邮箱、哈希密码等敏感信息。数据篡改Data Manipulation如果数据库用户拥有写权限INSERT,UPDATE,DELETE攻击者可以修改商品价格、清空用户表、甚至给自己添加一个管理员账户。例如输入1; UPDATE users SET password hacked WHERE user_id 1; --。--在SQL中是注释符用于注释掉原查询后面可能存在的其他字符确保语句完整执行。权限提升Privilege Escalation通过查询数据库的系统表如MySQL的information_schema攻击者可以探查数据库结构寻找其他高权限的账户或漏洞。命令执行Command Execution在某些极端且配置错误的情况下如启用xp_cmdshell的MSSQL或利用SELECT ... INTO OUTFILE写WebshellSQL注入可以导致在数据库服务器上执行任意系统命令从而完全控制服务器。理解这些危害层级能帮助我们在复现漏洞时不仅仅满足于“弹出数据”而是去思考“如果我是攻击者我下一步想干什么”。这种思维转变至关重要。4. 手把手实战在DVWA上复现SQL注入4.1 第一步漏洞探测与确认打开DVWA将安全级别设置为“Low”然后进入“SQL Injection”页面。页面上有一个输入框提示我们输入User ID。首先我们进行最基础的探测输入一个单引号。点击“Submit”。如果页面返回了一个SQL语法错误例如“You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version...”。这是一个强烈的信号它表明我们输入的单引号被直接拼接进了SQL语句破坏了其语法结构从而让数据库报错。错误信息本身可能泄露数据库类型这里是MariaDB、表结构等宝贵信息。错误回显是SQL注入的“好朋友”它为我们后续的构造提供了重要反馈。如果输入后页面只是空白、报错但不显示具体信息、或跳转到错误页则说明可能存在注入点但错误被屏蔽了需要采用盲注Blind SQLi等其他技术今天我们聚焦于有回显的注入。4.2 第二步构造永真条件绕过身份验证确认存在注入点后我们尝试经典的永真式攻击。在输入框中输入1 OR 11点击提交。你会发现页面返回了数据库中多条甚至全部的用户记录通常是ID为1的用户信息加上其他用户信息。这是因为我们构造的11这个条件永远为真使得WHERE子句整体为真查询不再受限于特定的user_id。为了更“干净”地获取所有数据我们还可以尝试 OR 11 --这里有几个关键点开头的用于闭合原查询中user_id 的这个引号。OR 11提供了永真条件。--注意后面有个空格是SQL的单行注释符。它的作用是注释掉原查询中我们输入值之后的部分比如可能存在的另一个闭合引号。这能确保我们的注入语句语法完整不会因为多余的引号而报错。提交后同样应该返回所有用户数据。这一步的成功标志着我们已能完全操控该查询语句的WHERE条件逻辑。4.3 第三步利用UNION查询获取更多信息UNION操作符是SQL注入中用于“扩充”查询结果、窃取其他表数据的利器。它可以将两个或多个SELECT语句的结果集合并成一个结果集。使用UNION有两个关键前提每个SELECT语句必须拥有相同数量的列。列的数据类型也必须相似。所以我们的首要任务是确定原查询返回的列数。这里有两种常用方法方法一使用ORDER BY子句探测。ORDER BY用于对结果集按某一列排序。如果ORDER BY 5表示按第5列排序。如果原查询只有3列那么ORDER BY 5就会报错未知列。我们可以利用这个特性来探测。 依次尝试输入1 ORDER BY 1 -- 1 ORDER BY 2 -- 1 ORDER BY 3 -- 1 ORDER BY 4 --当输入ORDER BY 4时如果页面返回错误或与ORDER BY 3时显示的结果不同则说明原查询的列数最大为3。在DVWA的SQL注入Low中我们可以测试出列数为2first_name,last_name。方法二使用UNION SELECT NULL递增探测。NULL可以匹配任何数据类型因此用起来很方便。1 UNION SELECT NULL --如果报错“使用的SELECT语句有不同的列数”说明列数不对。我们不断增加NULL的个数直到页面正常返回通常会多显示一行NULL数据1 UNION SELECT NULL, NULL --在DVWA中当使用两个NULL时页面应能正常显示这再次确认了原查询有2列。确定列数后我们就可以窃取信息了。首先替换NULL为具体信息确定这两列在页面中显示的位置。输入1 UNION SELECT Column1, Column2 --观察页面返回结果看‘Column1’和‘Column2’这两个字符串分别出现在页面的哪个位置通常是First name和Last name的位置。这能帮助我们理解数据回显的对应关系。接下来就是信息收集的狂欢。我们可以利用数据库的系统表。以MySQL/MariaDB为例获取当前数据库名和用户名1 UNION SELECT database(), user() --获取服务器上所有数据库的列表需要权限1 UNION SELECT schema_name, NULL FROM information_schema.schemata --获取当前数据库dvwa中的所有表名1 UNION SELECT table_name, NULL FROM information_schema.tables WHERE table_schemadatabase() --执行后你可能会看到guestbook,users等表名。获取users表的所有列名1 UNION SELECT column_name, NULL FROM information_schema.columns WHERE table_schemadatabase() AND table_nameusers --你会看到user_id,first_name,last_name,user,password,avatar等列名。最终一击dump出users表的所有用户名和密码哈希值1 UNION SELECT user, password FROM users --此时页面上会清晰地显示所有用户的登录名和经过MD5哈希处理的密码。例如admin的密码哈希是5f4dcc3b5aa765d61d8327deb882cf99这正是password的MD5值。实操心得在实际渗透测试中信息收集这一步往往比直接攻击更花时间。information_schema数据库是MySQL的“元数据宝库”熟练掌握对其的查询是进行高效SQL注入的关键。同时要注意观察页面回显有时数据可能只显示在页面源码中或需要触发特定条件才能显示。4.4 第四步自动化工具初探以SQLmap为例手动注入能帮助我们深刻理解原理但在面对更复杂的情况或需要快速测试时自动化工具是必不可少的。SQLmap是这方面的王者。请注意仅限在自己的靶场环境中使用。首先我们需要从DVWA页面获取当前有效的Cookie。在浏览器中按F12打开开发者工具切换到“网络”(Network)标签刷新DVWA页面点击任意一个请求在“请求头”(Headers)中找到Cookie:那一长串值通常包含PHPSESSID。假设我们的DVWA地址是http://127.0.0.1/DVWA/vulnerabilities/sqli/并且我们已登录拥有有效Cookie。在Kali终端中可以运行如下命令进行基础探测sqlmap -u http://127.0.0.1/DVWA/vulnerabilities/sqli/?id1SubmitSubmit --cookiePHPSESSID你的session值; securitylow参数解释-u: 指定目标URL。--cookie: 提供登录后的Cookie因为DVWA的SQL注入页面需要登录后才能访问。运行后SQLmap会进行一系列测试并最终告诉你是否存在注入点、是什么类型的注入。你可以通过添加更多参数来让它完成我们手动做的所有事情例如--dbs: 枚举所有数据库。-D dvwa --tables: 枚举dvwa数据库中的所有表。-D dvwa -T users --dump: 导出dumpusers表的所有数据。注意事项虽然SQLmap强大但切忌成为“脚本小子”。理解它每一步在做什么比单纯运行出一个结果更重要。在靶场中可以打开-v 3参数查看详细的payload发送和响应过程这是学习payload构造的绝佳方式。5. 漏洞防御原理与代码层面修复5.1 为什么Low、Medium、Impossible级别的代码不同DVWA为我们提供了三个安全级别的源代码对比这是绝佳的学习材料。通过对比我们可以直观地看到防御是如何层层加码的。Low级别如前所述直接拼接用户输入毫无防护。Medium级别查看源码你会发现它使用了mysql_real_escape_string()函数来处理输入。这个函数会对特殊字符如单引号、双引号、反斜杠等进行转义例如将转义为\。这样攻击者输入1 OR 11会被转换成1\ OR \1\\1这个字符串会被当作一个普通的文本值而不会被解析为SQL代码。但是Medium级别使用了下拉菜单select而非输入框并且通过$_POST和id $id没有引号的形式接收数字ID。这时如果攻击者通过抓包修改POST数据注入数字型的payload如1 OR 11mysql_real_escape_string()对数字是无效的因为数字本身不需要引号。因此Medium级别虽然引入了过滤但防御并不完整。High级别在High级别代码将输入限制在了单个字符并且查询逻辑发生了变化例如使用了LIMIT 1。这大大增加了注入的难度但理论上仍可能存在盲注。Impossible级别这才是真正的修复方案。它使用了预处理语句Prepared Statements和参数化查询Parameterized Queries。5.2 黄金法则使用预处理语句/参数化查询这是防御SQL注入唯一被广泛认可的根本性方法。我们以PHP的PDO扩展为例看看Impossible级别的代码是怎么写的$data $db-prepare( SELECT first_name, last_name FROM users WHERE user_id (:id) LIMIT 1; ); $data-bindParam( :id, $id, PDO::PARAM_INT ); $data-execute();这里发生了什么准备Prepare首先我们发送一个SQL语句模板给数据库。这个模板里用户输入的位置用一个占位符如:id表示。数据库会预先编译这个模板确定它的执行计划比如用哪个索引。绑定Bind然后我们将用户输入的变量$id“绑定”到占位符:id上。PDO::PARAM_INT明确告诉数据库这个参数是一个整数。执行Execute最后数据库将绑定的值代入已编译好的执行计划中运行。关键点在于无论用户输入1、1 OR 11还是任何乱七八糟的内容在“绑定”这一步这些输入都只会被当作纯粹的“数据”来处理而绝不会被解释为SQL“代码”的一部分。数据库清楚地知道:id位置应该是一个整数值即使你传入一个带引号的字符串它也会尝试转换或直接报错而不会改变查询的逻辑结构。这就好比寄信错误的拼接方式是把收件人地址代码和信件内容数据用胶水混在一起写在一张纸上邮递员数据库可能分不清。而参数化查询是准备一个标准信封模板信封上印好了“收件人____”的空白占位符然后把地址写在便签纸数据上再贴到空白处。邮递员永远不会把便签纸上的内容误认为是信封本身印刷的指令。5.3 其他辅助防御措施虽然参数化查询是核心但良好的安全实践需要多层防御最小权限原则为Web应用连接数据库的账户分配最小必要的权限。例如只授予SELECT权限在某些表上而不是整个数据库的ALL PRIVILEGES。这样即使发生注入危害也被限制在局部。输入验证与白名单在数据到达SQL层之前就进行过滤。例如如果期望输入是数字就用intval()函数强制转换为整数如果是特定选项就用白名单校验只允许预设的几个值。这能在前端阻止大量非法输入。关闭错误回显在生产环境中避免将详细的数据库错误信息直接显示给用户。应使用自定义的错误页面并将详细错误记录到安全的日志文件中供管理员查看。这可以增加攻击者探测漏洞的难度盲注。Web应用防火墙WAF部署WAF可以帮助过滤常见的攻击payload作为一道网络层的防线。6. 实战中常见问题与排查技巧6.1 靶场访问问题排查表问题现象可能原因排查步骤与解决方案访问http://127.0.0.1/DVWA显示404Apache未运行或DVWA目录位置错误1.sudo systemctl status apache2检查服务状态。2. 确认DVWA文件夹在/var/www/html/下。3. 检查目录名大小写是否准确。点击“Setup / Reset Database”后报错提示数据库连接失败config.inc.php配置错误或数据库服务未启动1.sudo systemctl status mariadb检查数据库服务。2. 仔细核对config.inc.php中的数据库IP、用户名、密码。3. 登录MySQL命令行确认dvwa用户和数据库已创建且有权限。登录后无法修改安全等级为LowPHP的会话session或Cookie问题1. 清除浏览器Cookie和缓存重新登录。2. 检查/var/www/html/DVWA/hackable/uploads/目录权限确保Web用户(www-data)可写。进行SQL注入时页面空白或报错但不显示数据PHP配置可能禁用了错误显示或代码逻辑有变1. 在DVWA的config.inc.php中可以临时设置$_DVWA[ display_errors ] true;以显示错误。2. 确认URL中的参数名是否正确如?id1。3. 使用Burp Suite等工具抓包查看原始HTTP响应信息可能在HTML源码里。6.2 SQL注入实操中的“坑”与技巧注释符的使用在MySQL中注释符--后面必须跟一个空格--才是有效的单行注释。很多新手因为少了这个空格导致payload执行失败。也可以使用#作为注释符。在URL中#有特殊含义可能需要编码为%23。字符串与数字型注入DVWA Low级别是字符型注入查询条件有引号$id。但很多注入点是数字型的如WHERE id $id。对于数字型注入不需要闭合引号payload更简单例如1 OR 11。判断类型是注入的第一步。信息获取的路径当UNION SELECT出来的数据没有直接显示在页面上时要善于利用浏览器的“查看页面源代码”功能。有时数据被隐藏在HTML注释、表单的value值或某个不显示的标签属性里。工具与手动的平衡SQLmap这类自动化工具在探测和利用方面非常高效但它发出的请求量大、特征明显极易被WAF拦截。在真实环境测试或CTF比赛中学会手动构造精巧的payload以及利用Burp Suite的Repeater模块进行手动测试和调试是更高级的技能。编码与绕过随着防御手段升级简单的payload可能被过滤。这时需要了解一些绕过技巧比如大小写混淆UnIoN SeLeCt双写关键字UNIUNIONON SELSELECTECT如果过滤代码是删除UNION这个单词双写后删除中间的UNION剩下的字符又会组合成UNION使用注释分割U/**/NION SEL/**/ECT十六进制或URL编码将关键部分编码。6.3 从复现到思考构建你的安全思维完成一次漏洞复现后千万不要就此停止。试着问自己以下几个问题把实验的价值最大化如果安全级别是Medium我该如何利用研究其源码看看它用了什么过滤这个过滤有什么弱点比如数字型注入是否有效我获取的密码哈希MD5如何破解可以尝试在cmd5.com等网站查询或使用Kali中的hashcat工具进行离线爆破。这引出了密码存储安全的话题。除了users表我还能获取什么尝试探索information_schema中的其他信息比如PROCESSLIST查看当前数据库连接、GLOBAL_VARIABLES查看数据库配置。如何发现一个网站是否存在SQL注入除了手动加测试如何系统性地对每个参数进行FUZZ模糊测试通过DVWA这个靶场我们完成了一次从环境搭建、原理理解、手动攻击、工具使用到防御分析的完整旅程。记住所有操作都必须在合法、授权的环境中进行。真正的网络安全工程师目标是利用这些知识去发现并修复漏洞筑起防御的城墙而不是去破坏它。希望这篇手把手的长文能成为你网络安全实践之路上一块坚实的垫脚石。

相关新闻