DVWA靶场实战(七)

七、SQL Injection:

1.漏洞原理:

  SQL Inject中文叫做SQL注入,是发生在web端的安全漏洞,主要是实现非法操作,例如欺骗服务器执行非法查询,他的危害在于黑客会有恶意获取,甚至篡改数据库信息,绕过登录验证,原理是针对程序员编写数据库程序的疏忽,通过执行SQL语句,实现目的性攻击,他的流程可以分为判断数据库类型、判断数据库版本、判断注入点、判断注入类型、判断数据字段数、判断显示位、获取数据库中的信息。

  简单来说就是通过web表单把SQL命令提交到数据库,由于管理员没有细致的过滤用户输入的数据,造成字符串拼接,进而恶意的SQL语句被执行,造成数据库信息泄露、网页篡改、数据库被恶意操作等后果。

2.SQL Injection分类:

  从注入参数类型分类:数字型注入、字符型注入、搜索型注入

  从注入方法分:报错注入、布尔盲注、时间盲注、联合查询注入、堆叠注入、内联查询注入、宽字节注入

  从提交方式分:GET注入、POST注入、COOKIE注入、HTTP头注入

3.SQL注入漏洞的利用思路:

(1)第一步:

  寻找可能的漏洞站点,也就是目标站点。

(2)第二步:

  通过站点的后缀名来判断网站的使用的是哪一种数据库,简单的判断可以观察脚本后缀,如果是“.asp”为后缀,则数据库可能是access,如果是“.aspx”为后缀可能是MsSql,如果是“.php”为后缀的可能是mysql数据库,如果是“.jsp”,可能是orcale数据库。

(3)第三步:

  是寻找站点存在的注入点,可以再URL中进行尝试输入参数后在拼接上引号,通过回显可以判断该站点传输方式,为GET或POST方式POST需要查看表单数据,POST注入在表单中提交引号,而cookie注入可以通过burpsuite工具来判断注入点。

(4)第四步:

  判断注入点的类型,如果加减法运算按照是否是数字型注入,如果单引号和页面报错信息来进一步判断是哪一种的字符型注入。

(5)第五步:

  闭合我们输入的SQL语句,通过注释的方式来获取数据,有以下几种情况:

    ①当页面有回显但是没有显示位的时候,可以选择报错注入,常见的报错注入利用函数有那么几个:floor()、exp()、updatexml()、exteractvalue()等函数。

    ②当页面没有明确的回显信息的时候,但是输入正确和输入错误的时候页面不相同的情况下,可以考虑报错注入,报错注入常见的函数有:ascii()、substr()、length()、concat()等函数。

    ③当页面没有会回显也没有报错信息的时候,可以使用时间盲注去获取数据库中的数据,时间盲注常见的函数有:sleep()。

    其他:当然还有很多其他的注入方式,比如:宽字节注入、base64注入、cookie注入、http头部注入、二次注入、堆叠注入等。

4.漏洞危害:

  (1)获取企业内部、个人未授权的隐私信息,或一些机密数据。

  (2)页面内容伪造篡改。

  (3)数据库、服务器、网络(内网、局域网)受到攻击,严重时可导致服务器瘫痪,无法正常运行。

5.防御以及修复措施:

  (1)对数据库进行严格的监控。

  (2)对用户提交的数据进行严格的把关,多次筛选过滤。

  (3)对用户内数据内容进行加密。

  (4)代码层面最佳防御sql漏洞方案:采用sql语句预编译和绑定变量,是防御sql注入的最佳方式。

6.注意事项:

  我们在进行查询的时候可能会遇到union联合查询我们利用Navicat Premium 15链接我们的dvwa的MySQL数据库,然后我们找到dvwa然后右键右键点击选择“设计表”。接下来我们将“first_name”、“last_name”、“user”等全部将默认排序的“utf8_unicode_ci”修改为“utf8_general_ci”。修改完成然后保存,完成修改。就可以正常使用union联合查询语句了。

7.实战:

(1)Low:

  代码分析:

<?php

if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
} mysqli_close($GLOBALS["___mysqli_ston"]);
break;
case SQLITE:
global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']);
#$sqlite_db_connection->enableExceptions(true); $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
} if ($results) {
while ($row = $results->fetchArray()) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
} ?> 

  可以看出来基本上没有防护,所以我们直接开始攻击了。

  首先利用语句“1’and’1’=’1”和“1’and’1’=’2”来判断是否有注入点。以下为两种语句的不同回显,可以判断出是有注入点的。

  判断完注入点我们尝试获取他的判断他的列数,利用“1’order by 1#”语句替换“1”来判断行数,这里我们“#”或者“--+”的作用是注释掉原本语句后面的内容,让我们能够自如的进行查询。然后我们最后查询到“1’order by 3#”就弹出报错,就说明列数应该为两列。

  判断完列数后,我们开始利用联合查询语句,这里使用“-1’union select 1,2#”,来判断显示位。我们这里可以看见回显了另外一个语句,就说明显示位为2,一般靶场中比如sqli-labs那种就会需要将前面的“1”改为“-1”,也就是“-1’union select 1,2#”才会正常回显我们查询的内容。这里我们也可以,之后的演示排除干扰就将第一行结果屏蔽了。

  这里我们收集数据库名称利用database()函数,它的作用是返回数据库名,我们在后续查询中是需要数据库才能进行的所以利用语句“-1’union select 1,database()#”接下来进行查询,得到结果数据库名称为“dvwa”。

  我们收集完以上的数据库信息后,我们再查询一下数据库的版本,因为mysql数据库注入大概是以5.0版本为分界线,5.0以下没有information表,5.0以上则都有information表。这里的MySQL版本为5.7.26,那么我们就可以查询information表来找到数据库的表名。

  接下来,我们查询dvwa数据库有哪些表名,利用联合查询语句“-1'union select 1,table_name from information_schema.tables where table_schema='dvwa'#”来进行对表名的查询。得到两个表名“guestbook”和“users”。

  我们查询好表名后,我们查询列名,利用语句“-1'union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name='users')#”得到“user_id,first_name,last_name,user,password,avatar,last_login,failed_login

”的结果,这个时候我们就可以知道我们应该查询“user”和“password”。

  然后我们查询好表名为“users”和列名“user”、列名“password”后,我们利用查询语句“-1’union select user,password from users”,然后查询得到账号和密码,密码是MD5加密需要自己解密查询。

(2)Medium:

  代码分析:

<?php

if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ]; $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id); switch ($_DVWA['SQLI_DB']) {
case MYSQL:
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' ); // Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Display values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
break;
case SQLITE:
global $sqlite_db_connection; $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
} if ($results) {
while ($row = $results->fetchArray()) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
} // This is used later on in the index.php page
// Setting it here so we can close the database connection in here like in the rest of the source scripts
$query = "SELECT COUNT(*) FROM users;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
$number_of_rows = mysqli_fetch_row( $result )[0]; mysqli_close($GLOBALS["___mysqli_ston"]);
?>

  使用POST提交方式,还使用了转义预防SQL注入。

  我们开始攻击,首先我们打开BP进行截包,得到如下的数据包。并将其发送到“Repeater”,方便接下来的注入回显操作。

  我们同样利用“1 and 1=1”和“1 and 1=2”来判断,是否这里为注入点,观察两者的有差异且页面未报错,就说明这里是注入点。

  这里我们可以看到,同样是在“3”的时候,我们这里用“order by 3”查询返回报错,所以我们这里判断前面只查询两列。利用语句“1 union select 1,2#”来进行验证,返回正确,验证成功。

  此时同样判断完列数后,我们同时对版本和数据库名称进行查询,利用语句“1 union select database(),version()#”。此时观察回显,发现同时回显了数据库名称和数据库版本dvwa和5.7.26。

  在查询完数据库后,我们先查询表名,然后查询列名,利用语句“1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=’dvwa’)#”,但发现报错,没有任何反应,将“dvwa”改为“database()”后查询得到“users”表名后。后来发现是对单引号进行了转义。所以我们将单引号连同users一起写为16进制表示为“0x75736572”。

  查询列名“1 union select (select group_concat(column_name) from information_schema.columns where table_name=0x75736572),(select group_concat(table_name) from information_schema.tables where table_schema=database())”,得到关键列名“user”和“password”。

  最后我们利用,“1 union select user,password from users#”语句,得到最后的结果。

(3)High:

  代码分析:

<?php

if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ]; switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' ); // Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
break;
case SQLITE:
global $sqlite_db_connection; $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
} if ($results) {
while ($row = $results->fetchArray()) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
} ?> 

  使用了session 获取id 值,闭合方式单引号闭合。

  虽然用了session来获取id值,但是同样也是数字型注入,利用同样的方法,然后最后用“-1’union select user,password from users #”,即可得到答案。

(4)Impossible:

  代码分析:

<?php

if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input
$id = $_GET[ 'id' ]; // Was a number entered?
if(is_numeric( $id )) {
$id = intval ($id);
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// Check the database
$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();
$row = $data->fetch(); // Make sure only 1 result is returned
if( $data->rowCount() == 1 ) {
// Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ]; // Feedback for end user
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
break;
case SQLITE:
global $sqlite_db_connection; $stmt = $sqlite_db_connection->prepare('SELECT first_name, last_name FROM users WHERE user_id = :id LIMIT 1;' );
$stmt->bindValue(':id',$id,SQLITE3_INTEGER);
$result = $stmt->execute();
$result->finalize();
if ($result !== false) {
// There is no way to get the number of rows returned
// This checks the number of columns (not rows) just
// as a precaution, but it won't stop someone dumping
// multiple rows and viewing them one at a time. $num_columns = $result->numColumns();
if ($num_columns == 2) {
$row = $result->fetchArray(); // Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ]; // Feedback for end user
$html .= "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} break;
}
}
} // Generate Anti-CSRF token
generateSessionToken(); ?>

  此为防御模板,CSRF、检测 id 是否是数字,prepare 预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 SQL 注入。

DVWA靶场实战(七)——SQL Injection的更多相关文章

  1. DVWA全级别之SQL Injection(SQL注入)

    DVWA全级别之SQL Injection(注入)   DVWA简介 DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web ...

  2. [靶场实战]:SQL注入-显错注入

    SQL注入的本质:就是将用户输入的数据当作代码带入执行. 注入条件: 1.用户能控制输入 2.能够将程序原本执行的代码,拼接上用户输入的数据进行执行 首先检查是否存在注入点 Rank1: 构造语句 ? ...

  3. 使用sqlmap注入DVWA的SQL Injection菜单

    1 使用sqlmap注入DVWA的SQL Injection菜单 本教程中的登陆地址:http://192.168.0.112/dvwa/login.php 1.1 获取cookie信息 1) 使用a ...

  4. sqlmap dvwa SQL Injection使用小记

    刚刚开始学习sql injection,初步使用sqlmap,使用 GET http://www.dvssc.com/dvwa/vulnerabilities/sqli/?id=1&Submi ...

  5. DVWA SQL Injection 通关教程

    SQL Injection,即SQL注入,SQLi,是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的.SQL注入漏洞的危害巨大,常常会导致整个数据库被“脱 ...

  6. DVWA SQL Injection(Blind) 通关教程

    SQL Injection(Blind),即SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是 ...

  7. 【DVWA】SQL Injection(SQL 注入)通关教程

    日期:2019-07-28 20:43:48 更新: 作者:Bay0net 介绍: 0x00.基本信息 关于 mysql 相关的注入,传送门. SQL 注入漏洞之 mysql - Bay0net - ...

  8. (十二)DVWA全等级SQL Injection(Blind)盲注--SQLMap测试过程解析

    一.测试前分析 前文<DVWA全等级SQL Injection(Blind)盲注-手工测试过程解析> 通过手工测试的方式详细分析了SQL Injection(Blind)盲注漏洞的利用过程 ...

  9. (十一)DVWA全等级SQL Injection(Blind)盲注--手工测试过程解析

    一.DVWA-SQL Injection(Blind)测试分析 SQL盲注 VS 普通SQL注入: 普通SQL注入 SQL盲注 1.执行SQL注入攻击时,服务器会响应来自数据库服务器的错误信息,信息提 ...

  10. DVWA之 SQL Injection(Blind)

    SQL Injection(Blind) SQL Injection(Blind),即SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法 ...

随机推荐

  1. 7_vue的数据代理,双向绑定

    回顾 object.defineProperty() 方法 区别 defineProperty == 给对象定义属性用的 需要传递三个基本参数 需要定义属性的对象名 你要定义的属性叫什么名字(比如给p ...

  2. XPAND模板语言语法1.0

    XPAND模板语言语法1.0 Xpand模板语言一般写在以.xpt为结尾的文本文件中 ,以"« »" 作为开头和结尾  .Xpand语言主要包括以下几个标签: «IMPORT», ...

  3. 十六、资源控制器之DaemonSet

    资源控制器之DaemonSet DaemonSet 确保全部(或者一些) Node上运行一个 Pod 的副本,当有 Node 加入集群时,也会为他们新增一个 Pod,当有 Node 从集群移除时,这些 ...

  4. JS逆向实战4--cookie——__jsl_clearance_s 生成

    分析 网站返回状态码521,从浏览器抓包来看,浏览器一共对此地址请求了三次(中间是设置cookie的过程): 第一次请求:网站返回的响应状态码为 521,响应返回的为经过 混淆的 JS 代码:但是这些 ...

  5. Vue 实现小小记事本

    1.实现效果 用户输入后按回车,输入的内容自动保存,下方会显示记录的条数,鼠标移动到文字所在div上,会显示删除按钮,点击按钮,相应记录会被删除,下方的记录条数会相应变化,点击clear,所有记录会被 ...

  6. nginx性能监控

    nginx自带监控模块,需要在nginx编译安装时加入监控模块. 1. 编译安装时加入监控模块 ngin编译安装时,加入编译参数为:--with-http_stub_status_module.如下所 ...

  7. 【深入浅出 Yarn 架构与实现】2-2 Yarn 基础库 - 底层通信库 RPC

    RPC(Remote Procedure Call) 是 Hadoop 服务通信的关键库,支撑上层分布式环境下复杂的进程间(Inter-Process Communication, IPC)通信逻辑, ...

  8. 抠网页标题栏logo(图标)

    1.打开自己需要抠的网页,例如百度页面 2.在这个网页链接后面+" /favicon.ico " 就可以提取ico图片 3.回车进去,右键鼠标,选择另存为图片就可以成功保存网页中的 ...

  9. cookies和session总结

    1.作为基础知识,但是也是容易被我们忽略的知识. 2.从我的一次面试中,面试官问到,session是什么?和cookies有什么关系,当时我以为很简单,便顺口回答到,session是为了解决http无 ...

  10. 【2022-11-28】Docker部署搭建Gitlab

    一.环境准备 1. 准备一台虚拟机\或者购买服务器 2. 虚拟机硬件要求 2.1 内存不得少于4G,否则启动会报502错误,可自行百度解决,将虚拟机的swap分区调整为2G大小即可 2.2 CPU2核 ...