
패킷 검사 및 가변 프로파일 상관 분석을 통해 블루 팀, AV, EDR, 스캐너를 차단하는 Cobalt Strike C2 리버스 프록시
(이전에는 proxy2's의 malleable_redirector 플러그인으로 알려짐)
C2 리다이렉터의 IR 회복탄력성 수준을 한 단계 더 높여볼까요?

Red Teaming 업계에서는 사고 대응자와 교전하고 동시에 저항력 있는 C2 리다이렉터 네트워크를 제공하면서 사고 대응자들을 잘못된 방향으로 유도하는 여러 훌륭한 아이디어들을 보아 왔습니다.
이 작업은 그러한 많은 훌륭한 아이디어들을 하나의 가벼운 유틸리티로 결합하여, Apache2가 단순한 HTTP(S) 리버스 프록시로서의 근본을 모방합니다.
Malleable C2 프로필 이해, 알려진 불량 IP 주소 풀에 대한 지식, 그리고 새로운 검사 및 잘못된 라우팅 로직을 쉽게 추가할 수 있는 유연성을 결합하여 IR 검사에 대한 교묘한 퇴치 도구를 탄생시켰습니다.

잘못된 인바운드 패킷이 RedWarden에 도달하면 redirect, reset 또는 단순히 proxy하여 처리할 수 있습니다!
이 프로그램은 HTTP/HTTPS 리버스 프록시 역할을 하며, 인바운드 C2 HTTP 요청에 여러 제한을 적용하여 Teamserver로 보낼 패킷과 드롭할 패킷을 선택합니다. 이는 Apache2의 mod_rewrite에서 규정된 .htaccess 파일 제한과 유사합니다.
RedWarden은 C2 리다이렉터 계층에서 IR/AV/EDR/Sandbox 회피 문제를 해결하기 위해 만들어졌습니다. 이 목적으로 사용되던 기존의 Apache2 + mod_rewrite 설정을 대체하기 위한 것입니다.
특징:
RedWarden은 입력으로 Malleable C2 프로필과 teamserver의 hostname:port를 받습니다. 그런 다음 제공된 Malleable 프로필 섹션을 구문 분석하여 계약을 이해하고, 이를 충족하는 인바운드 요청만 통과시키고 다른 요청은 잘못된 방향으로 유도합니다.
http-stager, http-get, http-post 같은 섹션과 해당 URI, 헤더, prepend/append 패턴, User-Agent는 모두 합법적인 Beacon 요청과 관련 없는 인터넷 소음 또는 IR/AV/EDR의 범위를 벗어난 패킷을 구별하는 데 사용됩니다.
이 프로그램은 다음에서 제공되는 훌륭한 알려진 불량 IP 범위를 활용합니다: curi0usJack 및 기타: https://gist.github.com/curi0usJack/971385e8334e189d93a6cb4671238b10
IP 주소 블랙리스트와 Reverse-IP DNS 쿼리 및 HTTP 헤더 검사를 통한 알려진 불량 키워드 조회를 함께 사용하면, 공격자 인프라를 조사하려는 승인되지 않은 피어에 대한 리다이렉터의 회복탄력성을 크게 향상시킬 수 있습니다.
잘못된 패킷은 세 가지 전략에 따라 잘못 라우팅될 수 있습니다:
이 구성은 설정 파일에 규정되어 있습니다:```yaml
drop_action: redirect
아래 예시는 `redirect`를 `https://googole.com`으로 설정한 결과를 보여줍니다:

현명하게 사용하고 안전을 유지하세요.
### 요구 사항
이 프로그램은 fork를 사용하여 여러 프로세스를 생성하므로 Linux 시스템에서만 실행할 수 있습니다.
또한 SSL 인증서 생성에 사용되는 `openssl` 시스템 명령어가 설치되어 있어야 합니다.
마지막으로, 다음 명령어로 Python3 PIP 요구 사항을 쉽게 설치할 수 있습니다:```shell
bash $ sudo pip3 install -r requirements.txt
최소 RedWarden의 config.yaml 설정 파일은 다음을 포함할 수 있습니다:```yaml port:
profile: jquery-c2.3.14.profile
ssl_cacert: /etc/letsencrypt/live/attacker.com/fullchain.pem ssl_cakey: /etc/letsencrypt/live/attacker.com/privkey.pem
teamserver_url:
drop_action: reset
그런 다음, 구성 파일의 경로를 제공하여 프로그램을 실행할 수 있습니다:```shell
bash$ sudo python3 RedWarden.py -c config.yaml
[INFO] 19:21:42: Loading 1 plugin...
[INFO] 19:21:42: Plugin "malleable_redirector" has been installed.
[INFO] 19:21:42: Preparing SSL certificates and keys for https traffic interception...
[INFO] 19:21:42: Using provided CA key file: ca-cert/ca.key
[INFO] 19:21:42: Using provided CA certificate file: ca-cert/ca.crt
[INFO] 19:21:42: Using provided Certificate key: ca-cert/cert.key
[INFO] 19:21:42: Serving http proxy on: 0.0.0.0, port: 80...
[INFO] 19:21:42: Serving https proxy on: 0.0.0.0, port: 443...
[INFO] 19:21:42: [REQUEST] GET /jquery-3.3.1.min.js
[INFO] 19:21:42: == Valid malleable http-get request inbound.
[INFO] 19:21:42: Plugin redirected request from [code.jquery.com] to [1.2.3.4:8080]
[INFO] 19:21:42: [RESPONSE] HTTP 200 OK, length: 5543
[INFO] 19:21:45: [REQUEST] GET /jquery-3.3.1.min.js
[INFO] 19:21:45: == Valid malleable http-get request inbound.
[INFO] 19:21:45: Plugin redirected request from [code.jquery.com] to [1.2.3.4:8080]
[INFO] 19:21:45: [RESPONSE] HTTP 200 OK, length: 5543
[INFO] 19:21:46: [REQUEST] GET /
[...]
[ERROR] 19:24:46: [DROP, reason:1] inbound User-Agent differs from the one defined in C2 profile.
[...]
[INFO] 19:24:46: [RESPONSE] HTTP 301 Moved Permanently, length: 212
[INFO] 19:24:48: [REQUEST] GET /jquery-3.3.1.min.js
[INFO] 19:24:48: == Valid malleable http-get request inbound.
[INFO] 19:24:48: Plugin redirected request from [code.jquery.com] to [1.2.3.4:8080]
[...]
위 출력에는 승인되지 않았으며 당사의 C2 프로필과 호환되지 않는 인바운드 요청이 있었음을 지적하는 줄이 포함되어 있습니다. 이 요청은 제시된 호환되지 않는 User-Agent 문자열로 인해 차단되었습니다.``` [...] [DROP, reason:1] inbound User-Agent differs from the one defined in C2 profile. [...]
## 사용 사례
### 비콘 트래픽 발신지에 IP 지리적 위치 정보 부과하기
사전 피싱(Pre-Phish) 및 OSINT를 매우 잘 수행했습니다. 이제 타겟이 어디에 살고 있는지 알고 있으며, 트래픽이 어디에서 발생해야 하는지에 대한 단서를 가지고 있거나, 적어도 완전히 보조적인 트래픽을 탐지하는 방법을 알고 있습니다.
리디렉터에서 비콘 요청에 IP 지리적 위치 정보를 어떻게 부과할까요?
RedWarden이 도움을 줍니다!
예를 들어, 유럽의 폴란드에서 발생하는 트래픽만 수락하려고 합니다.
사전 피싱/OSINT 결과는 다음을 나타냅니다:
- `89.64.64.150`은 폴란드에서 발생하는 타겟 중 하나의 합법적인 IP입니다.
- `59.99.140.76`은 그렇지 않으며 일반 인터넷 노이즈 패킷으로 시스템에 도달했습니다.
RedWarden의 유틸리티 `lib/ipLookupHelper.py`를 사용하여 이 두 주소에 대한 IP 지리적 위치 메타데이터를 수집할 수 있습니다:```shell
bash$ python3 ipLookupHelper.py
Usage: ./ipLookupHelper.py <ipaddress> [malleable-redirector-config]
Use this small utility to collect IP Lookup details on your target IPv4 address and verify whether
your 'ip_geolocation_requirements' section of proxy2 malleable-redirector-config.yaml would match that
IP address. If second param is not given - no
전자는 가져옵니다:```shell bash$ python3 ipLookupHelper.py 89.64.64.150 [dbg] Following IP Lookup providers will be used: ['ip_api_com', 'ipapi_co'] [.] Lookup of: 89.64.64.150 [dbg] Calling IP Lookup provider: ipapi_co [dbg] Calling IP Lookup provider: ip_api_com [dbg] New IP lookup entry cached: 89.64.64.150 [.] Output: { "organization": [ "UPC Polska Sp. z o.o.", "UPC.pl", "AS6830 Liberty Global B.V." ], "continent": "Europe", "continent_code": "EU", "country": "Poland", "country_code": "PL", "ip": "89.64.64.150", "city": "Warsaw", "timezone": "Europe/Warsaw", "fulldata": { "status": "success", "country": "Poland", "countryCode": "PL", "region": "14", "regionName": "Mazovia", "city": "Warsaw", "zip": "00-202", "lat": 52.2484, "lon": 21.0026, "timezone": "Europe/Warsaw", "isp": "UPC.pl", "org": "UPC Polska Sp. z o.o.", "as": "AS6830 Liberty Global B.V.", "query": "89.64.64.150" }, "reverse_ip": "89-64-64-150.dynamic.chello.pl" }
그리고 후자는 다음을 제공합니다:```shell
bash$ python3 ipLookupHelper.py 59.99.140.76
[dbg] Following IP Lookup providers will be used: ['ip_api_com', 'ipapi_co']
[dbg] Read 1 cached entries from file.
[.] Lookup of: 59.99.140.76
[dbg] Calling IP Lookup provider: ip_api_com
[dbg] New IP lookup entry cached: 59.99.140.76
[.] Output:
{
"organization": [
"",
"BSNL Internet",
"AS9829 National Internet Backbone"
],
"continent": "Asia",
"continent_code": "AS",
"country": "India",
"country_code": "IN",
"ip": "59.99.140.76",
"city": "Palakkad",
"timezone": "Asia/Kolkata",
"fulldata": {
"status": "success",
"country": "India",
"countryCode": "IN",
"region": "KL",
"regionName": "Kerala",
"city": "Palakkad",
"zip": "678001",
"lat": 10.7739,
"lon": 76.6487,
"timezone": "Asia/Kolkata",
"isp": "BSNL Internet",
"org": "",
"as": "AS9829 National Internet Backbone",
"query": "59.99.140.76"
},
"reverse_ip": ""
}
이제 전자에는 "country": "Poland"가 있고 후자에는 "country": "India"가 있음을 알 수 있습니다. 이 정보를 바탕으로 방대한 YAML 사전 형태로 제약 조건을 설계할 준비가 되었습니다:```yaml
ip_geolocation_requirements:
organization:
continent:
continent_code:
country:
- Poland
- PL
- Polska
country_code:
city:
timezone:
해당 사전의 각 항목은 인바운드 피어 IP 주소의 결정된 IP Geo 메타데이터와 일치시킬 정규식을 허용합니다.
`country` 속성에 세 개의 항목을 사용하여 지정된 값 중 하나를 가진 요청을 허용합니다.
구성에서 이를 설정하면, 두 번째 매개변수를 받는 `ipLookupHelper` 유틸리티를 사용하여 다른 IP 주소가 RedWarden의 IP Geolocation 차별기를 통과할 수 있는지 확인할 수 있습니다:

마지막 줄은 패킷이 차단될지 허용될지 알려줍니다.
그게 전부입니다! IP Geolocation 제약 조건을 현명하고 안전하게 구성하고, RedWarden 로그에서 IP Geo 관련 DROP 항목을 주의 깊게 검사하여 C2 트래픽을 깔끔하게 유지하세요!
### 변조된 Beacon 요청 복구
AWS Lambda 또는 CloudFlare와 같은 중간 시스템을 Domain Fronting/리다이렉터로 사용하는 경우, 일부 패킷이 합의된 malleable contract에서 벗어나 Teamserver에 수락되지 않는 상황을 분명히 겪어보셨을 것입니다. 변조되거나 제거된 HTTP 헤더, 재정렬된 쿠키 또는 기타 문제 등으로 인해 많은 시간을 낭비했을 것입니다.
C2 채널 설정 프로세스 문제와 중간 시스템의 변조에 대응하기 위해 RedWarden은 Beacon 패킷을 복구하는 기능을 제공합니다.
이는 Malleable Profile이 어떤 패킷을 기대하는지 확인하고, 프로필 요구 사항에 따라 구성된 HTTP 헤더를 합의된 값으로 복원할 수 있습니다.
다음의 간단한 프로필을 고려해 보세요:```
http-get {
set uri "/api/abc";
client {
header "Accept-Encoding" "gzip, deflate";
metadata {
base64url;
netbios;
base64url;
parameter "auth";
}
}
...
이 Accept-Encoding이 보이시나요? 모든 Beacon 요청에는 해당 헤더와 그 값이 있어야 합니다. Beacon이 CloudFlare 시스템에 도달했을 때 CloudFlare가 해당 헤더를 제거하거나 대신 Accept-Encoding: gzip을 포함한 요청을 내보내면 어떻게 될까요? Teamserver는 즉시 해당 요청을 거부합니다.
RedWarden 구성 섹션에서 repair_these_headers라고 불리는 이 헤더를 설정하면 연결을 안전하게 보호할 수 있습니다.:```yaml
repair_these_headers:
### 문제가 있는 응답 헤더 제거
Cobalt Strike 4.7+에서 Teamserver가 Content-Encoding 헤더를 자동으로 제거하여 아무런 통지 없이 우리의 malleable `http-(get|post).server` 계약을 위반하는 현상을 발견했습니다.
RedWarden이 계약을 따랐기 때문에 Beacon이 응답을 드롭하거나 잘못 압축 해제하는 상황이 발생했습니다.
이 옵션은 Teamserver 응답에서 Beacon 프로세스에 도달하기 전에 제거되어야 하는 헤더를 지정합니다:```yaml
remove_these_response_headers:
- Content-Encoding
RedWarden은 이제 Teamserver 응답에서 Content-Encoding 헤더를 기본적으로 제거하여 CS4.7+ 버전과의 호환성을 유지합니다.
프록시가 생성하는 출력을 살펴보겠습니다.
verbose: True 옵션에서, 정보 표시 수준은 최대 INFO로 설정되어 수락된 요청과 거부된 요청을 구분하여 알려줍니다.
요청이 RedWarden 구성 파일에 설정된 모든 기준을 충족하면 수락될 수 있습니다. 이러한 경우 [ALLOW, ...] 항목 로그가 뒤따릅니다:```
[INFO] 2021-04-24/17:30:48: [REQUEST] GET /js/scripts.js
[INFO] 2021-04-24/17:30:48: == Valid malleable http-get (variant: default) request inbound.
[INFO] 2021-04-24/17:30:48: [ALLOW, 2021-04-24/19:30:48, 111.222.223.224] "/js/scripts.js" - UA: "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
[INFO] 2021-04-24/17:30:48: Connected peer sent 2 valid http-get and 0 valid http-post requests so far, out of 15/5 required to consider him temporarily trusted
[INFO] 2021-04-24/17:30:48: Plugin redirected request from [attacker.com] to [127.0.0.1:5555]
요청이 RedWarden이 각 요청에 대해 수행하는 검사 중 하나라도 실패하면, 해당하는 `[DROP, ...]` 줄이 드롭 **이유**에 대한 정보를 포함하여 출력됩니다.:```
[INFO] 2021-04-24/16:48:28: [REQUEST] GET /
[ERROR] 2021-04-24/16:48:29: [DROP, 2021-04-24/18:48:28, reason:1, 128.14.211.186] inbound User-Agent differs from the one defined in C2 profile.
[INFO] 2021-04-24/16:48:29: [DROP, 2021-04-24/18:48:28, 128.14.211.186] "/" - UA: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"
[ERROR] 2021-04-24/16:48:29: [REDIRECTING invalid request from 128.14.211.186 (zl-dal-us-gp3-wk107.internet-census.org)] GET /
요청을 드롭할지 여부를 결정하는 많은 이유가 있습니다. 이러한 각 검사는 요구 사항에 따라 또는 세부 조정이나 오류 수정 과정에서 독립적으로 켜고 끌 수 있습니다.
example-config.yaml에서 발췌:```yaml
policy:
allow_proxy_pass: True
allow_dynamic_peer_whitelisting: True
drop_invalid_useragent: True
drop_http_banned_header_names: True
drop_http_banned_header_value: True
drop_dangerous_ip_reverse_lookup: True
drop_ipgeo_metadata_containing_banned_keywords: True
drop_malleable_without_expected_header: True
drop_malleable_without_expected_header_value: True
drop_malleable_without_expected_request_section: True
drop_malleable_without_request_section_in_uri: True
drop_malleable_without_prepend_pattern: True
drop_malleable_without_apppend_pattern: True
drop_malleable_unknown_uris: True
drop_malleable_with_invalid_uri_append: True
기본적으로 이러한 모든 검사가 시행됩니다.
`debug: True`로 설정하면 RedWarden이 복잡한 의사 결정 과정에서 각 단계를 설명하는 많은 로그 줄로 콘솔 버퍼가 넘쳐나게 됩니다.
요청과 응답의 전체 본문을 확인하려면 `debug`와 `trace`를 true로 설정하고 로깅의 폭발을 받아들이세요!
## 자주 묻는 질문
**- 이 프로그램이 Malleable Profile 없이 실행될 수 있나요?**
네, 가능합니다. 그러나 요청 검사 로직은 꺼지고, 나머지 기능(IP 지리적 위치 강제, 역방향 조회 로직, 차단된 IP 목록 등)은 정상 작동합니다.
**- 이 프로그램을 다른 C2 프레임워크(예: Mythic, Covenant 등)에도 쉽게 적용할 수 있나요?**
쉽지는 않습니다. 어느 정도 노력이 필요합니다. 아래에서 설명했듯이, 이 도구는 코드가 좋지 않아 다른 C2에 적용하는 데 어려움이 있습니다. 하지만 시간과 노력을 들이면 충분히 가능합니다.
**- 패킷이 드롭되고 있습니다. 왜 그런가요?**
`debug: True`와 `trace: True`를 활성화하여 가능한 한 많은 로그를 수집해 보세요. 그런 다음 로그를 살펴보고 무슨 일이 일어나고 있는지 검사해야 합니다. 패킷이 Malleable 프로필에서 예상한 대로 정확히 보입니까? 아니면 네트워크를 따라 미묘한 변조가 있어 RedWarden이 패킷을 드롭하게 만들었을 수도 있습니다(그리고 Teamserver도 드롭하게 만들 수 있습니까?).
## 알려진 문제점
- 대화형 수면 처리량에 약간의 오버헤드를 추가할 _수_ 있습니다.
- ProxyPass 처리 로직은 완벽과는 거리가 멀고 _정말_ 버그가 많습니다(그리고 정말 추합니다!).
- 비정상적인 형태의 설정 파일은 RedWarden 파서를 혼란에 빠뜨려 불평하게 만들 수 있습니다. 이를 극복하는 가장 쉬운 방법은 `example-config.yaml`을 복사하여 대신 작업하는 것입니다.
## 세상에, 왜 이 코드는 이렇게 엔지니어링 쓰레기인가요?
코드는 _하나의 거대한 엉망진창_입니다 – 인정합니다 – 그리고 그 이유도 정직합니다: 이 프로젝트는 90%가 실제 Red Team 업무 중에 개발되었습니다. 우리 모두 알다시피, 이런 종류의 업무는 해야 할 일이 너무 많아서, 제대로 된 복잡한 도구를 개발할 시간이 거의 없습니다. 또한 프로젝트 설정에서 이 프로그램의 중요성도 말할 것도 없습니다. 이 도구는 처음에 Python2로 작성된 간단한 프록시 스크립트로 시작하여, 플러그인이 있는 프록시로 진화했으며, `malleable_redirector` 플러그인을 받았습니다. 그 이후로 저는 `proxy2`가 이전 버전과의 호환성을 유지하도록(제가 마치 Microsoft 같았습니다!) 제가 만든 다른 플러그인들과 함께 원래 목적을 고수하기 위해 정말 열심히 노력해 왔습니다.
하지만 이제는 그만 놓아주고, 브랜드를 변경하고, 도입된 모든 나쁜 코드 냄새를 고치기 시작할 때가 왔습니다.
이 모든 점을 감안하여, 이슈를 제기하거나 풀 리퀘스트를 제출할 때 저에게 약간의 연민을 표현해 주시고, 판단보다는 도움을 주려고 노력해 주세요! :-)
감사합니다!
## TODO
- 위협 인텔리전스 피드를 악의적인 목적으로 사용할 가능성 연구 – 예를 들어 IP 기반으로 보안 업체 탐지
- MaxMind GeoIP 데이터베이스/API 지원 추가
- 탐지 및 차단 모두에서 JA3 서명 지원 구현, 그리고 nginx/Apache2/사용자 정의 설정을 위장하기 위한 가장
- 고유한 비콘 추적 로직을 추가하여 프록시 자체 재량으로 스테이징 및 통신 프로세스를 거부하는 유연성 제공
- 리디렉션 기능을 제공할 때 시간 제약 도입 (_업무 시간에만 프록시_)
- CONNECT/릴레이에 프록시 인증 및 권한 부여 로직 추가
- 모바일 사용자 대상 리디렉션 추가
- 주입할 사용자 정의 HTTP 헤더 또는 제거할 헤더를 정의하는 설정 옵션 추가
- ProxyPass 기준을 통과하는 요청에 특정 HTTP 헤더가 있어야 하는 설정 옵션 추가
- Nmap과 유사하게 간단한 문자를 입력하여 출력 로깅 상세도를 제어할 수 있는 대화형 인터페이스
- Malleable 프로필 파서 로직을 [pyMalleableC2](https://github.com/Porchetta-Industries/pyMalleableC2)로 재작성. 제가 처음 파서 로직을 코딩하기 시작했을 때는 Github에 그러한 툴킷이 없었습니다.
- 모든 코드베이스 리팩토링
---
### ☕ 후원하기 ☕
이 프로젝트와 다른 프로젝트들은 잠 못 이루는 밤과 **많은 노력**의 결과물입니다. 제가 하는 일을 좋아하시고 항상 커뮤니티에 환원하는 점을 감사하게 생각하신다면,
[저에게 커피 한 잔 사주세요](https://github.com/sponsors/mgeeky) _(또는 맥주가 더 좋습니다)_ 감사의 표시로! 💪
---
## 저자```
Mariusz Banach / mgeeky, '19-'21
<mb [at] binary-offensive.com>
(https://github.com/mgeeky)