Last Comment Bug 415401 - Arbitrary Referer Spoofing with Empty Username
: Arbitrary Referer Spoofing with Empty Username
Status: RESOLVED FIXED
[sg:dupe 415034]
: verified1.8.1.13
Product: Core
Classification: Components
Component: Networking: HTTP (show other bugs)
: unspecified
: All All
: -- major (vote)
: ---
Assigned To: Daniel Veditz [:dveditz]
:
Mentors:
http://pseudo-flaw.net/r/rspoof/?what...
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2008-02-02 20:38 PST by Gregory Fleischer
Modified: 2010-06-08 07:35 PDT (History)
7 users (show)
dveditz: blocking1.8.1.13+
dveditz: wanted1.8.1.x+
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Attachments

Description Gregory Fleischer 2008-02-02 20:38:43 PST
User-Agent:       Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11
Build Identifier: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11

This a generalization of bug 415034 that allows for spoofing of arbitrary referers.  In the URL, when the username portion of the authority is empty, arbitrary referers can be spoofed by using a specially constructed password field.  CSRF attacks can be performed against any site that depends only on referer checking for protection.

Online demo at: http://pseudo-flaw.net/r/rspoof/?whatever.example.com/

The demo URL above generates a page with an iframe with a source of 'http://:XXXXXXXXXXXXXXXXXXXXXXX@pseudo-flaw.net/r/rspoof/whatever.example.com/'.

There is no user notification because there is no username.  The page returned makes a POST to display the request information.

When the referer is determined, there is miscalculation in the URL spec.  As a result, when the userinfo portion is removed from the URL, it actually removes the first portion of the true URL.  So, by creating a password field that aligns with the length of the URL portion to remove, an arbitrary referer can be created.  

For example:

Instead of changing: 
http://:XXXXXXXXXXXXXXXXXXXXXXX@pseudo-flaw.net/r/rspoof/whatever.example.com/
to 
http://pseudo-flaw.net/r/rspoof/whatever.example.com/

The URL:
http://pseudo-flaw.net/r/rspoof/whatever.example.com/
is changed to 
http://whatever.example.com/

The two strings in question:
:XXXXXXXXXXXXXXXXXXXXXXX@
pseudo-flaw.net/r/rspoof/



Reproducible: Always

Steps to Reproduce:
1. Visit demo URL (http://pseudo-flaw.net/r/rspoof/?whatever.example.com/)

Actual Results:  
The line: 
  "HTTP_REFERER: http://whatever.example.com/"
is displayed.

Expected Results:  
The line should read: 
  "HTTP_REFERER: http://pseudo-flaw.net/r/rspoof/whatever.example.com/"


Change 'whatever.example.com' to desired referer in demo to see different values:

http://pseudo-flaw.net/r/rspoof/?[yoursitehere]
Comment 1 Gregory Fleischer 2008-02-02 21:00:29 PST
I believe that the problem is due to differing treatment of the 'mUsername.mLen' in the file mozilla/netwerk/base/src/nsStandardURL.cpp. 

In, "nsStandardURL::BuildNormalizedSpec", the length is tested to be greater than zero, but in "nsStandardURL::SetUserPass" the comparison is performed using greater than or equal zero.

So, the normalized spec doesn't have have the username and password added to it when the authority is calculated.  Then when the spec is adjusted in SetUserPass, the host portion is being damaged because it is assumed that it is actually the username/password that is being cleared. 
Comment 2 Daniel Veditz [:dveditz] 2008-02-03 13:40:09 PST
Wish I had seen this bug before I tracked it down for bug 415034 

You're exactly right, most of the URL code assumes that if there's no username there's no password, but ParseUserInfo() happily calculates its position anyway. BuildNormalizedSpec() ignores the  password when rebuilding the spec if there's no username, but does not clear the password position/length.

Places that call nsStandardURL::Userpass() get an empty string if there's no username despite any password lengths. That's actually correct, because the rebuilt spec doesn't have the password data in it anymore. Note comment "if there is no username, then there can be no password". This is why the exposable URI we create for the address bar is not munged -- that routine avoids touching the URI if it can so it checks if Userpass() is the empty string and only zaps the userpass if there is one.

The referrer, on the other hand, simply sets the userinfo to the empty string without checking (nsHttpChannel::SetReferrer, "clone->SetUserPass(EmptyCString());") and thus triggers this bug.

Couple of ways to fix this:

1) make SetUserPass() bail out on an empty username like everywhere else, checking "if (mUsername.mLen > 0) {" instead of the current >=

2) return an URI parsing error if there's a password part without a username (also need to fix SetPassword() so it errors if username length is <= 0, not just <0)

I'm uncomfortable with 1) alone, so 2) -- or both wouldn't hurt, actually

Confirming bug because of the good analysis and testcase, but this is really just a dupe of bug 415034 IMHO.
Comment 3 Daniel Veditz [:dveditz] 2008-02-20 17:25:58 PST
Fix for bug 415034 checked in to trunk
Comment 4 Daniel Veditz [:dveditz] 2008-03-03 12:41:02 PST
Fix checked into 1.8 branch
Comment 5 Al Billings [:abillings] 2008-03-13 17:04:39 PDT
Verified with Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/2008031114 Firefox/2.0.0.13.

Note You need to log in before you can comment on or make changes to this bug.