Skip to content

Commit 1c52cc5

Browse files
committed
Add support for relative relocations
1 parent c811fe7 commit 1c52cc5

File tree

3 files changed

+92
-14
lines changed

3 files changed

+92
-14
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ Exploit should now support the following firmwares:
3737
- Clang-based fine-grained Control Flow Integrity (CFI) is present and enforced.
3838
- Supervisor Mode Access Prevention/Execution (SMAP/SMEP) cannot be disabled, due to the HV.
3939
- The write primitive is somewhat constrained, as bytes 0x10-0x14 must be zero (or a valid network interface).
40+
- Though due to newer work using pipes, full arbitrary read/write is now possible
41+
4042

4143

4244

@@ -61,7 +63,9 @@ Exploit should now support the following firmwares:
6163
- [x] ~~Improve UAF reliability~~
6264
- [x] ~~Improve victim socket reliability (third prio)~~
6365
- [x] ~~Use a better / more consistent leak target than kqueue~~ (no longer necessary)
64-
- [ ] Make ELF loader support relocations
66+
- [x] Make ELF loader support relocations
67+
- [ ] Add support for more relocations and possibly full dynamic linkage?
68+
6569

6670

6771

document/en/ps5/exploit.js

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,39 +1294,49 @@ async function userland() {
12941294
await chain.add_syscall_ret(test_store_buf, SYSCALL_LISTEN, elf_loader_sock_fd, 5);
12951295
await chain.run();
12961296

1297-
// Accept and process connections
1297+
// ELF sizes and offsets
12981298
let SIZE_ELF_HEADER = 0x40;
12991299
let SIZE_ELF_PROGRAM_HEADER = 0x38;
1300+
13001301
let OFFSET_ELF_HEADER_ENTRY = 0x18;
13011302
let OFFSET_ELF_HEADER_PHOFF = 0x20;
13021303
let OFFSET_ELF_HEADER_PHNUM = 0x38;
1304+
13031305
let OFFSET_PROGRAM_HEADER_TYPE = 0x00;
13041306
let OFFSET_PROGRAM_HEADER_FLAGS = 0x04;
13051307
let OFFSET_PROGRAM_HEADER_OFFSET = 0x08;
13061308
let OFFSET_PROGRAM_HEADER_VADDR = 0x10;
1307-
let OFFSET_PROGRAM_HEADER_FILESZ = 0x20;
13081309
let OFFSET_PROGRAM_HEADER_MEMSZ = 0x28;
1309-
let ELF_PT_NULL = 0x00;
1310+
1311+
let OFFSET_RELA_OFFSET = 0x00;
1312+
let OFFSET_RELA_INFO = 0x08;
1313+
let OFFSET_RELA_ADDEND = 0x10;
1314+
1315+
// ELF program header types
13101316
let ELF_PT_LOAD = 0x01;
1317+
let ELF_PT_DYNAMIC = 0x02;
1318+
1319+
// ELF dynamic table types
1320+
let ELF_DT_NULL = 0x00;
1321+
let ELF_DT_RELA = 0x07;
1322+
let ELF_DT_RELASZ = 0x08;
1323+
let ELF_DT_RELAENT = 0x09;
1324+
let ELF_R_AMD64_RELATIVE = 0x08;
13111325

1326+
// Accept clients
13121327
let conn_fd_store = p.malloc(0x4);
13131328
let conn_addr_store = p.malloc(0x10);
13141329
let conn_addr_sz_store = p.malloc(0x4);
13151330
let conn_ret_store = p.malloc(0x8);
1316-
let segment_text_addr_store = p.malloc(0x8);
1317-
let segment_data_addr_store = p.malloc(0x8);
13181331
let elf_store_size = SIZE_ELF_HEADER + (SIZE_ELF_PROGRAM_HEADER * 0x10) + 0x200000;
13191332
let elf_store = p.malloc(elf_store_size);
13201333

13211334
let shadow_mapping_addr = new int64(0x20100000, 0x00000009);
13221335
let mapping_addr = new int64(0x26100000, 0x00000009);
1323-
let data_mapping_addr;
13241336

13251337
let elf_program_headers_offset = 0;
13261338
let elf_program_headers_num = 0;
13271339

1328-
let elf_mapped_addr = 0;
1329-
13301340
p.write4(conn_addr_sz_store, 0x10);
13311341

13321342
for (;;) {
@@ -1362,8 +1372,13 @@ async function userland() {
13621372

13631373
await log("[+] Received ELF file (" + total_sz.toString(10) + " bytes), loading...");
13641374

1365-
let text_segment_sz = 0;
1366-
let data_segment_sz = 0;
1375+
let text_segment_sz = 0;
1376+
let data_segment_sz = 0;
1377+
let rela_table_offset = 0;
1378+
let rela_table_count = 0;
1379+
let rela_table_size = 0;
1380+
let rela_table_entsize = 0;
1381+
let shadow_write_mapping = 0;
13671382

13681383
// Parse program headers and map segments
13691384
for (let i = 0; i < elf_program_headers_num; i++) {
@@ -1381,7 +1396,7 @@ async function userland() {
13811396
// Also, the mapping size is fixed at 0x100000. This is because jitshm requires to be aligned this way... for some dumb reason.
13821397
if ((program_flags & 1) == 1) {
13831398
// Executable segment
1384-
text_segment_sz = aligned_memsz;
1399+
text_segment_sz = program_memsz;
13851400

13861401
// Get exec
13871402
await chain.add_syscall_ret(jit_handle_store, SYSCALL_JITSHM_CREATE, 0x0, aligned_memsz, 0x7);
@@ -1396,6 +1411,7 @@ async function userland() {
13961411
// Map to shadow mapping
13971412
await chain.add_syscall_ret(conn_ret_store, SYSCALL_MMAP, shadow_mapping_addr, aligned_memsz, 0x3, 0x11, write_handle, 0);
13981413
await chain.run();
1414+
shadow_write_mapping = p.read8(conn_ret_store);
13991415

14001416
// Copy in segment data
14011417
let dest = p.read8(conn_ret_store);
@@ -1424,7 +1440,65 @@ async function userland() {
14241440
}
14251441
}
14261442

1427-
// TODO: Dynamic / relocations
1443+
if (program_type == ELF_PT_DYNAMIC) {
1444+
// Parse dynamic tags, the ones we truly care about are rela-related.
1445+
for (let j = 0x00; ; j += 0x10) {
1446+
let d_tag = p.read8(elf_store.add32(program_offset + j)).low;
1447+
let d_val = p.read8(elf_store.add32(program_offset + j + 0x08));
1448+
1449+
// DT_NULL means we reached the end of the table
1450+
if (d_tag == ELF_DT_NULL || j > 0x100) {
1451+
break;
1452+
}
1453+
1454+
switch (d_tag) {
1455+
case ELF_DT_RELA:
1456+
rela_table_offset = d_val.low;
1457+
break;
1458+
case ELF_DT_RELASZ:
1459+
rela_table_size = d_val.low;
1460+
break;
1461+
case ELF_DT_RELAENT:
1462+
rela_table_entsize = d_val.low;
1463+
break;
1464+
}
1465+
}
1466+
}
1467+
}
1468+
1469+
// Process relocations if they exist
1470+
if (rela_table_offset != 0) {
1471+
let base_address = 0x1000;
1472+
1473+
// The rela table offset from dynamic table is relative to the LOAD segment offset not file offset.
1474+
// The linker script should guarantee it ends up in the first LOAD segment (code).
1475+
rela_table_offset += base_address;
1476+
1477+
// Rela count can be gotten from dividing the table size by entry size
1478+
rela_table_count = rela_table_size / rela_table_entsize;
1479+
1480+
// Parse relocs and apply them
1481+
for (let i = 0; i < rela_table_count; i++) {
1482+
let r_offset = p.read8(elf_store.add32(rela_table_offset + (i * rela_table_entsize) +
1483+
OFFSET_RELA_OFFSET));
1484+
let r_info = p.read8(elf_store.add32(rela_table_offset + (i * rela_table_entsize) +
1485+
OFFSET_RELA_INFO));
1486+
let r_addend = p.read8(elf_store.add32(rela_table_offset + (i * rela_table_entsize) +
1487+
OFFSET_RELA_ADDEND));
1488+
1489+
let reloc_addr = mapping_addr.add32(r_offset.low);
1490+
1491+
// If the relocation falls in the executable section, we need to redirect the write to the
1492+
// writable shadow mapping or we'll crash
1493+
if (r_offset.low <= text_segment_sz) {
1494+
reloc_addr = shadow_write_mapping.add32(r_offset.low);
1495+
}
1496+
1497+
if ((r_info.low & 0xFF) == ELF_R_AMD64_RELATIVE) {
1498+
let reloc_value = mapping_addr.add32(r_addend.low); // B + A
1499+
p.write8(reloc_addr, reloc_value);
1500+
}
1501+
}
14281502
}
14291503

14301504
let rwpair_mem = p.malloc(0x8);

document/en/ps5/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878

7979
<center>
8080
<h3>
81-
<b>v1.02.</b>
81+
<b>v1.03.</b>
8282
<br />
8383
<a href="https://twitter.com/theflow0">@theflow0</a>,
8484
<a href="https://twitter.com/SpecterDev">@SpecterDev</a>,

0 commit comments

Comments
 (0)