1. 대체 경로, 대체 채널
- 인증이나 정상적인 보안 메커니즘을 우회하는 공격 경로를 의미 (CWE-288) [1]
- 대체 경로(Alternate Path)
> 시스템이 정상적으로 인증을 요구하는 주요 경로(로그인 페이지 등)를 우회할 수 있는 비표준적인(≒비공식적인) 경로
> 디버깅용 또는 개발 테스트용 백도어가 남아있는 경우
> 사용자 입력 값(URL 매개변수)을 조작해 비인가된 데이터를 조회
> 잘못된 권한 검증으로 특정 파일 또는 디렉토리에 접근
> 대응 : 디버깅 및 테스트 코드 제거, 입력 값 검증, 숨겨진 디렉터리 접근 방지 등
- 대체 채널(Alternate Channel)
> 정상적인 인증 프로세스와 보안 채널(HTTPS 등)을 우회하여 비정상적인 통신 채널을 통해 시스템에 접근하거나 데이터를 전송하는 것
> HTTP 요청을 통해 정보 전송 및 평문 가로채기
> 레거시 프로토콜을 통해 암호화되지 않은 정보 가로채기
> 모바일 앱, IoT 기기에서 SSL/TLS 인증서 검증이 불완전해 중간자 공격으로 데이터 탈취
> 대응 : HTTPS 강제 적용, 레거시 프로토콜 비활성화, SSL/TLS 검증 강화, 네트워크 모니터링 및 로그 관리 등
2. CVE-2024-55591
- Fortinet 제품의 대체 경로 또는 대체 채널 문제로 인해 발생하는 인증 우회 취약점 (CVSS: 9.8)
> 공격자는 Node.js 웹소켓 모듈에 대한 조작된 요청을 통해 슈퍼 관리자 권한을 얻을 수 있음
※ 취약점 관련 상세 내용 확인 불가
영향받는 제품
- FortiOS 7.0 : 7.0.0 이상 ~ 7.0.16 이하
- FortiProxy : 7.2.0 이상 ~ 7.2.12 이하 / 7.0.0 이상 ~ 7.0.19 이하
- 관련 PoC [3]
> 총 5개의 조건을 충족할 경우 취약 (status_code_1_check, status_code_2_check, body_checks, header_marker_check, connection_upgrade_check)
구분 | 설명 |
status_code_1_check | - 첫 번째 요청 및 응답으로 해당 페이지가 로그인 관련 페이지인지 확인 first_url = f"{base_url}/login?redir=/ng" first_response = requests.get(first_url, verify=False, timeout=10) <중략> status_code_1_check = first_response.status_code == 200 |
status_code_2_check | - 두 번째 요청 및 응답으로 WebSocket 업그레이드 가능 여부 확인 second_url = f"{base_url}/watchTowr-{random_suffix}" second_headers = { 'Sec-WebSocket-Version': '13', 'Sec-WebSocket-Key': 'thFz/fKwzu5wDEy0XO3fcw==', 'Connection': 'keep-alive, Upgrade', 'Upgrade': 'websocket' } second_response = requests.get(second_url, headers=second_headers, verify=False, timeout=10) <중략> status_code_2_check = second_response.status_code == 101 ※ 응답코드 101 : 클라이언트가 보낸 업그레이드 요청 헤더에 대한 응답으로, 서버가 클라이언트의 Upgrade 요청을 받아들여 프로토콜을 변경할 것임을 알림, 주로 WebSocket 프로토콜 전환 시 사용 [4] |
body_checks | - 첫 번째 응답에서 세 가지 값 (html_main_app_check, f_icon_warning_check, f_icon_closing_check)의 만족 여부 확인 html_main_app_check = '<html class="main-app">' in first_response.text f_icon_warning_check = '<f-icon class="fa-warning' in first_response.text f_icon_closing_check = '</f-icon>' in first_response.text <중략> body_checks = html_main_app_check and f_icon_warning_check and f_icon_closing_check |
header_marker_check | - 첫 번째 응답에서 특정 헤더 (APSCOOKIE_)의 존재 여부 확인 header_marker_check = any('APSCOOKIE_' in str(header) for header in first_response.headers.values()) |
connection_upgrade_check | - 두 번째 응답에서 Connection 헤더의 값 확인 connection_upgrade_check = 'Upgrade' in second_response.headers.get('Connection', '') |
import requests
import random
from uuid import uuid4
from datetime import datetime, timedelta
import argparse
banner = """\
__ ___ ___________
__ _ ______ _/ |__ ____ | |_\\__ ____\\____ _ ________
\\ \\/ \\/ \\__ \\ ___/ ___\\| | \\\\| | / _ \\ \\/ \\/ \\_ __ \\
\\ / / __ \\| | \\ \\\\___| Y | |( <_> \\ / | | \\\n \\/\\_/ (____ |__| \\\\\\\___ |___|__|__ | \\\\__ / \\\/\\_/ |__|
\\\ \\\ \\\
CVE-2024-55591.py
(*) Fortinet FortiOS Authentication Bypass (CVE-2024-55591) vulnerable detection by watchTowr
- Sonny , watchTowr (sonny@watchTowr.com)
- Aliz Hammond, watchTowr (aliz@watchTowr.com)
CVEs: [CVE-2024-55591]
"""
def generate_random_suffix(length=6):
"""Generate a random lowercase suffix."""
return ''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(length))
def perform_web_interaction(target, port):
"""
Perform a two-step web interaction with specific parameters.
Args:
target (str): Target IP address
port (int): Target port
Returns:
tuple: Results of the two requests
"""
# Construct base URL
base_url = f"https://{target}:{port}"
# Generate random suffix
random_suffix = generate_random_suffix()
# Disable SSL verification warnings
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
# First request - login-like endpoint
first_url = f"{base_url}/login?redir=/ng"
first_response = requests.get(first_url, verify=False, timeout=10)
# Second request - endpoint with random suffix
second_url = f"{base_url}/watchTowr-{random_suffix}"
second_headers = {
'Sec-WebSocket-Version': '13',
'Sec-WebSocket-Key': 'thFz/fKwzu5wDEy0XO3fcw==',
'Connection': 'keep-alive, Upgrade',
'Upgrade': 'websocket'
}
second_response = requests.get(second_url, headers=second_headers, verify=False, timeout=10)
return first_response, second_response
def validate_interaction_conditions(first_response, second_response):
"""
Validate specific conditions for the web interaction.
Args:
first_response (requests.Response): First HTTP response
second_response (requests.Response): Second HTTP response
Returns:
bool: Whether all conditions are met
"""
try:
# Check status codes
status_code_1_check = first_response.status_code == 200
status_code_2_check = second_response.status_code == 101
# Check body contents for first response
html_main_app_check = '<html class="main-app">' in first_response.text
f_icon_warning_check = '<f-icon class="fa-warning' in first_response.text
f_icon_closing_check = '</f-icon>' in first_response.text
body_checks = html_main_app_check and f_icon_warning_check and f_icon_closing_check
# Check for specific header marker
header_marker_check = any('APSCOOKIE_' in str(header) for header in first_response.headers.values())
# Check connection upgrade for second response
connection_upgrade_check = 'Upgrade' in second_response.headers.get('Connection', '')
# Print detailed information about first response matchers
if not html_main_app_check:
print("[!] Target is not a FortiOS Management Interface")
exit()
if not f_icon_warning_check:
print("[!] '<f-icon class=\"fa-warning\"' not found in response")
# Combine all checks
return all([
status_code_1_check,
status_code_2_check,
body_checks,
header_marker_check,
connection_upgrade_check
])
except Exception as e:
print(f"[!] Error during validation: {e}")
return False
def main():
"""
Main function to run the web interaction checks.
"""
print(banner)
parser = argparse.ArgumentParser(description='CVE-2024-55591 Detection Tool')
parser.add_argument('--target', '-t', type=str, help='IP address of the target', required=True)
parser.add_argument('--port', '-p', type=int, help='Port of the target', required=False, default=443)
args = parser.parse_args()
try:
print(f"[*] Targeting: https://{args.target}:{args.port}")
first_response, second_response = perform_web_interaction(args.target, args.port)
result = validate_interaction_conditions(first_response, second_response)
if result:
print("[!] VULNERABLE: All conditions were met")
else:
print("[*] NOT VULNERABLE: Conditions were not satisfied")
except requests.RequestException as e:
print(f"[!] Request error: {e}")
except Exception as e:
print(f"[!] Unexpected error: {e}")
if __name__ == "__main__":
main()
3. 대응방안
- 벤더사 제공 보안 업데이트 적용 [5]
제품명 | 영향받는 버전 | 해결 버전 |
FortiOS 7.0 | 7.0.0 이상 ~ 7.0.16 이하 | 7.0.17 이상 |
FortiProxy | 7.2.0 이상 ~ 7.2.12 이하 | 7.2.13 이상 |
7.0.0 이상 ~ 7.0.19 이하 | 7.0.20 이상 |
> Fortinet 권고사항 [6]
구분 | 설명 |
로그 점검 | - 랜덤 scrip 및 dstip가 포함된 로그인 활동 관련 로그: type="event" subtype="system" level="information" vd="root" logdesc="Admin login successful" sn="1733486785" user="admin" ui="jsconsole" method="jsconsole" srcip=1.1.1.1 dstip=1.1.1.1 action="login" status="success" reason="none" profile="super_admin" msg="Administrator admin logged in successfully from jsconsole" - 무작위로 생성된 것처럼 보이는 사용자 이름과 소스 IP가 포함된 관리자 생성 로그: type="event" subtype="system" level="information" vd="root" logdesc="Object attribute configured" user="admin" ui="jsconsole(127.0.0.1)" action="Add" cfgtid=1411317760 cfgpath="system.admin" cfgobj="vOcep" cfgattr="password[*]accprofile[super_admin]vdom[root]" msg="Add system.admin vOcep" - 로그에서 공격자들이 사용한 것으로 나타난 IP 주소: 1.1.1[.]1 127.0.0[.]1 2.2.2[.]2 8.8.8[.]8 8.8.4[.]4 |
위협행위자 수행 작업 점검 | - 임의의 사용자 이름으로 장치에 관리자 계정 생성 - 임의의 사용자 이름으로 장치에 로컬 사용자 계정 생성 - 사용자 그룹 생성 또는 기존 sslvpn 사용자 그룹에 위의 로컬 사용자 추가 - 기타 설정(방화벽 정책, 방화벽 주소 등) 추가/변경 - 위에 추가된 로컬 사용자로 sslvpn에 로그인하여 내부 네트워크로 가는 터널 생성 |
공격 IP 점검 및 차단 | - 45.55.158[.]47 [가장 많이 사용되는 IP 주소] - 87.249.138[.]47 - 155.133.4[.]175 - 37.19.196[.]65 - 149.22.94[.]37 |
권고 | - HTTP/HTTPS 관리 인터페이스 비활성화 - 로컬-인 정책을 통해 관리 인터페이스에 접근할 수 있는 IP 주소를 제한 |
4. 참고
[1] https://cwe.mitre.org/data/definitions/288.html
[2] https://nvd.nist.gov/vuln/detail/CVE-2024-55591
[3] https://github.com/watchtowrlabs/fortios-auth-bypass-check-CVE-2024-55591/tree/main?tab=readme-ov-file
[4] https://docs.whatap.io/url/url-http-status
[5] https://www.boho.or.kr/kr/bbs/view.do?searchCnd=&bbsId=B0000133&searchWrd=&menuNo=205020&pageIndex=1&categoryCode=&nttId=71632
[6] https://www.fortiguard.com/psirt/FG-IR-24-535
[7] https://arcticwolf.com/resources/blog/console-chaos-targets-fortinet-fortigate-firewalls/
[8] https://www.dailysecu.com/news/articleView.html?idxno=163036
'취약점 > By-Pass' 카테고리의 다른 글
Nuclei 서명 검증 우회 취약점 (CVE-2024-43405) (0) | 2025.01.06 |
---|---|
Microsoft 다중인증 우회 취약점 (0) | 2024.12.16 |
WordPress CleanTalk 플러그인 인증 우회 취약점 (CVE-2024-10542, CVE-2024-10781) (0) | 2024.11.27 |
NVIDIA Base Command Manager 인증 누락 취약점 (CVE-2024-0138) (1) | 2024.11.26 |
Palo Alto Networks PAN-OS 인증 우회 취약점 (CVE-2024-0012, CVE-2024-9474) (0) | 2024.11.23 |