Novinka pre web programátorov v ponuke - Vue.JS

Prečo je v PHP funkcia mail() nebezpečná?

kategória: Blog pridané: 5. marca 2018

Na našom webhostingu www.nakurze.sk, ktorý dostávajú účastníci našich webových kurzoch zdarma, je zakázané používanie funkcie mail(). V tomto článku sa pokúsim vysvetliť, prečo je táto funkcia nebezpečná a prečo by sa nemala používať.

Syntax funkcie mail() podľa manuálu PHP:

bool mail (
    string $to ,
    , string $subject
    , string $message
    [, string $additional_headers
        [, string $additional_parameters ]
    ]
)

$to – adresa príjemcu

$subject – predmet správy

$message – obsah správy

$additional_headers – ďalšie hlavičky správy

$additional_parameters – ďalšie správy pre odosielací program (často sendmail)

Väčšina PHP funkcií sa spolieha na to, že do funkcie prídu iba správne parametre. To musí samozrejme zabezpečiť vývojár, čo, povedzme si otvorene, sa často zanedbáva. Bohužiaľ, veľa vývojárov má buď chabé znalosti z bezpečnosti, alebo jednoducho sú iba leniví študovať manuál (napríklad práve k programu sendmail).

Schválne, ak ste PHP vývojár, poznáte program sendmail? Viete, aké má parametre? Viete, ako sa správa? Je jasné, že nikto nemôže vedieť všetko, ale práve zasielanie e-mailov je v dnešnej dobe často zneužívané na rôzne druhy útokov – od spamovania, cez phishing (tvárim sa, že som PayPal a nútim obeť k zmene hesla – samozrejme na mojej phishingovej – podvodnej webstránke) až po šírenie ransomware (často sa šíria práve v podobe zazipovanej fotografie ruskej krásky, ktorá sa do vás údajne zamilovala 🙂 ).

Header injection

Tento typ útoku funguje tak, že do e-mailovej správy sa vložia hlavičky, ktoré následne uvidí príjemca. Jednoduchý príklad budú hlavičky From alebo Reply-To, ktoré príjemcovi zobrazia odosielateľa a adresu na odpoveď, ak príjemca stlačí v mailovom klientovi tlačidlo Odpovedať.

Je zrejmé, že tieto hlavičky sú potrebné, keďže samotná funkcia mail() neobsahuje inú možnosť, ako zadefinovať odosielateľa. Jednotlivé hlavičky sa oddeľujú znakmi CRLF (\r\n) a pokiaľ obsah hlavičiek nie je správne očistený práve od týchto znakov, útočník môže vložiť do e-mailovej správy svoje vlastné hlavičky. Môže tým napríklad spôsobiť to, že odošle správu na rôzne e-mailové adresy (pomocou hlavičiek CC alebo BCC). Tu existuje pomerne jednoduchá ochrana – očisťovať akékoľvek vstupy od užívateľa o znaky, ktoré nemajú v danom parametri čo hľadať. Je asi jasné, že e-mailová adresa neobsahuje znak \ 🙂

Posledný parameter – najväčšia hrozba

A sme opäť pri programe sendmail. Tento program sa používa na odosielanie e-mailov z PHP na strane servera. Funguje to tak, že vy v PHP zavoláte funkciu mail() a tá zavolá program, ktorý odošle e-mailovú správu zo servera. Práve týmto programom najčastejšie býva spomínaný sendmail.

To, aký program sa použije na odoslanie e-mailu cez funkciu mail(), sa definuje v konfiguračnom súbore php.ini, kde je možné buď zadať adresu SMTP servera alebo cestu k MTA – Mail Transfer Agentovi. Hoci PHP interne volá funkciu escapeshellcmd(), ktorá zabraňuje spúšťaniu vlastného kódu, táto funkcia sa neaplikuje na posledný – piaty parameter funkcie mail(), keďže jeho úlohou je práve predať parametre MTA. Predstavme si nasledovný kód:

mail('prijemca@example.com', 'Predmet', 'Správa', '', '-f' . $_GET['from']);

Parameter -f definuje v programe sendmail adresu odosielateľa. Na tom by nebolo nič zlé, ale problém je, že vývojár neočistil vstupný parameter from, ktorý je predávaný do funkcie mail() z URL adresy. Väčšina by očakávala, že e-mailová adresa „niekto@example.com -OQueueDirectory=/tmp -X/var/www/stranka/subor.php“ je neplatná a PHP vypíše chybu, ale nestane sa tak. Parametre pre funkciu sendmail budú nasledovné:

-fniekto@example.com -OQueueDirectory=/tmp -X/var/www/stranka/subor.php

A čo to teda znamená? Adresa odosielateľa síce bude niekto@example.com, ale do sendmailu boli navyše pridané dva parametre:
-OQueueDirectory=/tmp spôsobí, že adresár fronty správ sa zmení na /tmp – sem môžu zapisovať v linuxových systémoch všetci užívatelia (a teda aj PHP), resp. je možné zmeniť ho na taký adresár, aby sa obišlo aj prípadné obmedzenie open_basedir.
-X/var/www/stranka/subor.php nastaví logovací súbor na /var/www/stranka/subor.php, v tomto súbore sa bude nachádzať napríklad predmet správy.

Ako je to teda možné zneužiť?

Jednoducho! Stačí ako predmet správy napísať napríklad: <?php system($_GET['prikaz']); ?> Tým vznikne v adresári /var/www/stranka súbor s názvom subor.php, ktorý bude obsahovať PHP kód a PHP ho pri zavolaní vykoná. V ňom sa bude nachádzať <?php system($_GET['prikaz']); ?> – funkcia, ktorá na príkazovom riadku systému spustí to, čo zadáme do parametra „prikaz“. Teda napríklad jednoduchým URL https://www.stranka.sk/subor.php?prikaz=rm%20-rf%20~ zmažeme kompletne celú webovú stránku. Samozrejme, toto je to najmenej kreatívne riešenie, dali by sa nájsť aj ďalšie a oveľa zaujímavejšie. Čo tak napríklad získať heslo k databáze a dostať sa ku kompletným osobným údajom všetkých zákazníkov? 😉

Problém majú aj veľkí hráči – aktualizujte!

Ak na svojich serveroch prevádzkujete aplikácie Roundcube, MediaWiki, PHPMailer, Zend Framework, SwiftMailer, SquirrelMail a podobné, odporúčam sa pozrieť na verzie a prípadne ich aktualizovať. Klikom na ich názvy sa dostanete na odkaz na zraniteľnosť, kde je uvedená aj zraniteľná verzia. Je samozrejme potrebné skontrolovať aj svoju verziu WordPressu, Joomly alebo Drupalu, nakoľko aj tieto aplikácie môžu využívať napr. PHPMailer vo verzii so zraniteľnosťou.

Ako sa nebrániť?

Použitie escapeshellarg() nestačí

Funkcie escapeshellarg() a escapeshellcmd() sa používajú na ochranu pri vykonávaní príkazov v shelli, napríklad použitie

<?php system(escapeshellcmd('./aplikacia -x ' . escapeshellarg($_GET['parameter_x'])); ?> chráni parameter -x v aplikácii pred zneužitím. Problémom ale je, že nechráni ostatné prípadne zneužiteľné parametre. Ak by sme napríklad za parameter_x dosadili reťazec nieco' -y foo, do shellu by sa dostalo niečo takéto: ./aplikacia -x 'nieco'\\'' -y foo \'
Tu je teda vidieť, že práve parameter -y bol podvrhnutý napriek tomu, že bola zavolaná funkcia escapeshellarg(), resp. escapeshellcmd()

A čo tak FILTER_VALIDATE_EMAIL?

Toto tiež nie je úplne bezpečné, pretože niektoré znaky, ktoré môžu spôsobiť problémy, tento filter neodhalí. Filter umožňuje napríklad escapovať biele znaky, ktoré sú v dvojitých úvodzovkách. Tým pádom je možné prekryť jednoduché a dvojité úvodzovky, čo vo funkciách escapeshellcmd() a mail() predpokladáme, že sa nemôže stať. Príkladom je takáto e-mailová adresa:'a."'\ -OQueueDirectory=\%0D<?=eval($_GET[prikaz])?>\ -X/var/www/stranka/"@a.php Toto by FILTER_VALIDATE_EMAIL vyhodnotil ako korektnú e-mailovú adresu a pri spustení by v adresári /var/www/stranka vznikol súbor s názvom @a.php, ktorý by vo svojom vnútri obsahoval chybu <?=eval($_GET[prikaz])?>\/): No such file or directory a sme tam, kde sme boli 🙂

Ako sa brániť?

  1. Minimalizovať vstupy od užívateľa. Vstupy od užívateľa by mali ísť iba do parametrov $subject a $message, v najhoršom prípade aj do $to.
  2. V parametri $additional_headers odstrániť z užívateľských vstupov znaky \r a \n
  3. V parametri $additional_parameters za žiadnych okolností nepoužívať vstup od užívateľa
  4. Nepoužívať funkciu filter_var() alebo filter_input() na overenie vstupov od užívateľa. Tieto funkcie na to neboli určené. E-mailové adresy by sa mali kontrolovať pomocou regulárnych výrazov – je to síce nepohodlnejšie pre vývojýra, ale zato oveľa účinnejšie

Overenie e-mailovej adresy sa dá urobiť napríklad takto:

function validateEmail($email) {
  $regex = "/^[a-z0-9][a-z0-9_-.]*@[a-z0-9-.]+.[a-z]{2,}$/i";
  return (bool)preg_match($regex, $email);
}

Samozrejme, že to nie je najdokonalejšie (bolo by vhodné overiť napríklad existenciu domény za zavináčom), ale funkcia vráti true, ak e-mailová adresa začína na písmeno alebo číslo, potom obsahuje písmeno, číslo, podčiarkovník, pomlčku alebo bodku, potom zavináč, potom aspoň jedno písmeno, číslicu, pomlčku alebo bodku a na konci musí byť bodka a minimálne dve písmená.

autorom článku je: Mgr. Michal Dobšovič
K IT som sa dostal už v útlom veku, kedy som sa zoznámil s HTML, neskôr s PHP v čase, keď sa ešte heslá do databáz ukladali v plaintext podobe :-). Na základnej škole som mal možnosť zoznámiť sa so systémom Windows NT Server a táto technológia ma natoľko uchvátila, že som sa tomu začal venovať a čoskoro bol zo mňa administrátor celej školskej siete. Keďže škola nemala webovú stránku (písal sa školský rok 2001/2002) rozhodol som sa, že tento web spravím, čo sa mi aj podarilo a stránka bola na svete aj s vlastným CMS systémom.

V roku 2005 som hľadal brigádu popri vysokoškolskom štúdiu na FIIT STU v Bratislave a náhodou som narazil na možnosť robiť počítačové kurzy. Keďže aké-také skúsenosti som mal už zo školy, kde som viedol informatický krúžok, povedal som si, že to skúsim. Pôvodne som si myslel, že to bude fajn brigáda popri škole, ale osud zariadil, že ma lektorské povolanie tak chytilo za srdce, že som opustil školu a začal sa naplno venovať lektoringu. Následne som študoval dištančné štúdium priemyselnej informatiky na FEI STU, ale keďže to nebolo pre mňa„to pravé orechové“, školu som opäť nechal. Nakoniec som svoj akademický zen našiel na Fakulte manažmentu na Univerzite Komenského, ktorú som aj doštudoval 🙂

V roku 2007 som spolupracoval ako lektor so spoločnosťou Telegrafia a spravil som si potrebné certifikácie - stal sa zo mňa držiteľ titulu MCT – Microsoft Certified Trainer. V roku 2008 sme spolu s kolegom a priateľom Petrom Hechtom založili spoločnosť IT LEARNING SLOVAKIA, kde dodnes pôsobím okrem iného aj ako lektor kurzov, pričom sa zameriavam najmä na technológie Microsoft Windows Server, SQL Server a Exchange Server.

Okrem iného pôsobím aj ako konzultant pre rôzne firmy v oblasti správy serverov a bezpečnosti a spravujem viaceré serverové infraštruktúry pre malé firmy, ale medzi mojich "lientov patria aj medzinárodné firmy s viac ako 10 000 zamestnancami, kde pomáham korporátnym administrátorom udržať najnovšie bezpečnostné štandardy a navrhujem inovácie.

Odporúčam prečítať/vyskúšať:

Manuál k sendmail

Tester regulárnych výrazov

a dokumentáciu k spomenutým PHP funkciám.