Example #1
0
def gnu_hash(s):
    """gnu_hash(str) -> int

    Function used to generated GNU-style hashes for strings.
    """
    s = bytearray(_encode(s))
    h = 5381
    for c in s:
        h = h * 33 + c
    return h & 0xffffffff
Example #2
0
    def write_text(self, data):
        r"""Write text to the file at this path

        >>> f = SSHPath('somefile', ssh=ssh_conn)
        >>> f.write_text("HELLO 😭")
        >>> f.read_bytes()
        b'HELLO \xf0\x9f\x98\xad'
        >>> f.read_text()
        'HELLO 😭'
        """
        data = _encode(data)
        self.write_bytes(data)
Example #3
0
def sysv_hash(symbol):
    """sysv_hash(str) -> int

    Function used to generate SYSV-style hashes for strings.
    """
    h = 0
    g = 0
    for c in bytearray(_encode(symbol)):
        h = (h << 4) + c
        g = h & 0xf0000000
        h ^= (g >> 24)
        h &= ~g
    return h & 0xffffffff
Example #4
0
    def _dynamic_load_dynelf(self, libname):
        """_dynamic_load_dynelf(libname) -> DynELF

        Looks up information about a loaded library via the link map.

        Arguments:
            libname(str):  Name of the library to resolve, or a substring (e.g. 'libc.so')

        Returns:
            A DynELF instance for the loaded library, or None.
        """
        cur = self.link_map
        leak = self.leak
        LinkMap = {
            32: elf.Elf32_Link_Map,
            64: elf.Elf64_Link_Map
        }[self.elfclass]

        # make sure we rewind to the beginning!
        while leak.field(cur, LinkMap.l_prev):
            cur = leak.field(cur, LinkMap.l_prev)

        libname = _encode(libname)

        while cur:
            self.status("link_map entry %#x" % cur)
            p_name = leak.field(cur, LinkMap.l_name)
            name = leak.s(p_name)

            if libname in name:
                break

            if name:
                self.status('Skipping %s' % name)

            cur = leak.field(cur, LinkMap.l_next)
        else:
            self.failure("Could not find library with name containing %r" %
                         libname)
            return None

        libbase = leak.field(cur, LinkMap.l_addr)

        self.status("Resolved library %r at %#x" % (libname, libbase))

        lib = DynELF(leak, libbase)
        lib._dynamic = leak.field(cur, LinkMap.l_ld)
        lib._waitfor = self._waitfor
        return lib
Example #5
0
    def __init__(self, elf, symbol, args, data_addr=None):
        self.elf = elf
        self.elf_load_address_fixup = self.elf.address - self.elf.load_addr
        self.strtab = elf.dynamic_value_by_tag("DT_STRTAB") + self.elf_load_address_fixup
        self.symtab = elf.dynamic_value_by_tag("DT_SYMTAB") + self.elf_load_address_fixup
        self.jmprel = elf.dynamic_value_by_tag("DT_JMPREL") + self.elf_load_address_fixup
        self.versym = elf.dynamic_value_by_tag("DT_VERSYM") + self.elf_load_address_fixup
        self.symbol = _encode(symbol)
        self.args = args
        self.real_args = self._format_args()
        self.unreliable = False

        self.data_addr = data_addr if data_addr is not None else self._get_recommended_address()

        # Will be set when built
        self.reloc_index = -1
        self.payload = b""

        # PIE is untested, gcc forces FULL-RELRO when PIE is set
        if self.elf.pie and self.elf_load_address_fixup == 0:
            log.warning("WARNING: ELF is PIE but has no base address set")

        self._build()
Example #6
0
 def aux(args):
     for i, arg in enumerate(args):
         if isinstance(arg, (str,bytes)):
             args[i] = _encode(args[i]) + b"\x00"
         elif isinstance(arg, (list, tuple)):
             aux(arg)
Example #7
0
def cyclic_find(subseq, alphabet = None, n = None):
    """cyclic_find(subseq, alphabet = None, n = None) -> int

    Calculates the position of a substring into a De Bruijn sequence.

    .. todo:

       "Calculates" is an overstatement. It simply traverses the list.

       There exists better algorithms for this, but they depend on generating
       the De Bruijn sequence in another fashion. Somebody should look at it:

       https://www.sciencedirect.com/science/article/pii/S0012365X00001175

    Arguments:
        subseq: The subsequence to look for. This can be a string, a list or an
                integer. If an integer is provided it will be packed as a
                little endian integer.
        alphabet: List or string to generate the sequence over.
                  By default, uses :obj:`.context.cyclic_alphabet`.
        n(int): The length of subsequences that should be unique.
                By default, uses :obj:`.context.cyclic_size`.

    Examples:

        Let's generate an example cyclic pattern.

        >>> cyclic(16)
        b'aaaabaaacaaadaaa'

        Note that 'baaa' starts at offset 4.  The `cyclic_find` routine shows us this:

        >>> cyclic_find(b'baaa')
        4

        The *default* length of a subsequence generated by `cyclic` is `4`.
        If a longer value is submitted, it is automatically truncated to four bytes.

        >>> cyclic_find(b'baaacaaa')
        4

        If you provided e.g. `n=8` to `cyclic` to generate larger subsequences,
        you must explicitly provide that argument.

        >>> cyclic_find(b'baaacaaa', n=8)
        3515208

        We can generate a large cyclic pattern, and grab a subset of it to
        check a deeper offset.

        >>> cyclic_find(cyclic(1000)[514:518])
        514

        Instead of passing in the byte representation of the pattern, you can
        also pass in the integer value.  Note that this is sensitive to the
        selected endianness via `context.endian`.

        >>> cyclic_find(0x61616162)
        4
        >>> cyclic_find(0x61616162, endian='big')
        1

        You can use anything for the cyclic pattern, including non-printable
        characters.

        >>> cyclic_find(0x00000000, alphabet=unhex('DEADBEEF00'))
        621
    """

    if n is None:
        n = context.cyclic_size

    if isinstance(subseq, six.integer_types):
        subseq = packing.pack(subseq, bytes=n)
    subseq = packing._encode(subseq)

    if len(subseq) != n:
        log.warn_once("cyclic_find() expects %i-byte subsequences by default, you gave %r\n"
            "Unless you specified cyclic(..., n=%i), you probably just want the first 4 bytes.\n"
            "Truncating the data at 4 bytes.  Specify cyclic_find(..., n=%i) to override this.",
            n, subseq, len(subseq), len(subseq))
        subseq = subseq[:n]

    if alphabet is None:
        alphabet = context.cyclic_alphabet
    alphabet = packing._encode(alphabet)

    if any(c not in alphabet for c in subseq):
        return -1

    n = n or len(subseq)

    return _gen_find(subseq, de_bruijn(alphabet, n))
Example #8
0
    def lookup(self, symb=None, lib=None):
        """lookup(symb = None, lib = None) -> int

        Find the address of ``symbol``, which is found in ``lib``.

        Arguments:
            symb(str): Named routine to look up
              If omitted, the base address of the library will be returned.
            lib(str): Substring to match for the library name.
              If omitted, the current library is searched.
              If set to ``'libc'``, ``'libc.so'`` is assumed.

        Returns:
            Address of the named symbol, or :const:`None`.
        """
        result = None

        if lib == 'libc':
            lib = 'libc.so'

        if symb:
            symb = _encode(symb)

        #
        # Get a pretty name for the symbol to show the user
        #
        if symb and lib:
            pretty = '%r in %r' % (symb, lib)
        else:
            pretty = repr(symb or lib)

        if not pretty:
            self.failure("Must specify a library or symbol")

        self.waitfor('Resolving %s' % pretty)

        #
        # If we are loading from a different library, create
        # a DynELF instance for it.
        #
        if lib is not None: dynlib = self._dynamic_load_dynelf(lib)
        else: dynlib = self

        if dynlib is None:
            log.failure("Could not find %r" % lib)
            return None

        #
        # If we are resolving a symbol in the library, find it.
        #
        if symb and self.libcdb:
            # Try a quick lookup by build ID
            self.status("Trying lookup based on Build ID")
            build_id = dynlib._lookup_build_id(lib=lib)
            if build_id:
                log.info("Trying lookup based on Build ID: %s" % build_id)
                path = libcdb.search_by_build_id(build_id)
                if path:
                    with context.local(log_level='error'):
                        e = ELF(path)
                        e.address = dynlib.libbase
                        result = e.symbols[symb]
        if symb and not result:
            self.status("Trying remote lookup")
            result = dynlib._lookup(symb)
        if not symb:
            result = dynlib.libbase

        #
        # Did we win?
        #
        if result: self.success("%#x" % result)
        else: self.failure("Could not find %s" % pretty)

        return result