microcorruption/chernobyl/notes.md

6.5 KiB

You can add multiple commands by delimiting with ; and without a space after:

new ibio 1337;new xnjc 1337;new folm 1337;

Command to print tree:

#define walk pc=45ba; r15=5000; b 465c; continue

Set Breakpoints at hash and rehash:

reset; b 4866; b 4870; b 490a

Q and A:

1: Figure out what 3 and 5 parameters are for.

  • The 5 stands for the entries per sub-table.
  • The 3 stands for the log2 number of sub-tables

2: Find out what rehash trigger depends on.

Rehash is triggered when a sub table is full (when I use aaaa, bbbb, cccc as usernames these result in the same hash and fill up the table).

Tree Structure Interpretation

@5000 [alloc] [p 5000] [n 5010] [s 000a]
 {5006} [ 0005 ; current entries
          0003 ; heap size log2, i.e. for 3 there are 8 tables, for 4 there are 16 tables and so on
          0005 ; max entries per table
          5016 ; pointer to array of row pointers
          502c ; pointer to array of curren entries for that table
        ]
@5010 [alloc] [p 5000] [n 5026] [s 0010]
 {5016} [ 5042 50a2 5102 5162 51c2 5222 5282 52e2 ] ; addess of each row
@5026 [alloc] [p 5010] [n 503c] [s 0010]
 {502c} [ 0005 0000 0000 0000 0000 0000 0000 0000 ] ; current entries for that row
@503c [alloc] [p 5026] [n 509c] [s 005a]
 {5042} [ 6161 6161 0000 0000 0000 0000 0000 0000 0539 6262 6262 0000 0000 0000 0000 0000 0000 0539 6363 6363 0000 0000 0000 0000 0000 0000 0539 6464 6464 0000 0000 0000 0000 0000 0000 0539 6565 6565 0000 0000 0000 0000 0000 0000 0539 ]
@509c [alloc] [p 503c] [n 50fc] [s 005a]
 {50a2} [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ]
@50fc [alloc] [p 509c] [n 515c] [s 005a]
 {5102} [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ]
@515c [alloc] [p 50fc] [n 51bc] [s 005a]
 {5162} [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ]
@51bc [alloc] [p 515c] [n 521c] [s 005a]
 {51c2} [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ]
@521c [alloc] [p 51bc] [n 527c] [s 005a]
 {5222} [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ]
@527c [alloc] [p 521c] [n 52dc] [s 005a]
 {5282} [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ]
@52dc [alloc] [p 527c] [n 533c] [s 005a]
 {52e2} [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ]
@533c [freed] [p 52dc] [n 5000] [s 7cbe]

Random Thoughts

The application has a user authentication mechanism where you can add user names together with a pin to a hash table. Then, when accessing an acount it is looked up in the table. The funny thing is that even if access is granted nothing happens, so that means there has to be some way to exploit the application.

What I have found out is that there is a walk function that shows the current dynamic memory allocation. The hash table has a control field with the current fill status, pointers to data rows and to the fill status of each data row.

There is one vulnerability where the dynamic memory allocation block can be overriden by writing more than five entries into the same hash table row. My first idea was to use that to pretend that there is free memory in the stack section, but the malloc function has a check that the following address is higher than the current one, so that didn't work.

At that point, I had not other ideas. If we think backwards from how a solution could look like, we get the following:

  • Put shell code that opens the door somewhere. This is trivial because there aren't any input constraints except (no null bytes).
  • Manipulate a return address on the stack to jump to our inserted shell code.
  • We could do that my malloc memory in the stack area and then use the input feature to override the return address. (This does not work because malloc checks the address of the next block and it has to be higher than the previous block.)

What can we assume:

  • Since we are able to override the memory allocation controll block, it seems reasonable that that's where the vulnerability is. We have walk, malloc, free as potential attack vectors. Actually, walk not because it's not called.
  • We have already poked at malloc a little, so let's check out free.

After trying to understand free, I can say that I don't fully understand it yet, but it definitely looks like things aren't properly check as they are in Malloc. I think I can use it to write to an arbitrary address.

Okay, I've found out that by overriding the prev value I can point it into the stack region. Specifically, it seems like 3dcc is the right address. I can then override next value with the address of my shell code. For now, I will just use 8080.

I found out that overriding the next address doesn't work, because malloc has a check that the address keep incrementing, so I cannot maniuplate next address. It's the same issue as mentioned above. However, I can manipulate prev address.

By combining prev address with status, I should be able to manipulate the return address.

However, I ran into one more issue. When freeing, the free function checks the next memory block and if it is free merges it with the current one which overrides the prev manipulation. That means we have to override the next pointer of the first block, and the prev pointer of the second block. We then have to maniuplate status so that the resulting return address ends up being at a location we like. Cool.

That's how I ended up with the solution with gen_first_override_block gen_second_override_block. That was fun.