forked from moxie0/knockknock
-
Notifications
You must be signed in to change notification settings - Fork 3
/
knockknock.py
173 lines (134 loc) · 4.91 KB
/
knockknock.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/usr/bin/env python
__author__ = "Moxie Marlinspike"
__email__ = "[email protected]"
__license__= """
Copyright (c) 2009 Moxie Marlinspike <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
--------
Mods to replace hping3 with scapy code, and update to Python 3.*
Copyright (c) 2019 Indy <[email protected]>
"""
import time, os, sys
import getopt
import subprocess
from struct import *
from knockknock.Profile import Profile
from scapy.all import *
from ipaddress import IPv6Address
from knockknock.AddressType import isIPv6
from socket import getaddrinfo, IPPROTO_UDP
def usage():
print('Usage: knockknock.py -p <portToOpen> [-s source_ip] [-d destination_ip] <host>'
+ '\n\t* source_ip can be optionally set, to specifically use a certain source IP'
+ '\n\t* destination_ip can be optionally set, to use that instead of resolving the'
+ '\n\t hostname; that way, the \"host\" is only used as a profile name')
sys.exit(2)
def parseArguments(argv):
try:
port = 0
host = ''
src_ip = ''
dst_ip = ''
opts, args = getopt.getopt(argv, 'h:p:s:d:')
for opt, arg in opts:
if opt in ('-p'):
port = arg
elif opt in ('-s'):
src_ip = arg
elif opt in ('-d'):
dst_ip = arg
else:
usage()
# if len(args) != 1:
if len(args) < 1:
usage()
else:
host = args[0]
except getopt.GetoptError:
usage()
if port == 0 or host == '':
usage()
return (port, host, src_ip, dst_ip)
def getProfile(host):
homedir = os.path.expanduser('~')
if not os.path.isdir(homedir + '/.knockknock/'):
print('Error: you need to setup your profiles in ' + homedir + '/.knockknock/')
sys.exit(2)
if not os.path.isdir(homedir + '/.knockknock/' + host):
print('Error: profile for host ' + host + ' not found at ' + homedir + '/.knockknock/' + host)
sys.exit(2)
return Profile(homedir + '/.knockknock/' + host)
def verifyPermissions():
if os.getuid() != 0:
print('Sorry, you must be root to run this.')
sys.exit(2)
def lookupHost(host):
hosts = getaddrinfo(host, None, proto=IPPROTO_UDP)
for i in range(len(hosts)):
hosts[i] = hosts[i][4][0]
return hosts
def chooseIP(hosts, whichAddr):
for i in range(len(hosts)):
print('{0} ... {1}'.format(i, hosts[i]))
choice = -1
while((choice < 0) or (choice > len(hosts)-1)):
choice = input('{0} address to use (0-{1}):'.format(whichAddr, len(hosts)-1))
try:
choice = int(choice)
except:
choice = -1
return choice
#another method:
#def lookupHost(host):
# output = run(['nslookup', '-type=AAAA', 'www.yahoo.com'], capture_output=True)
def main(argv):
(port, host, src_ip, dst_ip) = parseArguments(argv)
verifyPermissions()
profile = getProfile(host)
port = pack('!H', int(port))
packetData = profile.encrypt(port)
knockPort = profile.getKnockPort()
(idField, seqField, ackField, winField) = unpack('!HIIH', packetData)
sport = random.randint(1024,65535)
if dst_ip == '':
dstList = lookupHost(host)
if len(dstList) == 1:
dst_ip = dstList[0]
else:
dst_ip = dstList[chooseIP(dstList, 'destination')]
if isIPv6(dst_ip):
# IPv6
ip = IPv6(dst = dst_ip, fl = idField)
else:
# IPv4
ip = IP(dst = dst_ip, id = idField)
if src_ip != '':
ip.src = src_ip
# else:
# srcList = getHostAddrs
# if len(srcList) == 1:
# src_ip = srcList[0]
# else:
# src_ip = srcList[chooseIP(dstList, 'source')]
# uncomment for debugging
# print('dst={0}, id={1}'.format(dst_ip,idField))
# print('sport={0},dport={1},seq={2},window={3},ack={4}'.format(sport,int(knockPort),seqField,winField,ackField))
try:
syn=TCP(sport=sport,dport=int(knockPort),flags='S',seq=seqField,window=winField,ack=ackField)
send(ip/syn, verbose=False)
print('Knock sent from {0} to {1}, TCP port {2}.'.format(ip.src, ip.dst, syn.dport))
except OSError:
sys.exit(3)
if __name__ == '__main__':
main(sys.argv[1:])