关于《Python黑帽子:黑客与渗透测试编程之道》的学习笔记

本篇文章是学习《Python黑帽子:黑客与渗透测试编程之道》的笔记,会持续地将书上的代码自己敲一遍,从而让自己对Python的安全编程有更多的了解,同时希望各位可以给给建议,不足之处太多了。

第一章——设置Python环境:

Kali Linux的安装就不说了,最近有更新为2017版的可以下载。

确认是否安装了正确的Python版本:


确认是2.7版本的即可。

接着安装Python软件包管理工具easy_install和pip,由于之前安装过了所以显示如下:


接着安装github模块,并进行测试,没啥问题:


接着是安装WingIDE,由于个人使用习惯了使用Sublime Text就不再进行安装了。

关于Sublime Text的安装在之前那篇《Python基础编程与爬虫实现》中说过了,这里就不再多说了。


第二章——网络基础:

TCP客户端:

示例中socket对象有两个参数,AF_INET参数表明使用IPv4地址或主机名,SOCK_STREAM参数表示是一个TCP客户端。访问的URL是百度。

#coding=utf-8
import socket

target_host = "www.baidu.com"
target_port = 80

#建立一个socket对象
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#连接客户端
client.connect((target_host,target_port))

#发送一些数据
client.send("GET / HTTP/1.1\r\nHost: baidu.com\r\n\r\n")

#接收一些数据
response = client.recv(4096)

print response

运行结果:



UDP客户端:

与TCP客户端相比,将套接字的类型改为SOCK_DGRAM,然后调用sendto()函数发送数据,因为UDP是无连接的因此不需要调用connect()函数,最后使用recvfrom()函数接收返回的UDP数据包。

#coding=utf-8
import socket

target_host = "127.0.0.1"
target_port = 1234

#建立一个socket对象
client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

#发送一些数据
client.sendto("This is an UDP client",(target_host,target_port))

#接收一些数据
data, addr = client.recvfrom(4096)

print data
print addr

运行结果:



TCP服务端:

这里需要先调用bind()函数绑定IP和端口,然后通过调用listen()函数启动监听并将最大连接数设为5。

#!/usr/bin/python
#coding=utf-8
import socket
import threading

bind_ip = "0.0.0.0"
bind_port = 1234

server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

server.bind((bind_ip,bind_port))

server.listen(5)

print '[*] Listening on %s:%d'%(bind_ip,bind_port)

#客户处理线程
def handle_client(client_socket):
	
	#打印客户端发送得到的消息
	request = client_socket.recv(1024)

	print "[*] Received: %s"%request
	
	#返回一个数据包
	client_socket.send("ACK!")

	client_socket.close()

while True:
	
	client, addr = server.accept()

	print "[*] Accepted connection from: %s:%d"%(addr[0],addr[1])
	
	#挂起客户端线程,处理传入数据
	client_handler = threading.Thread(target=handle_client,args=(client,))
	client_handler.start()

运行结果:



取代netcat:

rstrip() 删除 string 字符串末尾的指定字符(默认为空格)。

subprocess.check_output():父进程等待子进程完成,返回子进程向标准输出的输出结果。

getopt模块是专门处理命令行参数的。

#!/usr/bin/python
#coding=utf-8
import sys
import socket
import getopt
import threading
import subprocess

#定义一些全局变量
listen = False
command = False
upload = False
execute = ""
target = ""
upload_destination = ""
port = 0

#使用帮助
def usage():
	print "BHP Net Tool"  
	print  
	print "Usage: bhpnet.py -t target_host - p port"  
	print "-l --listen              - listen on [host]:[port] for incoming connections"  
	print "-e --execute=file_to_run -execute the given file upon receiving a connection"  
	print "-c --command             - initialize a commandshell"  
	print "-u --upload=destination  - upon receiving connection upload a file and write to [destination]"  
	print  
	print  
	print "Examples:"  
	print "bhpnet.py -t 192.168.0.1 -p 5555 -l -c"  
	print "bhpnet.py -t 192.168.0.1 -p 5555 -l -u=c:\\target.exe"  
	print "bhpnet.py -t 192.168.0.1 -p 5555 -l -e=\"cat /etc/passwd\""  
	print "echo 'ABCDEFGHI' | python ./bhpnet.py -t 192.168.11.12 -p 135"  
	sys.exit(0) 

def client_sender(buffer):
	client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

	try:
		#连接到目标主机
		client.connect((target,port))

		if len(buffer):
			client.send(buffer)

		while True:
			
			#现在等待数据回传
			recv_len = 1
			response = ""

			while recv_len:
				
				data = client.recv(4096)
				recv_len = len(data)
				response += data

				if recv_len < 4096:
					break

			print response,

			#等待更多的输入
			buffer = raw_input("")
			buffer += "\n"

			#发送出去
			client.send(buffer)

	except:
		print "[*] Exception! Exiting. "

		#关闭连接
		client.close()

def server_loop():
	global target

	#如果没有定义目标,那么我们监听所有的接口
	if not len(target):
		target = "0.0.0.0"

	server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
	server.bind((target,port))

	server.listen(5)

	while  True:
		client_socket, addr = server.accept()

		#分拆一个线程处理新的客户端
		client_thread = threading.Thread(target=client_handler,args=(client_socket,))
		client_thread.start()

def run_command(command):
	
	#换行
	command = command.rstrip()

	#运行命令并将输出返回
	try:
		output = subprocess.check_output(command,stderr=subprocess.STDOUT,shell=True)
	except:
		output = "Failed to execute command. \r\n"

	#将输出发送
	return output

def client_handler(client_socket):
	global upload
	global execute
	global command

	#检测上传文件
	if len(upload_destination):
		
		#读取所有的字符并写下目标
		file_buffer = ""

		#持续读取数据直到没有符合的数据

		while True:
			data = client_socket.recv(1024)

			if not data:
				break
			else:
				file_buffer += data

		#现在我们接收这些数据并将他们写出来
		try:
			file_descriptor = open(upload_destination,"wb")
			file_descriptor.write(file_buffer)
			file_descriptor.close()

			#确认文件已经写出来
			client_socket.send("Successfully saved file to %s\r\n"%upload_destination)
		except:
			client_socket.send("Failed to save file to %s\r\n"%upload_destination)
	#检查命令执行
	if len(execute):
		
		#运行命令
		output = run_command(execute)

		client_socket.send(output)

	#如果需要一个命令行shell,那么我们进入另一个循环
	if command:

		while True:
			
			#跳出一个窗口
			client_socket.send("<BHP:#> ")

			#现在我们接收文件直到发现换行符(enter key)
			cmd_buffer = ""
			while "\n" not in cmd_buffer:
				cmd_buffer += client_socket.recv(1024)

			#返还命令输出
			response = run_command(cmd_buffer)

			#返回响应数据
			client_socket.send(response)

def main():
	global listen
	global port
	global execute
	global command
	global upload_destination
	global target

	if not len(sys.argv[1:]):
		usage()

	#读取命令行选项
	try:
		opts, args = getopt.getopt(sys.argv[1:],"hle:t:p:cu:",["help", "listen", "execute", "target", "port", "command", "upload"])
	except getopt.GetoptError as err:
		print str(err)
		usage()

	for o,a in opts:
		if o in ("-h","--help"):
			usage()
		elif o in ("-l","--listen"):
			listen = True
		elif o in ("-e","--execute"):
			execute = a
		elif o in ("-c","--commandshell"):
			command = True
		elif o in ("-u","--upload"):
			upload_destination = a
		elif o in ("-t","--target"):
			target = a
		elif o in ("-p","--port"):
			port = int(a)
		else:
			assert False,"Unhandled Option"

	#我们是进行监听还是仅从标准输入发送数据?
	if not listen and len(target) and port > 0 :

		#从命令行读取内存数据
		#这里将阻塞,所以不再向标准输入发送数据时发送CTRL-D
		buffer = sys.stdin.read()

		#发送数据
		client_sender(buffer)

	#我们开始监听并准备上传文件、执行命令
	#放置一个反弹shell
	#取决于上面的命令行选项
	if listen:
		server_loop()

main()

这里对程序说明一下:

usage()函数用于参数的说明帮助、当用户输入错误的参数时会输出相应的提示;

client_sender()函数用于与目标主机建立连接并交互数据直到没有更多的数据发送回来,然后等待用户下一步的输入并继续发送和接收数据,直到用户结束脚本运行;

server_loop()函数用于建立监听端口并实现多线程处理新的客户端;

run_command()函数用于执行命令,其中subprocess库提供多种与客户端程序交互的方法;

client_handler()函数用于实现文件上传、命令执行和与shell相关的功能,其中wb标识确保是以二进制的格式写入文件、从而确保上传和写入的二进制文件能够成功执行;

主函数main()中是先读取所有的命令行选项从而设置相应的变量,然后从标准输入中读取数据并通过网络发送数据,若需要交互式地发送数据需要发送CTRL-D以避免从标准输入中读取数据,若检测到listen参数为True则调用server_loop()函数准备处理下一步命令。

运行结果:

1、本地测试:


2、访问百度:


3、客户端Ubuntu访问,可以看到客户端访问时输入命令之后需要多输入一个换行符才可以输入成功从而看到输出结果:



创建一个TCP代理:

    #!/usr/bin/python  
    #coding=utf-8
    import socket  
    import sys  
    import threading  
      
    def server_loop(local_host,local_port,remote_host,remote_port,receive_first):  
          
        server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
      
        try:  
            server.bind((local_host,local_port))  
        except:  
            print "[!!] Failed to listen on %s:%d"%(local_host,local_port)  
            print "[!!] Check for other listening sockets or correct permissions. "  
            sys.exit(0)  
      
        print "[*] Listening on %s:%d"%(local_host,local_port)  
      
        server.listen(5)  
      
        while True:  
            client_socket, addr = server.accept()  
      
            #  打印出本地连接信息
            print "[==>] Received incoming connection from %s:%d"%(addr[0],addr[1])  
      
            #  开启一个线程与远程主机通信
            proxy_thread = threading.Thread(target=proxy_handler,args=(client_socket,remote_host,remote_port,receive_first))  
      
            proxy_thread.start()  
      
    def proxy_handler(client_socket,remote_host,remote_port,receive_first):  
          
        #  连接远程主机
        remote_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
        remote_socket.connect((remote_host,remote_port))  
      
        #  如果必要从远程主机接收数据
        if receive_first:  
      
            remote_buffer = receive_from(remote_socket)  
            hexdump(remote_buffer)  
      
            #  发送给我们的响应数据
            remote_buffer = response_handler(remote_buffer)  
      
            #  如果我们有数据传递给本地客户端,发送它
            if len(remote_buffer):  
                print "[<==] Sending %d bytes to localhost. "%len(remote_buffer)  
                client_socket.send(remote_buffer)  
      
        #  现在我们从本地循环读取数据,发送给远程主机和本地主机
        while True:  
              
            #  从本地读取主机
            local_buffer = receive_from(client_socket)  
      
            if len(local_buffer):  
                  
                print "[==>] Received %d bytes from localhost. "%len(local_buffer)  
                hexdump(local_buffer)  
      
                #  发送给我们的本地请求
                local_buffer = request_handler(local_buffer)  
      
                #  向远程主机发送数据
                remote_socket.send(local_buffer)  
                print "[==>] Sent to remote ."  
      
            #  接受响应的数据
            remote_buffer = receive_from(remote_socket)  
      
            if len(remote_buffer):  
                  
                print "[<==] Received %d bytes from remote . "%len(remote_buffer)  
                hexdump(remote_buffer)  
      
                #  发送到响应处理函数
                remote_buffer = response_handler(remote_buffer)  
      
                #  将响应发送给本地socket
                client_socket.send(remote_buffer)  
      
                print "[<==] Sent to localhost. "  
      
            #  如果两边都没有数据,关闭连接
            if not len(local_buffer) or not len(remote_buffer):  
                client_socket.close()  
                remote_socket.close()  
                print "[*] No more data. Closing cnnections. "  
      
                break  
      
    #  十六进制导出函数
    def hexdump(src,length=16):  
        result = []  
        digits = 4 if isinstance(src,unicode) else 2  
      
        for i in xrange(0,len(src),length):  
            s = src[i:i+length]  
            hexa = b' '.join(["%0*X" % (digits,ord(x)) for x in s])  
            text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])  
            result.append( b"%04X  %-*s  %s" % (i,length*(digits + 1),hexa,text))  
      
        print b'\n'.join(result)  
      
    def receive_from(connection):  
          
        buffer = ""  
      
        #  我们设置了两秒的超时,这取决于目标的情况,可能需要调整
        connection.settimeout(2)  
      
        try:  
            #  持续从缓存中读取数据直到没有数据或超时
            while True:  
                data = connection.recv(4096)  
                if not data:  
                    break  
                buffer += data  
        except:  
            pass  
      
        return buffer  
      
    #  对目标是远程主机的请求进行修改
    def request_handler(buffer):  
        #  执行包修改
        return buffer  
      
    #  对目标是本地主机的响应进行修改
    def response_handler(buffer):  
        #  执行包修改
        return buffer  
      
    def main():  
          
        #  没有华丽的命令行解析
        if len(sys.argv[1:]) != 5:  
            print "Usage : ./tcp_agent.py [localhost] [localport] [remotehost] [remoteport] [receive_first] "  
            print "Example : ./tcp_agent.py 127.0.0.1 9000 10.12.132.1 9000 True"  
            sys.exit(0)  
      
        #  设置本地监听参数
        local_host = sys.argv[1]  
        local_port = int(sys.argv[2])  
      
        #  设置远程目标
        remote_host = sys.argv[3]  
        remote_port = int(sys.argv[4])  
      
        #  告诉代理在发送给远程主机之前连接和接收数据
        receive_first = sys.argv[5]  
      
        if "True" in receive_first:  
            receive_first = True  
        else:  
            receive_first = False  
      
        #  现在设置好我们的监听socket
        server_loop(local_host,local_port,remote_host,remote_port,receive_first)  
      
    main()  

这里对每个函数说明一下:

proxy_handler()函数包含了代理的主要逻辑,先检查并确保在启动主循环之前不向建立连接的远程主机主动发送数据,启动循环之后接收本地和远程主机的数据然后再调用相应的函数进行处理之后再转发出去;
hexdump()函数仅输出数据包的十六进制值和可打印的ASCII码字符,对于了解未知的协议很有帮助,还能找到使用明文协议的认证信息等;
receive_from()函数用于接收本地和远程主机的数据,使用socket对象作为参数;
request_handler()和response_handler()函数允许用来修改代理双向的数据流量;
server_loop()函数用于循环以监听并连接请求,当有新的请求到达时会提交给proxy_handler()函数处理,接收每一个比特的数据,然后发送到目标远程主机;
main主函数先读入命令行参数,然后调用服务端的server_loop()函数。
运行结果:


结果可以看到,其实和Wireshark等抓包工具的效果是差不多的。


通过Paramiko使用SSH:

首先需要安装paramiko模块:



这里先进行简单的测试,连接Metasploit2 的主机。

#!/usr/bin/python
import paramiko
import threading
import subprocess

def ssh_command(ip,user,passwd,command):
        client = paramiko.SSHClient()
        #client.load_host_keys('/home/justin/.ssh/known_hosts') 
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(ip,username=user,password=passwd)
        ssh_session = client.get_transport().open_session()
        if ssh_session.active:
                ssh_session.exec_command(command)  
                print ssh_session.recv(1024)
        return

ssh_command('10.10.10.128','msfadmin','msfadmin','uname -a') 

运行结果:

反向SSH:

bh_sshRcmd.py:

后面测试成功再补上

bh_sshserver.py:

后面测试成功再补上


SSH隧道:

后面测试成功再补上


第三章——网络:原始套接字和流量嗅探

Windows和Linux上的包嗅探:

#!/usr/bin/python
import socket
import os

#监听的主机
host = "10.10.10.160"

#创建原始套接字,然后绑定在公开接口上
if os.name == "nt":
	socket_protocol = socket.IPPROTO_IP
else:
	socket_protocol = socket.IPPROTO_ICMP

sniffer = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket_protocol)

sniffer.bind((host,0))

#设置在捕获的数据包中包含IP头
sniffer.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL,1)

#在Windows平台上,我们需要设置IOCTL以启动混杂模式
if os.name == "nt":
	sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)

#读取单个数据包
print sniffer.recvfrom(65565)

#在Windows平台上关闭混杂模式
if os.name == "nt":
	sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_OFF)

运行结果:



解码IP层:

源代码:

#!/usr/bin/python
#coding=utf-8
import socket
import os
import struct
from ctypes import *

#监听的主机
host = "10.10.10.160"

#IP头定义
class IP(Structure):
	"""docstring for IP"""
	_fields_ = [
		("ihl",			c_ubyte, 4),
		("version",		c_ubyte, 4),
		("tos",			c_ubyte),
		("len",			c_ushort),
		("id",			c_ushort),
		("offset",		c_ushort),
		("ttl",			c_ubyte),
		("protocol_num",	c_ubyte),
		("sum",			c_ushort),
		("src",			c_ulong),
		("dst",			c_ulong)
	]

	def __new__(self,socket_buffer=None):
		return self.from_buffer_copy(socket_buffer)

	def __init__(self, socket_buffer=None):
		#协议字段与协议名称对应
		self.protocol_map = {1:"ICMP",6:"TCP",17:"UDP"}

		#可读性更强的IP地址
		self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
		self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst))

		#协议类型
		try:
			self
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值