441 bytes, text/html
Proof of concept: tiny Python web server that ignores request headers completely, and just serves a page.
810 bytes, text/plain
1.79 KB, text/plain
1.98 KB, application/octet-stream
2.37 KB, text/plain
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.
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.
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.
Created attachment 196316 [details] Proof of concept: tiny Python DNS server that always spoofs same address
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.
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.
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.
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 ***
Status: NEW → RESOLVED
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 behavior.
Status: RESOLVED → REOPENED
Resolution: DUPLICATE → ---
Assignee: nobody → gerv
Status: REOPENED → NEW
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
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-
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
Last Resolved: 13 years ago → 13 years ago
Resolution: --- → DUPLICATE
You need to log in before you can comment on or make changes to this bug.