Archive for the 'Security' Category

Basics of The Integer in the Binary World

Talking about overflows, Tom in my previous post mentioned -(-x) != x problem. Precisely, -(2^31) * -1 != 2^31 . What happened?

To understand this, we must understand how integers work in the reality and the binary world.

In reality, integers form a countably infinite set [1]. They have no upper or lower limits. So, in our mind, we can visualize it this way :

The line expands forever to the left and forever to the right.

In the binary world, this is another story. For an integer, we have only 4 bytes ( 32 bits ). By nature, an integer can only represent as many as 2^32 = 4294967296 values. Which means, integers in computers cannot represent the countably infinite nature of integers as in reality. Once the limits are exceeded, it wraps around. Like a wheel :

As you can see, if you subtract 1 from -2147483648 (-2^31), the integer in binary world no longer behaves in what we believe.

(-2^31) – 1
= -214783648 – 1
= +2147483647

Notice that overflowing by subtracting 1 from -(2^31) does not yield (2^31) but (2^31-1). Why? Because 0 is also a value in integer, and thus requires one representation as well. Now there are only (2^32-1) choices left, and so the positive value of -(2^31) is now missing.

That is what Tom is talking about. Since the positive of -(2^31) cannot be represented, -(-(2^31)) = -(2^31).

This goes the same for :

-(2^31) * -1 = -(2^31)
-(2^31) / -1 = -(2^31)

The following code compiling in VC++ demonstrates :

#include <cstdio>
#include <climits>

int main()
{
	printf("%12s\t%12s\t%12s\t%12s\t%12s\n","x","-x","x*-1","x/-1","x-1");
	for ( int i=0; i<10; ++i )
	{
		int x = INT_MIN+i;
		printf("%12d\t%12d\t%12d\t%12d\t%12d\n",x,-x,x*-1,x/-1,x-1);
	}
	return 0;
}

The output of the program is :

           x              -x            x*-1            x/-1             x-1
 -2147483648     -2147483648     -2147483648     -2147483648      2147483647
 -2147483647      2147483647      2147483647      2147483647     -2147483648
 -2147483646      2147483646      2147483646      2147483646     -2147483647
 -2147483645      2147483645      2147483645      2147483645     -2147483646
 -2147483644      2147483644      2147483644      2147483644     -2147483645
 -2147483643      2147483643      2147483643      2147483643     -2147483644
 -2147483642      2147483642      2147483642      2147483642     -2147483643
 -2147483641      2147483641      2147483641      2147483641     -2147483642
 -2147483640      2147483640      2147483640      2147483640     -2147483641
 -2147483639      2147483639      2147483639      2147483639     -2147483640

Look carefully at the 1st line. -2147483648 is -(2^31), our number of interest.

This is the basics of integer overflow problems, and I hope you have learned more about how integers work.

References :

[1] http://en.wikipedia.org/wiki/Integers

Advertisements

Do Not Detect Overflow With Overflow

Credits to a gweilo for the sharing below.

Integer overflow and underflow manifest themselves as vulnerabilities. Here is an overflow bug fired by Sir BugFinder. I assigned our fictional developer Sir FastFix ownership of the bug, and he jumped into the code straight.

First, look at this problematic pseudo-code snippet below :

SWORD param = 0;

while ( flag )
{
	param ++ ;
	//
	//manipulate the flag value...
	//
}

buffer = malloc(sizeof(BYTE) * param);
...

The param can increase definitely. No good. Sir FastFix quickly identifies the problem and sends me this code review below.

// sirfastfix: now uses unsigned.
UWORD param = 0;

while ( flag )
{
	// sirfastfix: code fix for overflow bug.
	if ( param > param + 1 )
	{
		TRACE_ERROR("Overflow occurred at param\n");
		return E_UNEXPECTED;
	}
	param ++ ;
	//
	//manipulate the flag value...
	//
}

buffer = malloc(sizeof(BYTE) * param);
...

Now, I have to review it. Let’s look at the changes.

  1. param is now checked with the condition (param > param + 1). Since it must be false, an overflow must have occurred if it is true. Intuitive.
  2. param is now unsigned using UWORD, and not signed SWORD. I find no reasons for negative buffers. A good move.

But, something smells stinky. Let’s think again.

  1. Why not use well-defined constants like MAX_INT, MAX_SHORT or MAX_LONG constants to check before incrementing param? Like MAX_INT – a < b ?
  2. Why the code to detect overflow is using yet another overflow to check?

Sir FastFix, I am not approving this code check-in. This fix is not going in anywhere into the source tree. Who knows what this overflow to check overflow can result in? Let’s write more solid and not college quality code, and not rushing to resolve the bug.

China is a Good Place to Pen Test

In the midst of crazy work, I breezed through certain websites and randomly injected some simple attack vectors over this month in China. I found several large sites that are vulnerable to XSS and SQL Injection.

Large sites including DangDang, Sina China, Sogou, Baidu, some of them fixed the problems after emailing them or maybe after reading the logs, too. However, the SQL Injection in DangDang remains unfixed and that is not good. I will not disclose here though ( you can certainly find it easily. It is just simple and buggy. )

To give you an idea of how big the sites above are relative to China, here are some analogies :

DangDang – Amazon

Sina China – Yahoo! News

Sogou – Ask.com

Baidu – Google ( bonus, Baidu beats Google in China )

I guess I will have to find more time to play with these sites to look for more holes. But for now, I have tons of work piling up. Ouch. I have vacation today, in office.

More About the Characters Causing XSS in Opera

I talked about an XSS in Opera 9.51 as discovered by Chris Weber [1]. I talked with Chris and he hinted me something about the character encoding, which I certainly have little concept about it, and I found out why it is happening.

Except U+180E, U+180F, they are all associated with spaces ( The Zs, Zl, Zp categories ) [2] [3]. In fact :

U+2028 – Line separator in unicode 3.0
U+2029 – Paragraph separator in unicode 3.0

Different kind of spaces in unicode :

U+00A0
U+1680
U+2000 to U+200A
U+202F
U+205F
U+3000

U+180E is a Mongolian Vowel Separator character [4], and U+180F is a non-existent character. Somehow U+180E fall into the Space Separator category as well. For U+180F, I really have no idea how it happened. If you know what is happening, I really appreciate your sharing.

Well, quite a good lesson on international character sets, no? I really recommend Chris Weber’s blog [5] because it contains a lot of information on character encoding and web application security that you should not miss it out.

References :

[1] – http://lookout.net/2008/08/26/advisory-attack-of-the-mongolian-space-evaders-and-other-medieval-xss-vectors/
[2] – http://srfi.schemers.org/srfi-14/srfi-14.html
[3] – http://msdn.microsoft.com/en-us/library/ms776456(VS.85).aspx
[4] – http://unicode.org/cldr/utility/character.jsp?a=180E
[5] – http://lookout.net/

Interesting XSS In Opera 9.51

Bad things can happen when things are not treated as what they are. Consider the HTML tag below :

<img src=non-existent-link&onerror=alert(1) />

The browser should treat it as the following content :

<img src=”non-existent-link&onerror=alert(1)” />

Not too bad, right? But, what if the character “&” is treated as space?

<img src=”non-existent-link” onerror=”alert(1)” />

Not too great, our image tag points to something non-existent, and inadvertently triggers the onerror callback, and free javascript for everyone who comes along… in Opera 9.51. Credits to Chris Weber to the discovery.

This is the case when some character becomes a space character. ( No, the “&” character is just for easier interpretation. )

Here is a list of characters that is treated as a space character :

U+00A0
U+1680
U+180E
U+180F
U+2000 to U+200A
U+2028
U+2029
U+202F
U+205F
U+3000

The list of Chris Weber seems to be smaller, but the above are working as I tested it against with Opera 9.51 on Windows XP. So I am pretty sure those are extra. =)

I also tested on Firefox 3.0.1, Internet Explorer 7.0.5730.13, Chrome 0.2.149.29. The vulnerability does not exist there. For Safari 3.1.2 (525.21), I *think* there are not problems because it passed some of tests, but I failed to run all the tests due to its serious performance problems ( guesstimating to be memory leak? ). More on that in the next post.

Reference :

Advisory : Attack of the Mongolian space evaders

Bypass Basic Authentication in Routers

A friend bought a router model GN-B46B of Gigabyte, and asked me if it is dangerous to expose the router to the WAN.

“Yes, of course, but you must have at least one point of contact anyway. By the way, if you cannot access the administrator page, the account name is ‘admin’ and password is ‘password’.”

Yup, I changed the password, Well, that was simple, as it was a creation of the year 2004. I searched SecurityFocus and immediately answered my friend’s question. No, I invented nothing. How did it happen?

The main page redirects to a login page secured by a HTTP Basic Authentication. However, the rest of the pages do not require the HTTP Basic Authentication. Here is the point, if you know the URL to the page that does certain function ( e.g. change password ), you can skip the login page and enter the URL to that page directly! The router site map is trivial to obtain, and I changed the password. Ouch…

This is old news, but such grave mistakes are still present out there. Time to check your own router!

References :
http://en.wikipedia.org/wiki/Basic_access_authentication
http://www.ietf.org/rfc/rfc2617.txt
http://www.securityfocus.com/bid/9740/discuss

Dump URL Handler Script

I will have a look into the URL Handler Bugs soon, and there must be a lot to learn inside. Prior to that, I still need to find out what to investigate. So here are the scripts to dump URL Handlers for Windows and Linux, scripted uglily in Python in minutes. My Macbook is pretty screwed for those who know, so no Mac version. Feel free to use.

Windows :

from _winreg import OpenKey, EnumValue, EnumKey, HKEY_CLASSES_ROOT

handlers = []

hkcrKey = OpenKey(HKEY_CLASSES_ROOT, "")
try:
	i = 0
	while 1:
		keyName = EnumKey(hkcrKey, i)
		keyHandle = OpenKey(HKEY_CLASSES_ROOT, keyName)
		try:
			j = 0
			while 1:
				valueName = EnumValue(keyHandle, j)
				if valueName[0] == 'URL Protocol':
					handlers.append(keyName)
				j = j + 1

		except WindowsError:
			pass
		i = i + 1
except WindowsError:
	pass

for handler in sorted(handlers):
	print handler

Linux :

import os
import re
import sys
from sets import Set

file = open('/usr/share/gconf/schemas/desktop_gnome_url_handlers.schemas', 'r')
data = file.read()
file.close()

"""
The interesting parts are "applyto" tags. The term between 4th and 5th slash is the URI we want.
"""

uris = re.compile('([a-zA-Z0-9/\-]+)', re.MULTILINE).findall(data)
handlers = []

for uri in uris:
    handler = uri.split('/')[4]
    handlers.append(handler)

for handler in sorted(Set(handlers)):
    print handler

Here we go…

I am so sorry the scripts look so awful, and thanks to Kane for the PRE tag tip!