Attacking Samsung
Attacking Samsung
Boot Chain
[1]: https://github.com/bkerler/mtkclient
4
Mediatek Secure Boot Process
5
Mediatek Secure Boot Process
6
Android partitions
■ boot.img
● Kernel and ramdisk
■ vbmeta.img
● For verified boot
■ super.img
● Dynamic partition combining system, vendor, and more
■ … many more…
7
Little Kernel (LK)
■ Open-source OS2
■ Common as bootloader in the Android world
■ Allows to boot Android or other modes
(Recovery)
■ Implements Android Verified Boot v2
● Verification of Android images
● Involving boot and vbmeta partitions
● Anti-rollback
[2]: https://github.com/littlekernel/lk
8
Little Kernel by Samsung
9
Why Targeting the JPEG Loader/Parser
[3]: https://www.binarly.io/blog/inside-the-logofail-poc-from-integer-overflow-to-arbitrary-code-execution
10
Why Targeting the JPEG Loader/Parser
[3]: https://www.binarly.io/blog/inside-the-logofail-poc-from-integer-overflow-to-arbitrary-code-execution
11
Heap Overflow in JPEG Loading
_JPEG_BUF = alloc(0x100000);
if (_JPEG_BUF == 0) {
log("%s: img buf alloc fail\n","drawimg");
uVar2 = 0xffffffff;
}
else {
memset(_JPEG_BUF,0,0x100000);
iVar1 = read_jpeg_file(file_name,_JPEG_BUF,0);
if (iVar1 == 0) {
log("%s: read %s from up_param as 0, size\n","drawimg",file_name);
uVar2 = 0xffffffff;
}
// ...
12
Heap Overflow in JPEG Loading
_JPEG_BUF = alloc(0x100000);
if (_JPEG_BUF == 0) {
Heap allocation of log("%s: img buf alloc fail\n","drawimg");
constant size for the uVar2 = 0xffffffff;
}
buffer else {
memset(_JPEG_BUF,0,0x100000);
iVar1 = read_jpeg_file(file_name,_JPEG_BUF,0);
if (iVar1 == 0) {
log("%s: read %s from up_param as 0, size\n","drawimg",file_name);
uVar2 = 0xffffffff;
}
// ...
13
Heap Overflow in JPEG Loading
_JPEG_BUF = alloc(0x100000);
if (_JPEG_BUF == 0) {
log("%s: img buf alloc fail\n","drawimg");
uVar2 = 0xffffffff;
}
else {
memset(_JPEG_BUF,0,0x100000);
iVar1 = read_jpeg_file(file_name,_JPEG_BUF,0);
Read the JPEG in if (iVar1 == 0) {
log("%s: read %s from up_param as 0, size\n","drawimg",file_name);
the buffer uVar2 = 0xffffffff;
}
// ...
14
Heap Overflow in JPEG Loading
_JPEG_BUF = alloc(0x100000);
if (_JPEG_BUF == 0) {
log("%s: img buf alloc fail\n","drawimg");
uVar2 = 0xffffffff;
}
else {
memset(_JPEG_BUF,0,0x100000);
iVar1 = read_jpeg_file(file_name,_JPEG_BUF,0);
if (iVar1 == 0) {
log("%s: read %s from up_param as 0, size\n","drawimg",file_name);
uVar2 = 0xffffffff;
}
// ...
15
Heap Overflow in JPEG Loading
_JPEG_BUF = alloc(0x100000);
if (_JPEG_BUF == 0) {
log("%s: img buf alloc fail\n","drawimg");
uVar2 = 0xffffffff;
}
else {
memset(_JPEG_BUF,0,0x100000);
iVar1 = read_jpeg_file(file_name,_JPEG_BUF,0);
if (iVar1 == 0) {
log("%s: read %s from up_param as 0, size\n","drawimg",file_name);
uVar2 = 0xffffffff;
}
// ...
16
Heap Overflow in JPEG Loading
file_size = string_to_int(tar_header_file.size,0,8);
if (size != 0 && size < file_size) {
file_size = print("read fail! (%d < %d)\n",size,file_size,size);
return file_size;
}
iVar1 = read(data_addr,index + 1,file_size,outbuf);
17
Heap Overflow in JPEG Loading
file_size = string_to_int(tar_header_file.size,0,8);
if (size != 0 && size < file_size) {
file_size = print("read fail! (%d < %d)\n",size,file_size,size);
return file_size;
}
iVar1 = read(data_addr,index + 1,file_size,outbuf);
18
Is it exploitable?
19
Exploiting a Heap Overflow in Little Kernel
struct free_chunk_head {
■ The heap algorithm is miniheap
● It relies on a doubly linked list struct free_chunk_head *prev;
20
From Heap Overflow to Arbitrary Write
node->next->prev = node->prev;
node->prev->next = node->next;
node->prev = node->next = 0;
21
From Heap Overflow to Arbitrary Write
node->next->prev = node->prev;
node->prev->next = node->next;
node->prev = node->next = 0;
22
From Arbitrary Write to Code Execution
23
From Arbitrary Write to Code Execution
25
Exploiting a Heap Overflow in Little Kernel
26
Exploiting a Heap Overflow in Little Kernel
27
Exploiting a Heap Overflow in Little Kernel
28
Exploiting a Heap Overflow in Little Kernel
29
Exploiting a Heap Overflow in Little Kernel
30
Exploiting a Heap Overflow in Little Kernel
31
Emulating and Debugging our Exploit
■ We used Unicorn
● Emulates CPU only
● We do not care about full-system emulation
● Easy to setup & tweak
✅ Exploiting the vulnerability is quite straightforward in the emulator
❌ But the same exploit does not work on the real device
32
Emulating and Debugging our Exploit
33
Emulating and Debugging our Exploit
34
Emulating and Debugging our Exploit
35
Emulating and Debugging our Exploit
36
Emulating and Debugging our Exploit
37
Emulating and Debugging our Exploit
node->next->prev = node->prev;
node->prev->next = node->next;
node->prev = node->next = 0;
38
Emulating and Debugging our Exploit
39
Emulating and Debugging our Exploit
40
Emulating and Debugging our Exploit
41
To sum-up
● SVE-2023-2079/CVE-2024-20832
✅ Leads to code execution
✅ Persistent (it survives reboots and factory reset)
✅ Gives full control over Normal World EL1/0
✅ Impacts Samsung devices based on Mediatek SoCs
■ Including those for which MTKClient does not work
❌ Requires to flash the up_param partition
42
How to write our JPEGs in the
up_param partition?
43
Odin: Samsung's recovery protocol
■ Odin is implemented in LK
■ It is available through the Download Mode
● It allows to flash partitions over USB
■ The Odin official client is closed source
■ There is an open-source client: Heimdall4
[4]: https://github.com/Benjamin-Dobell/Heimdall
44
Odin: Samsung's recovery protocol
45
Odin: Partition Information Table
46
Odin: Image Authentication
47
GPT: GUID Partition Table
Source: https://en.wikipedia.org/wiki/GUID_Partition_Table
48
GPT vs PIT
■ PIT and GPT are used for the same thing: to describe partitions
■ PIT is mainly used for Samsung features in LK
● Odin, JPEGs loading, etc
■ And GPT is used the rest of the time
49
PIT Loading
pit_address = 0x4400;
exist = get_part_table("pit");
if (exist == 0) {
pit_address = get_partition_offset("pit");
}
type = storage(3);
iVar1 = storage_read(type,0x4000,(int)pit_address,
(int)((ulonglong)pit_address >> 0x20),
&ODIN_TEMP_BUF_PIT,0x4000);
50
PIT Loading
pit_address = 0x4400;
exist = get_part_table("pit");
if (exist == 0) {
pit_address = get_partition_offset("pit");
}
type = storage(3);
iVar1 = storage_read(type,0x4000,(int)pit_address,
(int)((ulonglong)pit_address >> 0x20),
&ODIN_TEMP_BUF_PIT,0x4000);
51
PIT Loading
pit_address = 0x4400;
exist = get_part_table("pit"); Check for pit partition
if (exist == 0) { And use it if it exists
pit_address = get_partition_offset("pit");
}
type = storage(3);
iVar1 = storage_read(type,0x4000,(int)pit_address,
(int)((ulonglong)pit_address >> 0x20),
&ODIN_TEMP_BUF_PIT,0x4000);
52
PIT Loading
pit_address = 0x4400;
exist = get_part_table("pit");
Uses GPT table 😈
if (exist == 0) {
pit_address = get_partition_offset("pit");
}
type = storage(3);
iVar1 = storage_read(type,0x4000,(int)pit_address,
(int)((ulonglong)pit_address >> 0x20),
&ODIN_TEMP_BUF_PIT,0x4000);
53
Strategy to Bypass Odin Authentication
54
Strategy to Bypass Odin Authentication
55
Strategy to Bypass Odin Authentication
56
Strategy to Bypass Odin Authentication
57
Strategy to Bypass Odin Authentication
58
Strategy to Bypass Odin Authentication
59
Strategy to Bypass Odin Authentication
60
Strategy to Bypass Odin Authentication
61
To sum up
■ SVE-2024-0234/CVE-2024-20865
✅ Can bypass authentication in Odin
✅ We can flash anything in the eMMC
✅ Including our up_param partition
✅ Seems to impact most Samsung using
Mediatek SoCs
62
Post Exploitation: bypassing Android Verified Boot
63
Chaining Everything Together
64
To Conclude
65
Targeting ARM Trusted Firmware
66
Targeting ARM Trusted Firmware
67
Communication between NSW and SW
68
Vulnerability Research on ATF
■ Motivation:
● Highest privilege level → A bug here can be devastating
● Reachable from Normal World through SMCs
■ Code is simple
■ Interacts a lot with HW through unknown registers
● Fuzzing not particularly interesting in this case
■ Our approach: focus on static analysis
69
Few Words about TEEGRIS
[7]: https://www.riscure.com/tee-security-samsung-teegris-part-1/
70
Extracting ATF
71
SMC Handlers
if ((is_secure & 1) == 0) {
puVar1 = mediatek_plat_sip_handler_secure(smc_id,arg1,arg2,arg3
,arg4,arg5,output);
return puVar1;
}
[...]
if ((origin < 2) && (IN_BOOTLOADER == 0)) {
puVar1 = mediatek_plat_sip_handler_kernel(smc_id,arg1,arg2,arg3
,arg4,arg5,output);
return puVar1;
}
72
SMC Handlers
if ((is_secure & 1) == 0) {
puVar1 = mediatek_plat_sip_handler_secure(smc_id,arg1,arg2,arg3
,arg4,arg5,output);
return puVar1;
}
Arguments of SMC
[...]
if ((origin < 2) && (IN_BOOTLOADER == 0)) {
puVar1 = mediatek_plat_sip_handler_kernel(smc_id,arg1,arg2,arg3
,arg4,arg5,output);
return puVar1;
}
73
Leaking from Virtual Address Space
77
SVE-2023-2215 (CVE-2024-20820)
78
Mapping Any Physical Address in ATF
if (smc_id == 0x8200022a) {
spm_actions(arg1,arg2,arg3);
79
Mapping Any Physical Address in ATF
80
Mapping Any Physical Address in ATF
81
Mapping Any Physical Address in ATF
82
Mapping Any Physical Address in ATF
83
CVE-2024-20021
■ Also in mediatek_plat_sip_handler_kernel
■ Will mmap with physical base address to the same virtual address
● … however we can't munmap
○ So we are limited to 8 consecutives mmaps
○ Meaning we can leak up to 8MB of data
■ Introduced by Mediatek (impacts plenty of Mediatek SoCs)
■ Chained to our leak, we can read everything in Secure World
● Including TEEGRIS
84
Can we use this vulnerability to leak
Keystore keys?
85
Android Keystore system
86
Android Keystore system
87
Where to leak?
90
Our PoC
91
A Simple PoC
93
Hooking Keystore HAL Deamon
94
The result
95
The result
96
Our PoC
97
Demo
98
Conclusion
99
Thank you!
@max_r_b
[email protected] @DamianoMelotti
@pwissenlit