
phpMyAdmin 5.2.3 - 높음 - 원격 - 잔여 - setup/validate 여전히 접근 가능
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-setup-validate
분석 문서: https://abraxaslabs.tech/research/phpmyadmin-setup-validate
분류: SSRF 도달 범위: 원격
phpMyAdmin 5.2.3 (태그 RELEASE_5_2_3, 커밋 962857e). config.inc.php가 존재하면 setup/index.php는 종료된다. 하지만 setup/validate.php는 그렇지 않다. 이 파일은 여전히 $isMinimumCommon 하에서 로드되며, 공개 로그인 페이지에서 CSRF 토큰을 가져오고, JSON values 필드에 담긴 호스트, 포트, 사용자, 비밀번호를 대상으로 Validator::testDBConnection -> mysqli_connect를 호출한다.
인증되지 않은 클라이언트가 /에 GET 요청을 보내 세션 쿠키와 토큰을 얻은 뒤, 원하는 Servers/1/host와 Servers/1/port를 담아 setup/validate.php에 id=Server로 POST 요청을 보낸다. 그러면 phpMyAdmin 호스트가 해당 주소로 TCP MySQL 핸드셰이크를 연다. 이것이 바로 MySQL 프로토콜을 통한 SSRF다. 내부 3306 포트, 내부 서버를 대상으로 한 크리덴셜 스터핑, 타이밍과 mysqli 오류를 통한 포트 오라클 등이 가능하다. 해당 포트에서 MySQL을 말하는 무언가가 있지 않은 한, HTTP 메타데이터 SSRF는 아니다. 또한 hide_db는 사용자 정규식을 preg_match에 삽입한다. 이 실습실에서는 그 ReDoS 경로를 실행하지 않았다.
공식 phpmyadmin:5.2.3 이미지는 setup/을 삭제한다. 이 잔여물은 해당 디렉터리가 여전히 웹 루트에 남아 있을 때만 적용되며, 이는 설치 후 흔히 남는 잔여물이다. 실습실은 RELEASE_5_2_3과 핀이 일치하도록 5.2.3 tarball에서 setup/을 복원한다.
PMASA-2016-44 / CVE-2016-6621은 일부 setup SSRF를 다루었다. "config가 존재하면 setup 비활성화" 검사는 validate.php / config.php에는 적용된 적이 없다.
| ID | 아직 CVE 없음 |
| 분류 | SSRF (MySQL 프로토콜) |
| 도달 범위 | 원격 (setup/이 여전히 웹에서 접근 가능한 경우 인증 불필요) |
| CWE | CWE-918 |
| CVSS | 높음: 7.2 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N |
| 제품 | phpMyAdmin |
| 영향받는 버전 | 5.2.3 태그 RELEASE_5_2_3 (962857e), setup/이 여전히 docroot에 존재하는 경우 |
| 인증 | 인증 불필요. 공개 로그인 페이지에서 CSRF 토큰 획득. MySQL 로그인 불필요. |
| 라이선스 | GNU Affero GPL v3.0 |
| 실습실 | 127.0.0.1:19230 전용 |
잔여 setup/ 트리에 접근할 수 있는 사람은 누구든 phpMyAdmin 호스트가 자신이 선택한 호스트와 포트로 MySQL 프로토콜 TCP 연결을 열도록 만들 수 있다.
| 권한 | 메서드 / 경로 | 실습실 입증 또는 추론 |
|---|---|---|
| PMA 호스트에서 공격자 host:port로 TCP 열기 (아웃바운드 연결 무결성, 해당 포트 정찰) | 인증 없이 POST /setup/validate.php id=Server에 Servers/1/host + Servers/1/port와 GET /에서 얻은 토큰을 담아 전송 | 실습실 입증. oracle:13306의 오라클이 PMA 컨테이너로부터 PMA-SETUP-VALIDATE-WITNESS를 기록함 |
| setup UI는 꺼져 있지만 validate는 켜져 있음을 확인 | GET /setup/index.php | 실습실 입증. 본문에 "setup is disabled" / configuration already exists 포함 |
| 로그인 페이지 CSRF 토큰 없이 fail closed | 동일 POST, token 없음 | 실습실 입증. 오라클 적중 0회 |
| mysqli 오류와 타이밍을 통한 포트 / 자격 증명 오라클 | 동일한 testDBConnection | 추론. 오라클이 수락 후 연결을 닫은 뒤 실습실 본문은 mysqli_connect(): (HY000/2006): MySQL server has gone away였음 |
| 내부 3306과 MySQL로 통신하며 게시된 사용자/비밀번호 시도 | 동일한 mysqli_connect | 추론. 실습실 db 서비스로 향하지 않음 |
사용자 정규식을 삽입하는 validateRegex를 통한 ReDoS | id=Servers/1/hide_db | 추론. 실행하지 않음 |
이 랩에서 제외된 항목: HTTP 메타데이터 SSRF(핸드셰이크는 MySQL이며 GET /latest/meta-data가 아님), 인증 없는 PMA 로그인, OS 셸, 그리고 설정 마법사 자체(index.php는 비활성 상태로 유지됨). setup/이 배포되지 않은 경우(공식 이미지 기본값) FAIL.
RELEASE_5_2_3에 대한 8개의 병렬 소스 탐색. setup/index.php에는 config-exists 치명적 오류가 있다. setup/validate.php에는 없다. setup/lib/common.inc.php는 $isMinimumCommon을 설정하며 CONFIG_FILE을 찾지 않는다.
잘못된 방향: 공식 이미지를 이 잔여물로 취급함(공식 이미지는 setup/을 삭제함), 로그인 페이지 토큰 없이 POST함(오라클 적중 0회), 이를 HTTP 메타데이터 SSRF로 취급함(핸드셰이크는 MySQL).
python3 phpmyadmin-setup-validate-Abraxas-Labs.py
또는
cd lab
./run.sh
루프백 전용: http://127.0.0.1:19230. Compose 프로젝트 phpmyadmin-setup-validate. Dockerfile은 5.2.3 tarball에서 setup/을 복원하고 포트 13306에서 TCP 오라클을 실행합니다. Witness PMA-SETUP-VALIDATE-WITNESS.
SUCCESS phpmyadmin-setup-validate how=live tcp=yes setup-index-disabled=yes PMA-SETUP-VALIDATE-WITNESS
setup/lib/common.inc.php에 file_exists(CONFIG_FILE) 치명적 오류를 배치하여 모든 setup 스크립트가 종료되도록 하십시오. testDBConnection 호스트를 제한하십시오. 사용자 문자열로 preg_match 구분자를 구성하지 마십시오.
962857e)setup/index.php config-exists 치명적 오류setup/validate.php 해당 검사 없음libraries/classes/Config/Validator.php testDBConnection / mysqli_connectGNU Affero GPL v3.0. LICENSE를 참조하십시오. 루프백 랩 전용. 보증 없음.