Closed Bug 308800 Opened 18 years ago Closed 18 years ago

Character U+FF0F appears to allow URL spoofing

Categories

(Core :: Networking, defect)

x86
Linux
defect
Not set
major

Tracking

()

RESOLVED DUPLICATE of bug 316444

People

(Reporter: usenet, Assigned: darin.moz)

References

(Blocks 1 open bug)

Details

(Whiteboard: [sg:dupe 316444])

Attachments

(5 files)

1 Put www.pyth/on.info in your /etc/hosts file, mapped to 127.0.0,1. 
2 Run a local Apache webserver.
3 Visit the attached HTML page. Click on the http://www.pyth/on.info link at
left (where the wide slash character is Unicode character U+FF0F, FULLWIDTH
SOLIDUS. 

WHAT HAPPENS: 

Apache returns:
> Bad Request
>
>Your browser sent a request that this server could not understand.
> Apache/2.0.49 (Linux/SuSE) Server at www.pyth/on.info Port 80

with the location bar reading "http://www.pyth/on.info/", with the inserted
slash character (as verified by cut-and-paste from the location bar, and hex
dumping) again being a normal ASCII 0x2f slash character. Hovering over the link
also gives the same apparent URL.

WHAT SHOULD HAPPEN:
At the very least, the page should be blocked because the hostname is malformed.
DNS labels with 0x2f in them are neither valid standard LDH domain names (per
RFC 1035), nor are they valid Punycode encodings. 

RFC1035 wording:
> The labels must follow the rules for ARPANET host names.  They must
> start with a letter, end with a letter or digit, and have as interior
> characters only letters, digits, and hyphen.  There are also some
> restrictions on the length.  Labels must be 63 characters or less.

PROBLEM:
Sniffing the packets shows that Firefox connects to the webserver at 127.0.0.1,
and sends it a request for
  
> GET / HTTP/1.1
> Host: www.pyth/on.info

where the / character is an ASCII 0x2f in each case. 

This example uses a line in /etc/hosts to define the domain name. However,
removing this line reveals that Firefox is more than happy to attempt to resolve
this name, and will put DNS queries for names with slashes in on the wire. 

Removing the line in /etc/hosts  shows that Firefox actually generates DNS
requests for www.pyth/on.info (again with the slash character being an ASCII 0x2f).

POSSIBLE PHISHING EXPLOIT:
* attacker runs a Web server that does not regard hostnames with "/" in them as
an error
* attacker runs a DNS resolver at which is happy to resolve names with a "/" in
them, specifically, www,python.org/login
* attacker registers the screen.info. domain, and point its at this DNS resolver
* attacker sends out phishing messages containing "http:
//www.paypal.com/login.screen.info/login"
* waits users to click on it, see web content delivered with the location bar
saying http://www.paypal.com/login.screen.info/login"
* attacker phishes users' private information

Note that writing the name resolver / web server is easy, either by hacking
existing applications like BIND and Apache, or by writing trivial DNS and HTTP
client which almost completely ignore the content of requests, and just send out
the spoofed responses.
 
PROPOSED FIX:
* check within Necko that DNS names _only_ contain the characters
[A-Za-z0-9\-\.] before being looked up at low level. This check should occur
_after_ all URL processing, FQDN canonicalization, IDN processing etc. has been
performed, by performing it at the domain name resolver library entry point.
Generate an error code for all non-conforming names.

It might also be interesting to investigate why this special case gets through
the current URL/IDN/DNS processing code, but it's better to fix this at the low
level by enforcing the RFC, rather than trying to find and fix special cases
one-at-a-time.
This HTML file contains a test case for this bug. Don't forget to modify
/etc/hosts as specified in the bug report first. Try both links: you will get
different behaviour.
Proof of concept testing: This is a tiny Python web server that ignores request
headers completely, and just serves a page. You'll need to hard code the IP
address into this.
OK. After a lot of packet dumping, it looks like I was wrong about the DNS part
of this, and this is not nearly as severe as I thought.

The DNS lookup does not appear to have a slash in, as I thought (although I
could have sworn I saw it earlier; is there any way of turning off the DNS
caching?). Instead, the FQDN is terminated at the slash, and "www.pyth" is what
is looked up.

However, the reason why I came to this conclusion does appear to be caused by a
bug. When visiting the URL with the long slash in, the apparent FQDN fed to the
webserver appears to first have been normalized, converting the long slash to a
normal slash, and then passed out _including the slash_ to the web server in the
HTTP Host: header, thus:

GET / HTTP/1.1

Host: www.pyth/on.info

User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b4) Gecko/20050907
Firefox/1.4

Accept:
text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5

Accept-Language: en-us,en;q=0.5

Accept-Encoding: gzip,deflate

Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7

Keep-Alive: 300

Connection: keep-alive



HTTP/1.1 400 Bad Request

Date: Fri, 16 Sep 2005 13:49:57 GMT

Server: Apache/2.0.49 (Linux/SuSE)

Content-Length: 314

Connection: close

Content-Type: text/html; charset=iso-8859-1



<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr />
<address>Apache/2.0.49 (Linux/SuSE) Server at www.pyth/on.info Port 80</address>
</body></html>

Apache then dutifully echoes the result back, slash and all. Having the FQDN fed
to the server and the FQDN fed to the DNS system is probably a bad thing, but I
can't instantly work out an exploit based on it.

Severity: critical → major
No, it looks like I was right the first time. I hadn't removed the
www.pyth/on.info entry in my /etc/hosts. Having done so, I managed to capture
the malformed DNS requests using ethereal. So it looks like the bug may be real
after all.
Enclosed, the libpcap dump referred to in the previous comment. More to come.
OK, at the moment, it looks like if the malformed DNS request is answered,
there's no subsequent TCP connection attempt, and you don't get a page. So, it's
sort of "safe by luck". (On the other hand, if it isn't answered, do you get the
lookup of www.pyth?)

However, there are some _really strange_ things going on here, and it's going to
take some time to try all the variations. 

Please can someone have a go at replicating this, by simply clicking on the left
link in the testcase, _without_ either a DNS spoofer or an /etc/hosts entry, and
capturing the packet stream generated.

I'll attach the latest version of the tiny DNS server, which now knows not to
answer queries for anything but A records, below.
Duplicate of bug 301694 (beyond the overly-specific summary the patch itself
includes several other characters including U+FF0F)

*** This bug has been marked as a duplicate of 301694 ***
Group: security
Status: NEW → RESOLVED
Closed: 18 years ago
Resolution: --- → DUPLICATE
Reopening. I've misunderstood the issue, FF0F seems to be converted into a real
0x2F somewhere along the way, and according to Neil (via mail) the patch in bug
301694 does not fix the problem.

-------from mail--------
I was the person who added the patch for bug 301694. The filing of this bug was
based on _my testing of that patch:_ it blocked all of the funny characters but
one, which created very peculiar behavior. Hence the very specific mention of
that one character.

The characters specified in 301694 are all potential visual spoofs, but apart
from this one all appear to be Punycoded correctly. However, this _particular_
character, unlike the others, appears to do something really strange to the
processing of URLs and DNS requests, as witness the malformed DNS lookups
generated, and the malformed host name passed to in the Host: header of the HTTP
request. Unlike the other characters, this seems to be bypassing the IDN logic,
and ending up being converted into a slash within a DNS label. This occurs _even
after the patch for 301694 is applied_, which is unsurprising as that patch only
affects DNS display of domain name labels, not the logic of DNS processing.

See the Ethereal dump attached in comment #6 in bug 308800 as evidence.

This is bad. Note that the DNS lookup is malformed: a FQDN with a slash in it is
never valid, either in a standard ASCII lookup, or in a Punycoded lookup. See
RFC 1035. Similarly, a malformed host address should never be passed in an HTTP
call. Fortunately, at the moment, I can't get a page load to occur when the
malformed DNS entry is responded to, so at the moment it looks difficult to
exploit. But this looks like "security through luck", rather than security by
design, and there may be a real exploit possible by exploiting this or similar
behavior.
Group: security
Status: RESOLVED → REOPENED
Resolution: DUPLICATE → ---
Whiteboard: [sg:fix]
Assignee: nobody → gerv
Status: REOPENED → NEW
Flags: blocking1.8b5?
Bug 304904 might help.
Component: Security → Networking
Product: Firefox → Core
Summary: Character U+FFOF appears to allow URL spoofing → Character U+FF0F appears to allow URL spoofing
Version: unspecified → Trunk
Flags: blocking1.8b5? → blocking1.8b5+
Whiteboard: [sg:fix] → [sg:spoof]
Why did this get assigned to me? :-)

Gerv
We now have an ASCII character blacklist which is applied before DNS resolving.
This was added in bug 304904. Here is the branch version of the patch:

+    const char* bad = net_FindCharInSet(hostname, end,
+                                        "\x01\x02\x03\x04\x05\x06\x07\x08"
+                                        "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
+                                        "\x11\x12\x13\x14\x15\x16\x17\x18"
+                                        "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
+                                        "\x21\x22\x23\x25\x26\x27\x28\x29"
+                                        "\x2a\x2b\x2c\x2f\x3b\x3c\x3d\x3e"
+                                        "\x3f\x40\x5c\x5e\x7b\x7c\x7e\x7f");

Even if we have bugs which allows the / character to make it through to the DNS
resolver, this should stop the lookup from happening (/ is 2f, which is on the
list). Does that deal with the security part of this bug?

Gerv
Darin, so are we covered here as far as the security concern goes, as Gerv
suggests in comment #13?
Assignee: gerv → darin
After talking with Darin, we're going to push this out to after the beta2 (first
RC).
Flags: blocking1.8b5+ → blocking1.8b5-
Blocks: 316730
Whilst the particular example given here has now been fixed by refining the DNS output character filter rules, this does not yet solve the general case of the underlying problem.

Resolving bug 316444 _will_ however fix the larger problem of which this is a special case. Therefore, I'm marking what remainst of this bug as a dup of 316444.


*** This bug has been marked as a duplicate of 316444 ***
Status: NEW → RESOLVED
Closed: 18 years ago18 years ago
Resolution: --- → DUPLICATE
Whiteboard: [sg:spoof] → [sg:dupe 316444]
Group: security
You need to log in before you can comment on or make changes to this bug.