Avatar
Part time CTF Player learn every day!!
🌠 I Love Hoshimachi Suisei!! 🌠
🌠 I Love Hoshimachi Suisei!! 🌠

OverTheWire Maze Level 4 → 5 tutorial!!

Login

ssh maze4@maze.labs.overthewire.org -p <PORT>
# password: ishipaeroo

Binary: /maze/maze5


Task

This binary asks for a username and a key, both exactly 8 characters long. If inputs satisfy the internal check in foo(), we get a shell.


Code Analysis

Main logic:

int main(void) {
  char user[9];
  char pass[9];

  printf(" Username: ");
  scanf("%8s", user);

  printf("      Key: ");
  scanf("%8s", pass);

  if (strlen(user)==8 && strlen(pass)==8) {
    if (ptrace(PTRACE_TRACEME,0,0,0) == 0) {
      if (foo(user, pass)) {
        puts("Yeh, here's your shell");
        system("/bin/sh");
      } else {
        puts("Nah, wrong.");
      }
    } else {
      puts("nahnah..."); // anti-debug
    }
  } else {
    puts("Wrong length you!");
  }
}

So the check is hidden inside foo(user, pass).


The foo() function

Reverse engineering gives us:

int foo(char* user, char* pass){
  char p[9] = {0x70, 0x72, 0x69, 0x6e, 0x74, 0x6c, 0x6f, 0x6c}; 
  // ASCII: "printlol"

  for(int i = 0; i < 8; i++){
    p[i] -= user[i] + 2*i - 0x41;
  }

  do {
    i--;
    if(i == 0) return 1; // success if all matched
  } while(pass[i] == p[i]);

  return 0; // fail
}

Key idea: We must choose user[i] such that p[i] stays unchanged after subtraction.

That means:

user[i] + 2*i - 0x41 == 0
→ user[i] == 0x41 - 2*i

Constructing Inputs

Let’s calculate user:

i=0 → 0x41 = 'A'
i=1 → 0x3F = '?'
i=2 → 0x3D = '='
i=3 → 0x3B = ';'
i=4 → 0x39 = '9'
i=5 → 0x37 = '7'
i=6 → 0x35 = '5'
i=7 → 0x33 = '3'

So user = "A?=;9753"

And pass = "printlol"


Solution

Run the binary:

/maze/maze5
 Username: A?=;9753
      Key: printlol

Result:

Yeh, here's your shell
$ id
$ cat /etc/maze_pass/maze5

Flag obtained:

epheghuoli

Why this works

  • The key idea is keeping p[i] unchanged inside foo().
  • Choosing user[i] = 0x41 - 2*i cancels out the subtraction.
  • So the comparison loop passes when we also supply pass = "printlol".

Thanks for reading!

Until next time — Otsumachi!! 💖☄️✨

Cinema

all tags

GOT-overwrite aboutme aead ai alphanumeric-shellcode apt argc0 argon2 aslr assembly asymmetric atoi automation backbox bandit base64 bash beginner behemoth binary binary-exploitation binary-to-ascii blackarch blind blind-sqli blogging blue-team bruteforce buffer-overflow buffer-overwrite c caesar canary capabilities checksec command-injection commonmark cookie cron crypto cryptography ctf cutter cyberchef cybersecurity defenders detection dev directory-traversal dnf docs drifter ecc education elf env envp exploitation finale forensics format-string formulaone frequency frequency-analysis gcc gdb getchar gfm ghidra github-pages governance gpg guide hashing hkdf http jekyll jmpbuf kali kasiski kdf kernel keylength kramdown krypton lab ld_preload leviathan lfi lfsr linux linux-syscall llmops log-poisoning ltrace manpage markdown maze memcpy mitigations mitmproxy mlops narnia natas networking newline-injection nonce nop-sled nx object-injection obsidian openssl osint overflow overthewire package-manager pacman parrot path path-hijacking pathname php pie pkc pki pointer-trick pqc priv-esc privilege-escalation provable-security pwn pwntools pyshark python race-condition radare2 rag randomness recon red-team redirect relro requests ret2env ret2libc reverse-engineering reversing ricing roadmap rop rot13 rsa scapy security seed seo serialization session setjmp-longjmp setuid shell shellcode smoke soc sockets sprintf sql-injection srop stack-canary stack-overflow strace strcmp strcpy streamcipher strings strncpy strtoul substitution suid suisei symlink symmetric terminal test threat-intel time-based tls troubleshooting tshark type-juggling ubuntu udp utumno vigenere virtualbox virtualization vmware vortex walkthrough web windows wireshark writing wsl x86
dash theme for Jekyll by bitbrain made with