tom@home.htb:~$

Blog o HTB

16 December 2020

NoSQL injection v loginu a extrakce přes `$regex` / `$ne`

Úvod a kontext

NoSQL injection se často podává jako exotická varianta SQLi. V praxi je ale užitečnější dívat se na ni přes to, co přesně backend udělá s uživatelským vstupem. Pokud aplikace převede parametry login formuláře přímo na operátory databázového dotazu, útočník pak neovládá jen hodnotu typu “uživatelské jméno”. Ovládá logiku dotazu.

Na Mango je to vidět velmi čistě. Login formulář nad MongoDB backendem nejdřív dovolí jednoduchý bypass přes $ne, ale skutečně cenné je něco jiného: stejný endpoint jde použít k postupné extrakci reálných přihlašovacích údajů přes $regex. To je důležitý rozdíl. Nejde jen o jednorázové “jsem přihlášený”. Jde o systematické získání dvojic uživatel:heslo, které pak fungují i mimo web.

Co se u NoSQL injection skutečně kazí

Relativně bezpečný login předá databázi prostá data:

{
  "username": "alice",
  "password": "Secret123!"
}

Zranitelný login udělá něco jiného. Uvěří, že vstup z HTTP requestu už je hotový dotaz nebo jeho část. V tu chvíli mohou parametry začít nést operátory typu:

To je zásadní rozdíl proti běžnému “špatně escapovanému stringu”. U NoSQL injection útočník často nemanipuluje se syntaxí jednoho řetězce. Manipuluje s celou strukturou dotazu.

Dva různé cíle: bypass a extrakce

1. Login bypass

Nejjednodušší varianta je donutit dotaz, aby přijal skoro cokoliv. Typický příklad je:

username[$ne]=x&password[$ne]=x

Pokud backend tento vstup bez filtrace pošle do Mongo-like dotazu, význam je zhruba:

To je pro mnoho záznamů pravda zároveň, takže login vrátí první odpovídající účet. Tohle je dobrý potvrzovací test, ale často ještě není nejhodnotnější.

2. Extrakce dat

Mnohem zajímavější je okamžik, kdy se stejný formulář stane orákulem pro čtení skutečných hodnot. Jakmile aplikace dovolí prefixový match přes $regex, jde znak po znaku ověřovat:

Tím se z login formuláře stává extrakční kanál, ne jen bypass.

Mango: když vendor/composer napoví správný směr

Na Mango není nejcennější první payload. Je cenné už to, že veřejný vendor/composer/installed.json zúží okruh technologií na MongoDB:

alcaeus/mongo-php-adapter
mongodb/mongodb

Právě tohle je dobrá metodická lekce. Bez této indicie by login formulář vypadal jako kandidát na SQLi, slabé heslo nebo klasický auth bug. Tady ale dává smysl zkusit rovnou strukturované parametry:

?login=login&username[$ne]=toto&password[$ne]=toto

To potvrdí, že backend interpretuje MongoDB operátory přímo z requestu. V tu chvíli už nemá největší hodnotu samotný login bypass. Větší hodnotu má systematická extrakce.

Jak funguje extrakce přes $regex

Jakmile je potvrzené, že backend akceptuje $regex, může útok postupovat po znacích. Praktická logika bývá jednoduchá:

  1. zkusit první znak,
  2. pokud aplikace vrátí úspěch nebo jiný rozlišitelný výsledek, znak sedí,
  3. rozšířit prefix o další znak,
  4. pokračovat až do celé hodnoty.

Na Mango právě tímto způsobem vznikly dvě reálné dvojice:

mango / h3mXK8RhU~f{]f5H
admin / t9KcS3>!0B#2

To je důležitý rozdíl proti běžné brute force. Útočník netestuje slovník hesel proti lockoutu. Používá aplikaci jako booleovské orákulum, které samo odpovídá, jestli daný prefix sedí.

Proč je $regex nebezpečnější než se zdá

Na první pohled by se mohlo zdát, že prefixová extrakce bude pomalá a málo praktická. Ve skutečnosti bývá velmi použitelná, pokud se sejdou tyto podmínky:

V tu chvíli už nejde o teoretickou injekci. Jde o plnohodnotný credential recovery kanál.

Kde se podobná chyba bere

Prakticky se tenhle problém objevuje tam, kde aplikace:

Jinými slovy: problém není v tom, že by MongoDB samo o sobě bylo nebezpečné. Problém je v tom, že aplikace dovolí uživateli přinést si vlastní operátory.

Jak takový login bezpečnostně číst

Při review nebo testu dává smysl jít po těchto otázkách:

Přijímá endpoint jen stringy

Je login odpověď rozlišitelná

Právě to často rozhodne, jestli půjde jen o bypass, nebo i o extrakci.

Co se stane po získání hesla

Mango ukazuje důležitou druhou vrstvu. Extrahované heslo nemusí mít cenu jen pro web. Může fungovat i pro:

Proto je užitečné vnímat NoSQL injection v loginu jako credential theft vektor, ne jen jako auth bypass.

Obrana a hardening

1. Vynutit typy vstupu

username a password mají být obyčejné stringy. Pokud aplikace dovolí, aby se z nich stal objekt nebo pole s operátorem, problém začíná ještě před samotným dotazem.

2. Nepředávat uživatelský vstup přímo do query objektu

Bezpečný login nemá stavět query tak, že uživatel dodá jeho strukturu. Aplikace má sama vytvořit pevný dotaz a uživatelský vstup do něj vložit jen jako datovou hodnotu.

3. Sjednotit odpovědi loginu

Pokud login vrací snadno rozlišitelné odpovědi, stává se z něj orákulum pro extrakci. U citlivých endpointů je proto důležité minimalizovat rozdíly v chování při neúspěchu.

4. Omezit rychlost a množství pokusů

Rate limiting a další ochrany samy problém neřeší, ale výrazně zvyšují cenu prefixové extrakce.

5. Neopakovat hesla mezi webem a shellovým účtem

Mango připomíná, že skutečný dopad často neurčí injekce samotná, ale až reuse extrahovaných hesel napříč vrstvami.

Shrnutí klíčových poznatků

Co si odnést do praxe

tags: nosql - mongodb - web - auth - login - injection