Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
wp2shell-lab — WordPress 코어 6.9.0-6.9.4 / 7.0.0-7.0.1에서 wp2shell(CVE-2026-63030 REST /batch/v1 라우트 혼동 + CVE-2026-60137 author__not_in SQLi)을 위한 비파괴적 탐지기 + Docker 랩 | Kitploit
도구/GitHubGitHub/dinosn/wp2shell-lab
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationLabs & Practice
GitHubdinosn/wp2shell-lab

wp2shell-lab

WordPress 코어 6.9.0-6.9.4 / 7.0.0-7.0.1에서 wp2shell(CVE-2026-63030 REST /batch/v1 라우트 혼동 + CVE-2026-60137 author__not_in SQLi)을 위한 비파괴적 탐지기 + Docker 랩

저장소 보기
5417212개월 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

wp2shell 랩 & 탐지기 + 사전 인증 RCE PoC

wp2shell — WordPress 코어의 사전 인증 취약점 체인 — 을 위한 자체 완비형 랩, 비파괴 탐지기, 그리고 **전체 사전 인증 RCE PoC(proof-of-concept)**입니다:

CVEComponentClassCVSS
CVE-2026-60137WP_Query::author__not_inSQL 인젝션 (CWE-89)9.1
CVE-2026-63030REST /batch/v1 라우트 혼동해석 충돌 (CWE-436) → RCE로 연결됨7.5

영향 범위: WordPress 코어 6.9.0–6.9.4 및 7.0.0–7.0.1 (SQLi 싱크만으로는 6.8.0–6.8.5에도 영향). 6.8.6 / 6.9.5 / 7.0.2에서 수정됨. Adam Kues(Assetnote / Searchlight Cyber)가 보고했으며, SQLi는 TF1T, dtro, haongo에게도 공로가 인정됩니다. 기본 구성(stock-default) RCE 체인(oEmbed → changeset → re-entry)은 Mustafa Can İPEKÇİ(nukedx)가 작성했습니다.

먼저 업데이트하세요. WordPress는 이 취약점에 대해 강제 자동 업데이트를 배포했습니다. 이 저장소는 여러분이 자신의 시스템이 패치되었는지 확인하고 버그를 이해하도록 돕기 위한 것이지, 누군가를 공격하기 위한 것이 아닙니다. SECURITY.md를 참조하세요.


실제로 무엇인가

항상 성립하는 프리미티브는 인증 없이(unauthenticated), 플러그인 없이, 기본 코어(stock-core)에서 동작하는 SQL 인젝션으로, 데이터베이스 전체 읽기(관리자 비밀번호 해시, wp_options/wp_users의 모든 데이터)를 가능하게 합니다. 이것만으로도 CVSS 9.1과 즉각적인 패치가 정당화됩니다.

RCE는 실제이며 기본 구성(stock-default) WordPress에서 동작합니다 — FILE 권한, 영구 객체 캐시, 플러그인, 잘못된 구성이 전혀 필요 없습니다. 이 체인은 읽기 전용 SQLi를 행 위조(row-forgery) 프리미티브로 사용하며(UNION ALL SELECT가 가짜 wp_posts 행을 주입), 이후 WordPress 자체의 콘텐츠 렌더링 파이프라인을 활용해 oEmbed 캐싱을 통해 위조된 행을 실제 데이터베이스 쓰기로 변환합니다. 여기서부터 changeset 승격과 재진입(re-entrant) parse_request가 관리자 컨텍스트에서 실행되어 새 관리자 계정을 생성합니다 — 모두 단일한 인증 없는 HTTP 요청 하나로 이루어집니다.

전체 체인 (자격 증명 없음, 단일 진입점 POST /?rest_route=/batch/v1)

1. Route confusion    — double-nested batch desyncs $matches/$validation so a GET
                        /wp/v2/widgets runs under posts::get_items() (public), reaching
                        WP_Query's author__not_in with attacker-controlled input.

2. Row forgery        — author__not_in is string-concatenated into SQL;
                        "1) AND 1=0 UNION ALL SELECT <23 cols> -- -" injects fake
                        WP_Post rows. per_page=-1 bypasses split_the_query (WP_Query
                        treats -1 as "no limit" → empty $limits → split=false →
                        full SELECT wp_posts.* → UNION columns match).

3. oEmbed write       — forged posts carry [embed]<self-url>[/embed]; rendering via
                        context=view makes WordPress cache real oembed_cache posts in
                        the DB (turns read-only SQLi into writes with predictable IDs).

4. Elevation+re-entry — a forged customize_changeset (user_id = real admin) plus a
                        forged post_type=request row with parent loops drives an
                        in-process re-entrant parse_request in admin context.

5. Admin creation     — POST /wp/v2/users in the same batch passes
                        current_user_can('create_users') → new administrator.

6. RCE                — login → plugin webshell upload → command execution → cleanup.

핵심 가젯 (체인이 성립하는 이유)

새로움은 *조합(composition)*에 있지 단일 버그에 있는 것이 아닙니다 — 개별 가젯은 정당한 WordPress 동작입니다. (Adam Kues의 분석에 따라) 이름을 붙여두면 exploit()의 위조 행 그래프를 읽기 쉽게 만들고, 진입점이 패치된 후 재감사해야 할 부분을 표시해 줍니다:

  • 캐시/DB 조정(reconciliation) — 메모리 내 캐시된 포스트가 DB 행과 일치하지 않으면 WordPress는 wp_update_post()를 통해 조정하며 메모리 내 post_type/post_status를 우선합니다. 그 결과 oembed_cache 행이 실제 post/customize_changeset으로 재유형화(re-typed)될 수 있습니다.
  • post_content를 보존하는 사이클 감지(cycle-detection) — wp_insert_post_parent 필터가 부모 체인을 순회합니다. 사이클이 감지되면 post_content를 덮어쓰지 않고 부모를 수정하는 두 번째 wp_update_post()를 호출합니다. 이것이 핵심 연결고리입니다: 위조된 changeset의 악의적인 post_content가 살아남을 수 있게 해줍니다. (그래서 위조 행이 자기 자신/상호 부모 루프를 사용하는 이유가 여기 있습니다.)
  • parse_request를 통한 훅 재생(hook replay) — 포스트를 발행하면 do_action("{$status}_{$type}")가 실행됩니다. post_status=parse / post_type=request인 위조 행은 parse_request를 트리거하여, changeset이 가정한 관리자 신원(wp_set_current_user)이 유지되는 동안 배치 파이프라인을 다시 실행합니다.

이러한 가젯은 패치된 WordPress에도 여전히 존재합니다 — 닫힌 것은 두 진입점(배치 역동기화 + author__not_in 스칼라 우회)뿐입니다. 메모리 내 포스트 캐시를 위조하거나 oembed_cache 행을 쓰는 새로운 프리미티브가 발견되면 동일한 관리자 탈취 후반부(admin-takeover tail)가 다시 활성화될 수 있습니다.

렌더링 시점 쓰기 프리미티브

네 가지 렌더링 시점 쓰기 프리미티브가 모두 7.0.1을 대상으로 실측 확인되었습니다 — 각각 인증 없는 포스트로 위조되고, 배치 혼동(batch confusion)을 통해 렌더링되며, 결과적인 DB 쓰기는 블라인드 SQLi로 검증되었습니다:

프리미티브트리거 마크업싱크예측 식별자검증 결과
oembed[embed]<url>[/embed]wp_posts 행 (oembed_cache)post_name = md5(url+attrs)post ID 생성됨
rsswp:rss {feedURL}wp_options 사이트 임시값(site-transient)_site_transient_feed_<md5(url)>option_id, 5192 B 캐시됨
navigationwp:navigationwp_posts 행 (wp_navigation)post_name = 'navigation' (고정)ID 생성됨, slug navigation
calendarwp:calendarwp_optionswp_calendar_block_has_published_postsoption_id, 값 '1'

각 결과가 입증하는 것:

  • oembed — 기준 프리미티브입니다: 공격자가 예측할 수 있는 slug(md5(url+serialize(attrs)))와 실제 자동 증가(auto-increment) ID를 가진 새로운 wp_posts 행을 만듭니다. 이는 여러 개의, 요청 시 생성되는(on-demand), 공격자가 이름을 지정한 포스트 행을 제공하는 유일한 방식이라서, RCE 체인이 위조된 changeset/request 그래프를 뒷받침하는 데 사용합니다.
  • rss — 가장 강력한 일반적인 쓰기입니다: 키 _site_transient_feed_<md5(url)>가 완전히 예측 가능하며, 저장되는 바이트는 공격자의 URL이 서빙하는 피드 본문입니다 — 즉 공격자가 키와 값 모두를 제어합니다. wp_options 쓰기(post ID 없음)이므로 changeset 백킹을 대체하는(drop-in) 방식이 아니라 옵션 오염(option-poisoning) 프리미티브입니다.
  • navigation — 인증 없이 "렌더링이 실제 포스트 행을 생성"하는 유일한 또 다른 경로입니다. 고정 slug를 가지며 단발성(single-shot)입니다(발행된 wp_navigation이 하나라도 있으면 건너뜀). 따라서 oEmbed의 N개 행과 달리 최대 하나의 위조 객체만 뒷받침할 수 있습니다.
  • calendar — 렌더링→update_option 경로가 인증 없이 실행됨을 확인하지만, 옵션 이름과 그 '1'/'0' 값은 고정/DB 기반입니다. 따라서 키나 값에 대한 공격자 제어 없이 "쓰기가 발생함"을 보여주는 데모입니다.

이전의 조건부 체인 (위의 기본 구성 체인으로 대체됨)

  • INTO OUTFILE 웹셸: WordPress DB 사용자가 전역 FILE 권한을 보유하고, 웹에서 접근 가능한 secure_file_priv가 설정되어 있으며, 드롭(drop) 디렉터리를 웹 사용자가 읽을 수 있어야 합니다. 일반/관리형 호스트에서는 어느 것도 성립하지 않습니다.
  • SimplePie → WP_HTML_Token POP: call_user_func('wp_insert_user', user_data_array) — gc_enabled()=false와 유효한 HMAC(정확한 직렬화 바이트에 대한 wp_hash, wp-config.php 시크릿 필요)가 필요합니다.

빠른 시작

요구 사항: Docker + Docker Compose v2, Python 3.8+ (표준 라이브러리만), make, curl.

make up          # WordPress 6.9.4 (vulnerable) + MySQL 8.0, auto-installed on :8093
make check       # -> [VULNERABLE] http://localhost:8093 (WordPress 6.9.4 ...)
make proof       # -> also reads @@version and current_user() as read-only evidence
make exploit     # -> full pre-auth RCE: creates admin, deploys webshell, runs "id"
make patched     # rebuild on the fixed image and re-check -> [not vulnerable]
make down        # tear down (removes volumes)

포트는 WP_PORT=8100 make up으로 변경할 수 있습니다.

패치된 이미지에 대한 참고: 공식 Docker wordpress 이미지는 WordPress 코어 보안 릴리스보다 하루 이틀 늦게 배포됩니다. make patched가 wordpress:7.0.2가 아직 Docker Hub에 없다고 보고하면, 나중에 다시 시도하거나 게시된 수정 태그를 지정하세요: make patched WP_PATCHED_TAG=6.9.5 (또는 7.0.2 / 6.8.6). WordPress ≥ 6.9.5 / 7.0.2 / 6.8.6이면 not vulnerable을 반환합니다.

예상 출력

$ make check
[VULNERABLE] http://localhost:8093  (WordPress 6.9.4, affected-full-chain)  [active=fired | method=boolean rows(true/false)=5/0 via x-wp-total | delivery=json | slot=users]
        confirmed: unauthenticated SQL injection
        rce: reachable on stock config; additionally requires no persistent object cache (not verified remotely -- the RCE PoC preflights it before writing)

$ make exploit
[*] seeding oEmbed caches ...
[*] extracting table prefix ...
[+] table prefix: wp_
[*] extracting admin user ID ...
[+] admin ID: 1
[*] recovering oEmbed cache post IDs ...
[+] cache IDs: [5, 6, 7]
[*] forging changeset + re-entry, creating administrator ...
[+] administrator created: w2s_...:W2s!...  ([email protected])
[*] logging in, deploying webshell, executing command ...
[+] vulnerable (unauth SQLi confirmed: method=boolean slot=users delivery=json)
[+] RCE output:
도구 다운로드