Initial commit, basic helper classes created
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.swp
|
||||||
|
*.pyc
|
||||||
144
py/Airmon.py
Normal file
144
py/Airmon.py
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from Interface import Interface
|
||||||
|
from Process import Process
|
||||||
|
from Color import Color
|
||||||
|
|
||||||
|
class Airmon(object):
|
||||||
|
''' Wrapper around the 'airmon-ng' program '''
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
''' Get airmon-recognized interfaces '''
|
||||||
|
self.interfaces = Airmon.get_interfaces()
|
||||||
|
|
||||||
|
def print_menu(self):
|
||||||
|
''' Prints menu '''
|
||||||
|
print Interface.menu_header()
|
||||||
|
for (index, iface) in enumerate(self.interfaces):
|
||||||
|
Color.pl(" {G}%d{W}. %s" % (index + 1, iface))
|
||||||
|
|
||||||
|
def get(self, index):
|
||||||
|
''' Gets interface at index (starts at 1) '''
|
||||||
|
if type(index) == str:
|
||||||
|
index = int(index)
|
||||||
|
return self.interfaces[index - 1]
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_interfaces():
|
||||||
|
'''
|
||||||
|
Returns:
|
||||||
|
List of Interface objects known by airmon-ng
|
||||||
|
'''
|
||||||
|
interfaces = []
|
||||||
|
p = Process('airmon-ng')
|
||||||
|
for line in p.stdout().split('\n'):
|
||||||
|
# Ignore blank/header lines
|
||||||
|
if len(line) == 0: continue
|
||||||
|
if line.startswith('Interface'): continue
|
||||||
|
if line.startswith('PHY'): continue
|
||||||
|
|
||||||
|
# Strip out interface information
|
||||||
|
fields = line.split("\t")
|
||||||
|
while '' in fields:
|
||||||
|
fields.remove('')
|
||||||
|
# Add Interface object to list
|
||||||
|
interfaces.append(Interface(fields))
|
||||||
|
return interfaces
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def start(iface):
|
||||||
|
'''
|
||||||
|
Starts an interface (iface) in monitor mode
|
||||||
|
Args:
|
||||||
|
iface - The interface to start in monitor mode
|
||||||
|
Either an instance of Interface object,
|
||||||
|
or the name of the interface (string).
|
||||||
|
Returns:
|
||||||
|
Name of the interface put into monitor mode.
|
||||||
|
Throws:
|
||||||
|
Exception - If an interface can't be put into monitor mode
|
||||||
|
'''
|
||||||
|
# Get interface name from input
|
||||||
|
if type(iface) == Interface:
|
||||||
|
iface = iface.name
|
||||||
|
|
||||||
|
# Call airmon-ng
|
||||||
|
Color.p("{+} enabling {G}monitor mode{W} on {C}%s{W}... " % iface)
|
||||||
|
(out,err) = Process.call(['airmon-ng', 'start', iface])
|
||||||
|
|
||||||
|
# Find the interface put into monitor mode (if any)
|
||||||
|
mon_iface = None
|
||||||
|
for line in out.split('\n'):
|
||||||
|
if 'monitor mode' in line and 'enabled' in line and ' on ' in line:
|
||||||
|
mon_iface = line.split(' on ')[1]
|
||||||
|
if ']' in mon_iface:
|
||||||
|
mon_iface = mon_iface.split(']')[1]
|
||||||
|
if ')' in mon_iface:
|
||||||
|
mon_iface = mon_iface.split(')')[0]
|
||||||
|
break
|
||||||
|
|
||||||
|
if mon_iface == None:
|
||||||
|
# Airmon did not enable monitor mode on an interface
|
||||||
|
Color.pl("{R}failed{W}")
|
||||||
|
|
||||||
|
mon_ifaces = Airmon.get_interfaces_in_monitor_mode()
|
||||||
|
|
||||||
|
# Assert that there is an interface in monitor mode
|
||||||
|
if len(mon_ifaces) == 0:
|
||||||
|
Color.pl("{R}failed{W}")
|
||||||
|
raise Exception("iwconfig does not see any interfaces in Mode:Monitor")
|
||||||
|
|
||||||
|
# Assert that the interface enabled by airmon-ng is in monitor mode
|
||||||
|
if mon_iface not in mon_ifaces:
|
||||||
|
Color.pl("{R}failed{W}")
|
||||||
|
raise Exception("iwconfig does not see %s in Mode:Monitor" % mon_iface)
|
||||||
|
|
||||||
|
# No errors found; the device 'mon_iface' was put into MM.
|
||||||
|
Color.pl("{G}enabled {C}%s{W}" % mon_iface)
|
||||||
|
return mon_iface
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stop(iface):
|
||||||
|
# TODO (this)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_interfaces_in_monitor_mode():
|
||||||
|
'''
|
||||||
|
Uses 'iwconfig' to find all interfaces in monitor mode
|
||||||
|
Returns:
|
||||||
|
List of interface names that are in monitor mode
|
||||||
|
'''
|
||||||
|
interfaces = []
|
||||||
|
(out, err) = Process.call("iwconfig")
|
||||||
|
for line in out.split("\n"):
|
||||||
|
if len(line) == 0: continue
|
||||||
|
if line[0] != ' ':
|
||||||
|
iface = line.split(' ')[0]
|
||||||
|
if '\t' in iface:
|
||||||
|
iface = iface.split('\t')[0]
|
||||||
|
if 'Mode:Monitor' in line and iface not in interfaces:
|
||||||
|
interfaces.append(iface)
|
||||||
|
return interfaces
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print "Interfaces in monitor mode:",
|
||||||
|
print ','.join(Airmon.get_interfaces_in_monitor_mode())
|
||||||
|
print ''
|
||||||
|
|
||||||
|
a = Airmon()
|
||||||
|
a.print_menu()
|
||||||
|
count = len(a.interfaces)
|
||||||
|
question = Color.s("Select interface ({G}1-%d{W}): " % (count))
|
||||||
|
choice = raw_input(question)
|
||||||
|
Color.pl("You chose: {G}%s{W}" % a.get(choice).name)
|
||||||
|
|
||||||
|
#a.start(a.interfaces[0])
|
||||||
|
|
||||||
98
py/Arguments.py
Normal file
98
py/Arguments.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
class Arguments(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.args = self.get_arguments()
|
||||||
|
|
||||||
|
def get_arguments(self):
|
||||||
|
description = 'Wrapper script around aircrack-ng and reaver'
|
||||||
|
description += ' https://github.com/derv82/wifite'
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=description)
|
||||||
|
|
||||||
|
# Global variables
|
||||||
|
glob = parser.add_argument_group('SETTINGS')
|
||||||
|
glob.add_argument('-i',
|
||||||
|
action='store',
|
||||||
|
dest='interface',
|
||||||
|
metavar='interface',
|
||||||
|
type=str,
|
||||||
|
help='Wireless interface to use (default: ask)')
|
||||||
|
glob.add_argument('-c',
|
||||||
|
action='store',
|
||||||
|
dest='channel',
|
||||||
|
metavar='channel',
|
||||||
|
type=int,
|
||||||
|
help='Wireless channel to scan (default: all channels)')
|
||||||
|
|
||||||
|
# WEP
|
||||||
|
wep = parser.add_argument_group('WEP-RELATED')
|
||||||
|
wep.add_argument('--wep',
|
||||||
|
action='store_true',
|
||||||
|
dest='wep_only',
|
||||||
|
help='Only target WEP-encrypted networks (ignores WPA)')
|
||||||
|
|
||||||
|
# WPA
|
||||||
|
wep = parser.add_argument_group('WPA-RELATED')
|
||||||
|
wep.add_argument('--wpa',
|
||||||
|
action='store_true',
|
||||||
|
dest='wpa_only',
|
||||||
|
help='Only target WPA-encrypted networks (ignores WEP)')
|
||||||
|
|
||||||
|
# WPS
|
||||||
|
wep = parser.add_argument_group('WPS-RELATED')
|
||||||
|
wep.add_argument('--wps',
|
||||||
|
action='store_true',
|
||||||
|
dest='wps_only',
|
||||||
|
help='Only target WPS-encrypted networks (ignores WEP/nonWPS)')
|
||||||
|
wep.add_argument('--pixie',
|
||||||
|
action='store_true',
|
||||||
|
dest='pixie_only',
|
||||||
|
help='Only use the WPS Pixie-Dust attack (do not crack PINs)')
|
||||||
|
|
||||||
|
# Cracking
|
||||||
|
crack = parser.add_argument_group('CRACKING')
|
||||||
|
crack.add_argument('--cracked',
|
||||||
|
action='store_true',
|
||||||
|
dest='cracked',
|
||||||
|
help='Display previously-cracked access points')
|
||||||
|
crack.add_argument('--check',
|
||||||
|
action='store',
|
||||||
|
metavar='[file]',
|
||||||
|
dest='check',
|
||||||
|
help='Check a .cap file for WPA handshakes')
|
||||||
|
crack.add_argument('--crack-wpa',
|
||||||
|
action='store',
|
||||||
|
type=str,
|
||||||
|
dest='crackwpa',
|
||||||
|
metavar='[file]',
|
||||||
|
help='Crack a .cap file containing a WPA handshake')
|
||||||
|
crack.add_argument('--crack-wep',
|
||||||
|
action='store',
|
||||||
|
type=str,
|
||||||
|
dest='crackwep',
|
||||||
|
metavar='[file]',
|
||||||
|
help='Crack a .cap file containing WEP IVS')
|
||||||
|
crack.add_argument('--dict',
|
||||||
|
action='store',
|
||||||
|
type=str,
|
||||||
|
dest='wordlist',
|
||||||
|
metavar='[file]',
|
||||||
|
help='Dictionary/wordlist to use for cracking')
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
commands = parser.add_argument_group('FUNCTIONS')
|
||||||
|
commands.add_argument('--update',
|
||||||
|
action='store_true',
|
||||||
|
dest='update',
|
||||||
|
help='Update to latest version of Wifite (on github)')
|
||||||
|
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
a = Arguments()
|
||||||
|
args = a.args
|
||||||
|
print args
|
||||||
|
|
||||||
19
py/CapFile.py
Normal file
19
py/CapFile.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
class CapFile(object):
|
||||||
|
"""
|
||||||
|
Holds data about an access point's .cap file,
|
||||||
|
including filename, AP's ESSID & BSSID.
|
||||||
|
"""
|
||||||
|
def __init__(self, filename, ssid, bssid):
|
||||||
|
self.filename = filename
|
||||||
|
self.ssid = ssid
|
||||||
|
self.bssid = bssid
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.filename
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
c = CapFile("cap-01.cap", "My Router", "AA:BB:CC:DD:EE:FF")
|
||||||
|
print c
|
||||||
|
|
||||||
11
py/Client.py
Normal file
11
py/Client.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
class Client:
|
||||||
|
"""
|
||||||
|
Holds data for a Client (device connected to Access Point/Router)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, bssid, station, power):
|
||||||
|
self.bssid = bssid
|
||||||
|
self.station = station
|
||||||
|
self.power = power
|
||||||
|
|
||||||
58
py/Color.py
Normal file
58
py/Color.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class Color(object):
|
||||||
|
''' Helper object for easily printing colored text to the terminal. '''
|
||||||
|
|
||||||
|
# Basic console colors
|
||||||
|
colors = {
|
||||||
|
'W' : '\033[0m', # white (normal)
|
||||||
|
'R' : '\033[31m', # red
|
||||||
|
'G' : '\033[32m', # green
|
||||||
|
'O' : '\033[33m', # orange
|
||||||
|
'B' : '\033[34m', # blue
|
||||||
|
'P' : '\033[35m', # purple
|
||||||
|
'C' : '\033[36m', # cyan
|
||||||
|
'GR': '\033[37m' # gray
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper string replacements
|
||||||
|
replacements = {
|
||||||
|
'{+}': '{W}[{G}+{W}]',
|
||||||
|
'{!}': '{W}[{R}!{W}]'
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def p(text):
|
||||||
|
'''
|
||||||
|
Prints text using colored format on same line.
|
||||||
|
Example:
|
||||||
|
Color.p("{R}This text is red. {W} This text is white")
|
||||||
|
'''
|
||||||
|
sys.stdout.write(Color.s(text))
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def pl(text):
|
||||||
|
'''
|
||||||
|
Prints text using colored format with trailing new line.
|
||||||
|
'''
|
||||||
|
Color.p('%s\n' % text)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def s(text):
|
||||||
|
''' Returns colored string '''
|
||||||
|
output = text
|
||||||
|
for (key,value) in Color.replacements.iteritems():
|
||||||
|
output = output.replace(key, value)
|
||||||
|
for (key,value) in Color.colors.iteritems():
|
||||||
|
output = output.replace("{%s}" % key, value)
|
||||||
|
return output
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Color.pl("{R}Testing{G}One{C}Two{P}Three{W}Done")
|
||||||
|
print Color.s("{C}Testing{P}String{W}")
|
||||||
|
Color.pl("{+} Good line")
|
||||||
|
Color.pl("{!} Danger")
|
||||||
|
|
||||||
110
py/Configuration.py
Normal file
110
py/Configuration.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
class Configuration(object):
|
||||||
|
''' Stores configuration variables for Wifite. '''
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
''' Sets up default initial configuration values '''
|
||||||
|
self.temp_dir = None # Temporary directory
|
||||||
|
|
||||||
|
self.version = 2.00 # Program version
|
||||||
|
self.tx_power = 0 # Wifi transmit power (0 is default)
|
||||||
|
self.interface = None
|
||||||
|
self.target_channel = None # User-defined channel to scan
|
||||||
|
self.target_essid = None # User-defined AP name
|
||||||
|
self.target_bssid = None # User-defined AP BSSID
|
||||||
|
self.pillage = False # "Pillage" mode to attack everything
|
||||||
|
|
||||||
|
# WEP variables
|
||||||
|
self.wep_only = False # Only attack WEP networks
|
||||||
|
self.wep_pps = 6000 # Packets per second
|
||||||
|
self.wep_timeout = 600 # Seconds to wait before failing
|
||||||
|
# WEP-specific attacks
|
||||||
|
self.wep_fragment = True
|
||||||
|
self.wep_caffelatte = True
|
||||||
|
self.wep_p0841 = True
|
||||||
|
self.wep_hirte = True
|
||||||
|
# Number of IVS at which we start cracking
|
||||||
|
self.wep_crack_at_ivs = 10000
|
||||||
|
|
||||||
|
# WPA variables
|
||||||
|
self.wpa_only = False # Only attack WPA networks
|
||||||
|
self.wpa_deauth_timeout = 10 # Seconds to wait between deauths
|
||||||
|
self.wpa_attack_timeout = 500 # Seconds to wait before failing
|
||||||
|
self.wpa_handshake_dir = "hs" # Directory to store handshakes
|
||||||
|
|
||||||
|
# Default dictionary for cracking
|
||||||
|
self.wordlist = None
|
||||||
|
wordlists = [
|
||||||
|
'/usr/share/wfuzz/wordlist/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt',
|
||||||
|
'/usr/share/fuzzdb/wordlists-user-passwd/passwds/phpbb.txt'
|
||||||
|
]
|
||||||
|
for wlist in wordlists:
|
||||||
|
if os.path.exists(wlist):
|
||||||
|
self.wordlist = wlist
|
||||||
|
break
|
||||||
|
|
||||||
|
# WPS variables
|
||||||
|
self.wps_only = False # Only attack WPS networks
|
||||||
|
self.pixie_only = False # Only use Pixie attack on WPS
|
||||||
|
self.wps_timeout = 600 # Seconds to wait before failing
|
||||||
|
self.wps_max_retries = 20 # Retries before failing
|
||||||
|
|
||||||
|
|
||||||
|
def load_from_arguments(self, args):
|
||||||
|
''' Sets configuration values based on Argument.args object '''
|
||||||
|
if args.channel: self.target_channel = args.channel
|
||||||
|
if args.interface: self.interface = args.interface
|
||||||
|
if args.wep_only: self.wep_only = args.wep_only
|
||||||
|
if args.wpa_only: self.wpa_only = args.wpa_only
|
||||||
|
if args.wps_only: self.wps_only = args.wps_only
|
||||||
|
if args.pixie_only: self.pixie_only = args.pixie_only
|
||||||
|
if args.wordlist: self.wordlist = args.wordlist
|
||||||
|
|
||||||
|
|
||||||
|
def temp(self):
|
||||||
|
''' Creates and/or returns the temporary directory '''
|
||||||
|
if self.temp_dir == None:
|
||||||
|
self.temp_dir = self.create_temp()
|
||||||
|
return self.temp_dir
|
||||||
|
|
||||||
|
def create_temp(self):
|
||||||
|
''' Creates and returns a temporary directory '''
|
||||||
|
from tempfile import mkdtemp
|
||||||
|
tmp = mkdtemp(prefix='wifite')
|
||||||
|
if not tmp.endswith(os.sep):
|
||||||
|
tmp += os.sep
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
def delete_temp(self):
|
||||||
|
''' Remove temp files and folder '''
|
||||||
|
if self.temp_dir == None: return
|
||||||
|
if os.path.exists(self.temp_dir):
|
||||||
|
for f in os.listdir(self.temp_dir):
|
||||||
|
os.remove(self.temp_dir + f)
|
||||||
|
os.rmdir(self.temp_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def exit_gracefully(self, code=0):
|
||||||
|
''' Deletes temp and exist with the given code '''
|
||||||
|
self.delete_temp()
|
||||||
|
exit(code)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
''' (Colorful) string representation of the configuration '''
|
||||||
|
from Color import Color
|
||||||
|
result = Color.s('{W}Wifite Configuration{W}\n')
|
||||||
|
result += Color.s('{W}--------------------{W}\n')
|
||||||
|
for (key,val) in sorted(c.__dict__.iteritems()):
|
||||||
|
result += Color.s("{G}%s{W}:\t{C}%s{W}\n" % (key,val))
|
||||||
|
return result
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
c = Configuration()
|
||||||
|
from Arguments import Arguments
|
||||||
|
a = Arguments()
|
||||||
|
c.load_from_arguments(a.args)
|
||||||
|
print c
|
||||||
|
|
||||||
70
py/Interface.py
Normal file
70
py/Interface.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from Color import Color
|
||||||
|
|
||||||
|
class Interface(object):
|
||||||
|
'''
|
||||||
|
Represents an 'interface' known by airmon-ng
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Max length of fields.
|
||||||
|
# Used for printing a table of interfaces.
|
||||||
|
PHY_LEN = 6
|
||||||
|
NAME_LEN = 12
|
||||||
|
DRIVER_LEN = 12
|
||||||
|
CHIPSET_LEN = 30
|
||||||
|
|
||||||
|
def __init__(self, fields):
|
||||||
|
'''
|
||||||
|
Initializes & stores info about an interface.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
Fields - list of fields
|
||||||
|
0: PHY
|
||||||
|
1: NAME
|
||||||
|
2: DRIVER
|
||||||
|
3: CHIPSET
|
||||||
|
'''
|
||||||
|
if len(fields) == 3:
|
||||||
|
fields.insert(0, 'phyX')
|
||||||
|
if len(fields) != 4:
|
||||||
|
raise Exception("Expected 4, got %d in %s" % (len(fields), fields))
|
||||||
|
self.phy = fields[0].strip()
|
||||||
|
self.name = fields[1].strip()
|
||||||
|
self.driver = fields[2].strip()
|
||||||
|
self.chipset = fields[3].strip()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
''' Colored string representation of interface '''
|
||||||
|
s = Color.s("{W}%s" % self.phy)
|
||||||
|
s += ' ' * max(Interface.PHY_LEN - len(self.phy), 0)
|
||||||
|
|
||||||
|
s += Color.s("{G}%s" % self.name)
|
||||||
|
s += ' ' * max(Interface.NAME_LEN - len(self.name), 0)
|
||||||
|
|
||||||
|
s += Color.s("{C}%s" % self.driver)
|
||||||
|
s += ' ' * max(Interface.DRIVER_LEN - len(self.driver), 0)
|
||||||
|
|
||||||
|
s += Color.s("{W}%s" % self.chipset)
|
||||||
|
s += ' ' * max(Interface.CHIPSET_LEN - len(self.chipset), 0)
|
||||||
|
return s
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def menu_header():
|
||||||
|
''' Colored header row for interfaces '''
|
||||||
|
s = ' '
|
||||||
|
s += 'PHY'
|
||||||
|
s += ' ' * (Interface.PHY_LEN - len("PHY"))
|
||||||
|
|
||||||
|
s += 'Interface'
|
||||||
|
s += ' ' * (Interface.NAME_LEN - len("Interface"))
|
||||||
|
s += 'Driver'
|
||||||
|
s += ' ' * (Interface.DRIVER_LEN - len("Driver"))
|
||||||
|
|
||||||
|
s += 'Chipset'
|
||||||
|
s += ' ' * (Interface.CHIPSET_LEN - len("Chipset"))
|
||||||
|
|
||||||
|
s += '\n---'
|
||||||
|
s += '-' * (Interface.PHY_LEN + Interface.NAME_LEN + Interface.DRIVER_LEN + Interface.CHIPSET_LEN)
|
||||||
|
return s
|
||||||
|
|
||||||
107
py/Process.py
Normal file
107
py/Process.py
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from subprocess import Popen, call, PIPE
|
||||||
|
|
||||||
|
class Process(object):
|
||||||
|
''' Represents a running/ran process '''
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def devnull():
|
||||||
|
''' Helper method for opening devnull '''
|
||||||
|
return open('/dev/null', 'w')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def call(command):
|
||||||
|
'''
|
||||||
|
Calls a command (either string or list of args).
|
||||||
|
Returns tuple:
|
||||||
|
(stdout, stderr)
|
||||||
|
'''
|
||||||
|
if type(command) != str or ' ' in command:
|
||||||
|
shell = True
|
||||||
|
else:
|
||||||
|
shell = False
|
||||||
|
pid = Popen(command, stdout=PIPE, stderr=PIPE, shell=shell)
|
||||||
|
pid.wait()
|
||||||
|
return pid.communicate()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def exists(program):
|
||||||
|
''' Checks if program is installed on this system '''
|
||||||
|
p = Process(['which', program])
|
||||||
|
if p.stdout().strip() == '' and p.stderr().strip() == '':
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, command):
|
||||||
|
''' Starts executing command '''
|
||||||
|
if type(command) == str:
|
||||||
|
# Commands have to be a list
|
||||||
|
command = command.split(' ')
|
||||||
|
self.command = command
|
||||||
|
self.out = None
|
||||||
|
self.err = None
|
||||||
|
self.pid = Popen(command, stdout=PIPE, stderr=PIPE)
|
||||||
|
|
||||||
|
def stdout(self):
|
||||||
|
''' Waits for process to finish, returns stdout output '''
|
||||||
|
self.get_output()
|
||||||
|
return self.out
|
||||||
|
|
||||||
|
def stderr(self):
|
||||||
|
''' Waits for process to finish, returns stderr output '''
|
||||||
|
self.get_output()
|
||||||
|
return self.err
|
||||||
|
|
||||||
|
def get_output(self):
|
||||||
|
''' Waits for process to finish, returns stdout & stderr '''
|
||||||
|
if self.pid.poll() == None:
|
||||||
|
self.pid.wait()
|
||||||
|
if self.out == None:
|
||||||
|
(self.out, self.err) = self.pid.communicate()
|
||||||
|
|
||||||
|
def poll(self):
|
||||||
|
''' Returns exit code if process is dead, otherwise "None" '''
|
||||||
|
return self.pid.poll()
|
||||||
|
|
||||||
|
def kill(self):
|
||||||
|
''' Kill current process '''
|
||||||
|
if self.pid.poll() == None:
|
||||||
|
# Process is already killed
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self.pid.kill()
|
||||||
|
except OSError, e:
|
||||||
|
if 'No such process' in e.__str__():
|
||||||
|
return
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def interrupt(self):
|
||||||
|
''' Send interrupt to current process '''
|
||||||
|
from signal import SIGINT
|
||||||
|
from os import kill
|
||||||
|
try:
|
||||||
|
kill(self.pid.pid, SIGINT)
|
||||||
|
except OSError, e:
|
||||||
|
if 'No such process' in e.__str__():
|
||||||
|
return
|
||||||
|
raise e # process cannot be killed
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
p = Process('ls')
|
||||||
|
print p.stdout(), p.stderr()
|
||||||
|
p.interrupt()
|
||||||
|
|
||||||
|
# Calling as list of arguments
|
||||||
|
(out,err) = Process.call(['ls', '-lah'])
|
||||||
|
print out,err
|
||||||
|
|
||||||
|
print '\n---------------------\n'
|
||||||
|
|
||||||
|
# Calling as string
|
||||||
|
(out,err) = Process.call('ls -l | head -2')
|
||||||
|
print out,err
|
||||||
|
|
||||||
|
print '"reaver" exists:', Process.exists('reaver')
|
||||||
|
|
||||||
0
py/__init__.py
Normal file
0
py/__init__.py
Normal file
Reference in New Issue
Block a user