The multi-mode tool is no more complicated than the modeless invocation. In the nmap.py
file, the modeless invocation only wraps one command, and the multi-mode wraps multiple commands.
Again take the nmap_python tool as an example:
-
Next, start to define the raw invocation mode of the tool. Users who use the raw invocation mode need to fill in the parameter list (arguments) by themselves. Through the raw mode, users can freely invoke the tool in the advanced mode of Leviathan^3. In this mode, the tool will receive a list of parameters. The tool author needs to define how the tool will pass the parameters and commands to the tool image and how to output the resulting data:
# Using the annot modifier to introduce and give examples of the mode and params (parameters). The parameters passed in in the raw mode are the list of native commands, that is, annot.ARGV. @annot.meta(desc="nmap native call", params=[annot.ARGV]) # ARGV = annot.Param("argv", "command line arguments") def raw(argv:list[str]) -> Cr: # Note that when defining the mode, you need to specify the parameter type of each parameter, such as a here is a list (array) """ nmap raw invocation \``` # Because of the characteristics of the md document, the backslash is added here, which is not required in the actual code. await nmap.raw(["-PE", "-sn", "192.168.1.1/24"]) \``` """ @remote def entry(argv): import subprocess output = subprocess.check_output(['nmap', *argv], text=True) # Because the output result is saved in json format, you can use python's json library to open the .json file in the tool container and read the data. data = {"result": output} # Pass the result data into the database, because mongodb is used for storage, the data passed into the mongodb database must be of dictionary type ctx.update(data) # Format is return Cr(".username.tool:tag", "username/tool.mode@version", entry=entry(argv)) return Cr("registry.cn-hangzhou.aliyuncs.com/levkit/nmap_python:v1.0", "szczecin/[email protected]", entry=entry(argv), host=True)
-
Next define the port_os mode of the nmap_python tool:
@annot.meta(desc="nmap SYN scan the open port , host name and operating system of target host ", params=[annot.Param("ip", "target ip or ip segment to scan", holder="192.168. 1.1/24")]) def port_os(ip: str) -> Cr: # Note that when defining the mode, you need to specify the parameter type of each parameter, such as ip here is str (string) """ nmap SYN scans the target host's open ports, host names and operating systems (mode description, cannot be omitted) ``` await nmap.port_os("192.168.1.1/24")(calling example, cannot be omitted) ``` """ @remote def entry(ip): import subprocess # Execute the command, because the system.run() function has the risk of injection, so use the subprocess.run() method here subprocess.run(['nmap', '-sS', '-Pn', '-p-', '-T4', '--open', '-O', '-oX', '/tmp/port_os.xml', ip]) # The following is the data processing code, which can be ignored soup = BeautifulSoup(open('/tmp/port_os.xml', 'r').read(), 'html.parser') port_open = [] if soup.host: if soup.host.status['state'] == 'up': try: hostname = soup.host.hostnames.hostname['name'] except: hostname = '-' if soup.host.ports.port: for port in soup.host.ports.find_all('port'): if port.state['state'] == 'open': try: port_open.append({ 'port': port['portid'], 'protocol': port['protocol'], 'service': port.service['name'], }) except: port_open.append({ 'port': port['portid'], 'protocol': port['protocol'], 'service': '-', }) try: os = soup.host.os.osmatch['name'] except: os = '-' ip_info = { 'ip': ip, 'hostname': hostname, 'os': os, 'port_info': port_open, 'status': True } else: ip_info = { 'ip': ip, 'status': False } ctx.update(ip_info) # Pass the result data into the database, because the data passed into the mongodb database must be of dictionary type using mongodb storage return Cr("registry.cn-hangzhou.aliyuncs.com/levkit/nmap_python:v1.0", "szczecin/[email protected]", entry=entry(ip), host=True)
-
Finally, write the tool mode (function), the name (desc) and type of the tool that need to be exported at the end of the tool code. The tool type (cats) can directly invoke the
Attck
andBlackArch
categories, and the first letter of the word is capitalized:# # The export mode, that is, the three functions that invoke nmap above, will appear in the position of the tool details, as shown in the following figure: __lev__ = annot.meta([raw, alive, port_os], # tool name desc="nmap-update", cats={ # tool category Attck: [Attck.Reconnaissance], BlackArch: [BlackArch.Scanner] })
-
Example of complete tool invocation (nmap.py):
""" nmap is a free and open source program for network discovery and security auditing, used for tasks such as network scanning, service upgrade plan management, and host or service uptime monitoring, By using raw IP packets to determine the hosts available on the network, the services provided by those hosts (application name and version), the operating system information they are running on, the type of packet filter/firewall, etc. The nmap_python image contains the real-time updated binary version of nmap, and is equipped with a python environment to update the nmap-os-db file in real time. """ from levrt import Cr, ctx, remote, annot from levrt.annot.cats import Attck, BlackArch @annot.meta(desc="nmap raw invocation", params=[annot.ARGV]) # # ARGV = annot.Param("argv", "command line arguments")2 def raw(argv:list[str]) -> Cr: # Mode descriptions and examples are omitted here in demo, but cannot be omitted in actual code. @remote def entry(argv): pass # The specific code is omitted here. return Cr("registry.cn-hangzhou.aliyuncs.com/levkit/nmap_python:v1.0", "szczecin/[email protected]", entry=entry(argv), host=True) @annot.meta(desc="nmap ICMP loopback message to determine host surviva", params=[annot.Param("ip", "target ip or ip segment to scan", holder="192.168.1.1/24")]) def alive(ip: str) -> Cr: # Mode descriptions and examples are omitted here in demo, but cannot be omitted in actual code @remote def entry(ip): pass # The specific code is omitted here return Cr("registry.cn-hangzhou.aliyuncs.com/levkit/nmap_python:v1.0", "szczecin/[email protected]", entry=entry(ip), host=True) @annot.meta(desc="nmap SYN scan target host open port, host name and operating system", params=[annot.Param("ip", "target ip or ip segment to scan", holder="192.168.1.1/24")]) def port_os(ip: str) -> Cr: # Mode descriptions and examples are omitted here in demo, but cannot be omitted in actual code @remote def entry(ip): pass # The specific code is omitted here return Cr("registry.cn-hangzhou.aliyuncs.com/levkit/nmap_python:v1.0", "szczecin/[email protected]", entry=entry(ip), host=True) # Export mode, that is, the three functions that call nmap everywhere above, will appear in the position of the tool details __lev__ = annot.meta([raw, alive, port_os], desc="nmap-update", cats={ Attck: [Attck.Reconnaissance], BlackArch: [BlackArch.Scanner] })