Below is a script to survey Unix systems.

This should work on most flavors of *nix systems.

#!/usr/bin/python
import re
import sys
import subprocess
import platform
from subprocess import PIPE

def banner():
    print(""""_____  ___   _       ___  ___  ___  ___   _   _______ ___________
/  ___|/ _ \ | |     / _ \ |  \/  | / _ \ | \ | |  _  \  ___| ___ \\
\ `--./ /_\ \| |    / /_\ \| .  . |/ /_\ \|  \| | | | | |__ | |_/ /
 `--. \  _  || |    |  _  || |\/| ||  _  || . ` | | | |  __||    / 
/\__/ / | | || |____| | | || |  | || | | || |\  | |/ /| |___| |\ \ 
\____/\_| |_/\_____/\_| |_/\_|  |_/\_| |_/\_| \_/___/ \____/\_| \_|
Survey Tool""")
    try:
        a = sys.argv[1]
    except:
        print("\n usage: ./salamander <output_file>")
        sys.exit()

known_exes = {}

def sh(command):
    #Emulates a shell command. It will use /bin/sh, so no bash tricks (ie. cat /etc/{file1,file2})
    p = subprocess.Popen([command],stdin=PIPE,stdout=PIPE,stderr=PIPE,shell=True)
    out,err = p.communicate()
    return out[:-1]

def exe(exe_name,known_exes=known_exes):
    #This checks if the executable is on the system or not, then saves the path into known_exes dictionary
    #If the executable doesnt exist, it maps the name to /dev/null and raises a warning
    if known_exes.has_key(exe_name):
        return known_exes[exe_name]
    exepath = sh("which {}".format(exe_name))
    if len(exepath) == 0:
        print(' * WARNING\n * "{}" not found on system'.format(exe_name))
        exepath = "/dev/null"
    known_exes[exe_name] = exepath
    return exepath

def init_system():
    #Checks if system is using init,systemd,upstart
    init = sh("{} /proc/1/comm".format(exe("cat")))
    if "init" in init:
        if re.findall("upstart",sh("/sbin/init --version"),re.IGNORECASE):
            return "upstart"
        else:
            return "init"
    else:
        return init

def all_data_to_file():
    #Writes all data to file specified in sys.argv[1]
    with open(sys.argv[1],"w") as f:
        for command_name,command in info.iteritems():
            f.write(" * SALAMANDER: {} information section".format(command_name))
            f.write(command)
            f.write("\n")

banner()

#This is where all the survey-ing happens. Data is populated into the dictionary, then written to a file.
#If you need your survey to be done remotely, this could be tweaked to have it send the data over the network
info = {
    "uname":sh("{} -a".format(exe("uname"))),
    "lsblk":sh("{}".format(exe("lsblk"))),
    "blkid":sh("{}".format(exe("blkid"))),
    "mount":sh("{}".format(exe("mount"))),
    "fdisk":sh("{} -l".format(exe("fdisk"))),
    "cpu":sh("{} name /proc/cpuinfo".format(exe("grep"))),
    "parted":sh("{} -l".format(exe("parted"))),
    "arch":sh("{} LONG_BIT".format(exe("getconf"))),
    "last":sh("{}".format(exe("last"))),
    "w":sh("{}".format(exe("w"))),
    "suid_files":sh("{} -uid 0 -perm /4000 -ls".format(exe("find"))),
    "ps":sh("{} aux".format(exe("ps"))),
    "os_info1":sh("{} /etc/*vers*".format(exe("cat"))),
    "os_info2":sh("{} /etc/*rele*".format(exe("cat"))),
    "netstat":sh("{} -anop".format(exe("netstat"))),
    "ifconfig":sh("{} -a".format(exe("ifconfig"))),
    "lsof":sh("{}".format(exe("lsof"))),
    "uptime":sh("{}".format(exe("uptime"))),
    "arp":sh("{} -a -v".format(exe("arp"))),
    "route":sh("{} -n -v".format(exe("route"))),
    "passwd":sh("{} /etc/passwd".format(exe("cat"))),
    "dmesg":sh("{}".format(exe("dmesg"))),
    "iptables":sh("{} -nvL".format(exe("iptables"))),
    "groups":sh("{} /etc/group".format(exe("cat"))),
    "cronjobs1":sh("{} -HP ^[^#].* /etc/*cron*".format(exe("grep"))),
    "cronjobs2":sh("{} -HP ^[^#].* /etc/*cron*/*".format(exe("grep"))),
    "cronjobs3":sh("{} -HP ^[^#].* /var/spool/cron/*/*".format(exe("grep"))),
    "kernel":platform.system(), #Linux
    "dist1":platform.dist()[0], #('Ubuntu', '16.04', 'xenial')
    "dist2":platform.dist()[1],
    "dist3":platform.dist()[2],
    "init":init_system(),
    "interfaces":sh("{} -a -s".format(exe("ifconfig"))),
    "lsmod":sh("{} -nvL".format(exe("lsmod"))),
    "memory":sh("{} -lh".format(exe("free"))),
    "who":sh("{}".format(exe("who")))
    #"":sh("{}".format(exe("")))
}

all_data_to_file()

#---OUTPUT SECTION
#All data will be written to a file, but its nice to output
#some data to the screen, just the pertinent stuff

def interesting_ttys(process_info):
    #TTYs that have a shell
    return re.findall(".*[pt]t[sy].*[sS][hH]",process_info,re.IGNORECASE)

def interesting_suid(suid_files):
    #SUID files that are known priv-esc vulnerable
    return re.findall("(python)|(perl)|(sh)|(nano)|(vi)|(ed)|(pico)|(nmap)",suid_files,re.IGNORECASE)



print(" *** SYSTEM INFO ***")
print("""
 [+] Kernel: {arch}-bit {kernel}
 [+] Distro: {dist1}-{dist2}
 [+] Codename: {dist3}
 [+] Uptime: {uptime}
 [+] Init System: {init}
 
 [+] Logged-in users:
 {who}
""".format(**info))

listening = ''.join([str(n)+'\n' for n in info["netstat"].split('\n') if "LISTEN" in n and "tcp" in n])
print(" *** NETWORK INFO ***")
print("""
 [+] Interfaces:
{interfaces}

 [+] Listening TCP:
{listening}

""".format(listening=listening,**info))

print(" *** DISK INFORMATION ***")
print("""
 [+] Hard Drives:
 
 {lsblk}
 
 [+] Partitions:
 
 {parted}
 
 [+] Memory:
 {memory}
""".format(**info))

print(" *** INTERESTING FILES/PROCESSES ***")
print("\n [+] Vulnerable SUID files:")
for suid_file in interesting_suid(info["suid_files"]):
    print(" [*] {}".format(suid_file))
print("\n [+] Shell TTYs:")
for tty in interesting_ttys(info["ps"]):
    print(" [*] {}".format(tty))
Python Survey Script

Leave a Reply

Your email address will not be published.