adding some new scripts and updated hack(le)s
This commit is contained in:
parent
6f450ab68f
commit
33043a3499
@ -12,9 +12,9 @@ def copyKeys(keystring, user = 'root'):
|
|||||||
homedir = os.path.expanduser('~{0}'.format(user))
|
homedir = os.path.expanduser('~{0}'.format(user))
|
||||||
sshdir = '{0}/.ssh'.format(homedir)
|
sshdir = '{0}/.ssh'.format(homedir)
|
||||||
authfile = '{0}/authorized_keys'.format(sshdir)
|
authfile = '{0}/authorized_keys'.format(sshdir)
|
||||||
|
os.makedirs(sshdir, mode = 0o700, exist_ok = True)
|
||||||
with open(authfile, 'a') as f:
|
with open(authfile, 'a') as f:
|
||||||
f.write(keystring)
|
f.write(keystring)
|
||||||
os.makedirs(sshdir, mode = 0o700, exist_ok = True)
|
|
||||||
for basedir, dirs, files in os.walk(sshdir):
|
for basedir, dirs, files in os.walk(sshdir):
|
||||||
os.chown(basedir, uid, gid)
|
os.chown(basedir, uid, gid)
|
||||||
os.chmod(basedir, 0o700)
|
os.chmod(basedir, 0o700)
|
||||||
@ -28,4 +28,4 @@ def main():
|
|||||||
copyKeys(keys.read().decode('utf-8'))
|
copyKeys(keys.read().decode('utf-8'))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
84
mysql/tblinfo.py
Executable file
84
mysql/tblinfo.py
Executable file
@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import configparser
|
||||||
|
import copy
|
||||||
|
import os
|
||||||
|
import pymysql
|
||||||
|
|
||||||
|
mysql_internal = ['information_schema', 'mysql']
|
||||||
|
|
||||||
|
# Not used, but could be in the future.
|
||||||
|
stat_hdrs = ['Name', 'Engine', 'Version', 'Row_format', 'Rows', 'Avg_row_length', 'Data_length',
|
||||||
|
'Max_data_length', 'Index_length', 'Data_free', 'Auto_increment', 'Create_time',
|
||||||
|
'Update_time', 'Check_time', 'Collation', 'Checksum', 'Create_options', 'Comment']
|
||||||
|
tblinfo_hdrs = ['Field', 'Type', 'Null', 'Key', 'Default', 'Extra']
|
||||||
|
|
||||||
|
def get_info(db, internal = False):
|
||||||
|
dbs = {}
|
||||||
|
if os.path.isfile(os.path.expanduser('~/.my.cnf')):
|
||||||
|
_cfg = configparser.ConfigParser(allow_no_value = True)
|
||||||
|
_cfg.read(os.path.expanduser('~/.my.cnf'))
|
||||||
|
_cfg = dict(_cfg['client'])
|
||||||
|
_cfg['ssl'] = {}
|
||||||
|
if 'host' not in _cfg:
|
||||||
|
_cfg['host'] = 'localhost'
|
||||||
|
conn = pymysql.connect(**_cfg, cursorclass = pymysql.cursors.DictCursor)
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Need mysql creds at ~/.my.cnf')
|
||||||
|
cur = conn.cursor()
|
||||||
|
if not db:
|
||||||
|
cur.execute("SHOW DATABASES")
|
||||||
|
db = [row['Database'] for row in cur.fetchall()]
|
||||||
|
if not internal:
|
||||||
|
for d in mysql_internal:
|
||||||
|
try:
|
||||||
|
db.remove(d)
|
||||||
|
except ValueError: # Not in the list; our user probably doesn't have access
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
db = [db]
|
||||||
|
for d in db:
|
||||||
|
dbs[d] = {}
|
||||||
|
cur.execute("SHOW TABLES FROM `{0}`".format(d))
|
||||||
|
for tbl in [t['Tables_in_{0}'.format(d)] for t in cur.fetchall()]:
|
||||||
|
dbs[d][tbl] = {}
|
||||||
|
# Status
|
||||||
|
cur.execute("SHOW TABLE STATUS FROM `{0}` WHERE Name = %s".format(d), (tbl, ))
|
||||||
|
dbs[d][tbl]['_STATUS'] = copy.deepcopy(cur.fetchone())
|
||||||
|
# Columns
|
||||||
|
dbs[d][tbl]['_COLUMNS'] = {}
|
||||||
|
#cur.execute("DESCRIBE {0}.{1}".format(d, tbl))
|
||||||
|
cur.execute("SHOW COLUMNS IN `{0}` FROM `{1}`".format(tbl, d))
|
||||||
|
for row in cur.fetchall():
|
||||||
|
colNm = row['Field']
|
||||||
|
dbs[d][tbl]['_COLUMNS'][colNm] = {}
|
||||||
|
for k in [x for x in tblinfo_hdrs if x is not 'Field']:
|
||||||
|
dbs[d][tbl]['_COLUMNS'][colNm][k] = row[k]
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
return(dbs)
|
||||||
|
|
||||||
|
def parseArgs():
|
||||||
|
args = argparse.ArgumentParser()
|
||||||
|
args.add_argument('-i', '--internal',
|
||||||
|
dest = 'internal',
|
||||||
|
action = 'store_true',
|
||||||
|
help = ('If specified, include the MySQL internal databases '
|
||||||
|
'(mysql, information_schema, etc.); only used if -d is not specified'))
|
||||||
|
args.add_argument('-d', '--database',
|
||||||
|
dest = 'db',
|
||||||
|
default = None,
|
||||||
|
help = 'If specified, only list table info for this DB')
|
||||||
|
return(args)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = vars(parseArgs().parse_args())
|
||||||
|
dbs = get_info(args['db'], internal = args['internal'])
|
||||||
|
#import json
|
||||||
|
#print(json.dumps(dbs, indent = 4, sort_keys = True, default = str))
|
||||||
|
import pprint
|
||||||
|
pprint.pprint(dbs)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
132
net/ssh/audit.py
Executable file
132
net/ssh/audit.py
Executable file
@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import paramiko
|
||||||
|
import socket
|
||||||
|
|
||||||
|
|
||||||
|
class SSHAuthInfo(object):
|
||||||
|
def __init__(self, target, port = 22, banner = True, ciphers = True, digests = True, kex = True, key_types = True,
|
||||||
|
methods = True, hostkeys = True, version = True):
|
||||||
|
self.target = target
|
||||||
|
self.port = int(port)
|
||||||
|
self.info = {'target': self.target,
|
||||||
|
'port': self.port,
|
||||||
|
'banner': banner,
|
||||||
|
'ciphers': ciphers,
|
||||||
|
'digests': digests,
|
||||||
|
'kex': kex,
|
||||||
|
'key_types': key_types,
|
||||||
|
'methods': methods,
|
||||||
|
'hostkeys': hostkeys,
|
||||||
|
'version': version}
|
||||||
|
self._ssh = None
|
||||||
|
if any((ciphers, banner, methods, digests, kex, key_types)): # These need an SSH connection.
|
||||||
|
self._ssh_dummy()
|
||||||
|
if banner:
|
||||||
|
self.getBanner()
|
||||||
|
if hostkeys:
|
||||||
|
self.getHostkeys()
|
||||||
|
if version:
|
||||||
|
self.getVersion()
|
||||||
|
self._close()
|
||||||
|
|
||||||
|
def _ssh_dummy(self):
|
||||||
|
self._ssh = paramiko.Transport((self.target, self.port))
|
||||||
|
self._ssh.connect()
|
||||||
|
try:
|
||||||
|
self._ssh.auth_none('')
|
||||||
|
except paramiko.ssh_exception.BadAuthenticationType as err:
|
||||||
|
secopts = self._ssh.get_security_options()
|
||||||
|
print(secopts.key_types)
|
||||||
|
if self.info['methods']:
|
||||||
|
# https://stackoverflow.com/a/1257769
|
||||||
|
self.info['methods'] = err.allowed_types
|
||||||
|
if self.info['ciphers']:
|
||||||
|
self.info['ciphers'] = list(secopts.ciphers)
|
||||||
|
if self.info['digests']:
|
||||||
|
self.info['digests'] = list(secopts.digests)
|
||||||
|
if self.info['kex']:
|
||||||
|
self.info['kex'] = list(secopts.kex)
|
||||||
|
if self.info['key_types']:
|
||||||
|
self.info['key_types'] = list(secopts.key_types)
|
||||||
|
return()
|
||||||
|
|
||||||
|
def getBanner(self):
|
||||||
|
self.info['banner'] = None
|
||||||
|
# https://github.com/paramiko/paramiko/issues/273#issuecomment-225058645 doesn't seem to work.
|
||||||
|
# But https://github.com/paramiko/paramiko/pull/58#issuecomment-63857078 did!
|
||||||
|
self.info['banner'] = self._ssh.get_banner()
|
||||||
|
return()
|
||||||
|
|
||||||
|
def getHostkeys(self):
|
||||||
|
# TODO: how the hell do I get *all* hostkeys served?
|
||||||
|
self.info['hostkeys'] = {}
|
||||||
|
k = self._ssh.get_remote_server_key()
|
||||||
|
self.info['hostkeys'][k.get_name()] = k.get_base64()
|
||||||
|
return()
|
||||||
|
|
||||||
|
def getVersion(self):
|
||||||
|
self.info['version'] = None
|
||||||
|
s = socket.socket()
|
||||||
|
s.connect((self.target, self.port))
|
||||||
|
try:
|
||||||
|
# 8192 bytes is kind of overkill considering most are probably going to be around 20 bytes or so.
|
||||||
|
self.info['version'] = s.recv(8192)
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
return()
|
||||||
|
|
||||||
|
def _close(self):
|
||||||
|
if self._ssh:
|
||||||
|
self._ssh.close()
|
||||||
|
|
||||||
|
def parseArgs():
|
||||||
|
args = argparse.ArgumentParser()
|
||||||
|
args.add_argument('-b', '--no-banner',
|
||||||
|
action = 'store_false',
|
||||||
|
dest = 'banner',
|
||||||
|
help = 'Do not gather the SSH banner')
|
||||||
|
args.add_argument('-c', '--no-ciphers',
|
||||||
|
action = 'store_false',
|
||||||
|
dest = 'ciphers',
|
||||||
|
help = 'Do not gather supported ciphers')
|
||||||
|
args.add_argument('-d', '--no-digests',
|
||||||
|
action = 'store_false',
|
||||||
|
dest = 'digests',
|
||||||
|
help = 'Do not gather supported digests')
|
||||||
|
args.add_argument('-m', '--no-methods',
|
||||||
|
action = 'store_false',
|
||||||
|
dest = 'methods',
|
||||||
|
help = 'Do not gather supported auth methods')
|
||||||
|
args.add_argument('-k', '--no-hostkeys',
|
||||||
|
action = 'store_false',
|
||||||
|
dest = 'hostkeys',
|
||||||
|
help = 'Do not gather hostkeys')
|
||||||
|
args.add_argument('-x', '--no-kex',
|
||||||
|
action = 'store_false',
|
||||||
|
dest = 'kex',
|
||||||
|
help = 'Do not gather supported key exchanges')
|
||||||
|
args.add_argument('-t', '--no-key-types',
|
||||||
|
action = 'store_false',
|
||||||
|
dest = 'key_types',
|
||||||
|
help = 'Do not gather supported key types')
|
||||||
|
args.add_argument('-v', '--no-version',
|
||||||
|
action = 'store_false',
|
||||||
|
dest = 'version',
|
||||||
|
help = 'Do not gather SSH version')
|
||||||
|
args.add_argument('-p', '--port',
|
||||||
|
default = 22,
|
||||||
|
help = 'The port on target that the SSH daemon is running on. Default is 22')
|
||||||
|
args.add_argument('target',
|
||||||
|
help = 'The server to run the check against')
|
||||||
|
return(args)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = vars(parseArgs().parse_args())
|
||||||
|
i = SSHAuthInfo(**args)
|
||||||
|
import pprint
|
||||||
|
pprint.pprint(i.info)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -118,3 +118,17 @@ To issue an equivalent of "reset" command in linux, assuming console is ANSI-com
|
|||||||
print('\x1bc', end = '')
|
print('\x1bc', end = '')
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
|
To get the default route via pyroute2,
|
||||||
|
----
|
||||||
|
import socket
|
||||||
|
from pyroute2 import IPDB
|
||||||
|
ip = IPDB()
|
||||||
|
def_rt = ip.routes['default'] # a route object
|
||||||
|
iface = ip.interfaces[def_rt.oif] # an interface object. name is e.g. iface.ifname, IPs are in tuple-of-tuples iface.ipaddr, etc.
|
||||||
|
gw = def_rt.gateway # etc.
|
||||||
|
ip.release()
|
||||||
|
----
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
Loading…
Reference in New Issue
Block a user