1. SAP NetWeaver Visual Composer
- SAP NetWeaver : SAP의 애플리케이션 통합 및 실행 플랫폼으로, 다양한 SAP 모듈과 시스템 간 연결을 지원 [1]
- SAP NetWeaver Visual Composer : NetWeaver 상에서 동작하는 시각적 UI 개발 도구로, 코드 없이 SAP 비즈니스 앱의 화면을 설계할 수 있음 [2]
2. CVE-2025-31324
- Metadata Uploader 컴포넌트에서 접근 제어가 제대로 이루어지지 않아 임의의 파일 업로드가 가능한 취약점 (CVSS: 10.0)
> /developmentserver/metadatauploader 엔드포인트에서 접근 제어가 제대로 이루어지지 않아, 공격자가 인증 없이 JSP 웹셸 파일을 서버에 업로드 가능
> SAP Visual Composer는 기본 설치 항목은 아니지만, 다수의 시스템에서 활성화되어 있음
> 공격자가 JSP 웹쉘을 서버의 퍼블릭 디렉터리에 업로드해 인증 없이 원격 제어하는 등 활발히 악용 중이므로, 긴급 패치 권고
-영향받는 버전
SAP NetWeaver VCFRAMEWORK 7.50
2.1 취약점 스캐너
- 보안 기업 Onapsis는 취약점을 확인할 수 있는 스캐너를 제공 [5]
> GitHub에서 스캐너의 최신 버전을 확인한 후 지정한 SAP 서버의 취약점 여부 확인
① 대상 SAP 서버의 /developmentserver/metadatauploader URL로 HEAD 요청 전송
⒜ 200 응답과 Set-Cookie 헤더가 없는 경우 취약
⒝ 404 응답 또는 다른 응답의 경우 취약하지 않음
② 사전 정의된 웹쉘 목록(KNOWN_WEBSHELLS)과 경로(/irj)를 대상으로 업로드된 웹쉘 확인
⒜ 200 응답일 경우 웹쉘 존재
※ 사전 정의된 웹쉘 목록과 특정 경로만을 대상으로 스캔을 수행하므로 정의되지 않은 웹쉘명과 경로에대한 검증은 불가
import requests
import argparse
import json
from packaging.version import parse as parse_version
__version__ = "1.0.2"
KNOWN_WEBSHELLS = ["cache.jsp", "helper.jsp"]
GITHUB_REPO = (
"Onapsis/Onapsis_CVE-2025-31324_Scanner_Tools"
)
def check_cve_2025_31324(hostname, port, use_ssl):
protocol = "https" if use_ssl else "http"
url = f"{protocol}://{hostname}:{port}/developmentserver/metadatauploader"
try:
response = requests.head(url, timeout=10, verify=False)
status_code = response.status_code
if status_code == 200 and 'Set-Cookie' not in response.headers:
print(
f"[CRITICAL] SAP System at {url} appears to be vulnerable to "
"CVE-2025-31324."
)
elif status_code == 404:
print(
f"[INFO] Visual Composer SAP System at {url} appears to not "
"be installed or unavailable."
)
else:
print(
f"[INFO] The SAP system at {url} does not appear to be "
"vulnerable to CVE-2025-31324."
)
except requests.exceptions.RequestException as e:
print(f"Error connecting to {url} for vulnerability testing: {e}")
def test_webshell(hostname, port, use_ssl):
webshell_found = False
for webshell_filename in KNOWN_WEBSHELLS:
protocol = "https" if use_ssl else "http"
url = f"{protocol}://{hostname}:{port}/irj/{webshell_filename}"
try:
response = requests.get(url, timeout=10, verify=False)
if response.status_code == 200:
print(f"[CRITICAL] Known webshell found at: {url}")
webshell_found = True
except requests.exceptions.RequestException as e:
print(
f"[ERROR] Error connecting to {url} for webshell testing: {e}"
)
if not webshell_found:
print("[INFO] No known webshells found.")
def check_for_updates():
try:
url = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest"
response = requests.get(url)
response.raise_for_status()
release_info = response.json()
latest_version = release_info.get("tag_name")
if latest_version:
latest_version = latest_version.lstrip("v")
current_version = parse_version(__version__)
latest_parsed_version = parse_version(latest_version)
if latest_parsed_version > current_version:
print(f"[WARNING] There is a newer version, {latest_version}.")
print(f"You are currently using version {__version__}.")
else:
print("Could not retrieve the latest release information.")
except requests.exceptions.RequestException as e:
print(f"Error checking for updates: {e}")
except json.JSONDecodeError:
print("Error decoding release information.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description=(
"Onapsis Scanner for Vulnerability CVE-2025-31324 (SAP Security "
"3594142) - CVSS 10 (Critical). This tool checks for the presence "
"of the vulnerability and known webshells in the SAP system. \n\n"
"DISCLAIMER: This tool is provided from Onapsis via open source "
"license Apache 2.0, as a contribution to the security, incident "
"response, and SAP communities to aid in response to active "
"exploitation of CVE-2025-31324. This tool is under development "
"and will continue to iterate rapidly as more information becomes "
"available either from Onapsis Research Labs or publicly. "
"This is a best-effort development and offered as-is with no "
"warranty or liability."
)
)
parser.add_argument(
"hostname",
help=(
"Hostname or IP address of the SAP system."
)
)
parser.add_argument(
"port",
type=int,
help="Port number of the SAP system (i.e. 50000)."
)
parser.add_argument(
"--ssl",
action="store_true",
help="Use SSL/TLS for the connection."
)
args = parser.parse_args()
check_for_updates()
check_cve_2025_31324(args.hostname, args.port, args.ssl)
test_webshell(args.hostname, args.port, args.ssl)
3. 대응방안
- 벤더사 제공 업데이트 적용 [6][7][8]
제품명 | 영향받는 버전 | 해결 버전 |
SAP NetWeaver | VCFRAMEWORK 7.50 | 별도 보안 패치 제공 [6][7][8] |
- 침해 여부 확인 방법 [9]
> 다음 OS 디렉토리의 루트에 'jsp', 'java', 'class' 파일 존재 여부 확인
① C:\usr\sap\<SID>\<InstanceID>\j2ee\cluster\apps\sap.com\irj\servlet_jsp\irj\root
② C:\usr\sap\<SID>\<InstanceID>\j2ee\cluster\apps\sap.com\irj\servlet_jsp\irj\work
③ C:\usr\sap\<SID>\<InstanceID>\j2ee\cluster\apps\sap.com\irj\servlet_jsp\irj\work\sync
[예시]
[root@sapserver irj]# pwd
/usr/sap/<SID>/<INSTANCE>/j2ee/cluster/apps/sap.com/irj/servlet_jsp/irj
[root@sapserver irj]# find . -type f -name “*.jsp” -ls
[root@sapserver irj]# find . -type f -name “*.java” -ls
[root@sapserver irj]# find . -type f -name “*.class” -ls
> SAP 악용에 사용된 웹쉘 및 악용 IP IOC 제공 [9]
① 몇 가지 예외를 제외하고 대부분 파일명은 "무작위 8자리.JSP" 형태
구분 | SHA256 |
Helper.jsp | 1f72bd2643995fab4ecf7150b6367fa1b3fab17afd2abed30a98f075e4913087 |
Cache.jsp | 794cb0a92f51e1387a6b316b8b5ff83d33a51ecf9bf7cc8e88a619ecb64f1dcf |
Random 8-character names ([a-z]{8}).jsp | b3e4c4018f2d18ec93a62f59b5f7341321aff70d08812a4839b762ad3ade74ee |
② 다음 디렉토리 내에 .jsp, .class, .java 확장자 파일은 악성으로 간주
⒜ /usr/sap/<SID>/<InstanceID>/j2ee/cluster/apps/sap.com/irj/servlet_jsp/irj/root
⒝ /usr/sap/<SID>/<InstanceID>/j2ee/cluster/apps/sap.com/irj/servlet_jsp/irj/work
⒞ /usr/sap/<SID>/<InstanceID>/j2ee/cluster/apps/sap.com/irj/servlet_jsp/irj/work/sync
- 탐지 규칙
[YARA]
rule detect_CVE202531324_webshells_by_name
{
meta:
description = “Detects the known webshell file names that are uploaded in the root directory”
author = “Emanuela Ionas, Onapsis Research Labs”
date = “2025-04-30”
tags = “CVE-2025-31324”
strings:
$path_1 = “/irj/root/”
$path_2 = “/irj/”
$webshell_1 = “cache.jsp” nocase
$webshell_2 = “helper.jsp” nocase
$webshell_4 = “[a-zA-Z0-9]{8}\.jsp”
$status = “HTTP/[1,2]\.[0,1,2] 200”
condition:
($webshell_1 or $webshell_2 or $webshell_4) and ($path_1 or $path_2) and $status
}
[SNORT]
alert tcp any any -> any any (msg:"CVE-2025-31324";flow:to_server,established;content:"POST";content:"/developmentserver/metadatauploader";content:"multipart/form-data";content:"filename="; content:".jsp";nocase;)
4. 참고
[1] https://help.sap.com/docs/SAP_NETWEAVER_702/ff55ab4f6c5510149ce7df0d5dc0da07/4a24dbfa64550455e10000000a421937.html
[2] https://help.sap.com/docs/SAP_NETWEAVER_702/ff55ab4f6c5510149ce7df0d5dc0da07/48db676f63f45c97e10000000a42189d.html
[3] https://nvd.nist.gov/vuln/detail/CVE-2025-31324
[4] https://www.picussecurity.com/resource/blog/cve-2025-31324-sap-netweaver-remote-code-execution
[5] https://github.com/Onapsis/Onapsis_CVE-2025-31324_Scanner_Tools
[6] https://support.sap.com/en/my-support/knowledge-base/security-notes-news/april-2025.html
[7] https://accounts.sap.com/saml2/idp/sso
[8] https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&pageIndex=1&nttId=71729&menuNo=205020
[9] https://onapsis.com/blog/active-exploitation-of-sap-vulnerability-cve-2025-31324/
[10] https://www.rapid7.com/blog/post/2025/04/28/etr-active-exploitation-of-sap-netweaver-visual-composer-cve-2025-31324
[11] https://reliaquest.com/blog/threat-spotlight-reliaquest-uncovers-vulnerability-behind-sap-netweaver-compromise
[12] https://www.dailysecu.com/news/articleView.html?idxno=165680
'취약점 > File Up&Download, Inclusion' 카테고리의 다른 글
Cisco 무선 LAN 컨트롤러 파일 업로드 취약점 (CVE-2025-20188) (0) | 2025.05.12 |
---|---|
WordPress WPLMS 플러그인 파일 업로드 취약점 (CVE-2024-56046, CVE-2024-56050, CVE-2024-56052) (0) | 2025.01.01 |
Apache Struts 임의 파일 업로드 취약점 (CVE-2024-53677) (0) | 2024.12.19 |
Cleo 제품 임의 파일 읽기/쓰기 취약점 (CVE-2024-50623) (0) | 2024.12.15 |
Apache Struts 파일 업로드 취약점 (CVE-2023-50164)_내용추가 (2) | 2023.12.18 |