Новоразкрита верига от експлойти в GitLab показва как две отдавна скрити грешки, свързани с безопасността на паметта в Ruby библиотеката за парсване на JSON, Oj, могат да бъдат комбинирани за постигане на отдалечено изпълнение на код при инсталации на GitLab по подразбиране, излагайки на риск изходния код, Rails тайните и вътрешните услуги.
Като част от инициативата Open Defense Initiative, изследователят от Depthfirst Юханг Ву (Yuhang Wu) използва автоматизираната система за анализ, за да сканира Oj – високопроизводителен JSON парсер, базиран на C, който се използва широко в приложения на Ruby, включително GitLab.
Сканирането откри 18 уязвимости с висок приоритет, седем от които са свързани с безопасността на паметта, а две са съществували скрито в Oj в продължение на почти пет години, преди да бъдат превърнати в работеща верига от експлойти.
Двата пропуска са некоректно записване в стека при влагане (unchecked nesting-stack write) в Oj::Parser.usual.parse и небезопасно стесняване на 16-битов ключ, което води до изтичане на указател към динамичната памет (heap pointer).
Всяка от уязвимостите поотделно имаше ограничен обхват: едната предлагаше само примитив за повторно еднобайтово „писане“, а другата разкриваше фиксиран 29-байтов сегмент от паметта. Свързани заедно чрез внимателна манипулация на разпределителя на динамичната памет, те дават на атакуващите пълен контрол над указателя за обратно извикване (callback pointer) и начин за заобикаляне на ASLR, което в крайна сметка позволява изпълнение на произволен код с правата на системния потребител „git“.
Уязвимостите в GitLab позволяват изпълнение на код
GitLab визуализира четими от човека разлики (diffs) за файлове на Jupyter Notebook (.ipynb), използвайки вградена библиотека (gem), наречена ipynbdiff. Преди генерирането на тази разлика, библиотеката парсва всяка версия на бележника с помощта на вградения парсер Oj, за да потвърди, че JSON форматът съдържа полето „cells“.
Тъй като файлът на бележника по същество представлява JSON документ, всеки удостоверен потребител, който може да изпраща промени (push) и да преглежда разликата в коммитите, би могъл да прокара злонамерени JSON структури в това извикване.
Експлойтът функционира чрез изпращане на два специално създадени файла на бележника в една заявка за разлика в коммитите. Голямата дълбочина на влагане на първия файл компрометира защитата чрез записване в стека, за да пренасочи вътрешен указател на буфера, а последващите операции в динамичната памет карат паметта на масива на Ruby (Ruby Array) да се припокрие с указателя за обратно извикване на парсера, позволявайки на атакуващите да внедрят избран адрес в p->start.
Второ изтичане на указател от динамичната памет, промъкнато в извънредно голям ключ на JSON обект и визуализирано в HTML изхода на разликата, дава на атакуващите адреса, необходим за изчисляване на местоположението в паметта на основни библиотеки като libc и libruby, заобикаляйки защитите на ASLR.
Тъй като Puma (сървърът за приложения на Ruby в GitLab) изпълнява множество нишки, които споделят една инстанция на вградения парсер за всеки работник (worker), и двата подготвени файла се обработват от един и същ уязвим парсер в рамките на една заявка, което позволява на втория файл да задейства компрометираното обратно извикване и да изпълни команден ред чрез system().
За разлика от по-ранните проблеми с отдалечено изпълнение на код в GitLab, които разчитаха на подправяне на заявки от страна на сървъра (SSRF) срещу вътрешни инстанции на Redis, тази верига заобикаля изцяло съвременните защити на GitLab срещу SSRF, като атакува вградена зависимост с небезопасна памет, интегрирана в иначе безопасния откъм памет код на Ruby.
Всеки член на проект с обикновен достъп за изпращане на промени и преглед на разликите може да задейства веригата без администраторски права, достъп до CI/CD или взаимодействие от страна на жертвата, което я прави особено опасна за споделени или мултинаемателски (multi-tenant) самостоятелно управлявани инстанции на GitLab.
Успешното експлоатиране позволи изпълнението на команди с правата на акаунта „git“, който обслужва работните процеси на Puma в GitLab. Това потенциално може да изложи на риск изходния код на хранилището, тайните на Rails приложението, идентификационните данни за услуги и всякакви вътрешни услуги, достъпни от хоста на GitLab. В резултат на това съществува риск от кражба на данни, подмяна на код и странично движение (lateral movement), се казва в изявление на Depthfirst пред CybersecurityNews.
GitLab.com вече беше коригиран към момента на разкриване на уязвимостта и за клиентите на Dedicated не се изискваха действия, но администраторите на самостоятелно управлявани инстанции в засегнатите диапазони от версии трябва незабавно да извършат обновяване.
Уязвимият код на парсера Oj е внедрен през август 2021 г., а GitLab започва да използва засегнатото извикване за парсване през юли 2022 г. от версия GitLab 15.2.0.
Изследователят е докладвал основните грешки в Oj на 21 май 2026 г.; в Oj бяха внесени корекции на 27 май, след като пропуските бяха останали неотстранени в продължение на 1753 дни, а версия Oj 3.17.3 бе публикувана на 4 юни. Специфичната за GitLab верига е докладвана на 5 юни, потвърдена на 8 юни и за нея е инсталирана корекция за сигурност на 10 юни 2026 г. във версии 19.0.2, 18.11.5 и 18.10.8.
Със същото изследователско проучване бяха публикувани още девет CVE уязвимости за Oj извън двете, използвани в тази верига, обхващащи препълвания на буфера в стека и динамичната памет, множество състояния на използване след освобождаване (use-after-free) в SAJ извикванията и итераторите на документи, memcpy с отрицателен размер и препълване на цели числа при големи файлове, което подчертава колко дълбоко рискът от повреждане на паметта може да се крие във вградени разширения, пакетирани с иначе „безопасни“ приложения на Ruby.
Екипите за сигурност, управляващи самостоятелни инстанции на GitLab, трябва приоритетно да инсталират корекциите за сигурност до споменатите по-горе стабилни версии и да одитират дърветата на зависимостите на Ruby за вградени C разширения, тъй като небезопасен откъм памет код в рамките на доверена библиотека (gem) може да подкопае гаранциите за безопасност на паметта на целия стек от приложения на Ruby.