
phpMyAdmin 5.2.3 - 높음 - 원격 - XSS - Designer Visual Query Builder
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · phpmyadmin-vqb-xss
분류: 저장형 XSS 도달 범위: 원격
phpMyAdmin 5.2.3 (RELEASE_5_2_3 / 962857e) - phpMyAdmin
js/src/designer/history.js는 innerHTML로 시각적 쿼리 기록을 구성한다. 컬럼 이름은 $('<div/>').text(...).html()을 거친다. 테이블 이름은 그렇지 않다. TableName은 여전히 <와 >를 허용한다. 공유 데이터베이스에 CREATE TABLE 권한이 있는 저권한 계정이 HTML 식별자를 심는다. 더 높은 권한의 사용자가 Designer를 열면 getTableName()이 페이지에 남아 있고 DesignerHistory.display()가 이를 #ab에 기록한다.
phpMyAdmin 오리진의 저장형 XSS. PMASA-2025-1과 같은 클래스, 다른 기능. Check-tables 제목은 이스케이프되었다. 이 경로는 그렇지 않았다.
| ID | 아직 CVE 없음 |
| 분류 | 저장형 XSS |
| 도달 범위 | 원격 (인증된 CREATE TABLE; 피해자가 Designer를 엶) |
| CWE | CWE-79 |
| CVSS | 높음: 8.0 CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N |
| 제품 | phpMyAdmin |
| 영향받는 버전 | 5.2.3 태그 RELEASE_5_2_3 (962857e4f63d42e38f11ff4d63f5e722018add76) |
| 인증 | 인증됨. 공격자는 피해자가 Designer에서 여는 데이터베이스에 대한 CREATE TABLE 권한이 필요함 |
| 라이선스 | GNU Affero GPL v3.0 |
| 랩 | 127.0.0.1 전용 |
HTML 테이블 이름을 심은 다음, 더 높은 권한의 사용자가 해당 데이터베이스에서 Designer를 열고 시각적 쿼리 기록을 렌더링할 때까지 기다린다.
| 권한 | 메서드 / 싱크 | 정찰 / 무결성 / 가용성 | 랩 입증 또는 추론 |
|---|---|---|---|
| phpMyAdmin 오리진에 마크업 주입 | DesignerHistory.display()가 getTab()을 #ab innerHTML에 연결 | 피해자 오리진의 무결성 | 랩 입증. phpmyadmin:5.2.3의 라이브 history.js. <h3>에 <i id="pma-vqb"> 포함 |
designer table_name 속성 탈출 | database_tables.twig small_tab_pref_1이 designerTable.getTableName() 사용 | Designer DOM에서 원시 MySQL 이름 정찰 | 랩 입증, 원시 식별자로 읽힘 |
피해자 세션 쿠키와 CSRF token 읽기 | 기록이 렌더링되면 동일 오리진 스크립트 | 피해자 PMA 세션 정찰 | PMA 오리진의 저장형 XSS에서 추론. 이 랩은 스크립트가 아닌 <i> 마커 사용 |
| 피해자 MySQL 계정으로 SQL 실행, 사용자 관리, 내보내기 | 토큰 기반 POST /sql, /server/privileges, export | 해당 MySQL 계정이 접근할 수 있는 모든 것의 무결성 | 추론. PMASA-2025-1과 같은 영향 클래스 |
| 2FA / userconfig 변경 | 피해자로서 POST /config/set | 피해자 환경설정 저장소의 무결성 | 추론. 인접 잔여 항목, 이 랩은 아님 |
이 잔여 항목에서 제외된 것: 인증되지 않은 접근, OS RCE, VQB OK 버튼 경로. .small_tab_pref_click_opt는 table_name을 미리 이스케이프하고 Twig가 다시 자동 이스케이프하므로, 해당 클릭은 현재 엔티티를 getTab()에 공급한다. 그것은 history.js의 수정이 아니다. 컬럼 셀은 텍스트 이스케이프 상태로 유지된다(c<b id=pma-col>y, <b id="pma-col"> 노드 없음).
동일 핀: WebAuthn CustomServer 잔여 항목.
phpMyAdmin RELEASE_5_2_3을 고정했다. PMASA-2025-1/2/3은 이미 5.2.2에 있다. Designer는 여전히 VQB 기록 HTML을 수작업으로 구성한다.
js/src/designer/history.js (js/dist/designer/history.js로 배포됨):
temp = historyArray[i].getTab();
str += '<h3 class="tiger"><a href="#">' + temp + '</a></h3>';
// ...
'<td width="175" style="padding-left: 5px">' + $('<div/>').text(historyArray[i].getColumnName()).html() + '<td>';
libraries/classes/Dbal/TableName.php는 비어 있지 않음, 최대 64자, 후행 공백 없음만 검사한다. <와 >는 합법이다. MySQL은 따옴표로 묶인 식별자에서 이를 허용한다.
templates/database/designer/database_tables.twig는 designerTable.getTableName()을 .small_tab_pref_1의 table_name에 복사한다. VQB 옵션 셀은 같은 이름의 미리 이스케이프된 복사본을 사용한다.
이미 기록된 잘못된 방향: 이중 이스케이프된 옵션 버튼 속성을 수정으로 간주(그렇지 않음 - small_tab_pref_1은 여전히 원시 이름을 노출하고 history.js가 싱크임); 컬럼 헬퍼가 테이블 이름을 커버한다고 간주; 인증되지 않은 XSS 주장; 리버스 셸. 연극.
python3 phpmyadmin-vqb-xss-Abraxas-Labs.py
# or: cd lab && ./run.sh
대상은 오직 http://127.0.0.1:19250. 이미지 phpmyadmin:5.2.3 및 mysql:8.0. Compose 프로젝트 phpmyadmin-vqb-xss. poc 서비스의 Playwright Chromium. 실행 후 스택은 해체된다.
두 사용자, 공유 shareddb. 저권한 creator가 CREATE TABLE \tx` (`cy` INT)를 실행한다. 고권한 victim이 phpMyAdmin에 로그인하고 query=1로 Designer를 연다. 라이브 history.js는 컨테이너의 복사본이다(h3-unescaped=yes, 컬럼 헬퍼 존재). Chromium이 페이지의 getTableName()에서 가져온 테이블 이름으로 DesignerHistory.display()`를 호출한다.
결과: #ab h3.tiger innerHTML은 <a href="#">t<i id="pma-vqb">x</i></a>. 컬럼 td 텍스트는 c<b id=pma-col>y이며 b#pma-col 노드는 없다.
SUCCESS phpmyadmin-vqb-xss h3-markup=yes col-escaped=yes how=live PMA-VQB-XSS-WITNESS
<h3>에 연결하기 전에 getTab()을 $('<div/>').text(temp).html() 또는 Functions.escapeHtml로 이스케이프하라. 하나의 속성에 대한 Twig 이중 인코딩에 의존하지 마라. 컬럼 이름 헬퍼를 모델로 유지하라.
962857e4f63d42e38f11ff4d63f5e722018add76)js/src/designer/history.jslibraries/classes/Dbal/TableName.phpGNU Affero GPL v3.0. LICENSE 참조. 루프백 랩 전용. 보증 없음.