-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
remote.py
140 lines (110 loc) · 4.35 KB
/
remote.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
from __future__ import absolute_import
from __future__ import division
import socket
import ssl as _ssl
from pwnlib.log import getLogger
from pwnlib.timeout import Timeout
from pwnlib.tubes.sock import sock
log = getLogger(__name__)
class remote(sock):
r"""Creates a TCP or UDP-connection to a remote host. It supports
both IPv4 and IPv6.
The returned object supports all the methods from
:class:`pwnlib.tubes.sock` and :class:`pwnlib.tubes.tube`.
Arguments:
host(str): The host to connect to.
port(int): The port to connect to.
fam: The string "any", "ipv4" or "ipv6" or an integer to pass to :func:`socket.getaddrinfo`.
typ: The string "tcp" or "udp" or an integer to pass to :func:`socket.getaddrinfo`.
timeout: A positive number, None or the string "default".
ssl(bool): Wrap the socket with SSL
sock(socket.socket): Socket to inherit, rather than connecting
Examples:
>>> r = remote('google.com', 443, ssl=True)
>>> r.send('GET /\r\n\r\n')
>>> r.recvn(4)
'HTTP'
If a connection cannot be made, an exception is raised.
>>> r = remote('127.0.0.1', 1)
Traceback (most recent call last):
...
PwnlibException: Could not connect to 127.0.0.1 on port 1
You can also use :meth:`.remote.fromsocket` to wrap an existing socket.
>>> import socket
>>> s = socket.socket()
>>> s.connect(('google.com', 80))
>>> s.send('GET /' + '\r\n'*2)
9
>>> r = remote.fromsocket(s)
>>> r.recvn(4)
'HTTP'
"""
def __init__(self, host, port,
fam = "any", typ = "tcp",
ssl=False, sock=None, *args, **kwargs):
super(remote, self).__init__(*args, **kwargs)
self.rport = int(port)
self.rhost = host
if sock:
self.family = sock.family
self.type = sock.type
self.proto = sock.proto
self.sock = sock
else:
typ = self._get_type(typ)
fam = self._get_family(fam)
try:
self.sock = self._connect(fam, typ)
except socket.gaierror as e:
if e.errno != socket.EAI_NONAME:
raise
self.error('Could not resolve hostname: %r' % host)
if self.sock:
self.settimeout(self.timeout)
self.lhost, self.lport = self.sock.getsockname()[:2]
if ssl:
self.sock = _ssl.wrap_socket(self.sock)
def _connect(self, fam, typ):
sock = None
timeout = self.timeout
with self.waitfor('Opening connection to %s on port %d' % (self.rhost, self.rport)) as h:
for res in socket.getaddrinfo(self.rhost, self.rport, fam, typ, 0, socket.AI_PASSIVE):
self.family, self.type, self.proto, _canonname, sockaddr = res
if self.type not in [socket.SOCK_STREAM, socket.SOCK_DGRAM]:
continue
h.status("Trying %s" % sockaddr[0])
sock = socket.socket(self.family, self.type, self.proto)
if timeout != None and timeout <= 0:
sock.setblocking(0)
else:
sock.setblocking(1)
sock.settimeout(timeout)
try:
sock.connect(sockaddr)
return sock
except socket.error:
pass
self.error("Could not connect to %s on port %d" % (self.rhost, self.rport))
@classmethod
def fromsocket(cls, socket):
"""
Helper method to wrap a standard python socket.socket with the
tube APIs.
Arguments:
socket: Instance of socket.socket
Returns:
Instance of pwnlib.tubes.remote.remote.
"""
s = socket
host, port = s.getpeername()
return remote(host, port, fam=s.family, typ=s.type, sock=s)
class tcp(remote):
__doc__ = remote.__doc__
def __init__(self, host, port, *a, **kw):
return super(tcp, self).__init__(host, port, typ="tcp", *a, **kw)
class udp(remote):
__doc__ = remote.__doc__
def __init__(self, host, port, *a, **kw):
return super(udp, self).__init__(host, port, typ="udp", *a, **kw)
class connect(remote):
__doc__ = remote.__doc__