-
Notifications
You must be signed in to change notification settings - Fork 0
/
clayPigeons.py
178 lines (158 loc) · 6.83 KB
/
clayPigeons.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
173
174
175
176
#!/usr/bin/env python3
import subprocess
from time import sleep
from probeType import Probe
from matchType import Match
from cpType import ClayPigeon
from multiprocessing import Process
import random
import os
from ast import literal_eval
import json
def loadServiceDefs():
def stringToPorts(stringports): # Translates nmap-style port specs to a list of ports
ports = []
for port in stringports:
if "-" not in port:
ports.append(int(port))
else:
pair = port.split('-')
assert len(pair) == 2
pair[0] = int(pair[0])
pair[1] = int(pair[1])
assert pair[0] <= pair[1]
for n in range(pair[0], pair[1] + 1):
ports.append(n)
return ports
def stringToMatch(rawMatch): # Cleans up the match string in nmap-service-probes
assert rawMatch[0] == 'm'
delim = rawMatch[1]
stringEnd = rawMatch[2:].find(delim) + 2
return rawMatch[2:stringEnd], rawMatch[stringEnd + 2:].rstrip('\n')
def stringToProbe(rawProbe, debug = False): # Cleans up the probe string in nmap-service-probes
assert rawProbe[0] == 'q'
delim = rawProbe[1]
stringEnd = rawProbe[2:].find(delim) + 2
newVal = rawProbe[2:stringEnd]
newVal = newVal.replace(r"\0",r"\x00")
returnVal = literal_eval('"' + newVal.replace('"', '\\"') + '"').encode('latin-1')
if debug:
print(newVal)
print(returnVal)
return returnVal
def findProbesFile(): # Find the nmap-service-probes file
checkme = ['./', '/usr/share/nmap/', '/usr/share/nmap/']
filename = 'nmap-service-probes'
for directory in checkme:
path = directory + filename
if os.path.exists(path):
return path
located = subprocess.check_output(['locate', filename])
if len(located) == 0:
raise Exception('Cannot locate ' + filename + ' in filesystem.')
else:
return located.decode('latin-1').partition('\n')[0]
probes = []
filename = findProbesFile()
with open(filename) as f:
data = f.readlines()
x = 0
while x < len(data):
if data[x][0:6] == 'Probe ':
probe = data[x].split(maxsplit=3) # Determine protocol, probe name, and string sent as probe
if probe[2] != "oracle-tns":
probeQuery = stringToProbe(probe[3])
else:
probeQuery = stringToProbe(probe[3],True)
x += 1
matches = []
ports = []
sslports = []
while x < len(data) and data[x][0:6] != 'Probe ': # Everything in here applies to a single probe
if data[x][0:6] == 'match ': # Determine what we are supposed to match
rawmatch = data[x].split(maxsplit=2)
pattern, version = stringToMatch(rawmatch[2])
matches.append(Match(rawmatch[1], pattern, version, softmatch=False))
elif data[x][0:10] == 'softmatch ': # Same as above but for soft match
rawmatch = data[x].split(maxsplit=2)
pattern, version = stringToMatch(rawmatch[2])
matches.append(Match(rawmatch[1], pattern, version, softmatch=True))
elif data[x][0:6] == 'ports ': # Determine applicable ports if specified
ports = stringToPorts(data[x][6:].rstrip('\n').split(','))
elif data[x][0:9] == 'sslports ': # Determine applicable SSL ports if specified
sslports = stringToPorts(data[x][9:].rstrip('\n').split(','))
x += 1
probes.append(Probe(probe[1], probe[2], probeQuery, matches, ports, sslports))
x += 1
return probes
def createConfig(probes):
def sortFunc(e):
return e["port"]
numberofClayPigeons = 30
config = readConfig(probes) # Attempt to read config if one exists,
if config == []: # Otherwise create a random config
portList = []
config = []
iAmRoot = True if os.geteuid() == 0 else False
for x in range(numberofClayPigeons):
while portList == [] or port in portList or (port < 1024 and not iAmRoot):
probe = random.choice(probes)
match = probe.getRandomMatch()
port = probe.getRandomPort()
if portList == []:
portList = [-1]
portList.append(port)
config.append({"probe": probe, "match": match, "port": port})
config.sort(key=sortFunc)
print("Created config with", len(config), "clayPigeons.")
else:
print("Loaded config with", len(config), "clayPigeons.")
return config
def saveConfig(config):
filename = "cp.conf"
pigeonList = []
f = open(filename, "w")
for x in config:
pigeonList.append({"probe": str(x["probe"]), "match": str(x["match"]), "port": str(x["port"])})
f.write(json.dumps(pigeonList))
f.close()
def readConfig(probes):
# Attempt to read a config if it exists, otherwise return an empty list
pigeonList = []
filename = "cp.conf"
if os.path.exists(filename):
f = open(filename, "r")
rawData = f.read()
pigeonStrings = json.loads(rawData) # The config contains dictionaries of strings.
for x in pigeonStrings: # We need to convert them to dictionaries of actual probes and matches.
for candidateProbe in probes: # This has unpredictable behavior if a match can't be found.
if x["probe"] == str(candidateProbe):
probe = candidateProbe
break
for candidateMatch in probe.matches:
if x["match"] == str(candidateMatch):
match = candidateMatch
break
port = int(x["port"])
pigeonList.append({"probe": probe, "match": match, "port": port})
return pigeonList
def makeClayPigeon(probe, match, port): # Created for multiProcessing
try:
return ClayPigeon(probe, match, port)
except KeyboardInterrupt:
pass
if __name__ == '__main__':
probes = loadServiceDefs()
z = []
config = createConfig(probes)
saveConfig(config)
numberOfClayPigeons = len(config)
for x in range(numberOfClayPigeons):
# Uses multiprocessing to start listeners. Maybe there is a more efficient way?
probe = config[x]["probe"]
match = config[x]["match"]
port = config[x]["port"]
proc = Process(target=makeClayPigeon, args=(probe, match, port,))
z.append(proc)
z[x].start()
sleep(.01) # Makes pigeons start in order so the list appears sorted