Closed Bug 240053 Opened 21 years ago Closed 21 years ago

SSL Certificate Spoof -- Allows malicious page to present SSL certificate from another site

Categories

(Core :: Security, defect, P1)

x86
Windows XP
defect

Tracking

()

RESOLVED FIXED
mozilla1.7final

People

(Reporter: tolga, Assigned: darin.moz)

References

()

Details

(Keywords: fixed1.4.3, Whiteboard: [sg:fix])

Attachments

(7 files, 1 obsolete file)

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322) Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 I believe I have discovered a potential security vulnerability in Mozilla 1.6 and FireFox 0.8. It is likely that the bug also extends to other versions of Mozilla. The bug is a confidence-hack of sorts, allowing a malicious page to appear encrypted and present the certificate of another site. Reproducible: Always Steps to Reproduce: 1. Create a page on a non-SSL server that has a JavaScript or META redirect to the SSL-site whose certificate you want to spoof. 2. Your redirect should go to a script on that SSL-site that will redirect you somewhere else, and you need to be able to control where. 3. Have the SSL-site redirect the browser to an invalid domain (something syntactically invalid like http://a.b&c) 4. Use FireFox 0.8 to browse to the page you created in step 1. 6. An error will popup in FireFox. Click ok. 7. Your browser will still be on the original page from step 1 but the security- lock icon will still be on in the lower-left corner of FireFox. 8. Click the security icon and click the "View" button to view the certificate. 9. FireFox will present the certificate from the SSL-enabled site. I've created a simple test-case of the above scenario. I simply searched on Google for "redirect.cfm" to find any site with a common ColdFusion redirect script. I found emailfactory.com as the third result in Google. Then I created a page to redirect the browser to https://www.emailfactory.com/redirect.cfm?redirect=a.b&c. This makes emailfactory.com redirect the browser to a.b&c, which is invalid and causes Mozilla to remain on the current page and display a domain not found error. You can view this example at: http://www.ttar.org/test.html Actual Results: Mozilla's security icon remained on and clicking it showed the certificate of the spoofed SSL site. While there is an error popup notifying the user that Mozilla could not resolve the domain, that warning is likely not enough for the average user to realize that the security-icon and certificate visible on the page are invalid. Expected Results: The security icon shouldn't be on. This bug has also been emailed to security@mozilla.org
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: blocking1.7?
Priority: -- → P1
Target Milestone: --- → mozilla1.7final
Darin, any thoughts on this?
To make the spoof complete, you should initially link to <https://www.emailfactory.com/redirect.cfm?redirect=www.ttar.org/test.html>. FYI, the attack does not work when you're behind a proxy, because the proxy will return (and Mozilla will display) an error page, replacing the old content.
Flags: blocking1.7? → blocking1.7+
Just an FYI -- Netscape Navigator 7.1 (and likely other versions) is also vulnerable. In Netscape, the security icon does not turn-on, but if you click on the "unlocked" security icon, it will still show the cert that belongs to the spoofed site. It's very likely that almost anybody embedding Mozilla needs to address this issue.
Not an NSS bug.
Adding PSM owner to CC list
With the seamonkey trunk, I get a dialog telling me that I am leaving an encrypted site and entering an unencrypted site. Next, I get a dialog telling me that the host a.b&c could not be found. Finally, I am left with the lock icon set and the old page content. So, this bug is definitely not Firefox specific. I'm collecting a nsSecureBrowserUI NSPR log now to see if I spot anything in there. I also confirmed this bug on the Mozilla 1.4 branch.
Most people quickly turn off the "entering" and "leaving" warning dialogs so they'd only see the host not found error. For bonus points make the invalid host a typical adserver name and people would actually be glad to see it thinking they're getting one less ad somewhere. combine with user@host spoof urls and phishing attacks become that much more effective. When I opened page info (in Mozilla) it said explicitly that the site www.ttar.org supports authentication for the page. Only if you view the certificate itself do you see it's a different site.
Things just got much worse: I’ve found a way to use this exploit without having the “host not found” dialog popup. It’s done using simple JavaScript. First, you call setTimeout() with about a one second timeout before you set document.location. Then, the function called by the timeout just calls window.stop(). If the timing is right, window.stop() will get called after the redirect has comeback from the spoofed site, but before the host not found dialog pops-up. The result is the same as the original exploit, but without the suspicious popup. I’ve combined the above with a much more convincing spoof. Try going to this URL and imagine that the “Click here” link on this page was placed wisely in a well-crafted (but fake) email: http://www.ttar.org/test_aol.html Notice that you’re not really at aol.com when you get the AOL main page – which contains a login form. However, unlike normal user@host spoofs, this one has the security-icon show-up as locked AND if you view the certificate, it shows that it belongs to America Online. This would likely convince any novice user that they could safely login to this page. For completeness I’ve changed the action URL on the login form to a CGI at ttar.org that will print out the username and password that was entered on the form. This should demonstrate the full potential of this bug.
Here's a log file that I generated by adding PR_LOG statements to nsDocLoaderImpl::OnSecurityChange. It shows that there is no call to OnSecurityChange for http://a.b&c/. I think one solution to this bug would be to suppress OnSecurityChange calls for requests that report a failure status, but I need to think about that some more to be sure.
Assignee: security-bugs → darin
Status: NEW → ASSIGNED
Futher investigation reveals that this bug is triggered by the fact that nsHttpChannel makes calls to nsIProgressEventSink::OnProgress prior to processing its headers. As a result, the DocLoader observes the nsHttpChannel downloading content for the URL that results in a redirect. This causes the DocLoader to send STATE_TRANSFERRING notifications to its nsIWebProgressListener array. As a result, the nsSecureBrowserUI thinks that some content will be displayed for the https:// URL, and we end up with a lock icon. This can't be solved by the nsSecureBrowserUI since it cannot know (given our APIs) that the transferred data will actually never be displayed. Yes, it finds out later on that the URL was redirected (it sees a STATE_REDIRECTING event), but by then it is too late... some content was effectively (as far as its concerned) delivered to layout for rendering. I believe the correct solution to this bug is to suppress progress notification until the channel has received and processed its headers. I wrote a patch to do this and it works; however, there is one problem. We use OnProgress to cause the UI to be updated with progress of a form submission. That certainly corresponds to progress prior to receipt of response headers, and unfortunately our API does not provide an easy way for the observer to distinguish upload from download. Hmm.....
What we really need is a better API between Necko and the DocLoader... nsIProgressEventSink is so not sufficient! :-(
Actually, I can probably deal with the form submission problem by making DocLoader suppress OnStateChange from OnProgress until it receives an OnStatus with nsISocketTransport::STATUS_RECEIVING_FROM or nsITransport::STATUS_READING. Yeah, that might work well in absence of a better API.
On second thought, the form submission problem is perhaps less of an issue. In order to replicate this security bug using a form submission, the redirect would need to be of type 307 in order to preserve the HTTP method when following the redirect. However, a 307 requires user prompting, which we do. The user would therefore see a dialog asking them whether or not they wish to submit the contents of the form to the invalid URI. That may not be much protection. What do folks think? Should we worry about the form submission case? Tolga, can you modify your testcase so that it returns a 307 instead of a 302?
Attached patch v1 patch (obsolete) (deleted) — Splinter Review
This patch is sufficient to fix the bug as reported. It likely does not protect against the same scenario applied to a form submission redirected via a 307 response. NOTE: while RFC 2616 states that a user-agent should preserve the request method in response to a 302, it also comments that most user-agents treat a 302 like a 303. Mozilla likewise behaves contrary to spec for historical consistency.
Attachment #145762 - Flags: superreview?(jst)
Attachment #145762 - Flags: review?(cbiesinger)
Per Darin's request: http://ttar.org/test_form.html This page contains a form which, when submitted, will submit to an https URL that returns a 307 to an invalid domain. Also, if you'd like to cook-up your own test cases, I've created a script on a SSL-enabled site that will redirect you to any URL with any status code: https://app.pbnext.com/test/redirect.em?code=CODE&url=URL For example: https://app.pbnext.com/test/redirect.em?code=302&url=http://a.b&c
I tried my new test-case and viewed the form-redirect popup as you'd indicated. I do not believe this is sufficient for novice users. It only states that your form submission has been redirected, and that's not that unusual. Old Netscape used to say that on POST to a 302 and people just ignored it. Also, Mozilla does not show the URL that the client is being redirected to. This means the person will never see that it's invalid.
I've considered Darin's solution and the form problem in more depth and: a) If you think about it, the security lock should actually be on during a POST while data is uploaded to a secure site. This makes sense because the content is in-fact being sent over SSL. It's arguable that the lock icon should also come on during a GET while the request is sent to the server -- since the request is sent over SSL. b) However when the redirect comes through, the lock icon should turn off -- before the redirection actually starts. c) It occurs to me that the lock icon should be turned off at the beginning off each hit (even internally generated "hits", like a redirect) and turned back on after an SSL connection has been established and the certificate verified, etc. d) I don't know much about the Mozilla object model, but it appears that nsSecureBrowserUi should not assume that a page is secure just because the URL is an https:// URL. The security-status of a page should be more explicitly returned to the UI from the channel. This way, it can be turned off at the beginning of each hit and then turned-back on only after an SSL connection has been established. e) Again, I'm not familiar with the Mozilla code. I知 making assumptions only based on the comments posted in this bug.
Comment on attachment 145762 [details] [diff] [review] v1 patch nevermind this patch. i found a problem with it.
Attachment #145762 - Attachment is obsolete: true
Attachment #145762 - Flags: superreview?(jst)
Attachment #145762 - Flags: review?(cbiesinger)
So, the problem with the last patch was that it created the possibility that we wouldn't generate any progress notifications for a channel, and this in turn means that nsDocLoaderImpl wouldn't generate a STATE_TRANSFERRING event. That seems bad given the way the code in nsSecureBrowserUI works.
Attached patch v2 patch (deleted) — Splinter Review
Here is a more involved patch. It solves both the GET and POST versions of this bug. I ended up synthesizing OnProgress events in nsHttpChannel:: OnDataAvailable since this was the best way to ensure that the progress events occur when they should (i.e., closest to where the data is actually handed to "layout"). I reworked nsHttpTransaction::OnTransportStatus with the changes to nsHttpChannel in mind. So, it now only sends status messages to the nsHttpChannel when necessary. I also had to make changes to nsDocLoaderImpl to make it reset its progress totals when switching from reporting upload progress to download progress. A side effect of these changes is that bug 237958 is also fixed (due to synthesized OnProgress in OnDataAvailable).
Oh, one other comment: I also changed nsDocLoaderImpl so that its OnProgress implementation only calls OnStateChange when data is first downloaded. Previously, as I have mentioned above, it would call OnStateChange(STATE_TRANSFERRING) whenever any progress was reported by the channel. However, we need to do that only in the download case and not in the upload case. So, this requirement translated to me adding a new field to nsRequestInfo to flag whether or not we are currently uploading (based on the previous call to OnStatus).
Blocks: 237958
Comment on attachment 145782 [details] [diff] [review] v2 patch biesi: this is mostly what we talked about and then some ;-)
Attachment #145782 - Flags: review?(cbiesinger)
Comment on attachment 145782 [details] [diff] [review] v2 patch + PRBool mUploading; PRPackedBool, maybe? // if (aStatus) { + + // Remember the current status for this request the newline here seems unnecessary would be good if nsHttpTransaction used doxygen-compatible comment style for the member variables... and if it documented all of them :) ah well. looks good otherwise
Attachment #145782 - Flags: review?(cbiesinger) → review+
the only thing I'm a bit worried about... what if you have an HTTPS file of zero length? You wouldn't send any OnProgress messages then... but does it matter? it's a bit of an edge case... I wonder what the uriloader/contentsink would do with such a request... hm...
Attachment #145782 - Flags: superreview?(bzbarsky)
(In reply to comment #24) > the only thing I'm a bit worried about... what if you have an HTTPS file of zero > length? You wouldn't send any OnProgress messages then... but does it matter? > it's a bit of an edge case... well, we currently do not send any progress for such a request.. and it doesn't seem like you would need to worry about showing the lock icon for it since there is no content for the user to see. but, maybe i'm missing something?
Comment on attachment 145782 [details] [diff] [review] v2 patch sr=bzbarsky, I guess.... All this stuff needs some documentation, deciding on exactly what the contracts are, and freezing...
Attachment #145782 - Flags: superreview?(bzbarsky) → superreview+
Attachment #145782 - Flags: approval1.7?
bz: yeah, i agree. time willing, my plan is to document these interactions better and write up a testcase that can be added to tinderbox.
Attachment #145782 - Flags: approval1.7? → approval1.7+
I left mUploading as a PRBool since converting to PRPackedBool wouldn't help the nsRequestInfo struct be any smaller. fixed-on-trunk for 1.7 final
Status: ASSIGNED → RESOLVED
Closed: 21 years ago
Resolution: --- → FIXED
Hmm... There was a bit of a Tp hit from this change. I guess it's us updating the status bar or something, but it may be something to look into.
(In reply to comment #29) > Hmm... There was a bit of a Tp hit from this change. I guess it's us updating > the status bar or something, but it may be something to look into. nsBrowserStatusFilter goes to some length to do that only rarely...
Yes, but there are some issues with the way it does do it (eg forcing sync reflow every time it does it) that could be problems here. Also, its definition of "rarely" is actually not that rare....
Couple possibilities: (1) we are firing DOCUMENT_START later to all webprogresslisteners, so we start tearing down the old document a bit later. (2) we are now reporting progress for cached loads (NOTE: this wouldn't affect UI since nsBrowserStatusHandler shows number of completed requests over total number of requests in progress meter. it would only matter when we are loading a single document.)
> (1) we are firing DOCUMENT_START later to all webprogresslisteners, so we start > tearing down the old document a bit later. nevermind this comment. DOCUMENT_START happens when the first request is added to the loadgroup, which happens in AsyncOpen calls. that's not related to this bug.
Compare http://tinderbox.mozilla.org/showlog.cgi?log=SeaMonkey/1081626540.8740.gz to http://tinderbox.mozilla.org/showlog.cgi?log=SeaMonkey/1081627500.16234.gz&fulltext=1 Most of the pages are not affected, really. A few got noticeably slowed (lxr page, quicken page, etc). The quicken page certainly has stuff it links to (at least on the web). The lxr page does not. So this could indeed be the cached loads issue (since many of those loads are cached, I would assume).
At the same time that I submitted this vulnerability to this mailing list and to bugzilla, I also dropped a note to CERT (knowing the CERT would obviously keep this confidential for now). CERT has since contacted me and asked several questions. I've updated them on the general status of this vulnerability and provided them with a copy of the bug history from Bugzilla. They also asked me: "Were you given any indications on the timeline for a fix for this issue? Likewise, did you have any expectations for publishing your findings personally? Our preference is give the vendor an opportunity to produce patches before we would publish something." I responded to the above question by telling CERT that I would coordinate with the Mozilla security team prior to releasing anything publicly -- assuming that such a process was complete by the first week in June. I picked this date very intentionally because, as far as I can, Mozilla 1.7 final is slated for release around May 21st. As you all know, this bug has already been fixed in 1.7. With that, I pose these questions to you: a) Is Mozilla planning to release a patch that current Mozilla users can use prior to the release of 1.7 final? My assumption is no. b) Does the patch that's already been put into CVS fix FireFox as well? Will others that embed Gecko need to make changes to their code, other than updating their Gecko engine? c) Does Mozilla have a list of projects embedding Gecko? Will those projects be notified by Mozilla? Do you require any assistance in that endeavor? d) Does Mozilla intend to release their own security announcement, other than what might be released by CERT or myself? e) Does Mozilla have a preference or policy regarding the release-date of this vulnerability? If asked to wait until after the release of 1.7 final, both CERT and I will. In either case, please provide some guidance on your preferences.
Answering just the questions I know answers to. Ccing some people who should be able to answer the rest. Also, you may want to pose those questions to security@mozilla.org, per http://www.mozilla.org/projects/security/security-bugs-policy.html > b) Does the patch that's already been put into CVS fix FireFox as well? Yes. > Will others that embed Gecko need to make changes to their code, other than > updating their Gecko engine? They will not.
Just to clarify -- I did post this to the security list as well. I just figured it'd be appropriate to post a copy here.
Adding Jon Granrose to CC list to help round up QA resources for verification
Comment on attachment 152720 [details] [diff] [review] Backport to 1.4 branch Darin, it would be great if you could take a look at this since I had to do some conflict resolution, especially in nsHttpTransaction::OnTransportStatus which looks substantially different than the version you patched against. I have verified this to plug the hole as demonstrated at http://www.ttar.org/test.html
Attachment #152720 - Flags: superreview?(darin)
Comment on attachment 152720 [details] [diff] [review] Backport to 1.4 branch sr=darin
Attachment #152720 - Flags: superreview?(darin) → superreview+
Comment on attachment 152720 [details] [diff] [review] Backport to 1.4 branch a=blizzard for the 1.4.3 branch
Attachment #152720 - Flags: approval1.4.3+
Checked into the 1.4.3 branch
Keywords: fixed1.4.3
Whiteboard: [sg:fix]
Removing security-sensitive flag for bugs on the known-vulnerabilities list
Group: security
This patch appears to have caused a crash. See bug 242393.
Note: The Common Vulnerabilities and Exposures project (cve.mitre.org) has assigned the name CAN-2004-0761 to this issue.
Attaching testcases from www.ttar.org so we'll have them if that server ever goes away or gets cleaned up.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: