Olyan anyagot kaptam Bob Putton-tól, hogy a tíz ujjamat megnyaltam utána: részletes elemzés a David Litchfield által az idei BlackHat-en bemutatott, majd nem rég az Oracle által javított jogosultságkiterjesztésre alkalmas sérülékenységről. Bár mostanában hangos vita folyik a még javítatlan, 0-day sérülékenységekről, nem szabad elfelejtenünk a itt bemutatandóhoz hasonló "1-day"-ek jelentőségét sem, sok helyre ugyanis a ma megjelenő javítások még hónapok múltán sem kerülnek fel. Bob Putton munkája bemutatja, hogy hogyan lehet nekifogni egy olyan, javításairól csak igen-igen szűkszavúan nyilatkozó gyártó frissítéseinek, mint az Oracle, valamint jó kiindulópontot ad hasonló sérülékenységek felfedezéséhez.
Az augusztus 19-i "Hírek - 2012/33. hét" című blogbejegyzésedben írtál egy Oracle DB sebezhetőségről az Oracle Text modulban, amelyet David Litchfield a BlackHat-es előadásán mutatott be. Sajnos nem volt lehetőségem ennek az előadásnak a megtekintésére, és a netet böngészve sem találtam semmi konkrétumot magáról a sebezhetőségről. Mivel nap mint nap Oracle környezetben dolgozom, így magam jártam kicsit utána, hogy vajon mi is lehet a sebezhetőség mögött (természetesen segítettek a neten itt-ott elejtett információmorzsák: [1] és [2])
Először összeszedtem az összes infót amit lehetett az internetről. Abból a két hivatkozásból amit küldtem, a védekezésre vonatkozó részben elég sok információt leírtak, hogy mik a gyanús jelek és mire figyeljünk oda, és ebből a következők derültek ki:
- CREATE TABLE, CREATE PROCEDURE jog kell hozzá, és EXECUTE jog a DBMS_STATS csomagon
- az egyik helyen azt írták, hogy a CTXSYS.CTX_DDL csomagra is kell EXECUTE jog
- a folyamat során létre kell hozni egy Oracle Text indexet (egy olyan indexet aminek az indextípusa CTXSYS.CONTEXT)
- statisztikát kell gyűjteni a DBMS_STATS.GATHER_TABLE_STATS eljárással
- minden olyan index gyanús, amit olyan oszlopra hoztak létre, amiben szerepel a || karaktersorozat (!)
Itt az utolsó szösszenet adta a legtöbb segítséget. A SQL és PL/SQL nyelv nem érzékeny a kis és nagybetűkre, de létre lehet hozni olyan azonosítókat, amik speciális karaktereket tartalmaznak (akár szóközt is) dupla aposztrófok (") között. Tehát létrehoztam egy táblát, egy olyan oszlopnévvel amiben van ' (karaktersorozatokat határoló jel) és || (konkatenáció operátor). Valószínű volt hogy az oszlopnevet valahol az Oracle hozzáfűzi egy lekérdezéshez, amit később lefuttat dinamikus SQL-lel (EXECUTE IMMEDIATE vagy dbms_sql.parse segítségével), így az oszlopnevet már eleve úgy szerkesztettem meg, hogy ha tényleg ez a helyzet, akkor lefusson egy általam megírt teszt függvény, ami egy log táblába szúr adatokat, így egyből látom ha sikeres volt. Erre az oszlopra tettem egy Oracle Text indexet, majd gyűjtöttem a táblára statisztikát a fenti leírás szerint.
Viszont ezt így lefuttatva nem jártam sikerrel. Csináltam pár DB trace-t, és nézegettem, hogy milyen SQL-ek futnak a háttérben, rákerestem az oszlopnévre is a trace fájlban, de nem igazán találtam semmi olyat, ami segített volna. Elkezdtem visszafejteni a DBMS_STATS csomagot. A beépített csomagok általában obfuszkálva vannak, amit az Oracle wrapping-nek hív, de ezeket egyszerűen dekódolni lehet, mivel az egész folyamat nagyjából csak egy base64 átalakításból és egy ZIP tömörítésből áll és ráadásul online eszközök is rendelkezésre állnak. Ezután eltöltöttem néhány órát további beépített Oracle csomagoknak a deobfuszkálásával és nézegetésével, amiket a DBMS_STATS csomag hív (DBMS_STATS_INTERNAL, CTX_DDL, DRVDDL, DRVDML, DRVUTL, stb.) de egyikben sem találtam semmi használhatót, ahol dinamikusan rakna össze olyan SQL utasítást, ami ellenőrizetlenül fűzné össze az oszlopnevet. Minden helyen szépen meghívta a DBMS_ASSERT csomagot (ami különböző inputok, pl. szöveges literál, azonosító validálására szolgál), ahogy ennek lennie kell.
Ezen a ponton arra gondoltam, hogy mivel ezek a viszonylag (absztrakció tekintetében) alacsony színtű csomagok gyakran hívnak ki C-ben megírt shared library-kba (Unix/Linux alatt .so, Windows alatt általában .dll fájlok), ezért lehet hiába nézegetem a PL/SQL kódot, lehet az injektálható, hibás SQL-t egy C eljárás rakja össze. És már-már feladtam, mikor észrevettem, hogy a log táblában van néhány sor. :)
Rájöttem, hogy mikor a próbálkozások között eldobtam és újra létrehoztam a táblát, valahogy mégiscsak lefutott az az injektált kód, és ezt a trace fájl is megerősítette. A trace fájlban lévő SQL-t továbbra sem találtam meg az adatbázisban, tehát ez azt a teóriát erősíti, hogy nem az adatbázisban van megírva PL/SQL csomagként, hanem valami külső library-ban. Ezután még vagy 1 órát elbütyköltem azzal, hogy hátha a tábla eldobása helyett elég a statisztikát törölni, de miután különböző DBMS_STATS hívásokkal nem jártam sikerrel, ezért feladtam a további próbálkozást. Most így utólag átolvasva az dolgokat, lehet a CTX_DDL csomaggal tovább kellett volna próbálkoznom, hiszen azt írták, hogy erre is kell futtatási jog. :)
A jól felkommentezett PoC és a részletes trace fájlok letölthetők innen.
synapse · http://www.synsecblog.com 2012.09.14. 15:40:12