
mTLS를 통한 x509 인증서를 사용하는 프로토타입 악성코드 C2 채널
먼저, 왜 이것을 오픈소스로 공개하는가?
MITRE ATT&CK는 탈취되거나 자체 서명된 인증서에 대해서만 다루며, NDR(네트워크 탐지 및 대응)은 (내가 아는 한) x509 인증서의 내용에 대해 발급 CA가 누구인지 외에는 거의 주의를 기울이지 않는다. 일반적으로 x509 인증서는 신뢰되며 우리 방화벽을 아무런 제재 없이 통과하도록 허용된다. 그러나 본질적으로 인증서는 다른 파일과 마찬가지로 악성 페이로드를 쉽게 포함할 수 있는 파일에 불과하다. 우리는 인증서를 당연하게 여겨 온 암호화 프로세스의 핵심 구성 요소이기 때문에 신뢰하고 무시한다. 이 프로젝트의 주요 목표는 우리가 신뢰하게 된 보안 지표 유형에 대한 인식을 높이고, 이를 악의적으로 사용하는 것을 탐지하는 데 사용할 수 있는 방법을 조명하는 것이다.
나는 위협 행위자들이 C2 통신의 일부로 x509 인증서를 사용한 적이 있는지 항상 궁금했다. 네트워크 트래픽을 암호화하기 위해서가 아니라, 실제로 C2 통신을 x509 인증서에 삽입하는 것이다. 5년 동안 야생에서 이와 같은 사례를 찾아다닌 끝에 마침내 직접 코딩해서 가능한지 확인하기로 했다... 가능하다.
HTTPS/TLS를 통해 전송되는 모든 암호화 메시지는 x509 인증서의 전송을 통해 이루어진다. TLS 핸드셰이크를 설정할 때(아래 그림), 네 번째 단계에서 서버는 클라이언트에게 x509 인증서를 보낸다. 클라이언트는 인증서를 검증하고, 서버가 지원하는 암호화 알고리즘을 비교한 후 이후의 모든 통신에 사용할 알고리즘을 선택한다.

이 다이어그램에서 볼 수 있듯이, 이는 서버에서 클라이언트로의 x509 인증서 단방향 전송일 뿐이다. 클라이언트가 서버에 응답할 방법이 없기 때문에 이는 C2 통신에 적합하지 않다. 기껏해야 단방향 데이터 전송 메커니즘으로만 사용될 수 있다(아래 선행 연구 섹션 참조).
하지만 상호 TLS 인증(mTLS)이라고 하는 또 다른 유형의 TLS 세션이 있는데, 클라이언트와 서버가 서로를 인증하는 방식으로 x509 인증서를 교환한다.

위 그림에서 볼 수 있듯이, 상호 인증 중에는 서버의 x509 인증서가 인증을 위해 클라이언트로 전송되고, 그런 다음 클라이언트의 x509 인증서가 인증을 위해 서버로 전송된다. 이러한 아티팩트 교환은 C2 서버를 위한 양방향 통신 채널을 생성할 기회를 나타낸다.
서버와 클라이언트 인증서는 기본 SSL 라이브러리에 의해 교환되므로 클라이언트가 단일 mTLS 연결 내에서 서버 인증서에서 메시지를 꺼내 명령을 실행하고 응답 인증서를 생성할 기회는 없다. 이는 C2 채널이 요청-응답 교환이 두 개의 서로 다른 상호 TLS 연결을 통해 이루어지도록 설계되어야 함을 의미하며, 일종의 의사 반이중(pseudo-half duplex) 전송 모드와 같다.

요청/응답 프로세스는 다음 단계를 따른다:
이것이 작동하게 된 후 나는 창의적이고 뭐 그런 일을 해냈다는 것에 꽤 자부심을 느꼈다.
그러다가 2018년 BSides에서 Jason Reaves의 발표를 우연히 발견했는데, 그는 TLS를 통한 x509 인증서를 사용하는 악성코드 바이너리 드로퍼를 작성했다. 1년 후 Jason은 mTLS를 사용하는 완전한 양방향 통신 채널을 자세히 설명하는 이 논문을 발표했다.
mTLS는 클라이언트와 서버의 인증서가 모두 동일한 CA 인증서로 서명되어야 하므로, 첫 번째 단계는 자체 CA 개인 키/인증서 쌍을 생성하는 것이다.
루트 CA 개인 키 생성:
openssl genrsa -des3 -out hmCA.key 2048
참고: 암호문구는 개인 키를 획득한 사람이 자체 루트 인증서를 생성하는 것을 방지한다.
루트 CA 인증서 생성
openssl req -x509 -new -nodes -key hmCA.key -sha256 -days 1825 -out hmCA.pem
생성된 키와 인증서 파일을 certs/ca_certs 폴더에 복사한다. 이 프로젝트에는 데모
키/인증서 쌍이 포함되어 있으므로, 원한다면 이 단계를 건너뛸 수 있다.
클라이언트 시작:
python client.py
서버 시작:
python server.py
잠재적으로 악성인 것을 배포하면서 네트워크 로그에서 이를 탐지하는 방법을 자세히 설명하지 않고는 절대 공개하지 않는다.
이런 유형의 TLS 패턴을 탐지하는 것이 쉬울 거라고 생각하겠지만, 그렇게 단순하지 않다. 이 C2 채널의 주요 신호 중 하나는 반이중 방식의 통신이다. 서버와 클라이언트 간의 전체 요청/응답을 완료하려면 두 번의 상호 인증 흐름이 필요하다. 그런 다음 서버가 클라이언트에게 다른 명령을 보내면서 이 작업이 여러 번 발생한다.
즉, 다음을 찾아야 한다:
이것은 완벽해 보이는 탐지 규칙 세트처럼 보이지만, 앞서 말했듯이 그렇게 쉽지 않다. 알고 보니 비슷한 mTLS 트래픽 패턴을 가진 엔터프라이즈 서비스들이 있다:
이들 중 상당수는 자산/장치 관리 서비스로 보이므로, 이론적으로는 모든 장치를 순회할 때마다 동일한 인증서 세트를 보내야 한다. N시간마다 반복되는 여러 mTLS 세션 세트가 있는지 확인한 다음, 서로 다른 두 mTLS 세션 세트 간의 인증서 해시가 일치하거나 대부분 일치하는지 확인할 수 있다. 또한 각 mTLS 세션마다 클라이언트 인증서는 다르지만 모든 세션에서 동일한 서버 인증서가 사용되는지 확인할 수도 있다.
SSL 검사는 이러한 유형의 C2 통신 채널을 차단할 수 있는 한 가지 방법이다. SSL 검사 서버는 클라이언트 인증서를 인증하는 데 필요한 악성 CA 인증서를 보유하지 않기 때문이다.