GEEKCON 2024 国际站将于 5 月 25 日 - 5 月 26 日在新加坡举办。其中,“对抗研判 AVSS 挑战赛”专场延续基于真实的网络安全“碰撞测试场”设定,主要方向扩大为手机及车联网安全,并加入了多种目标软件及系统。
北京时间 4 月 20 日 10:00 到 4 月 22 日 10:00,GEEKCON·AVSS 2024 线上选拔赛面向全球参赛者开启。经过 48h 的挑战,进入 5 月 25 日线下决赛的 8 支队伍正式揭晓。
第一名 sleeper 队因故无法参与决赛,
决赛资格顺延至第九名。
Introduction of AVSS Contest
-
The "AVSS Contest 2024 International" is designed to target a diverse range of software and systems, with a particular emphasis on systems of mobile phones and V2X.
-
The competition encompasses multiple challenge sets, each featuring distinct system environments that share common vulnerabilities.
-
The primary objective is to evaluate participants' proficiency in exploiting these vulnerabilities across varying systems.
01 MTE
This series of challenges is designed to help players learn the basic knowledge and bypass methods of MTE. The total four challenges share the same functionality and vulnerability, with different environment setups and heap allocators. BBO_BB and BBO_PT are equipped with PTMalloc, where BB does not enable MTE. BBO_PA and BBO_SC are equipped with PartitionAlloc and Scudo respectively. For the characteristics and weaknesses of MTE in each heap allocator, you can refer to our blog post (https://www.darknavy.org/blog/strengthening_the_shield_mte_in_memory_allocators/).
The bug is apparent: the offset in edit does not have strict boundary checks (i.e., negative index). Therefore, we can modify the control data (size, ptr, etc.) of the heap block to gain OOB write on the heap.
BBO_BB
The first challenge is a typical glibc heap challenge without MTE in 2.35. The only point is how to exploit it without hooks. You can refer to angry-FSROP (https://blog.kylebot.net/2022/10/22/angry-FSROP/) or other materials for help.
BBO_PT
Since MTE is enabled, we cannot simply achieve arbitrary OOB write on the heap because the heap ptr is tagged. However, we can edit the tag of the data ptr to 0, so as to write data to memory with 0 tag.
As for how to control PC, the intended solution is to edit the freed heap chunk (which is tagged 0 in glibc). Then, we can use large bin attack to modify IO_list_all to our fake FILE and trigger file stream attack. However, there is an unintended circumstance: the distance between heap and libc is so close that we can directly OOB write libc :upside_down_face:.
BBO_PA
As PartitionAlloc is able to leak the tag of the heap chunk, we can simply make two heap chunks have the same tag and OOB write data ptr to achieve arbitrary write.
BBO_SC
We think there is a rare possibility to solve this problem under the current challenge setting. If you have more insights, please feel free to discuss with us.
02 Vehicle: BLE
ble_challenge01:
The first challenge is designed to help players learn and complete BLE connections and interactions.
The CBC encryption key is calculated from the broadcast manufacturer and VIN code, which can obviously be obtained from the traffic packet, and also can decrypt the DKid and Phoneid from the traffic packet.
What players need to do is to obtain the manufacturer in the broadcast and calculate the encryption key of the CBC and re-encrypt the plaintext dkid、phoneid and other information before sending.
The main problem that many players meet is that they do not enable the notify, and to open the notify requires writing "x01x00" to the corresponding channel.
ble_challenge02:
This challenge is similar to the previous challenge, but simulates a more complete vehicle BLE verification process. After step 1, players need to send the app certificate, after the certificate is verified, the two sides carry out ECDH key exchange, and finally use the exchanged key to encrypt the digital key. The problem is that the certificate verification process uses the sender's certificate public key, so players can complete the challenge by forging the certificate. Another point is that players need to use a longer key for RSA signature.
ble_challenge_final:
This challenge is the closest to the actual situation, and two schemes are tried. The first is to use the public and private key of the certificate of another owner to complete the interaction, the problem is that the last step will check the digest of the certificate of the owner; the second is that there is a risk of iv reuse in AES-GCM encryption. We can obtain the certificate of the original owner and the ECDH data. Now our only problem is that we cannot know the exchanged key, but the iv reuse problem allows us to encrypt the plaintext data of the same length when we know multiple ciphertext pairs. The actual problem is that the returned data length is too short. So We don't have an expected solution.
03 Vehicle: AAOS
AAOS_G
This challenge is designed to help players to be familiar with the development of Automotive. The main difficulty is the obscure document on the Internet and the ability to get the system application permission.
For the former point, challengers can spend time and do some research on it, there are many samples and blogs to make an HVAC application in the Automotive systems, just make a project and try their resolutions.
And when you try to change the air condition temperature set, the Android Studio tells you that your project needs CLIMATE permission, but u cannot be granted CLIMATE permission by just declaring it in the manifest, because it is a system permission that can only be granted to the system application. Then things become to how to get the system application permission in Automotive.
For AAOS_G, we compile the Automotive from AOSP without any modifications, which means we use the test-keys to sign our system. Players can get the test-keys from AOSP, and use test-keys to sign their applications, the applications signed by test-keys will be granted system application permission, and now the application can be granted the CLIMATE permissions successfully.
AAOS_P & AAOS_V
For AAOS_P and AAOS_V, we use the production image from the vendor, which means they use the private key to sign the system, we cannot create a system application with previous methods.
Although we don't have an expected solution for those two challenges, these systems are based on Android 9, some enclosed vulnerabilities may be exploited on these systems.
04 Vehicle: FORMULA
TheVehicle: FORMULAis a series of challenges about vehicle security based on real-world devices. Players will connect to the components of the real car.
We know that sometimes cars need to be diagnosed or check the status of ECUs(Electronic Control Unit). It's necessary for vendors to place an engineering mode entry in the center controller of the car, which could do some private operations, such as turning on the debug mode or enabling debug interfaces. But if attackers access the mode, it may compromise the confidentiality, integrity and accessibility of the device and attackers could misguide the autopilot or even shut down the device while driving, so this mode should not allow unauthorized access. This series shows how vehicles provide and protect the powerful engineering mode.
There are three versions of authentication methods of engineering mode.
-
KARTING: Challenge-response-based authentication and challenge is generated from a unique hardware ID. The interface is Implemented as a secret code from a dial number.
-
VEE: Challenge-response-based authentication based on a hardcode key. The interface is Implemented as a DoIP server which needs to connect to the vehicle ethernet.
-
ONE: Challenge-response-based authentication based on a unique key in each machine. The interface is Implemented as a DoIP server which needs to connect to the vehicle ethernet.
In this series, we provide a remote real-world device environment for players and players could connect to the infotainment system from the internet. Here is the Network Topology.
FORMULA_KARTING
In this challenge, the authentication is implemented in a pre-installed APP. The APP registered a secret code broadcast receiver. After you pass the UUID auth of the remote connection, you can send a secret code broadcast, just like you input the code from the dialing panel. And you will get the screenshot of the device.
The secret code will be handled by the APP.
In thecom.test.cardevsettings.SECRETCODECLASS, we can see that it has two types of secret code. The first one is to get the challenge, and the second one is to do verification.
In the native, we could find the logic of the Hardware ID generated by the VIN(Vehicle Identification Number), and the VIN is different for each car.
After you get the VIN, you can analyze the verification login. It uses an HMAC with a hardcode key to generate the key of the stream cipher, decrypt the secret code, and check the time. So you need to calculate a correct verification code based on the current time.
FORMULA_VEE
VEE is based on a more modern car than KARTING. It cancels the engineering mode from the dialing panel and implements a DoIP server on its vehicle ethernet which is exposed as an OBD interface.
In the VEE challenge, we connect the vehicle ethernet and forward the port of the DoIP server to players so you can just use UDS protocol to communicate with the device.
In UDS protocol, has several security levels. Only by passing the authentication, we can the privileged operations, such as some sensitive identifiers reading or writing.
To get the flag of VEE, you need to set the value of the identifierd09a. However, the accessd09a is required for security level 3 and session 3.
After the DoIP server receives the Security Access request, it will generate 3 random bytes as the challenge and give them to the challenger. You need to calculate the response of these 3 bytes by the specific algorithm. In this case, the algorithm is the standard UDS security access algorithm which has 5 bytes secret key.
You can locate the seed generation and verification in the DoIP server, but each security level has different verification implementation. The authentication of level 3 uses a fixed key and you can do the same thing to get the 3-bytes response.
After you get a successful reply from the device, just read and write the identifier.
Put them together, you need:
-
Select the session 3
-
Pass the authentication ofSecurity Accesslevel 3
-
Write thed09aidentifier
-
Let the server check the d09aidentifier and get the flag
Just for indication, but not the same key
FORMULA_ONE
ONE has a similar environment and the same goal as VEE. It also requires players to change the identifierd09afrom 0 to 1.
But the key of authentication is not hardcode. The key is randomly generated and unique for each device and stored in TEE.
And the authentication has an anti bruteforce mechanism, if an invalid security access response is received, it needs about 10 seconds for the next try.
Just for indication, but not the same security level
So we think it is difficult to collide these 3-byte response values during the game and we don't have an expected solution for ONE. But it may have some memory corruption in the protocol stack.
05 KERNEL:INST
This challenge is about exploiting different privilege escalation vulnerabilities across different Android kernel versions. The challenge adds a syscall with two vulnerabilities and provides the patch file, requiring participants to escalate privileges to root from the adb shell in the emulator.
There are 4 functions in the syscall, namely,ADD, DELETE, EDIT, andRUN. ADDwill allocate aninst object with a function pointer inkmalloc-512slab and put it on the global list.DELETEwill remove an object from the list.EDITwill set the property of an object with the provided variable-length operands. RUN will traverse the list, execute the function pointer of the object, and then remove the whole list.
This challenge provides a backdoor function that will never be called. If you can call it in the kernel context, you can easily get to root.
noinline __int128 do_backdoor(__int128 input, __int128 *operands, unsigned long operand_num) {
struct cred *cred;
int ret;
cred = prepare_kernel_cred(NULL);
if (!cred) {
return -1;
}
ret = commit_creds(cred);
if (ret) {
return -1;
}
selinux_enforcing = 0;
return 0;
}
The first vulnerability is an overflow in EDIT, which does not check theoperand_num properly. The size of theinstobject is 40 andMEM_SIZEis 512.round_up(472,16)equals 480, leading to an 8-byte-overflow inkmalloc-512.
if(_inst.operand_num > round_up(MEM_SIZE-sizeof(struct inst), sizeof(__int128))/sizeof(__int128))
The second vulnerability is a use-after-free inRUN. After executing all the function pointers, it willkfreeall the objects in the list, but it does not clear inst_head. WithEDIT, we can edit anything in a freedkmalloc-512 object, except the first 40 bytes.
list_for_each_entry_safe(curr, ptr, &inst_head->list, list) {
list_del(&curr->list);
kfree(curr);
}
kfree(inst_head);
return 0;
KASLRis not enabled in the emulator, so no kernel address leak is needed.
Android 7
The kernel version of Android 7 is3.10.0and there is hardly any protection. Slab objects are allocated continuously in the memory, so 8-byte-overflow can overwrite the function pointer of the nextinstobject.
We can just use the overflow vulnerability to hijack the function pointer into the backdoor function and then useRUNto get to root
Android 11
The kernel version of Android 11 is 5.4.50, which enablesCONFIG_HARDENED_USERCOPY. This config will check the target object is fully in the slab object when callingcopy_*_user. So the overflow vulnerability is no longer exploitable any more.
This version also enableskCFIprotection, the backdoor function cannot be easily called by hijacking a function pointer.
To exploit theUAFvulnerability, we can spray some objects of kmalloc-512to take the place of theUAFobject and use the vulnerability to modify the data inside it.
pipe_bufferis a good object :
We can useF_SETPIPE_SZoption of the fcntl to adjustpipe_bufferto be allocated in kmalloc-512
Thepage variable inpipe_buffercan be utilized to achieve arbitrary read/write in physical memory.
Finally, we can traverse thetask_listto find the current task and set its uid, gid, etc. to zero. selinux_enforingshould also be cleared to disable SELinux.
Android 13
The kernel version of Android 11 is 5.15.78, which adds a new set ofkmalloc-cg-<n> (KMALLOC_CGROUP) caches for accounted objects only. The inst objects are allocated in normal caches, whilepipe_buffer objects are allocated in accounted objects. They are separated, thus spraying pipe_buffercannot easily reuse theUAFobject.
We can use the cross-cache attack to solve the problem. The main idea is to change the objectUAF into slab UAF:
Release all objects located in the slab(kmalloc-512) containing theUAFobject.
Return the slab into the buddy system.
Sprayingpipe_buffer to obtain it as a kmalloc-cg-512slab.
Exploiting theUAFvulnerability in the same way as in Android 11.
06 OLD-LOG
This challenge is based on the latest version (for Java 1.8) of the default Grails generated project and demonstrates the differences in exploiting the classic log4shell vulnerability across different versions of the Java runtime environment.
All four versions of the challenge have solutions! I hope to see everyone's creativity in finding different chains of exploitation, which is why I specifically used the default project and did not remove any dependencies unrelated to my own solution.
Java 1.8, 11, 17 and 21 are all LTS versions, so they are chosen.
v1.8 & v11
Both ldap and rmi can be used. Java module system(https://openjdk.org/projects/jigsaw/) andencapsulated packages(https://cr.openjdk.org/~mr/jigsaw/jdk8-packages-strongly-encapsulated)protect (https://openjdk.org/jeps/396) was not introduced.
Some security researchers have found and shared many useful deserialization chains for Java 1.8. In this challenge, the most commonly used for v1.8 is Jackson as source and TemplatesImpl as sink. I think it is the obvious one since Grails depends on Spring Boot.
Note 1:
Tomcat's BeanFactory can't be used in this challenge because they removed forceString(https://github.com/apache/tomcat/commit/df7da6c29aace17c92fe47fe386ab14ece59b5d4) in 9.0.63.
Note 2:
Since 8u291, two vm properties are added:jdk.jndi.object.factoriesFilterand com.sun.jndi.ldap.object.trustSerialData. The latter property is default to true.
Since 8u311, the scope ofcom.sun.jndi.ldap.object.trustSerialDatais extended to javaReferenceAddress.
Note 3:
Java module system is introduced in Java 9, but strong encapsulation is relaxed by default due to migration, which means --illegal-access is default to permit.
v17
Two main differences: the first is that you can't use TemplatesImpl as the sink for the deserialization chain, and the second is that you can't use BadAttributeValueExpException to trigger Jackson's toString.
There are mainly two solutions: the first one is to utilize DataSourceFactory to trigger DataManager.getConnection,achieving RCE through the H2 JDBC Driver. The second one is to use GenericNamingResourcesFactory and SystemUtils to modify the org.apache.commons.collections.enableUnsafeSerialization property, and then RCE using the CC chain.
Note 1:
--illegal-accessis defaulted to deny on Java 16 and is removed on Java 17.
Note 2:
ThereadObject()method of BadAttributeValueExpException no longer callstoString(). It is patched by thiscommit(https://github.com/openjdk/jdk/commit/2d93a28447de4fa692a6282a0ba1e7d99c7c068b) (since Java 15?).
v21
Since Java 20, there are two patches related to JNDI and deserialization vulnerability:
JDK-8290367(https://bugs.openjdk.org/browse/JDK-8290367):Default value of com.sun.jndi.ldap.object.trustSerialDatais changed to false.
JDK-8290368(https://bugs.openjdk.org/browse/JDK-8290368):Add default ObjectFactoriesFilter for LDAP and RMI lookup in JNDI.
So, not only deserialization through JNDI lookup, but also Reference with ObjectFactory through JNDI or RMI, is unavailable for exploitation by default. There is only one viable path left, that is RMI lookup and deserialization gadgets.
My solution is hibernate → ExecutorTrackedRunnable → JFormattedTextField$FocusLostHandler → JFormattedTextField → DefaultFormatter → ClassPathXmlApplicationContext. If you use this chain, it is notable that serialVersionUID of some classes are different between Java 1.8 and Java 21. You can patch the serialVersionUID manually or run your tool on Java 21 with--add-opens. I think too many--add-opens are annoying for exploitation, so I write a simplelibrary magic.jms(https://github.com/ceclin/magic.jms), maybe helpful.
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论