Linux-Kernel-Exploit Stack Smashing



Principle of kernel stack overflow and the user mode stack overflow are the same, we can use it to hijack control flow and privilge Escalation in Ring 0.

Bug

Kernel stack overflow like in the user mode.
We focus on the function bug2_write,memcpy unsafe function result in potential thread of buffer overflow.

We drag stack_smashing.ko in IDA for analyzing the stack-frame of bug2_write.

bug2_write function stack frame as shown in the following figure:

Array localbuf[] can be overwritten and we can control the return address to hijack control flow.
Attention please ,at that time ,we are in Ring0 (kernel mode).
That's a simplest example of kernel stack smashing.

Poc

We run the poc in qemu,it's get the info below:

Our kernel protect the stack with a “canary” value,it's the same as the "stack canary" in user mode,so when we execute our poc directly,canary be covered with 0x0000000 ,it cause kernel panic. Qemu crashed!
So we need to compile a new kernel without the option of "Canary" by the operations.

Vim at .config in the root of linux kernel, comment the line CONFIG_CC_STACKPROTECTOR=y,and type n(no) when make point out open the stack canary protection or not.
Go on ,we re complile our module and poc in the new kernel and run poc again.

[ 28.484238] EIP: [<42424242>] 0x42424242 SS:ESP 0068:c7897f2c
Kernel jumped to 0x42424242 which is the address we want to control, it proves that we can hijack control flow in kernel mode.

Exploit

Our aim is to get a root shell.
For achieving our aim we should have two steps:

  1. commit_creds(prepare_kernel_cred(0)) for elevating privilege in kernel mode.
  2. system("/bin/sh") for getting shell in user mode

So we can control return address to executecommit_creds(prepare_kernel_cred(0)) in bug2_write function kernel mode.
But stack is trashed, so we can’t return normally. We could fix up the stack, but that’s boring.
Instead, let’s jump directly to user mode.

System call mechanism

Normal function calls:

  • Use instructions call and ret
  • Hardware saves return address on the stack

User → kernel calls: (ignoring some alternatives)

  • Use instructions int and iret
  • Hardware saves a “trap frame” on the stack

Our program should iret from kernel mode .
Ring0 -> Ring3 ,we first in kernel mode , use kernel stack ,when switch to running as a less-privileged user mode ,stack will switch to user stack. So we need to save our state information in the struct trap frame first when we go to kernel mode.

trap frame

Trap frame save on stack, we return to user mode, our user stat get from it.

We build a fake trap frame in our exploit, save all the stat information in it and change eip to execve("/bin/sh") address, when we return from kernel mode ,we will spawn a Root shell.
Our exploit as below:

In our exploit,

  1. Elevate privilege: as in user mode ,control return address to execute commit_creds(prepare_kernel_cred(0)) to have a ROOT, and then prepare for iret to set fake trap frame on right position.
  2. Get shell: we build a fake trap frame in use mode stack tf, and function prepare_tf() save the stat : CS,EFLAGS,ESP,SS to trap frame and change EIP=&launch_shell

debug

Ensure module .text address frist.

Run qemu , add symbols file to gdb (only .text is enough) and then we can set breakpoint in stack_smashing.ko.

As below, buffer overflow to cover return address to payload() fcuntion.

Saved fake trap frame (The state of user proc exp) as below.
EIP=0x80f112c
CS=0xbf9f0073
EFLAGS=0x282
ESP=0xbf9fcb68
SS =0xbf9f007b

When executed ireteip=0x8048ee0 the address of lanuch_shell, corresponding register have been set.

At the end, execute to get a Root shell.


Yes, we get ROOT.

Mitigate

Modern Linux kernels protect the stack with a “canary” value On function return, if canary was overwritten, kernel panics
Just like in user mode.
Prevents simple attacks, but there’s still a lot you can do.

References

Linux内核漏洞利用(二)NULL Pointer Dereference
Linux 内核漏洞利用教程(二):两个Demo
mmap_min_addr
write-kernel-exploits

发表评论