Zpět na seznam článků     Číst komentáře (5)     Verze pro tisk

Nebezpečné Register Globals

Autor: independent   
31.3.2013

Direktiva register_globals je pravděpodobně jednou z nejznámějších položek v konfiguračním souboru interpreteru jazyka PHP. Obecně je vřele doporučováno ji z bezpečnostních důvodů vypnout a ve verzi 5.4.0 již byla dokonce zcela zrušena. My si nyní ukážeme, co nastavení této direktivy vlastně ovlivňuje, a jak toho lze využít z pozice útočníka.


Úvod

Pokud jste četli předmluvu pečlivě, možná si kladete otázku, proč bychom se vlastně měli zabývat direktivou, která se již v PHP nadále nenachází. Odpověď je velmi jednoduchá. Některé nejmenované freehostingy, jako třeba Webzdarma a Internet Centrum, i nadále používají zastaralé verze PHP a tuto možnost mají povolenou - pravděpodobně záměrně pro zachování kompatibility s kvalitně napsanými aplikacemi uchovávanými ještě na hliněných destičkách.

Cílem tohoto článku není útočení na webové stránky na ani jednom ze zmiňovaných hostingů a dokonce ani na hostinzích jiných, nýbrž pouze demonstrace toho, jak může jediný řádek v rozsáhlém konfiguračním souboru zásadním způsobem narušit bezpečnost webových aplikací na daném serveru. Ukážeme si rovněž, jakým způsobem si můžete svoje webové stránky chránit.

Článek poskytuji výhradně ke studijním účelům a nesouhlasím s jakýmkoliv zneužitím uvedených informací pro destruktivní činnost. Zejména duševně narušeným script-kiddies vysloveně zakazuji tento článek dále číst.

O co se jedná

Direktiva register_globals ovlivňuje, jakým způsobem budou v PHP skriptech dostupné proměnné. Pokud je nastavená na možnost on, tedy zapnutá, budou i proměnné odeslané metodou GET či POST dostupné přímo pod svým názvem. Nebude tudíž nutné přistupovat k nim přes pole ($_GET a $_POST). Pro lepší pochopení uvedu raději praktický příklad.

Mějme velmi jednoduchý skript, který vypíše obsah proměnné $test:

  1. <?php
  2.     echo $test;
  3. ?>

V případě, že je register_globals zapnuto, můžeme nyní skriptu předat přes URL (tj. metodou GET) parametr "test" a přiřadit mu například hodnotu "ahoj". Pokud jste svůj testovací skript pojmenovali třeba index.php a spouštíte jej na svém lokálním počítači, může to vypadat například takto:

http://localhost/index.php?test=ahoj

Ve webovém prohlížeči se vám tedy zobrazí krásný a milý pozdrav "ahoj", který pohladí po dušičce a zahřeje na srdíčku. Méně již ovšem zahřeje na srdíčku skutečnost, že tímto způsobem lze do všech neinicializovaných proměnných ve zdrojových kódech injektovat libovolný obsah.

Pokud by byl register_globals vypnutý, s tímto pokusem samozřejmě narazíte a namísto hřejivého pozdravu se dočkáte pouze mrazivě bílé stránky (dle nastavení ještě s případným warningem o nedefinované proměnné).

Zkusíme nyní o něco praktičtější příklad s přihlašováním uživatelů:

  1. <?php
  2.         if ($name == "admin" && $password == "password")
  3.                 $logged = true;
  4.  
  5.         if ($logged)
  6.         {
  7.                 echo "Prihlasen!";
  8.         }
  9. ?>

Jak vidíte, proměnná logged nebyla nikde inicializována. O inicializaci se tedy můžeme postarat my přímo v URL pomocí parameteru:

...login.php?logged=1

Proměnná logged tedy bude již v době spouštění skriptu nastavena tak, že druhé podmínce vyhoví - a ačkoliv první podmínkou neprojde, úspěšně se do skryté části webu dostaneme.

O něco pravděpodobnější ovšem je, že pro přihlašování budou použity tzv. sessions. Představme si nyní, jak by takový zdrojový kód mohl vypadat:

  1. <?php
  2. session_start();
  3.                        
  4. if (isset($_GET['logout']))
  5. {
  6.         session_destroy();
  7.         Header("Location: test01.php");
  8. }
  9.  
  10. if (isset($_POST['name']) && isset($_POST['password']))
  11. {
  12.         if ($_POST['name'] == 'admin' && $_POST['password'] == 'password')
  13.         {
  14.                 $_SESSION['logged'] = true;
  15.                 Header("Location: test01.php");
  16.         }
  17. }
  18. ?>
  19.  
  20. <html>
  21.         <head>
  22.                 <title>Ultra tajna sekce!</title>
  23.         </head>
  24.         <body>
  25.                 <form action="" method="post">
  26.                         <table>
  27.                                 <tr><td>Jmeno: </td><td><input type='text' name='name'></td></tr>
  28.                                 <tr><td>Heslo: </td><td><input type='password' name='password'></td></tr>
  29.                                 <tr><td><input type='submit' value='Prihlasit!'></td></tr>
  30.                         </table>
  31.                 </form>
  32.                
  33.                 <?php          
  34.                         if ($logged)
  35.                         {
  36.                                 echo "<p>... obsah ultra tajne sekce ...</p>";
  37.                                 echo "<p><a href='?logout'>Odhlasit se</a></p>";
  38.                         }
  39.                 ?>
  40.         </body>
  41. </html>

Ačkoliv je takový kód doslova ukázkou toho, jak se to nemá dělat, je stále velmi pravděpodobné, že se s něčím podobným budeme moci běžně setkat.

Důvod, proč podobný kód bude fungovat, je ten, že při zapnutém register_globals jsou proměnné uložené do sezení přístupné i globálně. Pokud tedy programátor bude, byť pouze jednou, líný napsat v osudové podmínce $_SESSION['logged'] a namísto toho uvede pouze zkrácený tvar $logged, aplikace je při tomto nastavení okamžitě zranitelná.

Co je k útoku potřeba

Jak už je z předchozích ukázek patrné, samotné zapnutí register_globals ještě neznamená bezpečnostní díru. Jejich vzniku nicméně zásadním způsobem napomáhá a i kód, ve kterém na první pohled žádná chyba není, lze napadnout.

Zjevnou překážkou pro útočníka je potřeba znát názvy proměnných, které se v kódu využívají. V zásadě existují tři možnosti, jak se k nim dostat. První z nich, která by asi každého napadla, je uhodnutí. Existuje poměrně vysoká šance, že se podaří, ale stále to není to pravé ořechové. Pokud je web provozován na opensource systému, bylo by mnohem příhodnější si zdrojové kódy stáhnout a prostě se pokusit slabé místo najít tam. Poslední možnost by pak spočívala ve zneužití jiné bezpečnostní díry či chybné konfigurace. Například pomocí LFI by se útočníkovi mohlo podařit dostat se i k neveřejným zdrojovým kódům. Často to ale ani není potřeba, neboť PHP někdy (v závislosti na konfiguraci) může vypisovat chybové hlášky, ve kterých bude název proměnné přímo obsažen. Zde je potřeba dát pozor, protože chybová hláška nemusí být vidět přímo ve výstupu zobrazeném v prohlížeči, ale přesto se může nacházet ve vygenerovaném HTML kódu. Použité stylování apod. ji prostě může skrýt.

Znalost názvu proměnných a zapnuté register_globals ovšem samozřejmě nestačí a ne každá aplikace automaticky půjde napadnout. Základní předpoklad pro úspěšný útok je ten, že klíčová proměnná nebude inicializována. Pokud by totiž inicializována byla, jste s těmito pokusy bez šance. Inicializace vám totiž hodnotu injektovanou přes parametr přepíše.

Hrozba

Ačkoliv by se z dosavadního textu mohlo zdát, že se vesměs o nic zásadního nejedná, opak je dle mého názoru pravdou. Stačilo by projít zdrojové kódy několika opensource CMS, ideálně v ne zcela aktuálních verzích (mohou vyžadovat novější verze PHP) a hledat jakkékoliv neinicializované proměnné apod. Weby postavené na těchto systémech lze pak zpravidla snadno dohledat díky různým podpisům v patičkách. Pokud by navíc daná verze CMS ke svému běhu přímo vyžadovala zapnuté register_globals, pak s velkou pravděpodobností dokážete napadnout všechny jeho instalace - na hostingu s vypnutými register_globals by totiž CMS vůbec neběžel.

Ochrana

Zřejmě nejlepší ochranou by byla aktualizace na nejnovější verzi PHP, kde je toto nastavení již defaultně vypnuté (a zapnout už ani nejde). Pokud aktualizovat z nějakého důvodu nemůžete, ale máte přístup k souboru php.ini, můžete v něm řádek začínající "register_globals" upravit takto:

register_globals = Off

Takovou možnost však většina z vás mít nebude, proto si budete muset vypomoci se souborem .htaccess, který lze použít i na dříve zmiňovaném Webzdarma (a předpokládám, že i na Internet Centru):

php_flag register_globals off

V tom nejhorším případě, kdy nemůžete aktualizovat a nemáte k dispozici ani jeden zmíněný konfigurační soubor, popř. z nějakých jiných důvodů musíte nechat register_globals zapnutý, si alespoň projděte všechny zdrojové kódy a upravte je tak, aby na ně tímto způsobem nešlo útočit. Ideální by tedy bylo si na testovacím serveru nainstalovat naprosto identickou konfiguraci, jako je na produkčním serveru, a posléze si zapnout v PHP vypisování všech chybových hlášek. To by vás již mělo navigovat směrem k neinicializovaným proměnným apod. Poté byste měli být, alespoň co se register_globals týká, v bezpečí.

Závěr

V tomto článku jsem chtěl prezentovat trochu jiné způsoby útočení na webové aplikace, než jsou neustále dokola omílané zranitelnosti jako XSS, SQLi, LFI, RFI apod. Jsem přesvědčen o tom, že minimálně na většině (free)hostingů by se daly najít mnohem zákeřnější chyby, než je nějaký register_globals. Jmenovitě na Webzdarma nebyl v minulosti problém přepisovat soubory ostatních uživatelů a existoval tuším dokonce i exploit, který se o vše postaral automaticky.

O bezpečnost se zajímám spíše z pohledu programátora, který si chce zabezpečit svoje aplikace, než z pohledu útočníka. Na popisování nějakých "zákeřnějších" útoků, zneužívajících například sdílené adresáře pro dočasné soubory či sezení apod., tedy nemám v tuto chvíli dostatek znalostí. Doufám však, že článek splní svůj účel a ukáže nováčkům něco trošičku nového.


Líbil se Vám článek?
Budeme potěšeni, pokud vás zaujme také reklamní nabídka

Social Bookmarking

     





Hodnocení/Hlasovalo: 1.13/8

1  2  3  4  5    
(známkování jako ve škole)