예제 #1
0
def which(name, all=False, *a, **kw):
    """Retrieves the full path to a binary in ``$PATH`` on the device

    Arguments:
        name(str): Binary name
        all(bool): Whether to return all paths, or just the first
        *a: Additional arguments for :func:`.adb.process`
        **kw: Additional arguments for :func:`.adb.process`

    Returns:
        Either a path, or list of paths

    Example:

    .. doctest::
       :skipif: skip_android

        >>> adb.which('sh')
        '/system/bin/sh'
        >>> adb.which('sh', all=True)
        ['/system/bin/sh']

        >>> adb.which('foobar') is None
        True
        >>> adb.which('foobar', all=True)
        []
    """
    # Unfortunately, there is no native 'which' on many phones.
    which_cmd = '''
(IFS=:
  for directory in $PATH; do
      [ -x "$directory/{name}" ] || continue;
      echo -n "$directory/{name}\\x00";
  done
)
[ -x "{name}" ] && echo -n "$PWD/{name}\\x00"
'''.format(name=name)

    which_cmd = which_cmd.strip()
    data = process(['sh', '-c', which_cmd], *a, **kw).recvall()
    data = context._decode(data)
    result = []

    for path in data.split('\x00'):
        # Skip empty entries
        if not path:
            continue

        # Return the first entry if all=False
        if not all:
            return path

        # Accumulate all entries if all=True
        result.append(path)

    if all:
        return result

    return None
예제 #2
0
def getprop(name=None):
    """Reads a properties from the system property store.

    Arguments:
        name(str): Optional, read a single property.

    Returns:
        If ``name`` is not specified, a ``dict`` of all properties is returned.
        Otherwise, a string is returned with the contents of the named property.

    Example:

    .. doctest::
       :skipif: skip_android

        >>> adb.getprop() # doctest: +ELLIPSIS
        {...}
    """
    with context.quiet:
        if name:
            result = process(['getprop', name]).recvall().strip()
            result = context._decode(result)
            return result

        result = process(['getprop']).recvall()

    result = context._decode(result)
    expr = r'\[([^\]]+)\]: \[(.*)\]'

    props = {}
    for line in result.splitlines():
        if not line.startswith('['):
            continue

        name, value = re.search(expr, line).groups()

        if value.isdigit():
            value = int(value)

        props[name] = value

    return props
예제 #3
0
파일: ssh.py 프로젝트: tejas303525/pwntools
    def _s(self, other):
        # We want strings
        if isinstance(other, str):
            return other

        # We don't want unicode
        if isinstance(other, six.text_type):
            return str(other)

        # We also don't want binary
        if isinstance(other, six.binary_type):
            return str(context._decode(other))
예제 #4
0
파일: tube.py 프로젝트: cc-sir/pwntools
    def recvlinesS(self, numlines=2**20, keepends=False, timeout=default):
        r"""recvlinesS(numlines, keepends=False, timeout=default) -> str list

        This function is identical to :meth:`recvlines`, but decodes
        the received bytes into string using :func:`context.encoding`.
        You should use :meth:`recvlines` whenever possible for better performance.

        Examples:

            >>> t = tube()
            >>> t.recv_raw = lambda n: b'\n'
            >>> t.recvlinesS(3)
            ['', '', '']
            >>> t.recv_raw = lambda n: b'Foo\nBar\nBaz\n'
            >>> t.recvlinesS(3)
            ['Foo', 'Bar', 'Baz']
        """
        return [context._decode(x) for x in self.recvlines(numlines, keepends, timeout)]
예제 #5
0
def find_module_addresses(binary, ssh=None, ulimit=False):
    """
    Cheat to find modules by using GDB.

    We can't use ``/proc/$pid/map`` since some servers forbid it.
    This breaks ``info proc`` in GDB, but ``info sharedlibrary`` still works.
    Additionally, ``info sharedlibrary`` works on FreeBSD, which may not have
    procfs enabled or accessible.

    The output looks like this:

    ::

        info proc mapping
        process 13961
        warning: unable to open /proc file '/proc/13961/maps'

        info sharedlibrary
        From        To          Syms Read   Shared Object Library
        0xf7fdc820  0xf7ff505f  Yes (*)     /lib/ld-linux.so.2
        0xf7fbb650  0xf7fc79f8  Yes         /lib32/libpthread.so.0
        0xf7e26f10  0xf7f5b51c  Yes (*)     /lib32/libc.so.6
        (*): Shared library is missing debugging information.

    Note that the raw addresses provided by ``info sharedlibrary`` are actually
    the address of the ``.text`` segment, not the image base address.

    This routine automates the entire process of:

    1. Downloading the binaries from the remote server
    2. Scraping GDB for the information
    3. Loading each library into an ELF
    4. Fixing up the base address vs. the ``.text`` segment address

    Arguments:
        binary(str): Path to the binary on the remote server
        ssh(pwnlib.tubes.tube): SSH connection through which to load the libraries.
            If left as :const:`None`, will use a :class:`pwnlib.tubes.process.process`.
        ulimit(bool): Set to :const:`True` to run "ulimit -s unlimited" before GDB.

    Returns:
        A list of pwnlib.elf.ELF objects, with correct base addresses.

    Example:

    >>> with context.local(log_level=9999):
    ...     shell =  ssh(host='example.pwnme', user='******', password='******')
    ...     bash_libs = gdb.find_module_addresses('/bin/bash', shell)
    >>> os.path.basename(bash_libs[0].path)
    'libc.so.6'
    >>> hex(bash_libs[0].symbols['system']) # doctest: +SKIP
    '0x7ffff7634660'
    """
    #
    # Download all of the remote libraries
    #
    if ssh:
        runner = ssh.run
        local_bin = ssh.download_file(binary)
        local_elf = elf.ELF(os.path.basename(binary))
        local_libs = ssh.libs(binary)

    else:
        runner = tubes.process.process
        local_elf = elf.ELF(binary)
        local_libs = local_elf.libs

    #
    # Get the addresses from GDB
    #
    libs = {}
    cmd = "gdb -q -nh --args %s | cat" % (
        binary)  # pipe through cat to disable colored output on GDB 9+
    expr = re.compile(r'(0x\S+)[^/]+(.*)')

    if ulimit:
        cmd = ['sh', '-c', "(ulimit -s unlimited; %s)" % cmd]
    else:
        cmd = ['sh', '-c', cmd]

    with runner(cmd) as gdb:
        if context.aslr:
            gdb.sendline('set disable-randomization off')

        gdb.send("""
        set prompt
        catch load
        run
        """)
        gdb.sendline('info sharedlibrary')
        lines = context._decode(gdb.recvrepeat(2))

        for line in lines.splitlines():
            m = expr.match(line)
            if m:
                libs[m.group(2)] = int(m.group(1), 16)
        gdb.sendline('kill')
        gdb.sendline('y')
        gdb.sendline('quit')

    #
    # Fix up all of the addresses against the .text address
    #
    rv = []

    for remote_path, text_address in sorted(libs.items()):
        # Match up the local copy to the remote path
        try:
            path = next(p for p in local_libs.keys() if remote_path in p)
        except StopIteration:
            print("Skipping %r" % remote_path)
            continue

        # Load it
        lib = elf.ELF(path)

        # Find its text segment
        text = lib.get_section_by_name('.text')

        # Fix the address
        lib.address = text_address - text.header.sh_addr
        rv.append(lib)

    return rv
예제 #6
0
파일: tube.py 프로젝트: x0rzkov/pwntools
 def wrapperS(self, *a, **kw):
     return context._decode(func(self, *a, **kw))
예제 #7
0
파일: ssh.py 프로젝트: tejas303525/pwntools
 def mkdtemp(self):
     temp = context._decode(context.ssh_session.mkdtemp())
     return SSHPath(temp, ssh=context.ssh_session)