Sei sulla pagina 1di 11

BadIRET|}Q

@GRafal WojtczukAFeb 2 2015

GExploiting uBadIRETv vulnerability (CVE-2014-9322, Linux kernel privilege escalatio


http://labs.bromium.com/2015/02/02/exploiting-badiret-vulnerability-cve-2014-932
2-linux-kernel-privilege-escalation/
GShawn the R0ckA(PvWr[)
POC( PMickey):
https://rdot.org/forum/showthread.php?t=3341
ShawnGo|}AOSMEPMQLFASMAPOMA
ouQ@UPaX/GrsecurityUDEREFSMSMAPAuOn
{Aj2006~koSNwgFBQ@anarchysxC
o|}vTsADebianXGb@vTG
https://security-tracker.debian.org/tracker/CVE-2014-9322
RedHat~RHEL 4/5/6/7vTG
https://access.redhat.com/security/cve/CVE-2014-9322
--[ 0. Intro
CVE-2014-9322yzpUG
------------------------------------------------------------------linuxNXarch/x86/kernel/entry_64.Sb3.17.5eST
BzSS]^qHs~AoiHaqLo@
IRETOq~a}hXGSa}vC
------------------------------------------------------------------o|}2014~1123Q_[2]AS}QNXM
QCog|ho|}HQL{C
OALkIntel[3]eApGx@Nyi
HdIntelCObFedora 20 64-bitoWA
O3.11.10-301AQ64iC
nG
1. qLAo|}iHwQQC
2. SMEP[4]NNXFSMAP[5]iHNNXC
--[ 1. Digression: kernel, usermode, iret
...............................
aG
http://labs.bromium.com/2015/02/02/exploiting-badiret-vulnerability-cve-2014-932
2-linux-kernel-privilege-escalation/
...............................

--[ 2. |}
b@pUAlinuxqLiretO^|@`C`B
z{|^Fbad_iretAoFG
-------------------------------------------------------------------------/* So pretend we completed the iret and took the #GPF in user mode.*/
pushq $0
SWAPGS
jmp general_protection
-------------------------------------------------------------------------poAUNXyM@O@`(General
Protection)bo]#GPBz{^PCo`Bz
pjhOiretOoAe.g. #GPC
Db#SS`CpG|}]p3.17.5^]"espfix"\]q
3.16JS^Abad_iret|buW"push"OAo|
P~]page fault^|_~C{oFq{b}
lAu`b3.16HeS"espfix"C
o|}#SS`Bz{SX
upretend-it-was-#GP-in-userspacev[6]WAP#GPBz{A#SS`
Bz|h@swapgsOCpGAswapgsFAnLU`C
--[ 3. DGswapgsO
sqLgsqiXAoG
-----------------------------------------mov %gs:LOGICAL_ADDRESS, %eax
-----------------------------------------|oHUXBG
1. BASE_ADDRESSqqHsX
2. sua}LOGICAL_ADDRESS+BASE_ADDRESSQdereferenced]Shawn:
char *p; *pNOderef^C
a}OqGDT]LDT^~LCLpA@pOGSqa}Q
@nGDTPC
IntelG
uSWAPGSeGSHsMbMSRa}C0000102H(IA32_KERNEL_GS_BASE)]
tiCSWAPGSOO@tn]pSvOC(....)i
HGSeb`shX[per-cpu]cCv
LinuxCCPUbt@TwjpcsC
CCPU[IA32_KERNEL_GS_BASEca}WA]Aq`pA
ptBz{OG
1. swapgs]{bOGSV^
2. qLsOMgseXper-cpuc
3. swapgs]MPeswapgsAGSV^

4. ^
NXOHXagsepercpuA@
swapgsOOMC(Hgs baseVs^
--[ 4. o|}
{biHo|}NOXA]hF@swapgsOb|}
NX|A|qiQ~GSa}XncC
iretOF@#SS`HOAIntelbo(
Shawn:OS|QBIG BROTHER?)FyziretOAIntelo
G
---------------------------------------------------------------------64`G
#SS(0)
pG@qWpop@HFSSC
pG@qWpop@_Fnon-canonicala}]Shawn: 64-bitUu
\Xcanonicala}^C
---------------------------------------------------------------------S@QjboCLpAInteliretN
XiFt~@pGwhen the segment defined by the return frame is
not present:
---------------------------------------------------------------------IF stack segment is not present
THEN #SS(SS selector); FI;
---------------------------------------------------------------------HbAn]mssHsYsbCoOG
G
---------------------------------------------------------------------mov $nonpresent_segment_selector, %eax
mov %ax, %ss
---------------------------------------------------------------------GO|o#GPCqL]ptrace)]mssHsO\F
Asys_sigreturnt|b64tW]moHs]i32u
@^CMOG
1. u{AGqLsys_modify_ldttbLDT@wqX
2. u{BGs:=X_selector
3. u{AGqLsys_modify_ldtXL
4. u{BGw_

nb@i{u{]Oqt]]A
sys_modify_ldt^^OqLwsXF#sssysretOCpGXbP
u{LNP"ss:=X OuAssHs|B]mACB
HWNX|PpanicCNqkANn
gsa}FoiHqLtarch_prctl(ARCH_SET_GS)Q]mC
--[ 5. Achieving write primitive
pGBHWNXA#SSBz{|`^bad_iret]NOSs
GSa}^A#GP`Bz{A@qNFo
G
-------------------------------------------------------------------289 dotraplinkage void
290 do_general_protection(struct pt_regs *regs, long error_code)
291 {
292
struct task_struct *tsk;
...
306
tsk = current;
307
if (!user_mode(regs)) {
... it is not reached
317
}
318
319
tsk->thread.error_code = error_code;
320
tsk->thread.trap_nr = X86_TRAP_GP;
321
322
if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
323
printk_ratelimit()) {
324
pr_info("%s[%d] general protection ip:%lx sp:%lx
error:%lx",
325
tsk->comm, task_pid_nr(tsk),
326
regs->ip, regs->sp, error_code);
327
print_vma_addr(" in ", regs->ip);
328
pr_cont("\n");
329
}
330
331
force_sig_info(SIGSEGV, SEND_SIG_PRIV, tsk);
332 exit:
333
exception_exit(prev_state);
334 }
-------------------------------------------------------------------CNXAqgse{FtskC306OG
---------------------------------------------------------------0xffffffff8164b79d :

mov

%gs:0xc780,%rbx

---------------------------------------------------------------ooN_FCFcurrentwAoVyzLinuxi
{cC
---------------------------------------------------------------319

tsk->thread.error_code = error_code;

320

tsk->thread.trap_nr = X86_TRAP_GP;

---------------------------------------------------------------gJ]qtask_struct}lTw^a}C`NQ
]OO0M0xd`q^Ao@DCH
|AQ\@bXWncCpGHUBJG
1. bFAKE_PERCPUsA]mgsa}o
2. a}FAKE_PERCPU+0xc780swFAKE_CURRENT_WITH_OFFSETAH
FAKE_CURRENT_WITH_OFFSET= X V offsetof(struct task_struct,
thread.error_code)
3. o|}
do_general_protection|gJXCN|AXcurrent
task_currentLAe.g.unhandled_signal()qtask_structw
CSXA|b@~CKo
DHG
1. CLinuxWindowsALinuxO\@Ow
~bX{ApGiA|ei{~B
]Windows|^CojqVNLOFCqO
bei{QAswapgsOUAo|PLi{WU
h~C
2. utsk->thread.error_code = error_codev\~Bz{IDTJ
fC~o]Qunhandled_signal()o^CoNgb@M
\LCbo|\A]2]G
* LinuxIDTu
* NIDTigA]\ -- 00xdCSMEP/SMAP]
|ODC
3. iH@vCutsk->thread.error_code = error_codev|P
iNXAp\qLtNXwPCiHbCPU 0W
o|}AbP@qCPU 1iH`@tCoiHbCPU
0Q}aeqLCPU 1oNXAphook~Bz{AoCPU 0|
vThaAFokhAFCiP|}b
uWPPC
4. Throw a towel on utsk->thread.error_code = error_codev write.
McA|@C|currentVA]m
owiHqLderefsCMA[UN
XAhgderefC
--[ 6. Achieving write primitive continued, aka life after do_general_protection
U@|Odo_general_protection()G
----------------------------------------------------------------------int
force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
{

unsigned long int flags;


int ret, blocked, ignored;
struct k_sigaction *action;
spin_lock_irqsave(&t->sighand->siglock, flags);
action = &t->sighand->action[sig-1];
ignored = action->sa.sa_handler == SIG_IGN;
blocked = sigismember(&t->blocked, sig);
if (blocked || ignored) {
action->sa.sa_handler = SIG_DFL;
if (blocked) {
sigdelset(&t->blocked, sig);
recalc_sigpending_and_wake(t);
}
}
if (action->sa.sa_handler == SIG_DFL)
t->signal->flags &= ~SIGNAL_UNKILLABLE;
ret = specific_send_sig_info(sig, info, t);
spin_unlock_irqrestore(&t->sighand->siglock, flags);
}

return ret;

----------------------------------------------------------------------task_structsighandO@wAiH]mNC
----------------------------------------------------------------------action = &t->sighand->action[sig-1];
action->sa.sa_handler = SIG_DFL;
----------------------------------------------------------------------LkgASIG_DFLO`q0Cou@FAMC
]Q\a}XCytask_structAHX
t->sighand->action[sig-1].sa.sa_handlera}CW@n`NG
----------------------------------------------------------------------spin_lock_irqsave(&t->sighand->siglock, flags);
----------------------------------------------------------------------t->sighand->siglockbt->sighand->action[sig-1].sa.sa_handler`q
WA|spin_local_irqsavebYa}WAX+SPINLOCKeLkC
o|oOHiG
1. X+SPINLOCKbsa}_SspinlockCspin_lock_irqsave
|YCAspin_unlock_irqrestore|MPspin_lock_irqsaveg@C
2.X+SPINLOCKbsa}_WspinlockCpGJA
spin_lock_irqsave|Lu`spinlockCAnLoo
nL] --- X+SPINLOCKbsa}eCoOiAiHb
b.data]mXC

* AFAKE_CURRENTAt->sighand->siglockVW
ASPINLOCK_USERMODE
* force_sig_info()|bspin_lock_irqsave
* oAt~@u{bt~@CPUWBABF
t->sighandAHt->sighand->action[sig-1.sa.sa_handerF
\ASPINLOCK_USERMODE
* spin_lock_irqsave|^
* force_sig_info()|sJt->sighandAg@
yl2AYX+SPINLOCKblOS
CoO --- n@FAKE_CURRENTrqqNX
C|AzSh` --- ogBLOGwgF....U@B|oH
force_sig_info()Mdo_general_protection()^CUiretO|A
#SS`Bz]]MOssbWF@nonpresentq^A
o@A#SSBz{B~swapgsO|^eTswapgsC
do_general_protection()|M@utask_structAOy
FAKE_CURRENTCAcurrent|oXSIGSEGVHALi{|QC
otMOwC
................................................
G
http://labs.bromium.com/2015/02/02/exploiting-badiret-vulnerability-cve-2014-932
2-linux-kernel-privilege-escalation/
................................................
--[ 7. GSMEP
SMEPOIntelBzq3NCore]ShawnG^[JwSCpGH
sCR4SMEPQ]mARING0]ShawnGLinuxORING0Ab
XENUO~ARING0OHypervisor^NXOs
ACPUN|@~]ShawnGNO^CpGiALinux|q
{}SMEPC
--[ 8. {NX
e`zF@pH0bs\8sr`kCpGSMEP
}pUp{NXOH
\@NXwOCiHMstop bytes( Shawn: MSB)
- a}|bAHSMEP|owderefC
@AiHMsXlow bytes( Shawn: LSB)AOQo
wv]CC
n@wPVcX]tFNXwCiH\Ptop bytes
o@a}AoP->code_pointer_in_x()|@
a}CTwnHCqgA
proc_rootqAoO@cG
----------------------------------------------------------------------

struct proc_dir_entry {
...
const struct inode_operations *proc_iops;
const struct file_operations *proc_fops;
struct proc_dir_entry *next, *parent, *subdir;
...
u8 namelen;
char name[];
};
---------------------------------------------------------------------ocO@proctJf]proc_rootO/proc@proct
^C@W|}lb/procdAsubdirw]q
proc_root.subdir}l^|iAWrQCproc_iopsw|Q
G
---------------------------------------------------------------------struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int)
;
void * (*follow_link) (struct dentry *, struct nameidata *);
...many more...
int (*update_time)(struct inode *, struct timespec *, int);
...
} ____cacheline_aligned;
---------------------------------------------------------------------proc_rootnbNXqAoN|}QnDoa}CoH
iHq/proc/kallsymsoFMAh[TL\q
oCpGO@wbuild]GNU/Linuxo^Ao
a}iHQoFM@@ncFAKE_CURRENTC
|\proc_root.subdirAo@V@bQ
cproc_dir_entryCIxb\wCOFg
@Ou\80vCpGproc_root.subdir0A|hMgoA]
Linux\Mga}0W]ToOAC
/proc/sys/vm/mmap_min_addra}Aq{@O4k^C]ShawnGQQ
0ld good hacking daysAC@NULL pointer derefOhLD
;-))CoNnG
1. Mg16MBsa}4096
2. proc_dir_entryRAinode_operationsrqV
a}FAKE_IOPSAnamerqr"A"C
3. tm|}Qh\proc_root.subdirtop 5 bytesC
ADproc_root.subdirC3 bytesO0AiHTwbo
force_sig_info()\Aproc_root.subdir|VQsC
i{open("/proc/A",...)AFAKE_IOPSw|QCo
VOHpGA{OuVshellcodeuAA@MWRC
nFAKE_IOPSwV@stack pivot[1]CCoA]F
BpCq`"xchg %esp, %eax; ret"NXC]2r`A94 c3O
ba}0xffffffff8119f1ed^niH64ROPCNS
%raxAoxchgO@32Hs]M%rsp32%rsp
bsCbV|pUAiHtC4GBsM

RROPC
be]Fedora 20)khderefbFAKE_IOPSwG
1. %rax:=FAKE_IOPS; call *SOME_OFFSET(%rax)
2. %rax:=FAKE_IOPS; %rax:=SOME_OFFSET(%rax); call *%rax
1pAb%rspM%raxAo|FAKE_IOPSCnROPn
bFAKE_IOPS_lmAonuadd $A_LOT, %rsp; retvOAM
b~C
2pA%rsp|tC32AY0x8119f1edCnbo
a}WROPC
p@U%rax@wbSwVstack pivotCA
nROPR4GBsAunWa}YiC2pROP
G
---------------------------------------------------------------------unsigned long *stack=0x8119f1ed;
*stack++=0xffffffff81307bcdULL; // pop rdi, ret
*stack++=0x407e0;
//cr4 with smep bit cleared
*stack++=0xffffffff8104c394ULL; // mov rdi, cr4; pop %rbp; ret
*stack++=0xaabbccdd;
// placeholder for rbp
*stack++=actual_shellcode_in_usermode_pages;
-----------------------------------------------------------------------[ 9. GSMAP
SMAPOIntelq5NCoreBzX@wSCpGCR4Hs
SMAPQ]mACPU|QRING0X]ShawnGHzA
SMAPMSMEPjPDnOSMEPwNXqASMAPwq^CLinux
q`|q{}SMAPC@]Core-M 5Y10a CPU^X
McrashFG
---------------------------------------------------------------------[
[
[
[
[

314.099024]
389.885318]
389.885455]
389.885577]
389.887253]
48 8b

running with cr4=0x3407e0


BUG: unable to handle kernel paging request at 00007f9d87670000
IP: [ffffffffa0832029] test_write_proc+0x29/0x50 [smaptest]
PGD 427cf067 PUD 42b22067 PMD 41ef3067 PTE 80000000408f9867
Code: 48 8b 33 48 c7 c7 3f 30 83 a0 31 c0 e8 21 c1 f0 e0 44 89 e0

---------------------------------------------------------------------pAO`AX]F~CWindowst
SMAPFWindows 10Nwbuild 9926cr4=0x1506f8]SMEPA
SMAP^FLinux(Pw^AiHcr4bit 21OS]
mCo_AbLinuxAXOqLcopy_from_user(),
copy_to_user()MAHo@{SMAPOi
CbWindowsWANXXNXAuO]F@hX`
Bz{AHnSMAPu@`nXAoO@xu@C
--[ 10. SMAP to the rescue!

W|}QkbSwcAMj{
oOiHCok}SMAPS --- CPU|
qcNCOcyncAM
oCpG
---------------------------------------------------------------------write(pipe_filedescriptor, evil_data, ...
---------------------------------------------------------------------evil_data|Q@DwRCinqoa}F
some sort of heap spraying, combined with the fact that there is no
spoon^W effective kernel ASLR[9], could work, although it is likely to be
less reliable than exploitation without SMAP.
`A@ --- nFn]mgs basehV
|}QcCbW]SSMAP^A
arch_prctl(ARCH_SET_GS)tAoOob{G
---------------------------------------------------------------------long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
{
int ret = 0;
int doit = task == current;
int cpu;
switch (code) {
case ARCH_SET_GS:
if (addr >= TASK_SIZE_OF(task))
return -EPERM;
... honour the request otherwise
---------------------------------------------------------------------yA@ --- oAPIh]mgs baseHW
sI
CPUwrgsbaseOiH]mgs baseAoO@DSvOA
nqL]mCR4HsFSGSBASE bit( no 16)}CLinuxS
]moA]oOC
b64tWADtGDTMLDTMO8r`Abase fieldOj
4GB-1AHS|]m@a}qbCHAD|
Fb]mAgs baseLkAMSMAPO@CVE-2014-9322w
64LinuxNNX|}QC
[1] CVE-2014-9322
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-9322
[2] Upstream fix
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=6f442b
e2fb22be02cafa606f1769fa1e6f894441
[3] Intel Software Developerzs Manuals,

http://www.intel.com/content/www/us/en/processors/architectures-software-develop
er-manuals.html
[4] SMEP
http://vulnfactory.org/blog/2011/06/05/smep-what-is-it-and-how-to-beat-it-on-lin
ux/
[5] SMAP
http://lwn.net/Articles/517475
[6] "pretend-it-was-#GP-in-userspace"
https://lists.debian.org/debian-kernel/2014/12/msg00083.html
[7] Stack Pivoting
https://trailofbits.files.wordpress.com/2010/04/practical-rop.pdf
[8] TSX improves timing attacks against KASLR
http://labs.bromium.com/2014/10/27/tsx-improves-timing-attacks-against-kaslr/