2

I'm trying to exploit a basic C program (below) which I've written:

#include <stdio.h>
#include <string.h>

void main()
{
    char ch[10];
    scanf("%s", ch);
    if(strcmp("1235", ch))
    printf("\nAccess Denied\n");
    else
    printf("\nAccess Approved\n");
}

It will ask you to input a string (as a password) and if its "1235" it will print "Access Approved", otherwise "Access Denied".

The goal is to print "Access Approved" message without supplying "1235".

I've exploited it with in gdb with a buffer overflow of the ch array and replaced the stack frame's return address with the address which initiate the sequence for printing of the "Access Approved" message.

But outside gdb, linux shifts the addresses everytime I run the program. And now I can't figure out what to do to know what the address of the initiation sequence is for a certain instance and how I'll pass the address in that instance, as next time it will change.

1
  • Well, that's the point of ASLR, that you can't know the locations. The program has a buffer overflow vulnerability, but that vulnerability can't be used for your intended exploit.
    – amon
    Feb 10, 2021 at 19:50

1 Answer 1

1

This is intended behaviour! Your exploit is being thwarted by an exploit mitigation technique called address space layout randomisation (ASLR). The address at which the target executable is being loaded at is randomised at every launch in order to make it harder to exploit vulnerabilities.

When you debug a program with gdb, it disables ASLR on the target process by default in order to make debugging easier. You can turn this behaviour off with the set disable-randomization off command.

Many years ago the standard approach to exploiting this kind of stack buffer overflow vulnerability was to inject instructions into memory (usually the stack) and jump to that memory. Modern systems have a feature called no-execute (NX) - also referred to as Data Execution Prevention (DEP) in Windows - that prevents the CPU from being able to execute code in memory pages that are not explicitly marked as executable. This prevents you from just putting an executable payload into the stack and jumping to it.

In order to get around NX, folks instead started abusing existing executable code in the program. This is what you're doing here - jumping to existing instructions in order to modify the behaviour of the program, instead of trying to provide your own instructions. This is often referred to as ret2libc because a common approach with this technique is to cause the program to set up the stack and jump to a libc function such as system() in order to execute arbitrary commands, or mprotect() in order to mark some memory you control as executable in order to defeat NX and execute arbitrary instructions.

A more general form of this attack is known as return-oriented programming, in which gadgets - small chunks of code from the application code that are followed by a ret instruction - are chained together through stack manipulation in order to make a libc call.

With both NX and ASLR enabled, ret2libc attacks are much harder to pull off. You can't load your own instructions into the stack because of NX, and you don't know the memory addresses of instructions that you can abuse because of ASLR. Defeating both of these protections can be tricky. Usually you need to discover the address of some executable data in the program first. This might be possible if one of the libraries that is loaded is not marked as position-independent (PIE), and therefore is always at the same address. Alternatively, you might try to find a pointer leak in the target application that allows you to discover the address at which the program was loaded in memory.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .