Character U+FF0F appears to allow URL spoofing




13 years ago
12 years ago


(Reporter: usenet, Assigned: darin.moz)


(Blocks: 1 bug)

Bug Flags:
blocking1.8b5 -

Firefox Tracking Flags

(Not tracked)


(Whiteboard: [sg:dupe 316444])


(5 attachments)



13 years ago
1 Put www.pyth/ 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/ link at
left (where the wide slash character is Unicode character U+FF0F, FULLWIDTH


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/ Port 80

with the location bar reading "http://www.pyth/", 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.

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.

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

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/ (again with the slash character being an ASCII 0x2f).

* 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,
* attacker registers the domain, and point its at this DNS resolver
* attacker sends out phishing messages containing "http:
* waits users to click on it, see web content delivered with the location bar
* 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.
* 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

Comment 1

13 years ago
Created attachment 196304 [details]
Test HTML file containing URL examples

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.

Comment 2

13 years ago
Created attachment 196310 [details]
Proof of concept: tiny Python web server that ignores request headers completely, and just serves a page.

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.

Comment 3

13 years ago
Created attachment 196316 [details]
Proof of concept: tiny Python DNS server that always spoofs same address

Comment 4

13 years ago
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/

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


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

<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
<hr />
<address>Apache/2.0.49 (Linux/SuSE) Server at www.pyth/ Port 80</address>

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

Comment 5

13 years ago
No, it looks like I was right the first time. I hadn't removed the
www.pyth/ 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.

Comment 6

13 years ago
Created attachment 196322 [details]
Libpcap dump of malformed DNS behavior, captured by ethereal

Enclosed, the libpcap dump referred to in the previous comment. More to come.

Comment 7

13 years ago
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.

Comment 8

13 years ago
Created attachment 196327 [details]
Updated version of tiny DNS server, generates "no such name" for all but A-record queries

See comment above.
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
Last Resolved: 13 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
Group: security
Resolution: DUPLICATE → ---
Whiteboard: [sg:fix]
Assignee: nobody → gerv
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


13 years ago
Flags: blocking1.8b5? → blocking1.8b5+
Whiteboard: [sg:fix] → [sg:spoof]
Why did this get assigned to me? :-)

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?


Comment 14

13 years ago
Darin, so are we covered here as far as the security concern goes, as Gerv
suggests in comment #13?
Assignee: gerv → darin

Comment 15

13 years ago
After talking with Darin, we're going to push this out to after the beta2 (first
Flags: blocking1.8b5+ → blocking1.8b5-


13 years ago
Blocks: 316730

Comment 16

13 years ago
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 ***
Last Resolved: 13 years ago13 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.