14:59
5/1/2011

Jeśli do zmiennej w skrypcie PHP przypiszemy następującą wartość numeryczną: 2.2250738585072011e-308, to jest spora szansa na to, że skrypt najpierw pożre 100% zasobów procesora, a potem zaliczy crasha. Błąd jest o tyle uciążliwy, że za jego pomocą można zawieszać większość internetowych webaplikacji napisanych w PHP — wystarczy przekazać powyższą liczbę w URL-u jako parametr GET.

2.2250738585072011e-308: PHP x87 FPU bug

Za DoS w PHP odpowiedzialna jest funkcja zend_strod() konwertująca liczby zmiennoprzecinkowe. Wprowadza ona systemy Linux, Windows i FreeBSD w nieskończoną pętlę. Na atak podatne są architektury wykorzystujące koprocesor FPU z zestawem instrukcji x87 (o ile PHP nie skompilowano z flagami: -mfpmath=sse lub -ffloat-store, bo tak naprawdę całemu złu winny jest bug w gcc).

Numbers LOST

Liczba fatalna w skutkach...

Aby sprawdzić, czy twój serwer i instalacja PHP są podatne, stwórz i odpal skrypt o następującej zawartości:

<?php $d = 2.2250738585072011e-308; ?>

Warto nadmienić, że inne sposoby zapisu tej liczby również powodują ten sam błąd:

  • 0.22250738585072011e-307
  • 22.250738585072011e-309
  • 22250738585072011e-324

Błąd wynika ze zmiennoprzecinkowej arytmetyki IA-32, 80-bit. Funkcja zend_strtod osobno przetwarza podstawę (2.225…011) oraz wykładnik (-308), stosując przybliżenie typu m*10^e o coraz większej dokładności w poszczególnych iteracjach, aż do nastąpienia błędu mniejszego od 0.5ulp. Przy tej licznie, iteracja nie polepsza przybliżenia błędu i algorytm wpada w nieskończoną pętlę. Dotyczy to 80-bit FP, ale nie 64-bit FP, ponieważ x86-64 korzysta ze zbioru instrukcji SSE2 (z 64-bit FP) zamiast przestarzałego x87 — wyjaśnia lifthasiira

Floating Point

Floating Point

Ataki na aplikacje internetowe

Najgorsze w tym wszystkim jest jednak to, że błąd występuje w wielu popularnych serwisach internetowych i webaplikacjach, np. forum phpBB:

/phpBB3/viewforum.php?f=2.2250738585072011e-308

…i zapewne w setkach innych webaplikacji, które przyjmują (traktują) parametr jako liczbę (zmiennoprzecinkową) — na myśl przychodzi mi np. wyszukiwanie produktów po cenach…

Na szczęście w większości przypadków błąd nie jest straszny — CPU podskoczy do 100%, PHP na chwilę się powiesi, a potem zostanie zrestartowane.

Jak się zabezpieczyć przed błędem w PHP?

Developerzy PHP już przygotowali poprawkę. Można też przekompilować sobie PHP z wykorzystaniem flag -mfpmath=sse lub -ffloat-store. Jeśli jednak ktoś z was chciałby się na szybko zabezpieczyć przed atakami DoS na PHP, polecamy wrzucić powyższą linijkę na początku skryptu PHP:

if (strpos(str_replace('.', '', serialize($GLOBALS)), '22250738585072011')!==false) die();

Nie jest to oczywiście jedyna metoda ochrony webaplikacji przed atakami typu DoS. Na naszych szkoleniach zdradzamy kilka innych, sprytniejszych… :-)

Aktualizacja 7.01.2011
Krzysztof Rakowski informuje, że Zend rozesłał newsletter dotyczący błędu.

Zend critical vulnerability PHP

Zend critical vulnerability PHP

Hotfix dla Windows tu, a instrukcja dot. Linuksa tu

Przeczytaj także:



58 komentarzy

Dodaj komentarz
  1. No to kiszka…
    […]w większości przypadków błąd nie jest straszny[…] Ale są te inne przypadki i są one straszne :D

  2. Debian lenny bez aktualnych poprawek nie jest podatny na atak.
    PHP 5.2.6-1+lenny9 ,lighttpd-1.4.19, procesor Celeron (Mendocino).

  3. W tym momencie zaczynam się zastanawiać, czy sprawdzić to w rzeczywistości, czy wam zaufać… :)

  4. Na moim serwerze podziałało, leży ;-).

  5. Błąd nie dotyczy systemów 64-bitowych.

  6. Podobno php skompilowane bez optymalizacji w gcc jest wolne od tego bledu.

  7. Potwierdzam – na pingwinie 64bit nic się niezwykłego nie dzieje. Ot kolejny powód, żeby 32bit wyrzucić wreszcie na śmietnik historii.

  8. slack 13.1 32bit i nic sie nie stalo

  9. Debian, PHP5.2.6-1 + Apache/2.2.9 – nie działa

  10. z ciekawości sprawdziłem jak się zachowa świstak.pl. No i świstak oniemiał jak mu w GET podałem tę liczbę ;p po dłuższym czasie sieskrypt wykrzaczył ;)

  11. Repo DotDeba też wolne od wad ;-)

  12. Działa
    Apache 2.2.6
    PHP 5.2.5
    Procesor:
    Czestotliwość: 2500 MHz
    Nazwa: Intel (R) Celeron(R) CPU 2.80GHz
    Identyfikator: x86 Family 15 Model 3 Stepping 4

  13. Debian lenny z php5 odporny… Miło.

  14. A dlaczego manual PHP o takiej funkcji nie słyszał? http://pl.php.net/manual-lookup.php?pattern=zend_strod

  15. Ubuntu 10.04 32bit – Apache do restartu. Dobre to, całe szczęście nie mam chęci kładzenia nie swoich komputerów.

  16. Windows 7 Ultimate x64 PHP 5.3.1 Apache 2.2.14, AMD Athlon 260 x2 3.3Ghz przekroczono czas wykonywania skryptu. Po ustawieniu czasu wykonywania skryptu na nie skończoność proces httpd i apache ponad 90% procka

  17. Nginx + fastcgi php5 + Debian lenny 32bit = crash

  18. Błąd dotyczy PHP 5.3 na systemach 32bit, nie występuje wogóle w PHP 5.2
    @Drewniacki funkcja zend_strod() nie jest funckją języka PHP, lecz wewnętrzną funkcją jego interpretera, czyli ZendEngine

  19. Commodore C-64 Nie podatne :P

  20. Po nazwie zend_strod() brzmi jak funkcja należąca do frameworka ZEND. Mylę się? Wujek G00Gle milczy.

  21. Drewniacki: nie ma takiej funkcji bezpośrednio w PHP, ale jest w interpreterze (zapewne o to chodziło). Na szczęście mój serwer się nie wysypuje :)

  22. Ubuntu 10.10 32-bit również nie wyrabia :).

  23. CentOS x86 się nie daje

  24. @Drewniacki: Bo funkcja zend_strod to wewnętrzna funkcja PHP, jakby to ująć – jest w środku ;-)
    Grepnij sobie źródła PHP…

  25. Czy tu chodzi o zabezpieczenie przed operacjami nad rachunkiem niewymiernym?

  26. Przypomina mi to trochę scenariusz filmu “Pi” :D

  27. jeszcze gorzej się dzieje jak wpiszesz słowo google w google.

    • Jak już piszecie ze Wam działa/nie działa, to podawajcie wynik poleceń php -v oraz uname -a, inaczej to nie ma sensu ;)

  28. @gmo
    Nie spodziewałem się, że ktoś jeszcze używa tych procesorów.

  29. @PK
    $ php -v
    PHP 5.2.6-1+lenny9 with Suhosin-Patch 0.9.6.2 (cli) (built: Aug 4 2010 03:25:57)
    Copyright (c) 1997-2008 The PHP Group
    Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
    $ uname -a
    Linux 666 2.6.26-2-686 #1 SMP Thu Sep 16 19:35:51 UTC 2010 i686 GNU/Linux

    ;)

  30. No dobra, tu błąd występuje:

    $ php -v
    PHP 5.3.2-1ubuntu4.5 with Suhosin-Patch (cli) (built: Sep 17 2010 13:41:55)
    Copyright (c) 1997-2009 The PHP Group
    Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
    $ uname -a
    Linux XXXXXXXX 2.6.32-27-generic #49-Ubuntu SMP Wed Dec 1 23:52:12 UTC 2010 i686 GNU/Linux

  31. PHP 5.2.6-1+lenny9 with Suhosin-Patch 0.9.6.2 (cli) (built: Aug 4 2010 06:06:53)
    Copyright (c) 1997-2008 The PHP Group
    Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
    with eAccelerator v0.9.6.1, Copyright (c) 2004-2010 eAccelerator, by eAccelerator

    Linux XXXXXXXXXXXXX 2.6.34.6-xxxx-grs-ipv6-64 #3 SMP Fri Sep 17 16:06:38 UTC 2010 x86_64 GNU/Linux

    tutaj brak podatności :)

  32. PHP? A fuj! Ja tam wolę rozwiązania troszkę bardziej tradycyjne czyli skrypty CGI pisane w języku C a potem kompilowane! :)

  33. Co to jest, Fakt? Jak juz piszesz o bledzie, to wspomnij, ze podatny to jest system 32 bitowy, tylko.

    • @piotr: jak już komentujesz, to przeczytaj dokładnie treść artykułu.

  34. @Drewniacki bo to nie jest funkcja php, tylko funkcja z kodu źródłowego z php w c++
    php-5.3.4/Zend/zend_strtod.c

  35. HP 5.3.3-6 with Suhosin-Patch (cli) (built: Dec 7 2010 18:23:49)
    Copyright (c) 1997-2009 The PHP Group
    Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
    with Suhosin v0.9.32.1, Copyright (c) 2007-2010, by SektionEins GmbH

    Linux 2.6.32-3-686 #1 SMP Thu Feb 25 06:14:20 UTC 2010 i686 GNU/Linux

    Błąd występuje, ale działanie skryptu jest przerywane po 30 s.

  36. Przeciez jest jak byk w cytacie:
    “Dotyczy to 80-bit FP, ale nie 64-bit FP, ponieważ x86-64 korzysta ze zbioru instrukcji SSE2 (z 64-bit FP) zamiast przestarzałego x87 — wyjaśnia lifthasiira”

  37. php.net leży, ciekawe czy to tylko slashdot effect?

  38. Heh swoją drogą ciekawe ile osób samemu sobie zawiesiło serwer.

  39. Wybacz proszę o Autorze wiercenie dziury w brzuchu. Czy artykuł o spoofingu CallerID nie zaginął? :(

    pozdrawiam, świetna strona

  40. Źle mnie podlinkowaliście, paskudy :P Jak mam się wypozycjonować! :)

  41. CentOS – brak podatności.
    PHP 5.2.10 (cli) (built: Jun 22 2009 16:28:19)
    Linux 2.6.34.6-xxxx-grs-ipv6-64 #3 SMP Fri Sep 17 16:06:38 UTC 2010 x86_64 GNU/Linux

  42. Fatal error: Maximum execution time of 30 seconds exceeded in /mnt/hgfs/***/htdocs/test.php on line 1
    Bez żadnych poprawek – nawet ostatnio updateów nie robiłem xD
    $ uname -a
    Linux ubuntu 2.6.35-22-generic #33-Ubuntu SMP Sun Sep 19 20:34:50 UTC 2010 i686 GNU/Linux
    $ php -v
    PHP 5.3.3-1ubuntu9 with Suhosin-Patch (cli) (built: Sep 20 2010 22:40:29)
    Copyright (c) 1997-2009 The PHP Group
    Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
    Maszyna stoi pod VMWare Playerem – 32bit

  43. Zapomniałem dodać, że serwer oczywiście stoi dalej i się nie przejmuje xD

  44. NA WP powstała wtyczka: http://core.trac.wordpress.org/ticket/16097

  45. Błąd został poprawiony, w wersjach 5.3.5 i 5.2.17 wczoraj wydanych

  46. Czy:
    > tak naprawdę całemu złu winny jest bug w gcc
    oznacza, że podatne są również wszystkie aplikacje kompilowane tą wersją/z tymi opcjami gcc?

  47. Apache/2.2.14 (Win32) (na win7 64) bit lezy i kwiczy i nawet sie nie resetuje

  48. Dobra… to teraz zagadka. Co się stanie gdy na http://www.jakies-forum.pl wkleję obrazek
    ;-)

    Oczywiście nie trzeba być aż tak “złośliwym”, żeby wykorzystać do atakowania jakiejś strony, tą właśnie stronę… Można to zrobić gdziekolwiek, na przykład na 4chanie… Dlatego, jeśli nie chcemy aby nasze serwery brały udział w DDoS, to mimo wszystko radzę się jakoś zabezpieczyć…

  49. Dobra… obrazek taki:
    img src=”http://www.jakies-forum.pl/index.php?f=2.225O738585072011e-308″

    Moglibyście zmienić filtry.. :P

  50. To jest bug w procesorze a nie w gcc, gcc natomiast odmawiało workaroundowania go zamiast tego po prostu dokumentując zachowanie jako naturalne. Tu jest dość dobre podsumowanie:
    http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323#c109

  51. Gcc zawinilo, ale programisci php (zend) powinni pomyslec nad parsowaniem takich intow, a teraz ludzie maja zabawe crashujac procesy na serwerach :)

  52. Hm… Dość poważna sprawa. Myślałem, że Ci lepsi programiści starają się unikać sytuacji, w której można wprowadzić aplikacje w nieskończoną pętlę. Och ironio losu.

  53. postem też leci ? Bo na takiej jednej poleciało postem i wisi :X

  54. @Mekk

    wygląda na to, że faktycznie gcc dało ciała. Tutaj bardziej emocjonalny tekst o tym: http://blog.andreas.org/display?id=9

  55. okazuje, się, że kuzynka Java też cierpi na identyczny problem – tam nawet kompilator się może zawiesić :) http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/

    Jak komentują developerzy SUNa:

    “Some day, we’ll write a stopping test that takes account of the asymmetry of the spacing of floating-point numbers below perfect powers of 2. 26 Sept 96 is not that day.”
    / http://www.docjar.com/html/api/sun/misc/FloatingDecimal.java.html linia 694 /. No i się zemściło :)

  56. […] się, że nie tylko PHP jest podatne na opisane przez nas niedawno ataki DoS wynikające z błędu konwersji liczby 2.2250738585072011e-308. Co więcej, Java czyni ten bug jeszcze […]

Twój komentarz

Zamieszczając komentarz akceptujesz regulamin dodawania komentarzy. Przez moderację nie przejdą: wycieczki osobiste, komentarze nie na temat, wulgaryzmy.

RSS dla komentarzy: