diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index c65003023..5a440cde1 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -27,7 +27,7 @@ jobs: run: | set -x pip install pylint - pip install --upgrade -e . + pip install --upgrade -e .[full] pylint --exit-zero --errors-only pwnlib -f parseable | cut -d ' ' -f2- > current.txt git fetch origin git checkout origin/"$GITHUB_BASE_REF" diff --git a/README.md b/README.md index 7bd8fdf99..2142f2450 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Python3 is suggested, but Pwntools still works with Python 2.7. Most of the fun sudo apt-get update sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential python3 -m pip install --upgrade pip -python3 -m pip install --upgrade pwntools +python3 -m pip install --upgrade pwntools[full] ``` diff --git a/pwn/toplevel.py b/pwn/toplevel.py index 92b01ad1d..727997330 100644 --- a/pwn/toplevel.py +++ b/pwn/toplevel.py @@ -6,7 +6,6 @@ import os import platform import re -import socks import signal import string import struct @@ -84,6 +83,7 @@ debug = log.debug success = log.success +# optional deps try: import colored_traceback except ImportError: @@ -91,5 +91,10 @@ else: colored_traceback.add_hook() +try: + import socks +except ImportError: + pass + # Equivalence with the default behavior of "from import *" # __all__ = [x for x in tuple(globals()) if not x.startswith('_')] diff --git a/pwnlib/context/__init__.py b/pwnlib/context/__init__.py index 0750c7f20..7aaba70d2 100644 --- a/pwnlib/context/__init__.py +++ b/pwnlib/context/__init__.py @@ -23,8 +23,6 @@ import threading import time -import socks - from pwnlib.config import register_config from pwnlib.device import Device from pwnlib.timeout import Timeout @@ -1281,6 +1279,8 @@ def proxy(self, proxy): socket.socket = _original_socket return None + import socks # keep dependency optional + if isinstance(proxy, str): proxy = (socks.SOCKS5, proxy) diff --git a/pwnlib/protocols/adb/__init__.py b/pwnlib/protocols/adb/__init__.py index bf305c74b..1c7f199a5 100644 --- a/pwnlib/protocols/adb/__init__.py +++ b/pwnlib/protocols/adb/__init__.py @@ -23,7 +23,6 @@ from pwnlib.util.lists import group from pwnlib.util.misc import size from pwnlib.util.packing import p32 -from pwnlib.util.proc import pidof from pwnlib.util.sh_string import sh_string log = getLogger(__name__) diff --git a/pwnlib/tubes/remote.py b/pwnlib/tubes/remote.py index 58008194c..f749c88af 100644 --- a/pwnlib/tubes/remote.py +++ b/pwnlib/tubes/remote.py @@ -2,7 +2,6 @@ from __future__ import division import socket -import socks from pwnlib.log import getLogger from pwnlib.timeout import Timeout @@ -41,7 +40,7 @@ class remote(sock): >>> r = remote('127.0.0.1', 1) Traceback (most recent call last): ... - PwnlibException: Could not connect to 127.0.0.1 on port 1 + ConnectionRefusedError: [Errno 111] Connection refused You can also use :meth:`.remote.fromsocket` to wrap an existing socket. @@ -97,11 +96,12 @@ def __init__(self, host, port, self.sock = ssl_context.wrap_socket(self.sock,**ssl_args) def _connect(self, fam, typ): - sock = None + err = None + sock = None timeout = self.timeout with self.waitfor('Opening connection to %s on port %s' % (self.rhost, self.rport)) as h: - for res in socket.getaddrinfo(self.rhost, self.rport, fam, typ, 0, socket.AI_PASSIVE): + for res in socket.getaddrinfo(self.rhost, self.rport, fam, typ): self.family, self.type, self.proto, _canonname, sockaddr = res if self.type not in [socket.SOCK_STREAM, socket.SOCK_DGRAM]: @@ -119,11 +119,13 @@ def _connect(self, fam, typ): try: sock.connect(sockaddr) + err = None # break ref cycle return sock - except socks.ProxyError: - raise - except socket.error: - pass + except IOError as e: + if err is None: + err = e + if err is not None: + raise err self.error("Could not connect to %s on port %s", self.rhost, self.rport) @classmethod diff --git a/pwnlib/tubes/serialtube.py b/pwnlib/tubes/serialtube.py index f8d7b72b3..2cb06f931 100644 --- a/pwnlib/tubes/serialtube.py +++ b/pwnlib/tubes/serialtube.py @@ -6,8 +6,6 @@ import sys import time -import serial - from pwnlib.log import getLogger from pwnlib.tubes import tube @@ -30,6 +28,9 @@ def __init__( self.convert_newlines = convert_newlines # serial.Serial might throw an exception, which must be handled # and propagated accordingly using self.exception + + import serial + try: self.conn = serial.Serial( port = port, diff --git a/pyproject.toml b/pyproject.toml index ce59233f9..98285bfd7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,31 +34,35 @@ keywords = ["pwntools", "exploit", "ctf", "capture", "the", "flag", "binary", "w requires-python = ">=2.7" dependencies = [ - "paramiko>=1.15.2", "mako>=1.0.0", "pyelftools>=0.29, <0.30; python_version < '3'", "pyelftools>=0.29; python_version >= '3'", - "capstone>=3.0.5rc2", # see Gallopsled/pwntools#971, Gallopsled/pwntools#1160 "ropgadget>=5.3", - "pyserial>=2.7", - "requests>=2.0", "pip>=6.0.8", "pygments>=2.0", - "pysocks", "python-dateutil", "packaging", "psutil>=3.3.0", "intervaltree>=3.0", "sortedcontainers", - "unicorn>=2.0.1", "six>=1.12.0", - "rpyc", - "colored_traceback", "pathlib2; python_version < '3.4'", "unix-ar; python_version >= '3'", "zstandard", ] +[project.optional-dependencies] +full = [ + "capstone>=3.0.5rc2", # see Gallopsled/pwntools#971, Gallopsled/pwntools#1160 + "colored_traceback", + "paramiko>=1.15.2", + "pyserial>=2.7", + "pysocks", + "requests>=2.0", + "rpyc", + "unicorn>=2.0.1", +] + [project.urls] homepage = "https://pwntools.com" download = "https://github.com/Gallopsled/pwntools/releases"