Initial commit
This commit is contained in:
105
README.md
Normal file
105
README.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# slpscan - service location protocol scanner
|
||||
|
||||
## intro
|
||||
|
||||
This is a research tool, created for looking deeper into SLP at the internet.
|
||||
Due current events we decided to publish a version of it, to support defenders and researchers tackle the current ESXi exploitation scheme.
|
||||
|
||||
## usage
|
||||
Show all supported functions
|
||||
```
|
||||
./slpscan.py -m ?
|
||||
----------------------------------------------------------------------
|
||||
SLPv1 Modes Operation Description
|
||||
----------------------------------------------------------------------
|
||||
svc_req_v1 1
|
||||
svc_reply_v1 2
|
||||
svc_attr_req_v1 6
|
||||
svc_attr_reply_v1 7
|
||||
svc_type_req_v1 9
|
||||
svc_type_reply_v1 10
|
||||
----------------------------------------------------------------------
|
||||
SLPv2 Modes Operation Description
|
||||
----------------------------------------------------------------------
|
||||
svc_req_v2 1
|
||||
svc_reply_v2 2
|
||||
svc_attr_req_v2 6
|
||||
svc_attr_reply_v2 7
|
||||
svc_type_req_v2 9
|
||||
svc_type_reply_v2 10
|
||||
```
|
||||
|
||||
Do slp svc req v2
|
||||
`./slpscan.py -l 192.168.170.50 -m svc_req_v2`
|
||||
|
||||
Do slp svc type req v1
|
||||
`./slpscan.py -l 192.168.170.50 -m svc_type_req_v1`
|
||||
|
||||
|
||||
Do slp attribute req for vmware v2
|
||||
`./slpscan.py -l 192.168.170.50 -m svc_attr_req_v2`
|
||||
|
||||
Show supported probes
|
||||
```
|
||||
./slpscan.py -P?
|
||||
|
||||
SLP Request | Brief | Devices
|
||||
-------------------------------------------------------------------------------
|
||||
svc_type_req_holder_v1 | example pkt, svc_type_req_v1 |
|
||||
svc_attr_req_holder_v1 | example request, svc_attr_req_v1 |
|
||||
svc_req_holder_v2 | example pkt, svc_req_v2 |
|
||||
svc_type_req_holder_v2 | example pkt, svc_type_req_v2 |
|
||||
svc_attr_req_holder_v2 | example pkt, svc_attr_req_v2 |
|
||||
VMWARE_SVC_Request_https | service:https |
|
||||
|
||||
```
|
||||
|
||||
For SLP identification against ESXi Hosts use the probe published within the release:
|
||||
|
||||
```
|
||||
./slpscan.py -l <ip> -P VMWARE_SVC_Request_https
|
||||
```
|
||||
|
||||
If you have a datacenter and need to check a big list of hosts use the -L option.
|
||||
|
||||
If you have a specific probe you can easily add it to the probe json file in the libs directory. There are already several examples to do so.
|
||||
|
||||
General help:
|
||||
|
||||
```
|
||||
usage: slpscan.py [-h] [-l HOST] [-L HOSTLIST] [-p PORT] [-t THRCNT] [-m SLP_MODE]
|
||||
[-P PROBE_MODE] [-d PKT_DELAY] [-T TIMEOUT] [-o OUTFILE] [-oj OUTFILE_JSON]
|
||||
[-r UNRANDOM] [-R RANDOMIP]
|
||||
|
||||
service location protocol 0.3.7 by dash in published 2023
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-l HOST, --host HOST host to check version
|
||||
-L HOSTLIST, --hostlist HOSTLIST
|
||||
hostlist to check
|
||||
-p PORT, --port PORT slp port (default:427)
|
||||
-t THRCNT, --threads THRCNT
|
||||
how many threads
|
||||
-m SLP_MODE, --slp-mode SLP_MODE
|
||||
what attack mode to choose, ? for list
|
||||
-P PROBE_MODE, --probe-mode PROBE_MODE
|
||||
what probe to send, ? for list
|
||||
-d PKT_DELAY, --packet-delay PKT_DELAY
|
||||
set the delay(in seconds) a packet is sent, delay is per thread (1s and
|
||||
10 threads, each second 10 threads are working)
|
||||
-T TIMEOUT, --timeout TIMEOUT
|
||||
timeout of socket recv
|
||||
-o OUTFILE, --outfile OUTFILE
|
||||
outfile in txt format
|
||||
-oj OUTFILE_JSON, --outfile-json OUTFILE_JSON
|
||||
outfile in json format
|
||||
-r UNRANDOM, --unrandom UNRANDOM
|
||||
disable random targetlist
|
||||
-R RANDOMIP, --randomIP RANDOMIP
|
||||
generate random ips on the fly
|
||||
```
|
||||
|
||||
# outro
|
||||
|
||||
This tool is part of an ongoing research conducted by Marco Lux (ping@curesec.com) and Pedro Umbelino (pedro.umbelino@bitsight.com).
|
||||
0
libs/__init__.py
Normal file
0
libs/__init__.py
Normal file
16
libs/srvloc_fortune.py
Normal file
16
libs/srvloc_fortune.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# fortune cookies
|
||||
|
||||
import random
|
||||
|
||||
fck = ['2021 will **** less...',
|
||||
'"Youre not allowed to say this, but...", is usually the preamble for something pretty pretty stupid which is coming next.',
|
||||
'...',
|
||||
'the plot thickens',
|
||||
'just grabbing some b33rs'
|
||||
'it just had to happen in 2023'
|
||||
]
|
||||
|
||||
|
||||
def rnd_fck():
|
||||
nxt_fck = random.choice(fck)
|
||||
return nxt_fck
|
||||
42
libs/srvloc_globals.py
Normal file
42
libs/srvloc_globals.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import queue
|
||||
|
||||
global jout_Queue
|
||||
jout_Queue = queue.Queue()
|
||||
|
||||
global rQ
|
||||
rQ = queue.Queue()
|
||||
|
||||
global q
|
||||
q = queue.Queue()
|
||||
|
||||
__tool_version__ = '0.3.7'
|
||||
__tool_author__ = 'Marco Lux'
|
||||
__tool_date__ = 'published 2023'
|
||||
|
||||
SLP_SVC_REQ = 0x1
|
||||
SLP_SVC_REPLY = 0x2
|
||||
SLP_ATTR_REQ = 0x6
|
||||
SLP_ATTR_REPLY = 0x7
|
||||
SLP_SVC_TYPE_REQ = 0x9
|
||||
SLP_SVC_TYPE_REPLY = 0xa
|
||||
|
||||
|
||||
# basic v1 pkt
|
||||
req_dict_v1 = {'slp_ver': 1,
|
||||
'slp_func': SLP_ATTR_REQ,
|
||||
'slp_pkt_len': 0,
|
||||
'slp_flags': 0,
|
||||
'slp_dialect': 0,
|
||||
'slp_lang': 0x656e,
|
||||
'slp_enc': 3,
|
||||
'slp_transx': 0x29A}
|
||||
|
||||
# basic v2 pkt
|
||||
req_dict_v2 = {'slp_ver': 2,
|
||||
'slp_func': SLP_SVC_TYPE_REQ,
|
||||
'slp_pkt_len': 0,
|
||||
'slp_flags': 0,
|
||||
'slp_next_offset': 0,
|
||||
'slp_xid': 0x666,
|
||||
'slpintroduction_lang_tag_len': 2,
|
||||
'slp_lang_tag': 0x656e}
|
||||
176
libs/srvloc_helper.py
Normal file
176
libs/srvloc_helper.py
Normal file
@@ -0,0 +1,176 @@
|
||||
import os
|
||||
import sys
|
||||
import pytz
|
||||
import base64
|
||||
import datetime
|
||||
import random
|
||||
from random import randrange
|
||||
from libs.srvloc_globals import *
|
||||
from libs.srvloc_log import printd, printe
|
||||
|
||||
|
||||
def randomizeIP(iplist):
|
||||
''' function to randomize ips to scan'''
|
||||
# orig_list = iplist
|
||||
# run 1
|
||||
random.shuffle(iplist)
|
||||
|
||||
# run 2
|
||||
random.shuffle(iplist)
|
||||
return iplist
|
||||
|
||||
|
||||
def generateIP():
|
||||
blockOne = randrange(0, 255, 1)
|
||||
blockTwo = randrange(0, 255, 1)
|
||||
blockThree = randrange(0, 255, 1)
|
||||
blockFour = randrange(0, 255, 1)
|
||||
if blockOne == 10:
|
||||
return generateIP()
|
||||
elif blockOne == 172:
|
||||
return generateIP()
|
||||
elif blockOne == 192:
|
||||
return generateIP()
|
||||
else:
|
||||
d = str(blockOne) + '.' + str(blockTwo) + '.' + \
|
||||
str(blockThree) + '.' + str(blockFour)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def console_size():
|
||||
height, witdh = os.popen('stty size', 'r').read().split()
|
||||
|
||||
return (int(witdh), int(height))
|
||||
|
||||
|
||||
def generate_randomIP(q, count):
|
||||
i = 0
|
||||
count = int(count)
|
||||
# print 'cnt', count
|
||||
while i != count:
|
||||
ip = generateIP()
|
||||
check_ip = [ip]
|
||||
ip = check_blacklist(check_ip)
|
||||
if len(ip) > 0:
|
||||
q.put(ip[0])
|
||||
i += 1
|
||||
else:
|
||||
print('{0} BLACKLISTED.'.format(ip))
|
||||
|
||||
print('gen %d' % (q.qsize()))
|
||||
return
|
||||
|
||||
|
||||
def timefield_rfc3339():
|
||||
'''
|
||||
implementing timestamp like rfc3339
|
||||
'''
|
||||
d = datetime.datetime.utcnow()
|
||||
d_with_timezone = d.replace(tzinfo=pytz.UTC)
|
||||
timestamp = d_with_timezone.isoformat()
|
||||
return timestamp
|
||||
|
||||
|
||||
def timedict_rfc3339():
|
||||
'''
|
||||
implementing timestamp like rfc3339
|
||||
'''
|
||||
d = datetime.datetime.utcnow()
|
||||
d_with_timezone = d.replace(tzinfo=pytz.UTC)
|
||||
timestamp = d_with_timezone.isoformat()
|
||||
return {'timestamp': timestamp}
|
||||
|
||||
|
||||
def ascii_check(rec):
|
||||
'''check if banner has non-ascii values
|
||||
'''
|
||||
# yes, this is a bool now
|
||||
ascii_bool = False
|
||||
|
||||
data = rec
|
||||
# print(rec)
|
||||
# poor mans clause for checking if ascii or not
|
||||
try:
|
||||
if type(rec) != int:
|
||||
ascii_test = data.decode('ascii')
|
||||
ascii_bool = True
|
||||
else:
|
||||
return rec
|
||||
|
||||
except UnicodeDecodeError as e:
|
||||
ascii_bool = False
|
||||
|
||||
# its not ascii, so base64 encoding
|
||||
if ascii_bool == False:
|
||||
rec = base64.b64encode(data)
|
||||
|
||||
return(rec)
|
||||
|
||||
|
||||
def clean_line(line):
|
||||
line = line.rstrip('\r')
|
||||
line = line.rstrip('\n')
|
||||
return line
|
||||
|
||||
|
||||
def check_file_exists(fname):
|
||||
|
||||
try:
|
||||
stat = os.stat(fname)
|
||||
|
||||
except FileNotFoundError as e:
|
||||
print(repr(e))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_file_readable(fname):
|
||||
try:
|
||||
fr = open(fname, 'r', 1)
|
||||
|
||||
except PermissionError as e:
|
||||
print(repr(e))
|
||||
return False
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def create_hostlist(args):
|
||||
#ret = check_file_exists(args.hostlist)
|
||||
|
||||
# if not ret:
|
||||
# return False
|
||||
fr = open(args.hostlist, 'r', 1)
|
||||
|
||||
for line in fr.readlines():
|
||||
cline = clean_line(line)
|
||||
rQ.put(cline)
|
||||
rQ.put('')
|
||||
# req_queue.put('EOF')
|
||||
|
||||
|
||||
def check_blacklist(whites):
|
||||
# def check_blacklist(blacks, whites):
|
||||
'''
|
||||
'''
|
||||
fr = open('supply/blacklist.txt', 'r')
|
||||
bips = fr.readlines()
|
||||
white_len = len(whites)
|
||||
blacklisted = []
|
||||
for black in bips:
|
||||
black = clean_line(black)
|
||||
try:
|
||||
whites.index(black)
|
||||
whites.remove(black)
|
||||
blacklisted.append(black)
|
||||
print('BLACKLISTED {0}'.format(black))
|
||||
except ValueError as e:
|
||||
pass
|
||||
white_len_after = len(whites)
|
||||
#print('Whitelist: {0}/{1}'.format(white_len, white_len_after))
|
||||
return whites
|
||||
9
libs/srvloc_log.py
Normal file
9
libs/srvloc_log.py
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
def printd(data):
|
||||
# if DEBUG_PROTO:
|
||||
# print(data)
|
||||
pass
|
||||
|
||||
|
||||
def printe(data):
|
||||
pass
|
||||
267
libs/srvloc_main.py
Normal file
267
libs/srvloc_main.py
Normal file
@@ -0,0 +1,267 @@
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import socket
|
||||
import threading
|
||||
import argparse
|
||||
|
||||
from libs.srvloc_globals import q, rQ, __tool_author__, __tool_version__, __tool_date__, jout_Queue
|
||||
from libs.srvloc_proto_v1 import *
|
||||
from libs.srvloc_proto_v2 import *
|
||||
|
||||
from libs.srvloc_helper import randomizeIP, generate_randomIP, clean_line, check_blacklist
|
||||
from libs.srvloc_log import printd, printe
|
||||
|
||||
from libs.srvloc_fortune import rnd_fck
|
||||
|
||||
|
||||
def parser_main():
|
||||
parser_desc = 'service location protocol {0} by {1} in {2}'.format(
|
||||
__tool_version__, __tool_author__, __tool_date__)
|
||||
prog_desc = 'slpscan.py'
|
||||
parser = argparse.ArgumentParser(prog=prog_desc, description=parser_desc)
|
||||
parser.add_argument("-l", "--host", action="store",
|
||||
required=False, help='host to check version', dest='host')
|
||||
parser.add_argument("-L", "--hostlist", action="store",
|
||||
required=False, help='hostlist to check', dest='hostlist')
|
||||
parser.add_argument("-p", "--port", action="store", required=False,
|
||||
default=427, help='slp port (default:427)', dest='port')
|
||||
parser.add_argument("-t", "--threads", action="store", required=False,
|
||||
default=50, help='how many threads', dest='thrCnt', type=int)
|
||||
parser.add_argument("-m", "--slp-mode", action="store", required=False, default='',
|
||||
help='what attack mode to choose, ? for list', dest='slp_mode')
|
||||
parser.add_argument("-P", "--probe-mode", action="store", required=False, default=False,
|
||||
help='what probe to send, ? for list', dest='probe_mode')
|
||||
parser.add_argument("-d", "--packet-delay", action="store", required=False, type=float,
|
||||
help='set the delay(in seconds) a packet is sent, delay is per thread (1s and 10 threads, each second 10 threads are working)',
|
||||
dest='pkt_delay')
|
||||
|
||||
parser.add_argument("-T", "--timeout", action="store", required=False,
|
||||
default=5, help='timeout of socket recv', dest='timeout')
|
||||
parser.add_argument("-o", "--outfile", action="store",
|
||||
required=False, help='outfile in txt format', dest='outfile')
|
||||
parser.add_argument("-oj", "--outfile-json", action="store",
|
||||
required=False, help='outfile in json format', dest='outfile_json')
|
||||
|
||||
parser.add_argument("-r", "--unrandom", action="store", required=False,
|
||||
help='disable random targetlist', dest='unrandom')
|
||||
parser.add_argument("-R", "--randomIP", action="store", required=False,
|
||||
help='generate random ips on the fly', dest='randomip')
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
SLP_SVC_REQ = 0x1
|
||||
SLP_SVC_REPLY = 0x2
|
||||
SLP_ATTR_REQ = 0x6
|
||||
SLP_ATTR_REPLY = 0x7
|
||||
SLP_SVC_TYPE_REQ = 0x9
|
||||
SLP_SVC_TYPE_REPLY = 0xa
|
||||
|
||||
# FIXME build other structure for modes
|
||||
|
||||
|
||||
def choose_slp_mode(args):
|
||||
lsize = 70
|
||||
modes = {1: {'name': '{0:<30} {1:<15} {2:<30}'.format('SLPv1 Modes', 'Operation', 'Description'), 'Operation': '', 'Description': '', 'Method': ''},
|
||||
# 2: {'name': '-'*lsize, 'Operation': '', 'Description': '', 'Method': ''},
|
||||
# !!!!!!
|
||||
21: {'name': 'svc_req_v1', 'Operation': SLP_SVC_REQ, 'Description': '', 'Method': build_slp_svc_req_v1()},
|
||||
22: {'name': 'svc_reply_v1', 'Operation': SLP_SVC_REPLY, 'Description': '', 'Method': build_slp_reply_v1()},
|
||||
26: {'name': 'svc_attr_req_v1', 'Operation': SLP_ATTR_REQ, 'Description': '', 'Method': build_svc_attr_req_v1()},
|
||||
27: {'name': 'svc_attr_reply_v1', 'Operation': SLP_ATTR_REPLY, 'Description': '', 'Method': build_slp_attr_reply_v1()},
|
||||
29: {'name': 'svc_type_req_v1', 'Operation': SLP_SVC_TYPE_REQ, 'Description': '', 'Method': build_slp_svc_type_req_v1()},
|
||||
30: {'name': 'svc_type_reply_v1', 'Operation': SLP_SVC_TYPE_REPLY, 'Description': '', 'Method': build_slp_type_reply_v1()},
|
||||
|
||||
38: {'name': '{0:<30} {1:<15} {2:<30}'.format('SLPv2 Modes', 'Operation', 'Description'), 'Operation': '', 'Description': '', 'Method': ''},
|
||||
|
||||
40: {'name': 'svc_req_v2', 'Operation': SLP_SVC_REQ, 'Description': '', 'Method': build_slp_svc_req_v2()},
|
||||
41: {'name': 'svc_reply_v2', 'Operation': SLP_SVC_REPLY, 'Description': '', 'Method': build_slp_reply_v2()},
|
||||
45: {'name': 'svc_attr_req_v2', 'Operation': SLP_ATTR_REQ, 'Description': '', 'Method': build_slp_attr_req_v2()},
|
||||
46: {'name': 'svc_attr_reply_v2', 'Operation': SLP_ATTR_REPLY, 'Description': '', 'Method': build_slp_attr_reply_v2()},
|
||||
48: {'name': 'svc_type_req_v2', 'Operation': SLP_SVC_TYPE_REQ, 'Description': '', 'Method': build_slp_svc_type_req_v2()},
|
||||
49: {'name': 'svc_type_reply_v2', 'Operation': SLP_SVC_TYPE_REPLY, 'Description': '', 'Method': build_slp_type_reply_v2()},
|
||||
}
|
||||
|
||||
slp_mode = args.slp_mode
|
||||
|
||||
if slp_mode == '?':
|
||||
print()
|
||||
for k in modes.keys():
|
||||
# print(modes[k])
|
||||
name = modes[k]['name']
|
||||
operation = modes[k]['Operation']
|
||||
desc = modes[k]['Description']
|
||||
if name.startswith('SLPv'):
|
||||
print('-'*lsize)
|
||||
print('{0:<30} {1:<15} {2:<30}'.format(name, operation, desc))
|
||||
if name.startswith('SLPv'):
|
||||
print('-'*lsize)
|
||||
print()
|
||||
sys.exit()
|
||||
else:
|
||||
for k in modes.keys():
|
||||
if slp_mode == modes[k]['name']:
|
||||
pkt = modes[k]['Method']
|
||||
|
||||
return pkt
|
||||
|
||||
print('Unknown mode use -m? for showing supported modes')
|
||||
sys.exit()
|
||||
|
||||
|
||||
def make_request(host, port, args, pkt):
|
||||
human = []
|
||||
timeout = args.timeout
|
||||
slp_mode = args.slp_mode
|
||||
probe_mode = args.probe_mode
|
||||
pkt_delay = args.pkt_delay
|
||||
|
||||
if pkt_delay:
|
||||
time.sleep(pkt_delay)
|
||||
try:
|
||||
# build up socket
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
# we want to have a timeout
|
||||
s.settimeout(timeout)
|
||||
s.connect((host, port))
|
||||
|
||||
# send the discovery packet
|
||||
s.send(pkt)
|
||||
|
||||
# getting the data of the connection
|
||||
rec = s.recv(4096)
|
||||
data_dict = {'target': host+':' +
|
||||
str(port), 'reply_pkt': rec, 'pkt': pkt}
|
||||
hdata = '%s:%d' % (host, port)
|
||||
hdump = '%s' % (repr(rec))
|
||||
|
||||
# place stuff in one of the queues
|
||||
human.append(hdata)
|
||||
human.append(hdump)
|
||||
# human.append(reply_dict)
|
||||
rQ.put(human)
|
||||
|
||||
except socket.timeout:
|
||||
printe('%s timeout' % host)
|
||||
except socket.error:
|
||||
printe('%s refused' % host)
|
||||
|
||||
|
||||
def run_mainthreads(args, pkt):
|
||||
|
||||
# wanna have a c00kie?!
|
||||
fck = rnd_fck()
|
||||
printd(fck)
|
||||
|
||||
if args.outfile:
|
||||
fw = open(args.outfile, 'w')
|
||||
|
||||
if args.outfile_json:
|
||||
fwj = open(args.outfile_json, 'w')
|
||||
|
||||
if args.host:
|
||||
host = args.host
|
||||
print('Hostmode: %s' % host)
|
||||
line = clean_line(host)
|
||||
|
||||
bl = [host]
|
||||
wh = check_blacklist(bl)
|
||||
if len(wh) == 1:
|
||||
q.put(line)
|
||||
else:
|
||||
# print('{0} Blacklisted!!!'.format(host))
|
||||
sys.exit()
|
||||
|
||||
elif args.hostlist:
|
||||
ipL = []
|
||||
hostlist = args.hostlist
|
||||
print('Hostlistmode')
|
||||
fr = open(hostlist, 'r')
|
||||
rBuf = fr.readlines()
|
||||
for l in rBuf:
|
||||
l = clean_line(l)
|
||||
ipL.append(l)
|
||||
if not args.unrandom:
|
||||
iplist = randomizeIP(ipL)
|
||||
else:
|
||||
iplist = ipL
|
||||
|
||||
iplist = check_blacklist(iplist)
|
||||
|
||||
list = [q.put(query) for query in iplist]
|
||||
|
||||
elif args.randomip:
|
||||
randIP = int(args.randomip)
|
||||
print('RandomIPs: %d' % (randIP))
|
||||
|
||||
else:
|
||||
print('Unknown or no mode choosen. cya')
|
||||
sys.exit()
|
||||
|
||||
if not args.randomip:
|
||||
print('Targets: %d' % (q.qsize()))
|
||||
else:
|
||||
# lets start the thread for generating randomIPs
|
||||
printd('Starting random thread:')
|
||||
randIPThread = threading.Thread(
|
||||
target=generate_randomIP, args=(q, args.randomip))
|
||||
randIPThread.daemon = True
|
||||
randIPThread.start()
|
||||
# FIXME
|
||||
# quick fix so we do not miss the threading loop
|
||||
# better would be a counter in the loop itself
|
||||
time.sleep(5)
|
||||
|
||||
port = int(args.port)
|
||||
thrCnt = args.thrCnt
|
||||
|
||||
thrList = []
|
||||
|
||||
printd('Starting loop')
|
||||
while True:
|
||||
if len(thrList) < thrCnt and q.qsize() > 0:
|
||||
newthread = threading.Thread(target=make_request, args=(
|
||||
q.get(), port, args, pkt))
|
||||
newthread.daemon = True
|
||||
newthread.start()
|
||||
thrList.append(newthread)
|
||||
|
||||
for entry in thrList:
|
||||
if entry.is_alive() == False:
|
||||
entry.join()
|
||||
thrList.remove(entry)
|
||||
time.sleep(0.1)
|
||||
|
||||
if rQ.qsize() > 0:
|
||||
|
||||
pout = rQ.get()
|
||||
pp = '%s' % (pout)
|
||||
print('[RAW] ', pp)
|
||||
print()
|
||||
if args.outfile:
|
||||
fw.write(pp + '\n')
|
||||
|
||||
if jout_Queue.qsize() > 0:
|
||||
jdata = jout_Queue.get()
|
||||
print(jdata)
|
||||
|
||||
if args.outfile_json:
|
||||
fwj.write(jdata + '\n')
|
||||
if q.qsize() == 0 and len(thrList) == 0:
|
||||
break
|
||||
|
||||
|
||||
def print_slp_modes():
|
||||
|
||||
data = '''
|
||||
Supported modes:
|
||||
|
||||
* slp_type_request
|
||||
requesting the supported ressources at the remote device
|
||||
'''
|
||||
|
||||
print(data)
|
||||
71
libs/srvloc_parse.py
Normal file
71
libs/srvloc_parse.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import struct
|
||||
|
||||
|
||||
def parse_slp_reply(data_dict):
|
||||
'''
|
||||
Attribute Reply
|
||||
Version | Function | PktLen | Flags | Dialect | Lang | Encoding | TransactionID | Error Code | Attribute List Len | Attribdata
|
||||
1b 1b 2b 1b 1b 2b 2b 2b 2b 2b
|
||||
'''
|
||||
|
||||
reply_pkt = data_dict['reply_pkt']
|
||||
slp_ver, slp_func, slp_pkt_len, slp_flags, slp_dialect, slp_lang, slp_enc, slp_transx,\
|
||||
slp_err, slp_attr_list = struct.unpack(
|
||||
'>BBHBBHHHHH', reply_pkt[:16])
|
||||
reply_dict = {'slp_ver': slp_ver,
|
||||
'slp_func': slp_func,
|
||||
'slp_pkt_len': slp_pkt_len,
|
||||
'slp_flags': slp_flags,
|
||||
'slp_dialect': slp_dialect,
|
||||
'slp_lang': slp_lang,
|
||||
'slp_enc': slp_enc,
|
||||
'slp_transx': slp_transx,
|
||||
'slp_err': slp_err,
|
||||
'slp_attr_list': slp_attr_list}
|
||||
|
||||
# FIXME FIXME
|
||||
# ... disabling parsing for now
|
||||
# print(reply_dict)
|
||||
attr_data = reply_pkt[16:]
|
||||
# print(attr_data)
|
||||
s_attr_data = attr_data.split(b'(')
|
||||
print(s_attr_data)
|
||||
s_attr_data.remove(b'')
|
||||
hwdata = s_attr_data
|
||||
hw_dict = {}
|
||||
for item in hwdata:
|
||||
item = item.decode()
|
||||
item = item.rstrip(')')
|
||||
key_a, val_a = item.split('=')
|
||||
hw_dict[key_a] = val_a
|
||||
|
||||
#hwdata = hwdata.decode()
|
||||
shwdata = hwdata.split('(')
|
||||
#hw_dict = {}
|
||||
# shwdata.remove('')
|
||||
print('-'*80)
|
||||
print(hwdata)
|
||||
print(hw_dict)
|
||||
print('-'*80)
|
||||
for b in shwdata:
|
||||
b = b.rstrip(')')
|
||||
b = b.split('=')
|
||||
|
||||
key_b = b[0]
|
||||
val_b = b[1]
|
||||
hw_dict[key_b] = val_b
|
||||
print(b)
|
||||
if key_b == 'x-hp-p1':
|
||||
|
||||
hw_dict[key_b] = {}
|
||||
['x-hp-p1', 'MFG:Hewlett-Packard']
|
||||
|
||||
s_attr_data.remove(b')')
|
||||
print(s_attr_data)
|
||||
for entry in s_attr_data:
|
||||
ee = entry.decode()
|
||||
ee = ee.split(':')
|
||||
# print(ee)
|
||||
hw_dict[ee[0]] = ee[1]
|
||||
|
||||
return hw_dict
|
||||
151
libs/srvloc_probes.json
Normal file
151
libs/srvloc_probes.json
Normal file
@@ -0,0 +1,151 @@
|
||||
{
|
||||
"1": {
|
||||
"name": "svc_type_req_holder_v1",
|
||||
"brief": "example pkt, svc_type_req_v1",
|
||||
"devices": [],
|
||||
"description": "example pkt, svc_type_req_v1",
|
||||
"probe": {
|
||||
"base": {
|
||||
"slp_ver": 1,
|
||||
"slp_func": 9,
|
||||
"slp_pkt_len": 0,
|
||||
"slp_flags": 0,
|
||||
"slp_dialect": 0,
|
||||
"slp_lang": 25966,
|
||||
"slp_enc": 3,
|
||||
"slp_transx": 666
|
||||
},
|
||||
"data": {
|
||||
"slp_prev_res_list": 0,
|
||||
"slp_all": 65535,
|
||||
"slp_scope": "default"
|
||||
}
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"name": "svc_attr_req_holder_v1",
|
||||
"brief": "example request, svc_attr_req_v1",
|
||||
"devices": [],
|
||||
"description": "example request, svc_attr_req_v1",
|
||||
"probe": {
|
||||
"base": {
|
||||
"slp_ver": 1,
|
||||
"slp_func": 6,
|
||||
"slp_pkt_len": 0,
|
||||
"slp_flags": 0,
|
||||
"slp_dialect": 0,
|
||||
"slp_lang": 25966,
|
||||
"slp_enc": 3,
|
||||
"slp_transx": 667
|
||||
},
|
||||
"data": {
|
||||
"slp_prev_res_list": 0,
|
||||
"slp_svc_len": 8,
|
||||
"slp_svc_url": "service:",
|
||||
"slp_scope_len": 0,
|
||||
"slp_attr_len": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"3": {
|
||||
"name": "svc_req_holder_v2",
|
||||
"brief": "example pkt, svc_req_v2",
|
||||
"devices": [],
|
||||
"description": "example pkt, svc_req_v2",
|
||||
"probe": {
|
||||
"base": {
|
||||
"slp_ver": 2,
|
||||
"slp_func": 1,
|
||||
"slp_pkt_len": 0,
|
||||
"slp_flags": 0,
|
||||
"slp_next_offset": 0,
|
||||
"slp_xid": 12345,
|
||||
"slp_ltag_len": 2,
|
||||
"slp_ltag": 25966
|
||||
},
|
||||
"data": {
|
||||
"slp_prev_res_list": 0,
|
||||
"slp_svc_type_len": 0,
|
||||
"slp_svc_type": "service:https",
|
||||
"slp_scope_len": 13,
|
||||
"slp_scope": "default"
|
||||
}
|
||||
}
|
||||
},
|
||||
"4": {
|
||||
"name": "svc_type_req_holder_v2",
|
||||
"brief": "example pkt, svc_type_req_v2",
|
||||
"devices": [],
|
||||
"description": "example pkt, svc_type_req_v2",
|
||||
"probe": {
|
||||
"base": {
|
||||
"slp_ver": 2,
|
||||
"slp_func": 9,
|
||||
"slp_pkt_len": 0,
|
||||
"slp_flags": 0,
|
||||
"slp_next_offset": 0,
|
||||
"slp_xid": 45267,
|
||||
"slp_ltag_len": 2,
|
||||
"slp_ltag": 25966
|
||||
},
|
||||
"data": {
|
||||
"slp_prev_res_list": 0,
|
||||
"slp_all": 65535,
|
||||
"slp_scope": "default",
|
||||
"slp_scope_len": 7
|
||||
}
|
||||
}
|
||||
},
|
||||
"5": {
|
||||
"name": "svc_attr_req_holder_v2",
|
||||
"brief": "example pkt, svc_attr_req_v2",
|
||||
"devices": [],
|
||||
"description": "example pkt, svc_attr_req_v2",
|
||||
"probe": {
|
||||
"base": {
|
||||
"slp_ver": 2,
|
||||
"slp_func": 6,
|
||||
"slp_pkt_len": 0,
|
||||
"slp_flags": 0,
|
||||
"slp_next_offset": 0,
|
||||
"slp_xid": 19121,
|
||||
"slp_ltag_len": 2,
|
||||
"slp_ltag": 25966
|
||||
},
|
||||
"data": {
|
||||
"slp_prev_res_list": 0,
|
||||
"slp_svc_url_len": 13,
|
||||
"slp_svc_url": "service:https",
|
||||
"slp_scope_len": 0,
|
||||
"slp_scope": "",
|
||||
"slp_tag_len": 0,
|
||||
"slp_tag": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"6": {
|
||||
"name": "VMWARE_SVC_Request_https",
|
||||
"brief": "service:https",
|
||||
"devices": [],
|
||||
"description": "",
|
||||
"probe": {
|
||||
"base": {
|
||||
"slp_ver": 2,
|
||||
"slp_func": 1,
|
||||
"slp_pkt_len": 0,
|
||||
"slp_flags": 0,
|
||||
"slp_next_offset": 0,
|
||||
"slp_xid": 23152,
|
||||
"slp_ltag_len": 2,
|
||||
"slp_ltag": 25966
|
||||
},
|
||||
"data": {
|
||||
"slp_prev_res_list": 0,
|
||||
"slp_svc_type_len": 13,
|
||||
"slp_svc_type": "service:https",
|
||||
"slp_scope_len": 7,
|
||||
"slp_scope": "default"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
184
libs/srvloc_probes.py
Normal file
184
libs/srvloc_probes.py
Normal file
@@ -0,0 +1,184 @@
|
||||
import json
|
||||
from libs.srvloc_proto_v1 import build_slp_base_v1, compute_len_v1, _slp_attr_req_v1, _slp_svc_req_v1, \
|
||||
_slp_svc_reply_v1, _slp_attr_reply_v1, _slp_type_reply_v1, _slp_svc_type_req_v1
|
||||
|
||||
|
||||
from libs.srvloc_proto_v2 import _slp_svc_req_v2, _slp_svc_reply_v2, _slp_svc_type_req_v2, _slp_attr_req_v2,_slp_attr_reply_v2, _slp_type_reply_v2, compute_len_v2, build_slp_base_v2
|
||||
|
||||
|
||||
from libs.srvloc_helper import console_size
|
||||
|
||||
fname = 'srvloc_probes.json'
|
||||
|
||||
SLP_SVC_REQ = 0x1
|
||||
SLP_SVC_REPLY = 0x2
|
||||
SLP_ATTR_REQ = 0x6
|
||||
SLP_ATTR_REPLY = 0x7
|
||||
SLP_SVC_TYPE_REQ = 0x9
|
||||
SLP_SVC_TYPE_REPLY = 0xa
|
||||
|
||||
|
||||
def open_probe_file(fname):
|
||||
fr = open(fname, 'r')
|
||||
jprobes = json.loads(fr.read())
|
||||
fr.close()
|
||||
return jprobes
|
||||
|
||||
|
||||
def print_probes(jprobes):
|
||||
width, heigth = console_size()
|
||||
# 30% name
|
||||
# 40% brief
|
||||
# 15% devices
|
||||
# yeah i need to substract max width len as well ...
|
||||
name_res = 0.30
|
||||
brief_res = 0.40
|
||||
dev_res = 0.15
|
||||
tab_vert_res = 0.90
|
||||
width = width * 0.90
|
||||
name_space = int(width * name_res)
|
||||
brief_space = int(width * brief_res)
|
||||
dev_space = int(width * dev_res)
|
||||
max_table_vert = int(width * tab_vert_res)
|
||||
|
||||
print('{0: <{1}}| {2: <{3}}| {4: <{5}}'.format(
|
||||
'SLP Request', name_space, 'Brief', brief_space, 'Devices', dev_space))
|
||||
|
||||
print('-'*(max_table_vert))
|
||||
for k in jprobes.keys():
|
||||
name = jprobes[k]['name']
|
||||
desc = jprobes[k]['brief']
|
||||
devices = jprobes[k]['devices']
|
||||
str_devices = ",".join(devices)
|
||||
print('{0: <{1}}| {2: <{3}}| {4: <{5}}'.format(
|
||||
name, name_space, desc, brief_space, str_devices, dev_space))
|
||||
|
||||
|
||||
def probe_packet(jprobes, pname):
|
||||
# print('123')
|
||||
for k in jprobes.keys():
|
||||
name = jprobes[k]['name']
|
||||
if pname == name:
|
||||
# print('Found probe')
|
||||
base = jprobes[k]['probe']['base']
|
||||
data = jprobes[k]['probe']['data']
|
||||
slp_ver = jprobes[k]['probe']['base']['slp_ver']
|
||||
slp_func = jprobes[k]['probe']['base']['slp_func']
|
||||
|
||||
if slp_ver == 1:
|
||||
slp_ver, slp_func, slp_pkt_len, slp_flags, slp_dialect, slp_lang, slp_enc, slp_transx = jprobes[k]['probe']['base'].values(
|
||||
)
|
||||
pkt1 = build_slp_base_v1(
|
||||
slp_ver, slp_func, slp_pkt_len, slp_flags, slp_dialect, slp_lang, slp_enc, slp_transx)
|
||||
|
||||
if slp_func == SLP_SVC_REQ:
|
||||
slp_prev_res_list_len, slp_rest_list, slp_pred_len, slp_pred = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
pkt2 = _slp_svc_req_v1(
|
||||
slp_prev_res_list_len, slp_rest_list.encode(), slp_pred_len, slp_pred.encode())
|
||||
|
||||
elif slp_func == SLP_SVC_REPLY:
|
||||
err_code, num_urls, url_lifetime, url_len, urls, num_auths = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
pkt2 = _slp_svc_reply_v1(
|
||||
err_code, num_urls, url_lifetime, url_len, urls.encode(), num_auths)
|
||||
|
||||
elif slp_func == SLP_ATTR_REQ:
|
||||
slp_prev_res_list, slp_svc_len, slp_svc_url, slp_scope_len, slp_attr_len = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
pkt2 = _slp_attr_req_v1(
|
||||
slp_prev_res_list, slp_svc_len, slp_svc_url.encode(), slp_scope_len, slp_attr_len)
|
||||
|
||||
elif slp_func == SLP_ATTR_REPLY:
|
||||
err_code, attr_list_len, attr_list, attr_auths = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
pkt2 = _slp_attr_reply_v1(
|
||||
err_code, attr_list_len, attr_list.encode(), attr_auths)
|
||||
elif slp_func == SLP_SVC_TYPE_REQ:
|
||||
slp_prev_res_list, slp_all, slp_scope = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
|
||||
pkt2 = _slp_svc_type_req_v1(
|
||||
slp_prev_res_list, slp_all, slp_scope.encode())
|
||||
|
||||
elif slp_func == SLP_SVC_TYPE_REPLY:
|
||||
err_code, svc_type_count, svc_type_list_len, svc_type_list = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
|
||||
pkt2 = _slp_type_reply_v1(
|
||||
err_code, svc_type_count, svc_type_list_len, svc_type_list.encode())
|
||||
|
||||
else:
|
||||
|
||||
print('{0} function not yet supported.'.format(slp_func))
|
||||
|
||||
return False
|
||||
|
||||
pkt = pkt1 + pkt2
|
||||
pkt_rdy = compute_len_v1(pkt)
|
||||
|
||||
elif slp_ver == 2:
|
||||
slp_ver, slp_func, slp_pkt_len, slp_flags, slp_next_offset, slp_xid, slp_ltag_len, slp_ltag = jprobes[k]['probe']['base'].values(
|
||||
)
|
||||
|
||||
pkt1 = build_slp_base_v2(
|
||||
slp_ver, slp_func, slp_pkt_len, slp_flags, slp_next_offset, slp_xid, slp_ltag_len, slp_ltag)
|
||||
|
||||
if slp_func == SLP_SVC_REQ:
|
||||
slp_prev_res_list, slp_svc_type_len, slp_svc_type, slp_scope_len, slp_scope = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
|
||||
pkt2 = _slp_svc_req_v2(
|
||||
slp_prev_res_list, slp_svc_type_len, slp_svc_type.encode(), slp_scope_len, slp_scope.encode())
|
||||
|
||||
elif slp_func == SLP_SVC_REPLY:
|
||||
err_code, num_urls, reserved, url_lifetime, url_len, urls, num_auths = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
|
||||
pkt2 = _slp_svc_reply_v2(
|
||||
err_code, num_urls, reserved, url_lifetime, url_len, urls.encode(), num_auths)
|
||||
|
||||
elif slp_func == SLP_SVC_ACK:
|
||||
err_code = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
pkt2 = _slp_svc_ack_v2(
|
||||
err_code)
|
||||
|
||||
elif slp_func == SLP_ATTR_REQ:
|
||||
slp_prev_res_list, slp_svc_url_len, slp_svc_url, slp_scope_len, slp_scope, slp_tag_len, slp_tag = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
pkt2 = _slp_attr_req_v2(
|
||||
slp_prev_res_list, slp_svc_url_len, slp_svc_url.encode(), slp_scope_len, slp_scope.encode(), slp_tag_len, slp_tag.encode())
|
||||
|
||||
elif slp_func == SLP_ATTR_REPLY:
|
||||
err_code, attr_list_len, attr_list, attr_auths = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
pkt2 = _slp_attr_reply_v2(
|
||||
err_code, attr_list_len, attr_list.encode(), attr_auths)
|
||||
elif slp_func == SLP_SVC_TYPE_REQ:
|
||||
slp_prev_res_list, slp_all, slp_scope, slp_scope_len = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
pkt2 = _slp_svc_type_req_v2(
|
||||
slp_prev_res_list, slp_all, slp_scope.encode(), slp_scope_len)
|
||||
|
||||
elif slp_func == SLP_SVC_TYPE_REPLY:
|
||||
err_code, svc_type_list_len, svc_type_list = jprobes[k]['probe']['data'].values(
|
||||
)
|
||||
pkt2 = _slp_type_reply_v2(
|
||||
err_code, svc_type_list_len, svc_type_list.encode())
|
||||
|
||||
else:
|
||||
print('{0} function not yet supported.'.format(slp_func))
|
||||
|
||||
pkt = pkt1 + pkt2
|
||||
pkt_rdy = compute_len_v2(pkt)
|
||||
# print('* SLP_SVC_REQ implemented')
|
||||
|
||||
else:
|
||||
print('Not supported version {0}'.format(slp_ver))
|
||||
return False
|
||||
|
||||
print(base)
|
||||
print(data)
|
||||
|
||||
return pkt_rdy
|
||||
195
libs/srvloc_proto_v1.py
Normal file
195
libs/srvloc_proto_v1.py
Normal file
@@ -0,0 +1,195 @@
|
||||
import struct
|
||||
import random
|
||||
from libs.srvloc_log import printd
|
||||
|
||||
SLP_SVC_REQ = 0x1
|
||||
SLP_SVC_REPLY = 0x2
|
||||
SLP_ATTR_REQ = 0x6
|
||||
SLP_ATTR_REPLY = 0x7
|
||||
SLP_SVC_TYPE_REQ = 0x9
|
||||
SLP_SVC_TYPE_REPLY = 0xa
|
||||
|
||||
SLP_TRANSX_RAND = True
|
||||
SLP_XID_RAND = True
|
||||
CRAFT_AUTO_LEN = True
|
||||
DEBUG_PROTO = True
|
||||
|
||||
#####################
|
||||
###### SLP v1 #######
|
||||
#####################
|
||||
|
||||
|
||||
def build_slp_base_v1(slp_ver=1, slp_func=0, slp_pkt_len=0, slp_flags=0, slp_dialect=0, slp_lang=0x656e, slp_enc=3, slp_transx=0x29A):
|
||||
'''
|
||||
this method is used for building up what i call the *base* part of the SLPv1 specification. Base parameters are all parameters part
|
||||
of every valid SLPv1 packet.
|
||||
|
||||
Returns: pkt - a ready base packet, WARNING this packet is missing the function part and also pkt_len is not computed yet
|
||||
'''
|
||||
# print(slp_ver)
|
||||
if SLP_TRANSX_RAND:
|
||||
slp_transx = random.randint(1, 65535)
|
||||
|
||||
# basic pkt structure v1
|
||||
pkt = struct.pack('>BBHBBHHH', slp_ver, slp_func, slp_pkt_len,
|
||||
slp_flags, slp_dialect, slp_lang, slp_enc, slp_transx)
|
||||
|
||||
printd(pkt)
|
||||
return pkt
|
||||
|
||||
|
||||
def compute_len_v1(pkt):
|
||||
'''
|
||||
This method is used for computing the overall length of a complete SLPv1 packet. It's default usage is being called at the end of
|
||||
packet building process.
|
||||
|
||||
Params: pkt - a ready pkt without correct pkt_len, usually 0 (zero)
|
||||
Returns: pkt - a ready pkt with correct pkt_len
|
||||
'''
|
||||
pkt_len = len(pkt)
|
||||
|
||||
pkt_byte_len = struct.pack('>H', pkt_len)
|
||||
pkt = pkt[:2]+pkt_byte_len+pkt[4:]
|
||||
return pkt
|
||||
|
||||
|
||||
########SLP_SVC_REQ = 0x1
|
||||
def build_slp_svc_req_v1():
|
||||
pkt1 = build_slp_base_v1(slp_func=SLP_SVC_REQ)
|
||||
pkt2 = _slp_svc_req_v1()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v1(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_svc_req_v1(slp_prev_res_list_len=1, slp_resp_list=b'A', slp_pred_len=1, slp_pred=b'B'):
|
||||
'''
|
||||
'''
|
||||
|
||||
pkt2 = struct.pack('>H' + str(slp_prev_res_list_len) + 'sH' + str(slp_pred_len) + 's',
|
||||
slp_prev_res_list_len,
|
||||
slp_resp_list,
|
||||
slp_pred_len,
|
||||
slp_pred
|
||||
)
|
||||
|
||||
return pkt2
|
||||
|
||||
########################################################################################################################################
|
||||
|
||||
###### SLP_SVC_REPLY = 0x2
|
||||
|
||||
|
||||
def build_slp_reply_v1():
|
||||
pkt1 = build_slp_base_v1(slp_func=SLP_SVC_REPLY)
|
||||
pkt2 = _slp_svc_reply_v1()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v1(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_svc_reply_v1(err_code=0, num_urls=1, url_lifetime=667, url_len=12, urls=b'service:wbem', num_auths=0):
|
||||
'''
|
||||
'''
|
||||
|
||||
#url_len = len(urls)
|
||||
pkt2 = struct.pack('>HHHH'+str(url_len)+'sB', err_code,
|
||||
num_urls, url_lifetime, url_len, urls, 0)
|
||||
|
||||
return pkt2
|
||||
########################################################################################################################################
|
||||
|
||||
#############SLP_ATTR_REQ = 0x6
|
||||
def build_svc_attr_req_v1():
|
||||
pkt1 = build_slp_base_v1(slp_func=SLP_ATTR_REQ)
|
||||
pkt2 = _slp_attr_req_v1()
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v1(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_attr_req_v1(slp_prev_res_list=0, slp_url_len=8, slp_svc_url=b'service:', slp_scope_len=0, slp_attr_len=0):
|
||||
|
||||
# attr request structure
|
||||
pkt2 = struct.pack('>HH'+str(slp_url_len)+'sHH', slp_prev_res_list,
|
||||
slp_url_len, slp_svc_url, slp_scope_len, slp_attr_len)
|
||||
|
||||
return pkt2
|
||||
|
||||
########################################################################################################################################
|
||||
|
||||
#########SLP_ATTR_REPLY = 0x7
|
||||
def build_slp_attr_reply_v1():
|
||||
pkt1 = build_slp_base_v1(slp_func=SLP_ATTR_REPLY)
|
||||
pkt2 = _slp_attr_reply_v1()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v1(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_attr_reply_v1(err_code=0, attr_list_len=9, attr_list=b'attribute', attr_auths=0):
|
||||
|
||||
pkt2 = struct.pack('>HH' + str(attr_list_len) + 'sB',
|
||||
err_code,
|
||||
attr_list_len,
|
||||
attr_list,
|
||||
attr_auths
|
||||
)
|
||||
|
||||
return pkt2
|
||||
########################################################################################################################################
|
||||
|
||||
|
||||
##################SLP_SVC_TYPE_REQ = 0x9
|
||||
|
||||
|
||||
def build_slp_svc_type_req_v1():
|
||||
pkt1 = build_slp_base_v1(slp_func=SLP_SVC_TYPE_REQ)
|
||||
pkt2 = _slp_svc_type_req_v1()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v1(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_svc_type_req_v1(slp_prev_res_list=0, slp_all=65535, slp_scope=b'default'):
|
||||
|
||||
slp_scope_len = len(slp_scope)
|
||||
pkt2 = struct.pack('>HHH'+str(slp_scope_len)+'s', slp_prev_res_list,
|
||||
slp_all, slp_scope_len, slp_scope)
|
||||
|
||||
return pkt2
|
||||
########################################################################################################################################
|
||||
|
||||
########SLP_SVC_TYPE_REPLY = 0xa
|
||||
|
||||
|
||||
def build_slp_type_reply_v1():
|
||||
pkt1 = build_slp_base_v1(slp_func=SLP_SVC_TYPE_REPLY)
|
||||
pkt2 = _slp_type_reply_v1()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v1(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_type_reply_v1(err_code=0, svc_type_count=1, svc_type_list_len=31, svc_type_list=b'service:Windows:wbem:http:https'):
|
||||
|
||||
pkt2 = struct.pack('>HHH' + str(svc_type_list_len) + 's',
|
||||
err_code,
|
||||
svc_type_count,
|
||||
svc_type_list_len,
|
||||
svc_type_list
|
||||
)
|
||||
|
||||
return pkt2
|
||||
########################################################################################################################################
|
||||
172
libs/srvloc_proto_v2.py
Normal file
172
libs/srvloc_proto_v2.py
Normal file
@@ -0,0 +1,172 @@
|
||||
import struct
|
||||
import random
|
||||
from libs.srvloc_log import printd
|
||||
|
||||
SLP_SVC_REQ = 0x1
|
||||
SLP_SVC_REPLY = 0x2
|
||||
SLP_ATTR_REQ = 0x6
|
||||
SLP_ATTR_REPLY = 0x7
|
||||
SLP_SVC_TYPE_REQ = 0x9
|
||||
SLP_SVC_TYPE_REPLY = 0xa
|
||||
|
||||
SLP_TRANSX_RAND = True
|
||||
SLP_XID_RAND = True
|
||||
CRAFT_AUTO_LEN = True
|
||||
DEBUG_PROTO = True
|
||||
|
||||
#####################
|
||||
###### SLP v2 #######
|
||||
#####################
|
||||
|
||||
|
||||
def build_slp_base_v2(slp_ver=2, slp_func=0, slp_pkt_len=0, slp_flags=0, slp_next_offset=0, slp_xid=0x299, slp_ltag_len=2, slp_ltag=0x656e):
|
||||
|
||||
if SLP_XID_RAND:
|
||||
slp_xid = random.randint(1, 65535)
|
||||
|
||||
# basic pkt structure v2
|
||||
pkt = struct.pack('>BBBHHBHHHH', slp_ver, slp_func, 0, slp_pkt_len,
|
||||
slp_flags, 0, slp_next_offset, slp_xid, slp_ltag_len, slp_ltag)
|
||||
|
||||
return pkt
|
||||
|
||||
|
||||
def compute_len_v2(pkt):
|
||||
|
||||
pkt_len = len(pkt)
|
||||
|
||||
pkt_byte_len = struct.pack('>bH', 0, pkt_len)
|
||||
pkt = pkt[:2] + pkt_byte_len + pkt[5:]
|
||||
|
||||
return pkt
|
||||
|
||||
|
||||
#########SLP_SVC_REQ = 0x1
|
||||
def build_slp_svc_req_v2():
|
||||
pkt1 = build_slp_base_v2(slp_func=SLP_SVC_REQ)
|
||||
pkt2 = _slp_svc_req_v2()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v2(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_svc_req_v2(slp_prev_res_list=0, slp_svc_type_len=0, slp_svc_type=b'service:wbem', slp_scope_len=7, slp_scope=b'default'):
|
||||
'''
|
||||
'''
|
||||
|
||||
pkt2 = struct.pack('>HH'+str(slp_svc_type_len)+'sH'+str(slp_scope_len)+'sHH', slp_prev_res_list,
|
||||
slp_svc_type_len, slp_svc_type, slp_scope_len, slp_scope, 0, 0)
|
||||
|
||||
return pkt2
|
||||
##########
|
||||
|
||||
#######SLP_SVC_REPLY = 0x2
|
||||
|
||||
|
||||
def build_slp_reply_v2():
|
||||
pkt1 = build_slp_base_v2(slp_func=SLP_SVC_REPLY)
|
||||
pkt2 = _slp_svc_reply_v2()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v2(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_svc_reply_v2(err_code=0, num_urls=1, reserved=0, url_lifetime=667, url_len=12, urls=b'service:wbem', num_auths=0):
|
||||
'''
|
||||
'''
|
||||
|
||||
pkt2 = struct.pack('>HHBHH'+str(url_len)+'sB', err_code,
|
||||
num_urls, reserved, url_lifetime, url_len, urls, 0)
|
||||
|
||||
return pkt2
|
||||
|
||||
######SLP_ATTR_REQ = 0x6
|
||||
|
||||
|
||||
def build_slp_attr_req_v2():
|
||||
pkt1 = build_slp_base_v2(slp_func=SLP_ATTR_REQ)
|
||||
pkt2 = _slp_attr_req_v2()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v2(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_attr_req_v2(slp_prev_res_list=0, slp_svc_url_len=12, slp_svc_url=b'service:wbem', slp_scope_len=0, slp_scope=b'', slp_tag_len=0, slp_tag=b''):
|
||||
|
||||
pkt2 = struct.pack('>HH'+str(slp_svc_url_len)+'sH'+str(slp_scope_len)+'sH'+str(slp_tag_len)+'sH', slp_prev_res_list,
|
||||
slp_svc_url_len, slp_svc_url, slp_scope_len, slp_scope, slp_tag_len, slp_tag, 0)
|
||||
|
||||
return pkt2
|
||||
#######################
|
||||
|
||||
|
||||
######SLP_ATTR_REPLY = 0x7
|
||||
def build_slp_attr_reply_v2():
|
||||
pkt1 = build_slp_base_v2(slp_func=SLP_ATTR_REPLY)
|
||||
pkt2 = _slp_attr_reply_v2()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v2(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_attr_reply_v2(err_code=4, attr_list_len=0, attr_list=b'', attr_auths=4):
|
||||
|
||||
pkt2 = struct.pack('>HH' + str(attr_list_len) + 'sB',
|
||||
err_code,
|
||||
attr_list_len,
|
||||
attr_list,
|
||||
attr_auths
|
||||
)
|
||||
|
||||
return pkt2
|
||||
##########
|
||||
|
||||
#####SLP_SVC_TYPE_REQ = 0x9
|
||||
def build_slp_svc_type_req_v2():
|
||||
pkt1 = build_slp_base_v2(slp_func=SLP_SVC_TYPE_REQ)
|
||||
pkt2 = _slp_svc_type_req_v2()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v2(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_svc_type_req_v2(slp_prev_res_list=0, slp_all=65535, slp_scope=b'default', slp_scope_len=7):
|
||||
|
||||
pkt2 = struct.pack('>HHH'+str(slp_scope_len)+'s', slp_prev_res_list,
|
||||
slp_all, slp_scope_len, slp_scope)
|
||||
|
||||
return pkt2
|
||||
########################
|
||||
|
||||
|
||||
#####SLP_SVC_TYPE_REPLY = 0xa
|
||||
def build_slp_type_reply_v2():
|
||||
pkt1 = build_slp_base_v2(slp_func=SLP_SVC_TYPE_REPLY)
|
||||
pkt2 = _slp_type_reply_v2()
|
||||
|
||||
pkt = pkt1+pkt2
|
||||
pkt_rdy = compute_len_v2(pkt)
|
||||
|
||||
return pkt_rdy
|
||||
|
||||
|
||||
def _slp_type_reply_v2(err_code=0, svc_type_list_len=31, svc_type_list=b'service:Windows:wbem:http:https'):
|
||||
|
||||
pkt2 = struct.pack('>HH' + str(svc_type_list_len) + 's',
|
||||
err_code,
|
||||
svc_type_list_len,
|
||||
svc_type_list
|
||||
)
|
||||
|
||||
return pkt2
|
||||
###########################
|
||||
41
slpscan.py
Executable file
41
slpscan.py
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from libs.srvloc_proto_v1 import CRAFT_AUTO_LEN
|
||||
from libs.srvloc_main import print_slp_modes, parser_main, run_mainthreads, choose_slp_mode
|
||||
from libs.srvloc_globals import *
|
||||
from libs.srvloc_log import printe, printd
|
||||
from libs.srvloc_probes import open_probe_file, print_probes, probe_packet
|
||||
|
||||
|
||||
def run(args):
|
||||
|
||||
fname = 'libs/srvloc_probes.json'
|
||||
slp_mode = args.slp_mode
|
||||
global CRAFT_AUTO_LEN
|
||||
|
||||
if args.probe_mode:
|
||||
jprobes = open_probe_file(fname)
|
||||
if args.probe_mode == '?' or args.probe_mode == 'help':
|
||||
print_probes(jprobes)
|
||||
sys.exit()
|
||||
|
||||
else:
|
||||
pkt = probe_packet(jprobes, args.probe_mode)
|
||||
|
||||
else:
|
||||
pkt = choose_slp_mode(args)
|
||||
|
||||
print('PKT: ', pkt)
|
||||
run_mainthreads(args, pkt)
|
||||
|
||||
|
||||
def main():
|
||||
args = parser_main()
|
||||
run(args)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1
supply/blacklist.txt
Normal file
1
supply/blacklist.txt
Normal file
@@ -0,0 +1 @@
|
||||
127.0.0.2
|
||||
Reference in New Issue
Block a user