Re: CVE-2009-3094, CVE-2009-3095: mod_proxy_ftp issues
On Sat, Sep 12, 2009 at 10:43:29PM +0200, Stefan Fritsch wrote: On Fri, 11 Sep 2009, Joe Orton wrote: +char *p = ap_strchr(reply, '('), *ep, *term; +long port; + +/* Reply syntax per RFC 2428: 229 blah blah (|||port|) where '|' + * can be any character in ASCII from 33-126, obscurely. Verify + * the syntax. */ +if (p == NULL || p[1] != p[2] || p[1] != p[3] +|| (ep = strchr(p + 4, ')')) == NULL +|| ep == p + 4 || ep[-1] != p[1]) { +return 0; +} Shouldn't you also check for p[1] != 0 before p[1] != p[2], to catch the case where reply ends after the opening bracket? Yes indeed! Thanks a lot. I've rewritten that code slightly, tested again, and committed here: http://svn.apache.org/viewvc?view=revrevision=814652 I've not touched the PASV code in that commit, since there doesn't seem to be a security issue there, ugly as the code is. Regards, Joe
Re: CVE-2009-3094, CVE-2009-3095: mod_proxy_ftp issues
Shouldn't you also check for p[1] != 0 before p[1] != p[2], to catch the case where reply ends after the opening bracket? This should be p[1] == 0, of course.
Re: CVE-2009-3094, CVE-2009-3095: mod_proxy_ftp issues
On Fri, 11 Sep 2009, Joe Orton wrote: +char *p = ap_strchr(reply, '('), *ep, *term; +long port; + +/* Reply syntax per RFC 2428: 229 blah blah (|||port|) where '|' + * can be any character in ASCII from 33-126, obscurely. Verify + * the syntax. */ +if (p == NULL || p[1] != p[2] || p[1] != p[3] +|| (ep = strchr(p + 4, ')')) == NULL +|| ep == p + 4 || ep[-1] != p[1]) { +return 0; +} Shouldn't you also check for p[1] != 0 before p[1] != p[2], to catch the case where reply ends after the opening bracket? Apart from that, both this patch and the one you have already commited look fine. I haven't actually tested them, though. Stefan
Re: CVE-2009-3094, CVE-2009-3095: mod_proxy_ftp issues
On Thu, Sep 10, 2009 at 07:02:01PM +0200, Stefan Fritsch wrote: in case you haven't noticed yet, some new mod_proxy_ftp issues have been reported: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3094 The ap_proxy_ftp_handler function in modules/proxy/proxy_ftp.c in the mod_proxy_ftp module in the Apache HTTP Server 2.0.63 and 2.2.13 allows remote FTP servers to cause a denial of service (NULL pointer dereference and child process crash) via a malformed reply to an EPSV command. Hi Stefan, thanks for posting. These changes look good. Jeff noted on security@ that there is also a more specific problem with the parsing of the PASV/EPSV responses, which can read past the end of the string for a malformed response. I propose the following patch which: a) correctly parses EPSV responses following the RFC (I ripped off the code I wrote for sitecopy to do this) b) parses PASV responses less badly c) fixes the apr_socket_close(NULL) error pathsper your patch, and a later one which was pointed out by Tomas Hoger, though that one should not strictly be unnecessary I'll have a look at the other CVE next. This 1100-line trainwreck of a function should definitely win some kind of prize. Index: mod_proxy_ftp.c === --- mod_proxy_ftp.c (revision 813335) +++ mod_proxy_ftp.c (working copy) @@ -683,6 +683,34 @@ return APR_SUCCESS; } +/* Parse EPSV reply and return port, or zero on error. Modifies + * 'reply'. */ +static apr_port_t parse_epasv_reply(char *reply) +{ +char *p = ap_strchr(reply, '('), *ep, *term; +long port; + +/* Reply syntax per RFC 2428: 229 blah blah (|||port|) where '|' + * can be any character in ASCII from 33-126, obscurely. Verify + * the syntax. */ +if (p == NULL || p[1] != p[2] || p[1] != p[3] +|| (ep = strchr(p + 4, ')')) == NULL +|| ep == p + 4 || ep[-1] != p[1]) { +return 0; +} + +/* ...ep points to the closing ) */ +errno = 0; +port = strtol(p + 4, term, 10); +/* The integer portion must terminate at the byte before the + * closing ). */ +if (term != ep - 1 || errno || port 1 || port 65535) { +return 0; +} + +return (apr_port_t)port; +} + /* * Generic send FTP command to server routine, using the control socket. * Returns the FTP returncode (3 digit code) @@ -1291,26 +1319,11 @@ return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage); } else if (rc == 229) { -char *pstr; -char *tok_cntx; +/* Parse the port out of the EPSV reply. */ +data_port = parse_epasv_reply(ftpmessage); -pstr = ftpmessage; -pstr = apr_strtok(pstr, , tok_cntx);/* separate result code */ -if (pstr != NULL) { -if (*(pstr + strlen(pstr) + 1) == '=') { -pstr += strlen(pstr) + 2; -} -else { -pstr = apr_strtok(NULL, (, tok_cntx);/* separate address - * port params */ -if (pstr != NULL) -pstr = apr_strtok(NULL, ), tok_cntx); -} -} - -if (pstr) { +if (data_port) { apr_sockaddr_t *epsv_addr; -data_port = atoi(pstr + 3); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r-server, proxy: FTP: EPSV contacting remote host on port %d, @@ -1351,10 +1364,6 @@ connect = 1; } } -else { -/* and try the regular way */ -apr_socket_close(data_sock); -} } } @@ -1381,26 +1390,13 @@ char *pstr; char *tok_cntx; -/* FIXME: Check PASV against RFC1123 */ +/* Find the last opening bracket; this mostly works in + * practice though is not strictly required, as noted in + * RFC 1123 section 4.1.2.6, */ +pstr = strrchr(ftpmessage, '('); -pstr = ftpmessage; -pstr = apr_strtok(pstr, , tok_cntx);/* separate result code */ -if (pstr != NULL) { -if (*(pstr + strlen(pstr) + 1) == '=') { -pstr += strlen(pstr) + 2; -} -else { -pstr = apr_strtok(NULL, (, tok_cntx);/* separate address - * port params */ -if (pstr != NULL) -pstr = apr_strtok(NULL, ), tok_cntx); -} -} - -/* FIXME: Only supports IPV4 - fix in RFC2428 */ - if (pstr != NULL (sscanf(pstr, - %d,%d,%d,%d,%d,%d, h3, h2, h1, h0, p1, p0) == 6)) { +
Re: CVE-2009-3094, CVE-2009-3095: mod_proxy_ftp issues
On 09/11/2009 04:52 PM, Joe Orton wrote: On Thu, Sep 10, 2009 at 07:02:01PM +0200, Stefan Fritsch wrote: The (untested) patch below should fix CVE-2009-3094. For CVE-2009-3095 there is only little information. But looking at the code, it seems the username and password sent by the browser are sent to the ftp server without sanitization (i.e. they can contain LF characters). Spot on, good catch. using Authorization: Basic RkVBVApGRUFUCg== results in: read(11, 220 (vsFTPd 2.0.6)\r\n, 8000) = 20 write(2, [Fri Sep 11 15:46:18 2009] [debu..., 88) = 88 writev(11, [{USER FEAT\nFEAT\n\r\n, 17}], 1) = 17 write(2, [Fri Sep 11 15:46:18 2009] [debu..., 87) = 87 I think this should be sufficient - any other characters it's worth filtering for? Seems sufficient to me. Don't we need to this as well a few lines below for username and password fetched from the URL? else if ((user = r-parsed_uri.user) != NULL) { user = apr_pstrdup(p, user); decodeenc(user); if ((password = r-parsed_uri.password) != NULL) { char *tmp = apr_pstrdup(p, password); decodeenc(tmp); password = tmp; } } Couldn't the username / password part of the URL contain %0A / %OD? Regards RĂ¼diger
Re: CVE-2009-3094, CVE-2009-3095: mod_proxy_ftp issues
On Fri, Sep 11, 2009 at 10:51:11PM +0200, Ruediger Pluem wrote: On 09/11/2009 04:52 PM, Joe Orton wrote: On Thu, Sep 10, 2009 at 07:02:01PM +0200, Stefan Fritsch wrote: The (untested) patch below should fix CVE-2009-3094. For CVE-2009-3095 there is only little information. But looking at the code, it seems the username and password sent by the browser are sent to the ftp server without sanitization (i.e. they can contain LF characters). Spot on, good catch. using Authorization: Basic RkVBVApGRUFUCg== results in: read(11, 220 (vsFTPd 2.0.6)\r\n, 8000) = 20 write(2, [Fri Sep 11 15:46:18 2009] [debu..., 88) = 88 writev(11, [{USER FEAT\nFEAT\n\r\n, 17}], 1) = 17 write(2, [Fri Sep 11 15:46:18 2009] [debu..., 87) = 87 I think this should be sufficient - any other characters it's worth filtering for? Seems sufficient to me. Don't we need to this as well a few lines below for username and password fetched from the URL? ... Couldn't the username / password part of the URL contain %0A / %OD? It seems that the code already catches that case - proxy_ftp_canon extracts username/password and does: if (user != NULL !ftp_check_string(user)) return HTTP_BAD_REQUEST; if (password != NULL !ftp_check_string(password)) return HTTP_BAD_REQUEST; where ftp_check_string() checks specifically for CR/LF. I hadn't spotted ftp_check_string() before but clearly that should be used for the check here too - I'll adjust the patch and commit that part since it's less complicated than the other issue. Regards, Joe
CVE-2009-3094, CVE-2009-3095: mod_proxy_ftp issues
Hi, in case you haven't noticed yet, some new mod_proxy_ftp issues have been reported: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3094 The ap_proxy_ftp_handler function in modules/proxy/proxy_ftp.c in the mod_proxy_ftp module in the Apache HTTP Server 2.0.63 and 2.2.13 allows remote FTP servers to cause a denial of service (NULL pointer dereference and child process crash) via a malformed reply to an EPSV command. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3095 The mod_proxy_ftp module in the Apache HTTP Server allows remote attackers to bypass intended access restrictions and send arbitrary commands to an FTP server via vectors related to the embedding of these commands in the Authorization HTTP header, as demonstrated by a certain module in VulnDisco Pack Professional 8.11. The (untested) patch below should fix CVE-2009-3094. For CVE-2009-3095 there is only little information. But looking at the code, it seems the username and password sent by the browser are sent to the ftp server without sanitization (i.e. they can contain LF characters). Cheers, Stefan --- a/modules/proxy/mod_proxy_ftp.c +++ b/modules/proxy/mod_proxy_ftp.c @@ -1351,10 +1351,6 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, connect = 1; } } -else { -/* and try the regular way */ -apr_socket_close(data_sock); -} } } @@ -1441,10 +1437,6 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, connect = 1; } } -else { -/* and try the regular way */ -apr_socket_close(data_sock); -} } } /*bypass:*/
Re: CVE-2009-3094, CVE-2009-3095: mod_proxy_ftp issues
Stefan Fritsch wrote: Hi, in case you haven't noticed yet, some new mod_proxy_ftp issues have been reported: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3094 The ap_proxy_ftp_handler function in modules/proxy/proxy_ftp.c in the mod_proxy_ftp module in the Apache HTTP Server 2.0.63 and 2.2.13 allows remote FTP servers to cause a denial of service (NULL pointer dereference and child process crash) via a malformed reply to an EPSV command. The security list is discussing this issue. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3095 The mod_proxy_ftp module in the Apache HTTP Server allows remote attackers to bypass intended access restrictions and send arbitrary commands to an FTP server via vectors related to the embedding of these commands in the Authorization HTTP header, as demonstrated by a certain module in VulnDisco Pack Professional 8.11. The (untested) patch below should fix CVE-2009-3094. For CVE-2009-3095 there is only little information. But looking at the code, it seems the username and password sent by the browser are sent to the ftp server without sanitization (i.e. they can contain LF characters). While we should fix this, this is likely to be a FTP bug; FTP commands must be CRLF terminated, as spelled out in RFC854, RFC959 and later clarified further by RFC1123. If we transliterate LF to CRLF then this is an httpd mod_proxy_ftp issue, of course, and we should sanitize the data. As these are already disclosed, the final patches will simply be committed and discussion will move to this list.