Attacking Samsung Galaxy A*
Boot Chain
Maxime Rossi Bellom
Damiano Melotti
Raphael Neveu
Gabrielle Viala
Who we are
■ Maxime Rossi Bellom @max_r_b ■ Gabrielle Viala @pwissenlit
■ Security researcher ■ Security researcher
and R&D leader @ Quarkslab and R&D leader @ Quarkslab
■ Working on mobile and embedded ■ Playing with low-level stuff
software security
■ Damiano Melotti @DamianoMelotti ■ Raphaël Neveu
■ Ex security researcher @ Quarkslab ■ Security researcher @ Quarkslab
■ Interested in low-level mobile ■ Working on low-level mobile
security and fuzzing security
2
Our Device
■ Samsung Galaxy A225F
● Cheap (~300€)
● Mediatek SoC MT6769V
● Main OS: Android
● Mix of Mediatek and Samsung code
● Trustzone OS: TEEGRIS
● Secure Boot Bypass using MTKClient1
→ making debugging easier
[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
■ Samsung modified LK to include:
● The Odin recovery protocol
● Knox Security Bit
● Etc…
● And a JPEG parser/renderer
■ This version is closed source
9
Why Targeting the JPEG Loader/Parser
■ JPEGs are placed in a TAR archive in the up_param partition
■ The archive is signed… but the signature is not checked at boot
❗ Anyone able to write the flash can modify these JPEGs
■ Parsing JPEG is known to be hard (cf. LogoFail3)
[3]: https://www.binarly.io/blog/inside-the-logofail-poc-from-integer-overflow-to-arbitrary-code-execution
10
Why Targeting the JPEG Loader/Parser
■ JPEGs are placed in a TAR archive in the up_param partition
■ The archive is signed… but the signature is not checked at boot
❗ Anyone able to write the flash can modify these JPEGs
■ Parsing JPEG is known to be hard (cf. LogoFail3)
How are these JPEGs loaded by LK?
[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;
}
// ...
pimage(*(undefined4 *)(&DAT_4c5107fc + param_1 * 0x3c),
*(undefined4 *)(&DAT_4c510800 + param_1 * 0x3c),
0x2d0,0x640,1,_JPEG_BUF,iVar1);
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;
}
// ...
pimage(*(undefined4 *)(&DAT_4c5107fc + param_1 * 0x3c),
*(undefined4 *)(&DAT_4c510800 + param_1 * 0x3c),
0x2d0,0x640,1,_JPEG_BUF,iVar1);
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;
}
// ...
pimage(*(undefined4 *)(&DAT_4c5107fc + param_1 * 0x3c),
*(undefined4 *)(&DAT_4c510800 + param_1 * 0x3c),
0x2d0,0x640,1,_JPEG_BUF,iVar1);
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;
}
// ...
Parse and render pimage(*(undefined4 *)(&DAT_4c5107fc + param_1 * 0x3c),
*(undefined4 *)(&DAT_4c510800 + param_1 * 0x3c),
the JPEG 0x2d0,0x640,1,_JPEG_BUF,iVar1);
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;
}
// ...
pimage(*(undefined4 *)(&DAT_4c5107fc + param_1 * 0x3c),
*(undefined4 *)(&DAT_4c510800 + param_1 * 0x3c),
0x2d0,0x640,1,_JPEG_BUF,iVar1);
16
Heap Overflow in JPEG Loading
■ read_jpeg_file takes a size as 3rd argument
■ It triggers an error if the file does not fit the size provided
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
■ read_jpeg_file takes a size as 3rd argument
■ It triggers an error if the file does not fit the size provided
👉 Unless the size provided is 0…
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;
■ Chunks are in a unique memory pool struct free_chunk_head *next;
● An overflow may overwrite the metadata size_t len;
of next chunk }
20
From Heap Overflow to Arbitrary Write
■ After allocation, a chunk is removed from the free list
■ next and prev are dereferenced to change the corresponding nodes
⇒ Controlling a free chunk leads to a write-what-where
node->next->prev = node->prev;
node->prev->next = node->next;
node->prev = node->next = 0;
21
From Heap Overflow to Arbitrary Write
■ After allocation, a chunk is removed from the free list
■ next and prev are dereferenced to change the corresponding nodes
⇒ Controlling a free chunk leads to a write-what-where
❗ Both values must writable addresses
node->next->prev = node->prev;
node->prev->next = node->next;
node->prev = node->next = 0;
22
From Arbitrary Write to Code Execution
Important details about LK
❌ No ASLR
❌ No canaries
❌ No bounds checks in the heap algorithm
❌ Heap is executable!
23
From Arbitrary Write to Code Execution
Important details about LK
❌ No ASLR
❌ No canaries
❌ No bounds checks in the heap algorithm
❌ Heap is executable!
Exploit strategy becomes simple:
1. Overwrite a pointer that the code will jump to
👉 the return address in the stack
2. Make it point to a shellcode in our JPEG buffer 24
Exploiting a Heap Overflow in Little Kernel
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
What can go wrong?
33
Emulating and Debugging our Exploit
What can go wrong?
❌ Heap and stack are different from the ones IRL
34
Emulating and Debugging our Exploit
What can go wrong?
❌ Heap and stack are different from the ones IRL
✅ Dump it from the device
35
Emulating and Debugging our Exploit
What can go wrong?
❌ Heap and stack are different from the ones IRL
✅ Dump it from the device
👉 Memory state (addresses, sizes) is the same every boots
36
Emulating and Debugging our Exploit
What can go wrong?
❌ Heap and stack are different from the ones IRL
✅ Dump it from the device
❌ Heap algo writes something at the address *(shellcode+4)
37
Emulating and Debugging our Exploit
What can go wrong?
❌ Heap and stack are different from the ones IRL
✅ Dump it from the device
❌ Heap algo writes something at the address *(shellcode+4)
node->next->prev = node->prev;
node->prev->next = node->next;
node->prev = node->next = 0;
38
Emulating and Debugging our Exploit
What can go wrong?
❌ Heap and stack are different from the ones IRL
✅ Dump it from the device
❌ Heap algo writes something at the address *(shellcode+4)
✅ Skip the next instruction in the shellcode
add pc, pc, 0x4;
nop
nop
39
Emulating and Debugging our Exploit
What can go wrong?
❌ Heap and stack are different from the ones IRL
✅ Dump it from the device
❌ Heap algo writes something at the address *(shellcode+4)
✅ Skip the next instruction in the shellcode
❌ Heap after exploitation may crash during the next allocation
40
Emulating and Debugging our Exploit
What can go wrong?
❌ Heap and stack are different from the ones IRL
✅ Dump it from the device
❌ Heap algo writes something at the address *(shellcode+4)
✅ Skip the next instruction in the shellcode
❌ Heap after exploitation may crash during the next allocation
✅ Restore the heap in a working state
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
■ Images are authenticated and contain a footer signature
■ Two internal structures indicate which partitions to flash
● The Partition Information Table (PIT)
● A global structure indicating which partitions to authenticate
45
Odin: Partition Information Table
--- Entry #1 ---
Binary Type: 0 (AP)
■ PIT is retrieved statically from the eMMC Device Type: 2 (MMC)
■ It indicates where partitions are stored Identifier: 70
● Memory type, block count, etc Attributes: Read/Write
■ A partition not present in PIT can't be flashed Update Attributes: 1
■ PIT can be updated, but requires a signed Block Size/Offset: 0
image Block Count: 34
Partition Name: pgpt
…
46
Odin: Image Authentication
■ A global array indicates how an image should be authenticated
■ An image not present in this array will not be authenticated
● (Except for some specific images)
■ Comparing this array with PIT gives a set of images flashable without
authentication
md5hdr, md_udc, pgpt, sgpt, and vbmeta_vendor
47
GPT: GUID Partition Table
■ pgpt points to the Primary GPT Header
■ sgpt points to the Secondary GPT Header
■ Similarly to the PIT, it describes the partitions
○ (Names, sizes, addresses, etc)
■ Any GPT can be flashed through Odin
❗ No authentication required
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
❗ We can't just rename a partition to up_param to flash our JPEGs
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 default address
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 default address
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 default address
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
✅ It works (new jpegs are loaded)
❌ Android won't boot without the
vbmeta_vendor partition
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
■ Our ultimate goal is to bypass AVB checks in LK to load a modified
Android
● We patch LK code from our shellcode
● Memory already writable → no need to play with MMU
63
Chaining Everything Together
64
To Conclude
■ Chain based on 2 vulnerabilities
✅ Leads to code execution in LK
✅ Persistent (it survives reboots and factory reset)
✅ Impacts Samsung devices based on Mediatek SoCs
● Including those for which MTKClient does not work
✅ Can be triggered over USB thanks to Odin authentication bypass
✅ Gives full control over Normal World EL1/0
❌ Still no access to secrets stored in Secure World
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
■ Trustzone OS designed by Samsung
■ ROM images:
● tee-verified.img: ATF, TEEGRIS kernel, userboot.so
● tzar.img: TEE root filesystem
● super.img: Android system, Trusted Applications and Drivers
■ Excellent references online7
[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
uint* global_array = (uint *)0x4ce2f578;
[...]
if (smcid == 0x82000526) {
out_value = global_array[arg1 * 4];
goto exit;
}
[...]
output[2] = out_value;
output[1] = arg1;
*output = 0;
return output;
74
Leaking from Virtual Address Space
uint* global_array = (uint *)0x4ce2f578;
[...]
if (smcid == 0x82000526) {
out_value = global_array[arg1 * 4];
goto exit;
Fully controlled by
}
attacker
[...]
output[2] = out_value;
output[1] = arg1;
*output = 0;
return output;
75
Leaking from Virtual Address Space
uint* global_array = (uint *)0x4ce2f578;
[...]
if (smcid == 0x82000526) {
out_value = global_array[arg1 * 4];
goto exit;
Fully controlled by
}
attacker… And never
[...] checked
output[2] = out_value;
output[1] = arg1;
*output = 0;
return output;
76
SVE-2023-2215 (CVE-2024-20820)
■ In mediatek_plat_sip_handler_kernel, reachable from Linux Kernel
■ To exploit it, send the SMC 0x82000526 with
● (arbitrary_address - 0x4ce2f578) / 4
■ Bug introduced by Samsung only in some devices (including A225F)
■ It leaks 4 bytes from ATF virtual address space
● We can read all the internal data of ATF
● But we can't leak anything from other SW components
77
SVE-2023-2215 (CVE-2024-20820)
78
Mapping Any Physical Address in ATF
SMC 0x8200022A calls function spm_actions
if (smc_id == 0x8200022a) {
spm_actions(arg1,arg2,arg3);
79
Mapping Any Physical Address in ATF
SMC 0x8200022A calls function spm_actions
undefined * spm_actions(ulong cmdid,undefined *addr,ulong size) {
switch(cmdid & 0xffffffff) {
[...]
case 1:
if (size < 0x100001) {
mmap_wrap(addr,size);
[...]
}
80
Mapping Any Physical Address in ATF
SMC 0x8200022A calls function spm_actions
undefined * spm_actions(ulong cmdid,undefined *addr,ulong size) {
switch(cmdid & 0xffffffff) {
[...] Arguments fully
case 1: controlled
if (size < 0x100001) {
mmap_wrap(addr,size);
[...]
}
81
Mapping Any Physical Address in ATF
SMC 0x8200022A calls function spm_actions
undefined * spm_actions(ulong cmdid,undefined *addr,ulong size) {
switch(cmdid & 0xffffffff) {
[...] Arguments fully
case 1: controlled
if (size < 0x100001) {
mmap_wrap(addr,size);
[...]
And still no checks on
} the address
82
Mapping Any Physical Address in ATF
SMC 0x8200022A calls function spm_actions
undefined * spm_actions(ulong cmdid,undefined *addr,ulong size) {
switch(cmdid & 0xffffffff) {
[...]
Physical Address
case 1:
if (size < 0x100001) {
mmap_wrap(addr,size);
[...]
And still no checks on
} the address
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
■ Key storage and crypto services
■ Keys are stored as key blobs
■ Three protection levels:
● Software only
● TEE (default)
● Hardware-backed (StrongBox)
■ Raw key should never leave protected environment
86
Android Keystore system
87
Where to leak?
a22:/ # cat /proc/last_kmsg
[...]
[4425] mblock_reserve-R[5].start: 0x4ce00000, size: 0x60000 map:0
,name:atf-reserved
[...]
[4426] mblock_reserve-R[8].start: 0x7ac00000, size: 0x400000 map:0
,name:tee-secmem
[4426] mblock_reserve-R[9].start: 0x7f300000, size: 0xc0000 map:0
,name:SSPM-reserved
[4426] mblock_reserve-R[10].start: 0x7b200000, size: 0x4000000
, map:0 name:tee-reserved
[...]
[4436] lk finished --> jump to linux kernel 64Bit
88
Where to leak?
a22:/ # cat /proc/last_kmsg
[...]
[4425] mblock_reserve-R[5].start: 0x4ce00000, size: 0x60000 map:0
,name:atf-reserved
[...]
[4426] mblock_reserve-R[8].start: 0x7ac00000, size: 0x400000 map:0
,name:tee-secmem
[4426] mblock_reserve-R[9].start: 0x7f300000, size: 0xc0000 map:0
,name:SSPM-reserved
[4426] mblock_reserve-R[10].start: 0x7b200000, size: 0x4000000
, map:0 name:tee-reserved
[...]
[4436] lk finished --> jump to linux kernel 64Bit
89
Where to leak?
■ TAs should be part of the tee-reserved (0x7b200000) memory block
■ Keymaster TA binary contains many strings
● (path in Android fs: /vendor/tee/00000000-0000-0000-0000-4b45594d5354)
■ Try to find these strings in memory
● Usually present around 0x7c200000
90
Our PoC
1. Import a key into the Android Keystore
2. Encrypt using that key
3. Stop the execution after BeginOperation is called
○ To makes sure the key stays in memory
4. Leak the identified region of memory
91
A Simple PoC
byte[] key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".getBytes();
SecretKey yourKey = (SecretKey) new SecretKeySpec(key, 0, key.length,
"AES");
[...]
keyStore = KeyStore.getInstance("AndroidKeystore");
keyStore.load(null);
keyStore.setEntry("key1", new KeyStore.SecretKeyEntry(yourKey), new
KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
keyStoreKey = (SecretKey) keyStore.getKey("key1", null);
92
Communication between NSW and SW
93
Hooking Keystore HAL Deamon
94
The result
95
The result
96
Our PoC
1. Import a key into the Android Keystore
2. Encrypt using that key
3. Stop the execution after BeginOperation is called
○ To makes sure the key stays in memory
4. Leak the identified region of memory
5. Try all possible keys from from leak to decrypt ciphertext
97
Demo
98
Conclusion
■ We presented 4 vulnerabilities leading to
● Authentication bypass in Odin
● Code execution with persistence in LK
● Leak of SW memory, including Keystore keys
■ Impact low/middle end Samsung devices
● Vulnerabilities are simple, and yet super impactful
● No mitigations in LK nor ATF
■ All the vulnerabilities are now fixed
99
Thank you!
@max_r_b
contact@quarkslab.com @DamianoMelotti
@pwissenlit