OverTheWire FormulaOne Level 4 → 5 tutorial!!
Login
Connect to the FormulaOne game as formulaone4:
ssh formulaone4@formulaone.labs.overthewire.org -p 2232
# password: (from previous level)
Task
Find an exploit in the formulaone5 binary that gives us the password for user formulaone5.
Analyzing the Code
Here’s the vulnerable program (nemo1.c
), left behind on the server:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#define NBUFSIZ 1024
char *buf,*brrr;
void (*mfptrr)();
char buf2[NBUFSIZ];
void func1(char *arg)
{
char envar[NBUFSIZ+1];
strncpy(envar,arg,NBUFSIZ);
envar[NBUFSIZ] = 0;
printf("[*] Environment variable: %s\n",envar);
return;
}
void int_handler()
{
if(strlen(buf) >= NBUFSIZ -1) {
exit(1);
}
memcpy(buf2,buf,strlen(buf)-1);
printf("[+] Local buffer: %s.\n",buf2);
mfptrr(0);
}
void cont_handler()
{
printf("[+] :D\n");
mfptrr(0);
}
void check_main(char **av)
{
int a,b,c;
char *home;
long key;
if(home = getenv("HOME")) {
if(home[1]) {
a = rand();
b = (int)home[0];
c = (int)home[1];
key = a + b + c;
}
}
if(key == 0xdeadbeef) {
signal(SIGINT, int_handler);
signal(SIGCONT, cont_handler);
if(getenv("TIMER")) sleep(1);
buf = malloc(NBUFSIZ + 1);
strncpy(buf,av[1],NBUFSIZ);
buf[NBUFSIZ] = 0;
}
return;
}
int main(int ac, char **av, char **env)
{
char **tmp = env,*loc_brrr;
mfptrr = exit;
srand(0xcafebabe);
if((long)&buf2 > (long)&mfptrr) {
printf("[!] Sorry, it's unlikely you can exploit this with your version of gcc.\n");
exit(1);
}
if(getenv("BUFFER")) buf = strdup(getenv("BUFFER"));
if(getenv("TERM")) brrr = strdup(getenv("TERM"));
while(*(++tmp)) func1(*tmp);
check_main(av);
return 1;
}
Theory
This program sets up signal handlers (SIGINT
, SIGCONT
) and allows interaction with buffers of fixed size (buf2
, envar
). There is clearly a chance for buffer overflow / pointer overwrite.
However, the crucial piece is this runtime check:
if((long)&buf2 > (long)&mfptrr) {
printf("[!] Sorry, it's unlikely you can exploit this with your version of gcc.\n");
exit(1);
}
This ensures the relative stack layout must match a specific pattern (pointer mfptrr
below buf2
). On modern GCC / glibc builds, this layout is different, so the exploit path doesn’t work anymore.
That means the challenge is tied to a specific compiler and memory layout from when the wargame was first released.
Solution
- The intended exploit path is to trigger a buffer overflow and overwrite the function pointer
mfptrr
so that it points to malicious code. -
Unfortunately, the stack check aborts execution on modern systems:
[!] Sorry, it's unlikely you can exploit this with your version of gcc.
- This effectively blocks us unless we recompile with an older GCC that arranged variables differently.
So while we can inspect and understand the vulnerable code, we can’t practically exploit it on the current OTW servers.
Conclusion
This is the last playable level of FormulaOne. The intended exploit (overwriting the function pointer after manipulating buffers + signals) only works on certain legacy GCC versions.
Because of that, the OverTheWire admins left the challenge code up as a curiosity, but it cannot be solved under the current server configuration.
It’s a slightly anti-climactic ending, but that’s the nature of older wargames — sometimes compilers and protections evolve, breaking old challenges.
Thanks for reading!
Until next time — Otsumachi!! 💖☄️✨