ProFTPd Local pr_ctrls_connect Vulnerability - ftpdctl 漏洞及攻击代码分析

攻击代码网址:http://www.exploit-db.com/exploits/394/


1、运行环境:
1、ProFTPD 1.3.0/1.3.0a
2、编译ProFTPD时,--enable-ctrls选项必须打开
./configure --enable-ctrls
2、运行参数:
root@kali:~# gcc 394.c -o 394
root@kali:~# ./394 –s <option> [-p <option_path>] [-o <option_offset>]
参数-s后的值是攻击的两种不同的方式,值有1和2可以选择。第1种方式使用当前环境,第2种方式是使用ret-to-libc的方式。
注:return-to-libc 攻击中,其堆栈中的返回地址被替换为另一条指令的地址,并且堆栈的一部分被覆盖以提供其参数。这允许攻击者调用现有函数而无需注入恶意代码到程序中。
参数 -o参数-p无太大意义。仅仅是帮助使用该攻击代码。
3、代码分析
代码执行命令为:root@kali:~# ./394 –s 1
3.1分析程序参数

程序的第236行,是对394.c程序运行时的参数进行分析。getopt(int argc, char * const argv[ ], const char * optstring)用来分析命令行参数。参数argc和argv是由main()传递的参数个数和内容。参数optstring 则代表欲处理的选项字符串。选项字符串里的字母后接着冒号“:”,则表示还有相关的参数,全域变量optarg 即会指向此额外参数。然后下面就是针对不同的参数进行处理,由于最终起作用的只有-s一个参数,下面将着重的分析-s参数。
getopt处理到-s参数后,由于optstring中冒号“:”的存在,optarg会指向-s的下一个参数,也就是1。然后程序在246行将该参数值赋值给变量wybor,等待下一步处理。

3.2确定参数的有效性
由于394.c程序只提供了2种漏洞攻击方式,所以程序中241行会将-s后的参数值限定为1或2,其他的任何值都视为非法,将导致程序直接退出。

此外,程序中的另一个变量path,用于指定漏洞程序的绝对路径,值默认为/usr/local/bin/ftpdctl。也正是ProFTPD服务器的ftpdctl中调用了ctrls.c中的pr_ctrls_connect()函数,而该函数中的一个strncpy()是该漏洞的缓冲区溢出点。在394.c的267行通过fopen()打开文件的方式确定,该路径下的文件是否有效。

3.3构造溢出数据并执行攻击
最终实施攻击的语句是298行和324行的execle(path,path,"-s",buf,0,sh);
int execle(const char *path, const char *arg, ..., char * const envp[]);
用execle函数可以把当前进程替换为一个新进程,path参数表示你要启动程序的名称包括路径名,arg参数表示启动程序所带的参数,一般第一个参数为要执行命令名。将环境变量传递给需要替换的进程envp保存环境信息的数据
变量buf用于存放溢出数据,除了大量的无意义数据,最重要的是有/bin/sh的入口地址。当缓冲区溢出后,程序会被引导,跳转到/bin/sh,从而能执行任意指令。
构造溢出数据主要涉及到两个变量:buf[229]和sh[2],由于-s后的参数(1或2)决定了利用漏洞的两种不同方式,下面将针对这两种方式分开描述:
方式1也就是wybor=1时,buf中除了前两个字节数据”/A”,其余227个字节全部为/bin/sh的入口地址,如图。

envp[]则是使用0x90作为填充字符,并在末尾写入事先构造好的shellcode。shellcode的主要作用是执行: setuid(0)、setgid(0)、/bin/sh和exit(0)。

方式2也就是wybor=2时,由于使用ret-to-libc的方式,buf中的数据除了第一个字节为‘/’,最后3字节依次为LIBC_SYSTEM地址、LIBC_NEXT__地址和/BIN/SH地址以外,其余225个字节均为填充字符0x41。

envp[]是使用‘’’作为填充字符并在结尾写入字符串”/bin/sh”。

3、分析结果
由上面的分析,可以看出,394.c程序主要是通过直接调用ProFTPD服务器的命令ftpdctl -s来对漏洞实施攻击。之所以是这样,那是因为,命令ftpdctl中需要与服务器建立本地socket连接来进行进程间的通信,建立socket连接的时候,ftpdctl.c调用了在ctrls.c中874行定义的函数pr_ctrls_connect(char *socket_file)。
pr_ctrls_connect(char *socket_file)的主要作用是,创建AF_UNIX类型的流式套接字,并连接到服务器,用于连接的本地套接字地址为ctrl_sock。而ctrl_sock是struct sockaddr_un结构,它有两个参数sun_family、sun_path。sun_family是协议族,赋值为AF_UNIX,用于本地进程间通信。sun_path是本地文件的路径,在程序中使用socket_file对sun_path赋值。不幸的是在进行赋值时,使用了没有检查数据边界的strncpy(),可以看到在程序的923行写入内存的函数为strncpy(ctrl_sock.sun_path,socket_file,strlen(socket_file)),很显然这个函数并没有对写入的数据进行边界检查,也就是说可以向大小为sizeof(ctrl_sock)的内存区域写入任意长度的数据。ctrl_sock是在函数pr_ctrls_connect()中定义的局部变量,发生函数调用时计算机会在动态存储区为之开辟大小为sizeof(ctrl_sock)的内存存储区,与此同时动态存储区也会用于保存函数调用时的现场信息和函数返回地址,这就为缓冲区溢出攻击创造了条件。也正如394.c源码注释中所说,我们可以通过控制socket_file的长度来使缓冲区发生溢出。
的确394.c正是利用这个漏洞,构造了含有/bin/sh返回地址的超长数据,在调用ftpdctrl时使用参数-s来替换正常的socket_file路径。当ctrls.c执行strncpy()时,这个超长的shellcode使得缓冲区溢出,从而转去执行/bin/sh,以此来达到攻击的目的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章