I'm working on the OSCP, and Information Security certificate based around penetration testing. CLI-based tools seem to be the core of most pen-testing assignments, so I'd like to build a tool aiding in command/switch searching.
The goal of the program will to (eventually) load command line arguments by searching in real-time based on arguments, application names, common use-case, and application details. Something like a dynamic Google of the CLI for pen-testing tools.
I'm relatively new to Python. I've never really had anyone look over my code before. I'm hoping that there are not too big of gaps in the logic and syntax. I'm sure there are areas where my code could be simplified. Any suggestions are appreciated.
import threading
import xml.etree.ElementTree as et
import os
# Command to clear the CLI in NT-based systems
cls = lambda: os.system('cls')
# Application dictionary data structure for internal data use
app_dict = {}
# Reference data sets for associative commands and arguments
commands = []
command_key = {}
arguments = []
command_pointers = []
argument_pointers = []
# Function to return query results in a consistent format
def return_command(command_pointer):
raw_input('''
Application Name: {}
Arguments: {}
'''.format(command_pointer.name, command_pointer.arguments))
# Base class for a command, identified as the first argument to the CLI
class Command:
def __init__(self, name):
self.name = name
self.arguments = []
commands.append(name)
command_key[name] = self
command_pointers.append(self)
def set_argument(self, number, optional, prefix):
self.arguments.append(number)
self.argument = Argument(self.name, number)
self.argument.create_argument(optional, prefix)
def set_argument_details(self, details, common):
self.argument.set_argument_details(details, common)
# Subsequent CLI arguments following the base command
class Argument:
def __init__(self, parent_command, number):
self.parent_command = parent_command
self.number = number
arguments.append([parent_command, number])
argument_pointers.append(self)
def create_argument(self, optional, prefix):
self.optional = optional
self.prefix = prefix
def set_argument_details(self, details, common):
self.details = details
self.common = common
# Starts the XML parsing thread
class ReadThread (threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
xmldoc = et.parse('terms.xml')
data = xmldoc.getroot()
for app in data:
for details in app.iter():
try:
current_command = Command(details.attrib['name'])
except:
current_command.set_argument(details.attrib['number'],
details.attrib['optional'],
details.attrib['prefix'])
try:
current_command.set_argument_details(details.attrib['details'],
details.attrib['common'])
except:
pass # No argument details specified
# Searches XMl loaded commands
# Eventually switching to real-time search ability
class SearchThread (threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while True:
cls()
search_key = raw_input('>>> ')
if search_key in commands:
return_command(command_key[search_key])
# Program Start
ReadThread()
query = SearchThread()
query.run()
Here is an example of the base XML that is loaded on program start. I am using this data source until I can implement a functioning DB.
<?xml version="1.0" encoding="UTF-8"?>
<data>
<app name="Test Application 1">
<arg number="1" optional="no" prefix=""></arg>
<arg number="2" optional="yes" prefix="-" details="This is the second argument to the command, and is optional." common="Common use syntax"></arg>
</app>
<app name="Test Application 2">
<arg number="1" optional="no" prefix=""></arg>
<arg number="2" optional="yes" prefix="-" details="This is the second argument to the command, and is optional." common="Common use syntax"></arg>
</data>
It's working, so far. Here is an example of output searching the whole string of "Test Application 2". Eventually, a dynamic search would be added that would parse the input string dynamically and return results in real time against more than just the application name.
>>> Test Application 2
Application Name: Test Application 2
Arguments: ['1', '2']