21
Mar
On 28th of February, I’ve sent a short summary to lkrg-users mailing list (https://www.openwall.com/lists/lkrg-users/2020/02/28/1) regarding recent Linux kernel XFRM UAF exploit dropped by Vitaly Nikolenko. I believe it is worth reading and I’ve decided to reference it on my blog as well:
Hey,
Vitaly Nikolenko published an exploit for Linux kernel XFRM use-after-free. His tweet with more details can be found here:
Detailed description of the bug can be found here:
https://duasynt.com/pub/vnik/01-0311-2018.pdf
I’ve tested his exploit under the latest version of LKRG (from the repo) and it correctly detects and kills it:
[Fri Feb 28 10:04:24 2020] [p_lkrg] Loading LKRG… [Fri Feb 28 10:04:24 2020] Freezing user space processes … (elapsed 0.008 seconds) done. [Fri Feb 28 10:04:24 2020] OOM killer disabled. [Fri Feb 28 10:04:24 2020] [p_lkrg] Verifying 21 potential UMH paths for whitelisting… [Fri Feb 28 10:04:24 2020] [p_lkrg] 6 UMH paths were whitelisted… [Fri Feb 28 10:04:25 2020] [p_lkrg] [kretprobe] register_kretprobe() for failed! [err=-22] [Fri Feb 28 10:04:25 2020] [p_lkrg] ERROR: Can't hook ovl_create_or_link function :( [Fri Feb 28 10:04:25 2020] [p_lkrg] LKRG initialized successfully! [Fri Feb 28 10:04:25 2020] OOM killer enabled. [Fri Feb 28 10:04:25 2020] Restarting tasks … done. [Fri Feb 28 10:04:42 2020] [p_lkrg] [JUMP_LABEL] New modification: type[JUMP_LABEL_JMP]! [Fri Feb 28 10:04:42 2020] [p_lkrg] [JUMP_LABEL] Updating kernel core .text section hash! [Fri Feb 28 10:04:42 2020] [p_lkrg] [JUMP_LABEL] New modification: type[JUMP_LABEL_JMP]! [Fri Feb 28 10:04:42 2020] [p_lkrg] [JUMP_LABEL] Updating kernel core .text section hash! [Fri Feb 28 10:04:42 2020] [p_lkrg] [JUMP_LABEL] New modification: type[JUMP_LABEL_JMP]! [Fri Feb 28 10:04:42 2020] [p_lkrg] [JUMP_LABEL] Updating kernel core .text section hash! [Fri Feb 28 10:04:42 2020] [p_lkrg] [JUMP_LABEL] New modification: type[JUMP_LABEL_JMP]! [Fri Feb 28 10:04:42 2020] [p_lkrg] [JUMP_LABEL] Updating kernel core .text section hash! [Fri Feb 28 10:06:49 2020] [p_lkrg] process[67342 | lucky0] has different user_namespace! [Fri Feb 28 10:06:49 2020] [p_lkrg] process[67342 | lucky0] has different user_namespace! [Fri Feb 28 10:06:49 2020] [p_lkrg] Trying to kill process[lucky0 | 67342]! [Fri Feb 28 10:08:32 2020] [p_lkrg] process[81090 | lucky0] has different user_namespace! [Fri Feb 28 10:08:32 2020] [p_lkrg] process[81090 | lucky0] has different user_namespace! [Fri Feb 28 10:08:32 2020] [p_lkrg] Trying to kill process[lucky0 | 81090]! [Fri Feb 28 10:08:32 2020] [p_lkrg] process[81090 | lucky0] has different user_namespace! [Fri Feb 28 10:08:32 2020] [p_lkrg] process[81090 | lucky0] has different user_namespace! [Fri Feb 28 10:08:32 2020] [p_lkrg] Trying to kill process[lucky0 | 81090]! [Fri Feb 28 10:08:32 2020] [p_lkrg] process[81090 | lucky0] has different user_namespace! [Fri Feb 28 10:08:32 2020] [p_lkrg] process[81090 | lucky0] has different user_namespace! [Fri Feb 28 10:08:32 2020] [p_lkrg] Trying to kill process[lucky0 | 81090]! [Fri Feb 28 10:08:32 2020] [p_lkrg] process[81090 | lucky0] has different user_namespace! [Fri Feb 28 10:08:32 2020] [p_lkrg] process[81090 | lucky0] has different user_namespace! [Fri Feb 28 10:08:32 2020] [p_lkrg] Trying to kill process[lucky0 | 81090]!
Latest LKRG detects user_namespace corruption, which in a way proofs that our namespace escape logic works. When I’ve made the same test, but reverting LKRG code base to the commit just before namespace corruption detection, LKRG is still detecting it via standard method:
[Fri Feb 28 10:34:28 2020] [p_lkrg] process[17599 | lucky0] has different SUID! 1000 vs 0
[Fri Feb 28 10:34:28 2020] [p_lkrg] process[17599 | lucky0] has different GID! 1000 vs 0
[Fri Feb 28 10:34:28 2020] [p_lkrg] process[17599 | lucky0] has different SUID! 1000 vs 0
[Fri Feb 28 10:34:28 2020] [p_lkrg] process[17599 | lucky0] has different GID! 1000 vs 0
[Fri Feb 28 10:34:28 2020] [p_lkrg] Trying to kill process[lucky0 | 17599]!
…
[Fri Feb 28 10:35:02 2020] [p_lkrg] process[22293 | lucky0] has different SUID! 1000 vs 0
[Fri Feb 28 10:35:02 2020] [p_lkrg] process[22293 | lucky0] has different GID! 1000 vs 0
[Fri Feb 28 10:35:02 2020] [p_lkrg] process[22293 | lucky0] has different SUID! 1000 vs 0
[Fri Feb 28 10:35:02 2020] [p_lkrg] process[22293 | lucky0] has different GID! 1000 vs 0
[Fri Feb 28 10:35:02 2020] [p_lkrg] Trying to kill process[lucky0 | 22293]!
This is an interesting case. Vitaly published just a compiled binary of his exploit (not a source code). This means that adopting his exploit to play cat-and-mouse game with LKRG is not an easy task. It is possible to reverse-engineer it and modify the exploit binary, however it’s more work.
Thanks,
Adam
Comments
Leave a Reply
zerons on 03.23.2020
Hi, I’ve done the reverse-engineering and posted a .c file here https://github.com/snorez/exploits/blob/master/xfrm_poc_RE_challenge/lucky0_RE.c
Also, the output messages of LKRG before namespace corruption detection explain the exploit does clear both the cred->gid and cred->suid fields.
pi3 on 03.23.2020
Very impressive work! Your source-code looks like an original exploit, I’m impressed 🙂