xboxscene.org forums

Pages: 1 ... 9 10 [11] 12 13 ... 15

Author Topic: Xbox Live Exploit  (Read 2360 times)

PedrosPad

  • Archived User
  • Hero Member
  • *
  • Posts: 1277
Xbox Live Exploit
« Reply #150 on: August 28, 2003, 01:34:00 AM »

QUOTE
How could this be dumped on the heap?

It would have to be on the stack to be executed wouldn't it? That's the way the majority of buffer over/underruns work. Abitrary code just overflowing a variables boundries in the heap usually won't cause this type of behavior unless it punches out of the heap and into the stack.

Morden.


I'm familiar with how overflowing stack based storage can be used to insert a new subroutine return address of your choice.

My theory is that separate threads are used read in the font XTF files from the 'slow' IO device (Hard Disk) and that a structure is be pushed onto the heap for each thread to store thread specific metadata, such as the individual thread's SEH pointer. Once a thread 'collides', the OS would pull the SEH for 'that' thread from the thread's metadata, and jump to it.

Heap view:

|Bert.XTF buffer|Bert thread metadata|Ernie.XTF buffer|Ernie thread metadata|

When Bert.xtf 'underflows' it trashes it's own thread metadata (including it's SEH). Thereby gaining control of the IP.

Ok, an update to my 'mad' thread metadata theory:
After a cold start, the heap is empty and the OS has no option but to put the 'Bert thread metadata structure' consecutively on the heap.  At any other time, the heap may be fragmented, and space for a small thread metadata structure may be found somewhere completely different in the heap.

Possibly not a good theory, but an attempt to explain how Bert may gain control of the IP.

The latest theory in this thread, that Bert.XTF is put on the stack, but Erinie.XTF is put on the heap doesn't hold water.  Why would the OS treat two font files differently?

Pedro.

Footnote:
If threads do in fact utilise a thread metadata structure, and these are released automatically when the thread terminates, they'd have to be on the heap, as you can't fragment the stack.
Logged

PedrosPad

  • Archived User
  • Hero Member
  • *
  • Posts: 1277
Xbox Live Exploit
« Reply #151 on: August 28, 2003, 07:33:00 AM »

QUOTE
Here is what I don't get - if there are no virtual memory features in use, then it seems like an underflow would fail when it tried to allocate gigs of memory - after all there isn't enough ram to allocate and we can't use the hard-disk as virtual mem. Unless it's the act of loading the actual data that hoses things (eg, writing the data to all these addresses), causing the reset.


The technical analyses of Free-X’s “Bert & Ernie” exploit says that the underflow occurs because the header causes too little memory to be allocated (not too much, or your GBs).

Say the header is a structure of 20 bytes, and within that structure is the length of the whole font file (this would always be expected to be greater than the size of the fixed header).  The dash reads the fixed size header into a stack based structure, interrogates the 'length' field, allocates a memory buffer on the heap, and then block copies the fixed size header into the start of the heap based buffer.  If the length field in the fixed size header is faked to 10 bytes, 10 bytes would be allocated on the heap, but then the 20 bytes of the fixed size header would be block copied into the buffer.  Overflowing by 10 bytes, trashing whatever was adjacent.

e.g.
QUOTE
LoadFont( pzFilename)
{
   struct fontHeader_t fontHeader;  /* 20 bytes */
   char *pFontBuffer;
   FILE *in;

   in=fopen(pzFilename);
   fread(in, &fontHeader, sizeof(struct fontHeader_t));   /* Read first 20 bytes from file */
   pFontBuffer = malloc(fontHeader.fontlength);     /* Ah! Actually only allocate 10 bytes */
   memcpy(pFontBuffer, &fontHeader, sizeof(struct fontHeader_t))   /* Copy 20 bytes into 10 bytes - Overflow */

   /* Read in rest of font file. (this'll bail at EOF). */
   fread(in, pFontBuffer+sizeof(struct fontHeader_t), fontHeader.fontlength-sizeof(struct fontHeader_t));
   fclose(in);
}



Pedro.
Logged

Grospolina

  • Archived User
  • Full Member
  • *
  • Posts: 182
Xbox Live Exploit
« Reply #152 on: August 28, 2003, 07:37:00 AM »

QUOTE

Which bytes in the font header represent the size?


The size is a DWORD (32-bits) at offset 0x28 (40).  Don't forget that it's little Endian.  The data starts at 0x40 (64).

QUOTE

Here is what I don't get - if there are no virtual memory features in use, then it seems like an underflow would fail when it tried to allocate gigs of memory - after all there isn't enough ram to allocate and we can't use the hard-disk as virtual mem. Unless it's the act of loading the actual data that hoses things (eg, writing the data to all these addresses), causing the reset.


The size that it is asking to be allocated may be suffering from a signed/unsigned problem.  That is, the specified size 3, minus the size of the size field 4, equals -1.  It asks itself, "Is -1 less than the maximum size we can allocate?"  "Why yes, it is!"  Okay, so it allocates a buffer of size -1 (hmm?) and then tries to read in -1 bytes.  It takes this as an unsigned number (unchecked sign change), so it's 0xFFFFFFFF, which is almost 4 GB.  It reads Bert and overwrites data, but then comes to the end of the file and stops reading (with no error).  Lazy programming at its best.

QUOTE

EDIT: Here is one on non-stack based overflows (which is what we have here)
Non-stack-based overflows


I read this and what I don't get is why it's not considered a "stack-based" overflow, since we're overwriting the stack.  I can't access the other article to compare.  The articletself makes sense though.

Still, I can't see that happening in our case.  There's no way that the program would load two font files onto the stack.  In a 64 MB system, you just wouldn't let to stack grow to 30+ MB.  Besides, the fonts are dynamic in size, and you can't dynamically allocate stack space.  Dynamic allocation occurs on the heap (which was mentioned).

If so, then how does Bert get from the heap to the stack in so few bytes?  Bert would have had to be located at the stack pointer, since the first 4 bytes of Bert's data is the address we're replacing.  How would that be possible?  I don't think it is.  Besides, according to the writer at maxconsole, it's overwriting the SEH pointer, not the return address.

I think Pedro has got the right idea about heap fragmentation.  But why would Bert's thread metadata be located AFTER Bert's data?  Is the heap allocated backwards?  And if Pedro's theory IS true, then this problem may be unsolvable.
Logged

PedrosPad

  • Archived User
  • Hero Member
  • *
  • Posts: 1277
Xbox Live Exploit
« Reply #153 on: August 28, 2003, 08:20:00 AM »

QUOTE
I read this and what I don't get is why it's not considered a "stack-based" overflow, since we're overwriting the stack. I can't access the other article to compare. The article itself makes sense though.


Simple answer, because we're working with the heap not the stack.wink.gif  More helpful answer, the stack (aka the call stack) is primarily used to hold return addresses from function calls.  Stack based attacks overwrite the return addresses, in the safe knowledge that eventually the functions will exit and pop their return addresses, thereby hijacking the IP.  By contrast, heap based attacks can only hijack the IP if some pointers-to-functions happen to be in the heap.  This is a lot less common.


QUOTE
I think Pedro has got the right idea about heap fragmentation. But why would Bert's thread metadata be located AFTER Bert's data? Is the heap allocated backwards?


The heap grows up. (1st alloc @ 0x0000, 2nd alloc @ 0x0020, etc.)

How about this:
QUOTE
LoadFont( pzFilename)
{
struct fontHeader_t fontHeader;  /* 0x20 bytes */
char *pFontBuffer;
FILE *in;

in=fopen(pzFilename);
fread(in, &fontHeader, sizeof(struct fontHeader_t)); /* Read first 0x20 bytes from file */

pFontBuffer = malloc(fontHeader.fontlength);  /* Allocate font buffer on heap - First heap allocation (say @ 0x0000) */

SpinThread( pfFontLoader, pFontBuffer );  /* Spin a new thread to load in the rest. */
/* SpinThread may itself then allocate a thread metadata structure on the heap as one of it's first actions. - Second heap allocation (say @ 0x0021)*/

}


Just ideas.

Pedro.
Logged

Blindside

  • Archived User
  • Newbie
  • *
  • Posts: 13
Xbox Live Exploit
« Reply #154 on: August 28, 2003, 11:04:00 AM »

QUOTE (PedrosPad @ Aug 28 2003, 04:33 PM)

The technical analyses of Free-X’s “Bert & Ernie” exploit says that the underflow occurs because the header causes too little memory to be allocated (not too much, or your GBs).

Say the header is a structure of 20 bytes, and within that structure is the length of the whole font file (this would always be expected to be greater than the size of the fixed header).  The dash reads the fixed size header into a stack based structure, interrogates the 'length' field, allocates a memory buffer on the heap, and then block copies the fixed size header into the start of the heap based buffer.  If the length field in the fixed size header is faked to 10 bytes, 10 bytes would be allocated on the heap, but then the 20 bytes of the fixed size header would be block copied into the buffer.  Overflowing by 10 bytes, trashing whatever was adjacent.

Thanks Pedro,
   Now that I read that part of the analyses more closely (and with enlightenment from your point), I see where I was making the mistake at.

The allocation is done based on the size structure eg (which is clearly stated, I must have had brain-lock):

int* pbuf;
unsigned int size_of_file = 3;
pbuf = new int[3];
fread(bpuf, unsigned (size_of_file-4),....);

So we alloc 3 bytes on the heap, then read in -1 bytes, which of course becomes gigantic in unsingned land.

I was seeing it (for some reason) as:
unsigned int size_of_file = 3;
new int[unsigned(size_of_file-4)];   <---allocs big-a$$ number of bytes
fread(bpuf, unsigned (size_of_file-4),....);

Now it makes sense why the CPU doesn't throw an exception immediately.

Grospolina,
   The information in Bert after the header doesn't jump from the stack to the heap (a stack overflow) - it's already allocated on the heap by virtue of new/malloc. Whoever came up with this exploit knew that a function address for some other function was located near to where bert would be loaded.

I saw your earlier post about the jump location being the first 4 bytes following the header, but I don't know that we can say for sure this is the case. The size in the header structure for bert is 3, so the first 3 bytes allocated would be 'good' memory, and the first 3 bytes read could not be overwriting anything, since those are validly allocated addresses. Any exploit address would have to start on byte 67 or beyond of bert.

I am assuming here that the header is not being read into the font buffer. (eg, we're fseek()'ing to postion 64 of bert and reading/loading  from there). If it is loading the font header (or parts of it like the size) into the buffer, then of course bytes 64-67 could very well be the jump address.
Logged

Grospolina

  • Archived User
  • Full Member
  • *
  • Posts: 182
Xbox Live Exploit
« Reply #155 on: August 28, 2003, 11:43:00 AM »

QUOTE

1. 0x00C02020 in Bert -> 0x001E2018 in Ernie (found by shrinking the file until it crashes)
2. 0x00D02020 in Bert -> crashes (after shrinking)
3. 0x00A02020 in Bert -> crashes (as expected)
4. 0x00A22020 in Bert -> works (trying to shrink now)
5. 0x00B1F01E in Bert -> 0x00FF016 in Ernie (more shrinking)


Let me describe it in detail:

This is how I structured Ernie (top is the beginning):
Exploit code (less than 1 KB)
Jump to beginning of code (5 bytes; single line)
Jump table (110 bytes; jumps to 5-byte jump line)
Exception net (variable size; EB 90 - jumps up by 112 bytes)
Infinite loop area (256 bytes)

For step 1 (leaving Bert at 0x00C02020), I kept shrinking the exception net in Ernie (Trying it over and over) until it crashed.  Increasing and decreasing to find the exact location, I found that it jumped to location 0x001E2018.  This is about 1.88 MB.

For step 2, I changed the offset in Bert to 0x00D02020 and found that it crashed, because it jumped past the exception net (and even past the infinite loops).

For step 3, I changed the offset in Bert to 0x00A02020, and found that it crashed, because it jumped to somewhere before Ernie (which should start at relative offset 0x00A20008).

For step 4, I changed the offset in Bert to 0x00A22020 and found that it worked, because it jumped near the beginning of the exception net.

I then tried to shrink Ernie more, but found that it didn't work somewhere below 1 MB.  I believe that it was placing Ernie in a different area of memory since it was small enough now.

For step 5, I changed the offset in Bert to 0x00B1F01E and found that it worked.  I then shrank Ernie again to find where it jumped to, and found that it went to location 0x00FF016 (just below 1 MB).

By simply increasing the size of the exception net, without changing Bert, I also found that the maximum size for Ernie is somewhere over 34 MB (because it probably can't allocate that much space on the heap).

Comparing step 1 to step 5 confirmed that the relative offset from the jump point in code to Ernie was 0xA20008.  It also confirmed that the first four bytes of Bert are, in fact, the jump offset.

I believe the next 4 bytes cause corruption of the thread metadata, causing the exception to happen.
Logged

Luke_CH

  • Archived User
  • Newbie
  • *
  • Posts: 25
Xbox Live Exploit
« Reply #156 on: August 28, 2003, 12:00:00 PM »

CODE
MSDashBoard = "c:xboxdash.xbe"


the EvoX doesn't load up when you click on the XBOX LIVE button.
Then you change this setting and Evox load up fine!
smile.gif

By3z
Logged

mnm6687

  • Archived User
  • Jr. Member
  • *
  • Posts: 94
Xbox Live Exploit
« Reply #157 on: August 28, 2003, 01:09:00 PM »

QUOTE (Luke_CH @ Aug 28 2003, 04:00 PM)
Hi to all, I have inserted the EvoX in the xodash folder and...if in the Eovx.ini MSdash is set to : "c:xboxdash.xbe"

CODE
MSDashBoard = "c:xboxdash.xbe"


the EvoX doesn't load up when you click on the XBOX LIVE button.
Then you change this setting and Evox load up fine!
smile.gif

By3z

dude... no
Logged

underthebridge

  • Archived User
  • Full Member
  • *
  • Posts: 186
Xbox Live Exploit
« Reply #158 on: August 28, 2003, 01:15:00 PM »

QUOTE (Luke_CH @ Aug 28 2003, 09:00 PM)
Hi to all, I have inserted the EvoX in the xodash folder and...if in the Eovx.ini MSdash is set to : "c:xboxdash.xbe"

CODE
MSDashBoard = "c:xboxdash.xbe"


the EvoX doesn't load up when you click on the XBOX LIVE button.
Then you change this setting and Evox load up fine!
smile.gif

By3z

what? Impossible, evox is not MS-signed...
Logged

Luke_CH

  • Archived User
  • Newbie
  • *
  • Posts: 25
Xbox Live Exploit
« Reply #159 on: August 28, 2003, 02:03:00 PM »

smile.gif
Logged

Luke_CH

  • Archived User
  • Newbie
  • *
  • Posts: 25
Xbox Live Exploit
« Reply #160 on: August 28, 2003, 03:25:00 PM »

smile.gif By3z
Logged

PedrosPad

  • Archived User
  • Hero Member
  • *
  • Posts: 1277
Xbox Live Exploit
« Reply #161 on: August 29, 2003, 02:23:00 AM »

QUOTE
I saw your earlier post about the jump location being the first 4 bytes following the header, but I don't know that we can say for sure this is the case. The size in the header structure for bert is 3, so the first 3 bytes allocated would be 'good' memory, and the first 3 bytes read could not be overwriting anything, since those are validly allocated addresses. Any exploit address would have to start on byte 67 or beyond of bert.


Grospolina's findings support my theory.  I think the "Technical analyses of Free-X’s “Bert & Ernie” exploit" is slightly wrong.  I believe that the entire header is copied into the allocated buffer, ahead of further reads.  Meaning that anything after the first 3 bytes in the file will overwrite adjacent memory.  (Why put the length of the entire file in the font header, if you then have to subtract the fixed length of the header from it ahead of any usage?  Don't make sense.  This only makes sense if that is the size of the buffer you want to allocate.)

e.g.
QUOTE

LoadFont( pzFilename)
{
   struct fontHeader_t fontHeader;  /* 0x40 bytes */
   char *pFontBuffer;
   FILE *in;

   in=fopen(pzFilename);
   fread(in, &fontHeader, sizeof(struct fontHeader_t));   /* Read first 0x40 bytes from file */

   pFontBuffer = malloc(fontHeader.fontlength);     /* Ah! Actually only allocate 3 bytes */
   memcpy(pFontBuffer, &fontHeader, sizeof(struct fontHeader_t))   /* Copy 0x40 bytes into 3 bytes - Overflow */


   /* Read in rest of font file. (this'll bail at EOF). */
   fread(in, pFontBuffer+sizeof(struct fontHeader_t), fontHeader.fontlength-sizeof(struct fontHeader_t));
   fclose(in);
}


Theoretically, the entire exploit could be within the header block, depending on how close the adjacent target area is.
With heap alignment, and additional fields in the thread metadata structure, the thread metadata SEH pointer may well be ~0x3E bytes ahead in the heap.

Pedro.
(All talk and no code wink.gif)
Logged

PedrosPad

  • Archived User
  • Hero Member
  • *
  • Posts: 1277
Xbox Live Exploit
« Reply #162 on: August 29, 2003, 03:01:00 AM »

QUOTE
However, I have already proven that the first 4 bytes (starting at 0x40) ARE the jump offset:


Proven with Dash 4817 as your boot dashboard, right? (where I suspect the OS has no option but to put the Bert thread's thread metadata structure consecutively in the heap).

What do we do next?
It could be that when the Dash 4817 is executed from Dash 4290, Bert thread's thread metadata is only a bit further up the heap.  Try making Bert longer.  Replicate the 'jump-to-Ernie' address a few times in the Bert.XTF file (I'd try 10-15 times).  Since we're only interested in whether Bert is hijacking the IP and jumping into Ernie, can I suggest using a large Ernie (32MBs) that simply changes the LED colour and enters an infinite loop (skipping the rest of the shenanigans) for now.  You'll probably want the 'activity' code at the end of the jump net.  It could be that a bigger Bert is overwriting the start of Ernie.

(This could also be an issue of alignment, try bumping the 'jump-to-Ernie' address forward or backwards a couple of bytes).

Pedro.
(The theorist wink.gif).

PS. This may regain access to the IP but then the Bert-to-Ernie offset may also need to be applied.
Logged

Blindside

  • Archived User
  • Newbie
  • *
  • Posts: 13
Xbox Live Exploit
« Reply #163 on: August 29, 2003, 05:03:00 AM »

QUOTE (PedrosPad @ Aug 29 2003, 11:23 AM)
Blindside

Grospolina's findings support my theory.  I think the "Technical analyses of Free-X’s “Bert & Ernie” exploit" is slightly wrong.  I believe that the entire header is copied into the allocated buffer, ahead of further reads.  Meaning that anything after the first 3 bytes in the file will overwrite adjacent memory.  (Why put the length of the entire file in the font header, if you then have to subtract the fixed length of the header from it ahead of any usage?  Don't make sense.  This only makes sense if that is the size of the buffer you want to allocate.)

Theoretically, the entire exploit could be within the header block, depending on how close the adjacent target area is.
With heap alignment, and additional fields in the thread metadata structure, the thread metadata SEH pointer may well be ~0x3E bytes ahead in the heap.

Pedro.
(All talk and no code wink.gif)

Pedro,
 I agree about the analyses; maybe not wrong, just unclear. This one paragraph really stumps me:

QUOTE
In the header section of this file, there is a 4 byte “size” member, which specifies the size of the file including itself.  The dashboard first reads the header, subtracts the length of the header from this size, allocates to fit a file of this size, and reads that number of bytes into the allocated block.  Because the size variable includes itself, values of 0, 1, 2 or 3 will cause an underflow condition when the size of the size variable itself is subtracted.  The dashboard will then allocate only 0-3 bytes of memory, and attempt to read up to several gig into it, overwriting large sections of memory.


No matter how I read this, I keep coming up with this pseudo-code

CODE
    read fontheader
    fontdatasize=fontheader.size - 64 <-----64 is the size of the fontheader
    allocate fontdatasize bytes of data on the heap
    read fontdatasize bytes of data from the file

Which means that any size value of 64 or less will cause an underflow. Of course the example, seems to contradict this. What am I mis-reading here?

Your theory about it reading the font header onto the heap is certainly a possibility and it does allow basically anything beyond the first 3 bytes to potentially be an address ((actually 4 depending on the answer to the question below).

Does anyone recall how memory is allocated - eg, if I do:
myptr = new char;

Do I get only a single byte allocated on the heap or does it allocate 2 bytes. I'm thinking that I would get 2 or 4 bytes in an attempt to keep memory addresses on even boundaries.
The reason why I ask this is that if memory allocations are 2 bytes minimum, then basically the first 4 bytes read in from the file would be 'good' bytes (since 4 bytes are marked as in use) - we allocate 3 bytes, but the compiler marks 4 as in use. Byte number 5 would then have to be the start of any potential address overwrites.

Another question is how do you know what portions of the heap have already been allocated - where is this tracked by the program/compiler or by the processor?

Once I get into the XBox tonight, I will pull xboxdash.xbe (4920) and disassemble it. We'll see what we can see then.
Logged

PedrosPad

  • Archived User
  • Hero Member
  • *
  • Posts: 1277
Xbox Live Exploit
« Reply #164 on: August 29, 2003, 05:26:00 AM »

QUOTE (Blindside @ Aug 29 2003, 02:03 PM)
Pedro,
  I agree about the analyses; maybe not wrong, just unclear. This one paragraph really stumps me:

QUOTE
In the header section of this file, there is a 4 byte “size” member, which specifies the size of the file including itself.  The dashboard first reads the header, subtracts the length of the header from this size, allocates to fit a file of this size, and reads that number of bytes into the allocated block.  Because the size variable includes itself, values of 0, 1, 2 or 3 will cause an underflow condition when the size of the size variable itself is subtracted.  The dashboard will then allocate only 0-3 bytes of memory, and attempt to read up to several gig into it, overwriting large sections of memory.


No matter how I read this, I keep coming up with this pseudo-code

CODE
    read fontheader
    fontdatasize=fontheader.size - 64 <-----64 is the size of the fontheader
    allocate fontdatasize bytes of data on the heap
    read fontdatasize bytes of data from the file

Which means that any size value of 64 or less will cause an underflow. Of course the example, seems to contradict this. What am I mis-reading here?

This is the bit I think is plain wrong.  Remember that the 'technical analysis' isn't written by the exploit's author, and contains as much speculation as my own rubbish.

QUOTE (Blindside @ Aug 29 2003, 02:03 PM)
Does anyone recall how memory is allocated - eg, if I do:
myptr = new char;

Do I get only a single byte allocated on the heap or does it allocate 2 bytes. I'm thinking that I would get 2 or 4 bytes in an attempt to keep memory addresses on even boundaries.


Can't speak for XBOX, but on other 32bit systems, heap allocations always begin on word boundaries.  So I concur with you.

Pedro.
Logged
Pages: 1 ... 9 10 [11] 12 13 ... 15