The FortiGate SSL-VPN의 금광. CVE-2024-21762 및 CVE-2023-27997. 79개의 작동하는 익스플로잇 클라이언트. 53개의 하드웨어 SKU. 55개의 FortiOS 빌드.
연구 아카이브. 발견된 그대로 회수됨. 이 파일들은 제가 작성한 것이 아닙니다.
공개일: 2026년 9월 1일
이 저장소는 SKU별 FortiGate SSL-VPN 익스플로잇 카탈로그 위에 위치하는 오케스트레이터, 2차 페이로드, 운영자 리스너입니다. 전체 스토리, 수치, 헌팅 노트는 Abraxas Labs의 시리즈 The SSL-VPN pot of gold 에 있습니다.
이 자료를 실행하지 마십시오. 이 저장소를 호스팅하는 당사자와 대상 시스템 소유자 모두의 명시적 서면 허가 없이는 어떤 호스트에 대해서도 실행하지 마십시오. 관련 CVE는 이 공개 이전에 이미 공개되었고 패치되었습니다. 이 트리는 연구, 탐지, 역사적 분석을 위한 것입니다.
야생에서 비공개 FortiGate SSL-VPN 키트를 발견했습니다. 첫 번째 드롭은 작동하는 클라이언트들의 디렉토리였습니다: exp/exp_60E-v6.4.7.py, exp/exp_1000D-v7.4.0.py 같은 이름들. 각 파일은 SKU별, FortiOS별 메모리 손상 클라이언트입니다. 두 개의 공개 n-day가 하드웨어와 펌웨어 전반에 걸쳐 재스탬프되어 폴더가 부품 카탈로그처럼 보일 때까지 확장되었습니다.
진짜 가치는 오프셋 매트릭스이지, 새로운 버그가 아닙니다. 그 논증은 시리즈의 Phase 0에 있습니다. Phase 1은 두 프리미티브를 동작으로 다룹니다. Phase 2는 검색 가능한 SKU / 트레인 / CPU 맵입니다. Phase 3은 헌팅입니다.
이 저장소는 동일한 키트의 나머지 부분이지, 두 번째 익스플로잇 패밀리가 아닙니다.
exp/ 프로그램들은 시리즈에서 이미 설명된 이미지별 클라이언트입니다.shellcode/ 파일들은 해당 클라이언트들이 호출하도록 작성된 런처, 임플란트 페치, 설정 탈취 리스너입니다.exp_*.py 파일들은 임플란트를 포함하지 않았습니다. 그들은 (1) "셸코드 서버"에서 원시 바이트를 가져오거나 (2) GET /s.js 후 eval하는 것만 알았습니다. 그 누락된 부분들이 여기 있습니다.프리미티브:
| 패밀리 | CVE | Fortinet 권고 | 공개 자료 |
|---|---|---|---|
| A | CVE-2024-21762 | FG-IR-24-015 | Assetnote — Two Bytes is Plenty |
| B | CVE-2023-27997 | FG-IR-23-097 | Lexfo — XORtigate, Bishop Fox |
둘 다 CISA의 알려진 익스플로잇 취약점 카탈로그에 있습니다. poc.py는 두 CVE 중 어느 것도 구현하지 않습니다. 이미 분류된 두 패밀리(청크 쓰기 21762; enc= 힙 오버플로 27997)를 선택하고 래핑합니다.
.
├── poc.py # pocsuite3 런처 / 핑거프린트 / 프로세스 매니저
├── s.js # Node 2차 스테이지 (설정 탈취기)
├── send_cmd.py # 스테이저 경로용 콜백 핸들러
├── init.sh # 운영자 워크스테이션 패키지 설치
├── requirements.txt # pwntools
├── exp/
│ └── exp_<SKU>-v<FortiOS>.py
└── shellcode/
├── shellcode_server.py # 길이 프리픽스 블롭 펌프
├── shellcode_arm # ~2.0 MB 원시 2차 스테이지
└── shellcode_amd64 # ~2.7 MB 원시 2차 스테이지
exp/index.html과 shellcode/index.html은 일반적인 Python http.server 디렉토리 목록입니다. 이 트리가 한때 웹 루트로 호스팅되었음을 보여줄 뿐입니다.
이 exp/ 사본은 이전 카탈로그에 4개의 추가 클라이언트가 더해진 것입니다: exp_30E-v6.2.4.py, exp_30E-v6.2.12.py, exp_30E-v6.2.14.py, exp_40F-v7.0.5.py.
poc.py 오케스트레이터 (pocsuite3)
│
├─ 핑거프린트 포털 ─────── VERSION_LIBS (해시 → SKU + FortiOS)
├─ 파일 선택 ──────────────── exp/exp_<SKU>-v<ver>.py
│
├─ 클라이언트가 "스테이저" 종류인 경우 (패밀리 A ARM / 일부 amd64)
│ shellcode/shellcode_server.py 시작
│ shellcode/shellcode_arm 또는 shellcode_amd64 읽기
│ send_cmd.py 시작 (콜백 대기)
│ :9999에서 설정 수신기 시작
│ 선택된 exp_*.py 실행
│
└─ 클라이언트가 "Node /s.js" 종류인 경우 (대부분 패밀리 B + 많은 패밀리 A)
HTTP로 s.js 서빙
:9999에서 설정 수신기 시작
선택된 exp_*.py 실행
→ 방화벽 GET /s.js → eval → 외부 유출
한 줄로 된 파이프라인: 식별 → 오프셋 파일 선택 → sslvpnd 손상 → 임플란트 가져오기 → /data/config/*.gz 외부 유출 → 운영자 측에서 아카이브.
마지막 단계가 핵심입니다. 히트는 방화벽 자체의 sslvpnd에서의 인증 없는 코드 실행입니다 — TLS 터미네이터, 라우팅 정책, VPN 세션, 종종 LDAP/RADIUS 바인딩. FortiOS는 유용한 /bin/sh를 제공하지 않습니다. 공개 연구와 이 키트 모두 내부 명령 헬퍼 및/또는 FortiOS가 실제로 포함하는 /bin/node를 통해 진행됩니다. 확인된 히트는 네트워크 경계의 손상으로 취급하십시오, 충돌한 데몬이 아닙니다. 히트의 의미를 참조하십시오.
poc.py — 런처운영자 프론트 엔드 (pocsuite3 POCBase). CVE-2024-21762 또는 CVE-2023-27997을 구현하지 않습니다.
https://<target>/remote/login?lang=en을 가져옵니다 (폴백 GB2312)./sslvpn/js/login.js?q=<md5>에서 캐시 버스터 해시를 가져옵니다.VERSION_LIBS(182개의 hash,SKU,version 행)에서 조회합니다. 이 테이블이 키트가 운영자가 SKU를 지정하지 않고도 50개 이상의 어플라이언스 중에서 선택할 수 있는 이유입니다. 매트릭스와 동일한 SKU이며, SNMP나 관리 API가 아닌 공개 SSL-VPN 리소스 해시로 구동됩니다.exp/exp_<SKU>-v<version>.py를 확인합니다.s.js 포함 → 종류 2 (Node 로더)Shellcode Server 언급 → 종류 1 (스테이저); 그런 다음 스크립트에서 arm vs amd64 확인exp_*.py를 Popen합니다.이 사본의 기본 운영자 주소: 환경 변수의 HOST_IP, 그 외에는 ATTACKER_HOST. 이 트리의 리터럴 IPv4 주소는 역할 레이블로 대체되었습니다 (포트는 변경되지 않음):
| 레이블 | 역할 | 나타난 위치 |
|---|---|---|
TARGET_HOST | 공격 대상 FortiGate | 하드코딩 없음; argv의 rhost / target (poc.py 참조) |
ATTACKER_HOST | 운영자 워크스테이션 | poc.py의 기본 HOST_IP; poc.py, send_cmd.py, shellcode/shellcode_server.py의 바인드 주소; lhost로 채워지는 exp_*.py s.js / TFTP 플레이스홀더 |
C2_HOST | 이 임플란트 사본에 구워진 콜백 | s.js — 익스플로잇에 전달된 lhost가 아님 |
| 포트 | 역할 |
|---|---|
| 7777 | 콜백 / send_cmd.py |
| 8888 | 셸코드 서버 |
| 9999 | 설정 수신기 (s.js 및 send_cmd.py 외부 유출과 일치) |
포털 해시가 VERSION_LIBS에 없으면 "unknown target hash"로 중지합니다. 해시가 일치하지만 exp/ 파일이 없으면 "no exp"입니다.
s.js — 누락된 Node 2차 스테이지