@@ -91,7 +91,7 @@ if os.name != "nt":
91
91
92
92
APPNAME = "pwncat"
93
93
APPREPO = "https://github.com/cytopia/pwncat"
94
- VERSION = "0.0.16 -alpha"
94
+ VERSION = "0.0.17 -alpha"
95
95
96
96
# Default timeout for timeout-based sys.stdin and socket.recv
97
97
TIMEOUT_READ_STDIN = 0.1
@@ -272,6 +272,12 @@ class DsSock(object):
272
272
"""`bool`: Determines if we resolve hostnames or not."""
273
273
return self .__nodns
274
274
275
+ @property
276
+ def ipv6 (self ):
277
+ # type: () -> bool
278
+ """`bool`: Determines if we use IPv6 instead of IPv4."""
279
+ return self .__ipv6
280
+
275
281
@property
276
282
def udp (self ):
277
283
# type: () -> bool
@@ -281,17 +287,19 @@ class DsSock(object):
281
287
# --------------------------------------------------------------------------
282
288
# Constructor
283
289
# --------------------------------------------------------------------------
284
- def __init__ (self , bufsize , backlog , recv_timeout , nodns , udp ):
285
- # type: (int, int, Optional[float], bool, bool) -> None
290
+ def __init__ (self , bufsize , backlog , recv_timeout , nodns , ipv6 , udp ):
291
+ # type: (int, int, Optional[float], bool, bool, bool ) -> None
286
292
assert type (bufsize ) is int , type (bufsize )
287
293
assert type (backlog ) is int , type (backlog )
288
294
assert type (recv_timeout ) is float , type (recv_timeout )
289
295
assert type (nodns ) is bool , type (nodns )
296
+ assert type (ipv6 ) is bool , type (ipv6 )
290
297
assert type (udp ) is bool , type (udp )
291
298
self .__bufsize = bufsize
292
299
self .__backlog = backlog
293
300
self .__recv_timeout = recv_timeout
294
301
self .__nodns = nodns
302
+ self .__ipv6 = ipv6
295
303
self .__udp = udp
296
304
297
305
@@ -313,11 +321,11 @@ class DsIONetworkSock(DsSock):
313
321
# --------------------------------------------------------------------------
314
322
# Constructor
315
323
# --------------------------------------------------------------------------
316
- def __init__ (self , bufsize , backlog , recv_timeout , recv_timeout_retry , nodns , udp ):
317
- # type: (int, int, Optional[float], int, bool, bool) -> None
324
+ def __init__ (self , bufsize , backlog , recv_timeout , recv_timeout_retry , nodns , ipv6 , udp ):
325
+ # type: (int, int, Optional[float], int, bool, bool, bool ) -> None
318
326
assert type (recv_timeout_retry ) is int , type (recv_timeout_retry )
319
327
self .__recv_timeout_retry = recv_timeout_retry
320
- super (DsIONetworkSock , self ).__init__ (bufsize , backlog , recv_timeout , nodns , udp )
328
+ super (DsIONetworkSock , self ).__init__ (bufsize , backlog , recv_timeout , nodns , ipv6 , udp )
321
329
322
330
323
331
# -------------------------------------------------------------------------------------------------
@@ -880,7 +888,8 @@ class Sock(object):
880
888
# we can firstly/finally set its addr/port in order
881
889
# to send data back to it (see send() function)
882
890
if self .__options .udp :
883
- self .__remote_addr , self .__remote_port = addr
891
+ self .__remote_addr = addr [0 ]
892
+ self .__remote_port = addr [1 ]
884
893
self .__log .debug ("Client connected: %s:%d" , self .__remote_addr , self .__remote_port )
885
894
886
895
# [4/5] Upstream (server or client) is gone.
@@ -916,16 +925,18 @@ class Sock(object):
916
925
Raises:
917
926
socket.gaierror: If hostname cannot be resolved.
918
927
"""
919
- family = socket .AF_INET
928
+ family = socket .AF_INET6 if self . __options . ipv6 else socket . AF_INET
920
929
socktype = socket .SOCK_DGRAM if self .__options .udp else socket .SOCK_STREAM
921
930
proto = socket .SOL_UDP if self .__options .udp else socket .SOL_TCP
922
931
flags = 0
923
932
924
933
# Quickly do wildcards for listening addresses
925
934
if host is None :
926
935
if family == socket .AF_INET :
936
+ self .__log .debug ("Resolving hostname not required, using wildcard: 0.0.0.0" )
927
937
return "0.0.0.0"
928
938
if family == socket .AF_INET6 :
939
+ self .__log .debug ("Resolving hostname not required, using wildcard: ::" )
929
940
return "::"
930
941
931
942
if self .__options .nodns :
@@ -1005,18 +1016,20 @@ class Sock(object):
1005
1016
self .__close ("sock" , sock )
1006
1017
return False
1007
1018
1019
+ family = socket .AF_INET6 if self .__options .ipv6 else socket .AF_INET
1020
+
1008
1021
# [UDP 3/4] There is no listen or accept for UDP
1009
1022
if self .__options .udp :
1010
1023
self .__conn = sock
1011
- self .__log .info ("Listening on %s (family %d/UDP, port %d)" , addr , socket . AF_INET , port )
1024
+ self .__log .info ("Listening on %s (family %d/UDP, port %d)" , addr , family , port )
1012
1025
1013
1026
# [TCP 3/4] Requires listen and accept
1014
1027
else :
1015
1028
# Listen
1016
1029
if not self .__listen (sock ):
1017
1030
self .__close ("sock" , sock )
1018
1031
return False
1019
- self .__log .info ("Listening on %s (family %d/TCP, port %d)" , addr , socket . AF_INET , port )
1032
+ self .__log .info ("Listening on %s (family %d/TCP, port %d)" , addr , family , port )
1020
1033
# Accept
1021
1034
try :
1022
1035
conn = self .__accept (sock )
@@ -1081,15 +1094,17 @@ class Sock(object):
1081
1094
Raises:
1082
1095
socket.error: If socket cannot be created.
1083
1096
"""
1097
+ family_sock = socket .AF_INET6 if self .__options .ipv6 else socket .AF_INET
1098
+ family_name = "IPv6" if self .__options .ipv6 else "IPv4"
1084
1099
try :
1085
1100
if self .__options .udp :
1086
- self .__log .debug ("Creating UDP socket" )
1087
- sock = socket .socket (socket . AF_INET , socket .SOCK_DGRAM )
1101
+ self .__log .debug ("Creating %s UDP socket" , family_name )
1102
+ sock = socket .socket (family_sock , socket .SOCK_DGRAM )
1088
1103
else :
1089
- self .__log .debug ("Creating TCP socket" )
1090
- sock = socket .socket (socket . AF_INET , socket .SOCK_STREAM )
1104
+ self .__log .debug ("Creating %s TCP socket" , family_name )
1105
+ sock = socket .socket (family_sock , socket .SOCK_STREAM )
1091
1106
except socket .error as error :
1092
- msg = "Failed to create the socket: {}" .format (error )
1107
+ msg = "Failed to create {} socket: {}" .format (family_name , error )
1093
1108
self .__log .error (msg )
1094
1109
raise socket .error (msg )
1095
1110
# Get around the "[Errno 98] Address already in use" error, if the socket is still in wait
@@ -2491,7 +2506,7 @@ class CNCAutoDeploy(CNC):
2491
2506
command .append (self .python )
2492
2507
command .append (remote_path )
2493
2508
command .append ("--exec {}" .format (binary ))
2494
- command .append ("--reconn -1 " )
2509
+ command .append ("--reconn" )
2495
2510
command .append ("--reconn-wait 1" )
2496
2511
command .append (host )
2497
2512
command .append (port )
@@ -2834,6 +2849,9 @@ The connection to your listening server is given by
2834
2849
target machine via the positional arguments.
2835
2850
""" ,
2836
2851
)
2852
+ optional .add_argument (
2853
+ "-6" , dest = "ipv6" , action = "store_true" , default = False , help = "Use IPv6 instead of IPv4." ,
2854
+ )
2837
2855
optional .add_argument (
2838
2856
"-e" ,
2839
2857
"--exec" ,
@@ -2894,8 +2912,8 @@ color on Windows by default. (default: auto)
2894
2912
cnc .add_argument (
2895
2913
"--self-inject" ,
2896
2914
metavar = "cmd:host:port" ,
2897
- type = _args_check_upload_myself ,
2898
2915
default = None ,
2916
+ type = _args_check_upload_myself ,
2899
2917
help = """Listen mode (TCP only):
2900
2918
If you are about to inject a reverse shell onto the
2901
2919
victim machine (via php, bash, nc, ncat or similar),
@@ -2990,12 +3008,16 @@ disconnected or the connection is unterrupted otherwise.
2990
3008
advanced .add_argument (
2991
3009
"--rebind" ,
2992
3010
metavar = "x" ,
3011
+ nargs = "?" ,
2993
3012
default = 0 ,
2994
3013
type = int ,
2995
3014
help = """Listen mode (TCP and UDP):
2996
3015
If the server is unable to bind, it will re-initialize
2997
- itself x many times before giving up. Use -1 to re-init
2998
- endlessly. (default: fail after first unsuccessful try).
3016
+ itself x many times before giving up. Omit the
3017
+ quantifier to rebind endlessly or specify a positive
3018
+ integer for how many times to rebind before giving up.
3019
+ See --rebind-robin for an interesting use-case.
3020
+ (default: fail after first unsuccessful try).
2999
3021
3000
3022
""" ,
3001
3023
)
@@ -3027,12 +3049,14 @@ This option requires --rebind to be specified.
3027
3049
advanced .add_argument (
3028
3050
"--reconn" ,
3029
3051
metavar = "x" ,
3052
+ nargs = "?" ,
3030
3053
default = 0 ,
3031
- type = int ,
3032
3054
help = """Connect mode / Zero-I/O mode (TCP only):
3033
3055
If the remote server is not reachable or the connection
3034
3056
is interrupted, the client will connect again x many
3035
- times before giving up. Use -1 to retry endlessly.
3057
+ times before giving up. Omit the quantifier to retry
3058
+ endlessly or specify a positive integer for how many
3059
+ times to retry before giving up.
3036
3060
(default: quit if the remote is not available or the
3037
3061
connection was interrupted)
3038
3062
This might be handy for stable TCP reverse shells ;-)
@@ -3212,17 +3236,21 @@ def main():
3212
3236
host = args .hostname
3213
3237
ports = [args .port ]
3214
3238
3239
+ reconn = - 1 if args .reconn is None else args .reconn
3240
+ rebind = - 1 if args .rebind is None else args .rebind
3241
+
3215
3242
# Set pwncat options
3216
3243
sock_opts = DsIONetworkSock (
3217
3244
RECV_BUFSIZE ,
3218
3245
LISTEN_BACKLOG ,
3219
3246
TIMEOUT_RECV_SOCKET ,
3220
3247
TIMEOUT_RECV_SOCKET_RETRY ,
3221
3248
args .nodns ,
3249
+ args .ipv6 ,
3222
3250
args .udp ,
3223
3251
)
3224
- srv_opts = DsIONetworkSrv (args .keep_open , args . rebind , args .rebind_wait , args .rebind_robin )
3225
- cli_opts = DsIONetworkCli (args . reconn , args .reconn_wait , args .reconn_robin )
3252
+ srv_opts = DsIONetworkSrv (args .keep_open , rebind , args .rebind_wait , args .rebind_robin )
3253
+ cli_opts = DsIONetworkCli (reconn , args .reconn_wait , args .reconn_robin )
3226
3254
# TODO:
3227
3255
# "wait": args.wait,
3228
3256
# "ping_init": args.ping_init,
0 commit comments