【读书笔记】Python黑帽子黑客与渗透测试编程之道(一)

这篇博客介绍了Python中实现HTTP GET请求的简单TCP客户端,以及如何创建一个TCP服务器来处理客户端连接。此外,还讨论了一个类似于Netcat的工具,用于TCP通信、文件上传和命令执行。文章展示了如何使用Python实现这些功能,并提供了相关代码示例。
摘要由CSDN通过智能技术生成

1.http get示例代码

 最简单的tcp客户端,通过tcp模拟发出http get请求。

import socket
target_host = "www.baidu.com"
target_port = 80
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((target_host,target_port))
aaa = "GET / HTTP/1.1\r\nHost:baidu.com\r\n\r\n"
client.send(str.encode(aaa))  #这里只需要注意 send在python3中 接收的是 bytes 只需要做一个转换就好
response = client.recv(4096)
print (bytes.decode(response))

这是HTTP协议的header。

GET http://www.baidu.com/ HTTP/1.1
Accept-Encoding: gzip,deflate
Host: www.baidu.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

简化为

GET / HTTP/1.1\r\nHost:baidu.com\r\n\r\n

注意其中的编码问题:

 str.encode--- 以指定的编码格式编码字符串,默认编码为 'utf-8'。

errors 参数可选,设置不同错误的处理方案。默认为 'strict',意为编码错误引起一个UnicodeEncodeError。 其它可能值有 'ignore', 'replace', 'xmlcharrefreplace'以及通过 codecs.register_error() 注册其它的值。

2.TCP Server

import socket
import threading
bing_ip = '0.0.0.0'
bing_port = 12138
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bing_ip,bing_port))
server.listen(5)    #最大连接数 
print ("[*] listen on %s:%d" % (bing_ip,bing_port))


def handle_client(client_socket):   #客户端处理进程
    request = client_socket.recv(1024)    
    print ("[*] Received: %s" % request)   #接受类型并打印
    client_socket.send(str.encode('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()

TCP Client

import socket
import sys

HOST, PORT = "127.0.0.1", 12138
#data = " ".join(sys.argv[1:])
data = " i'm bell"

# Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    # Connect to server and send data
    sock.connect((HOST, PORT))
    print("begin send data\n")
    sock.sendall(bytes(data + "\n", "utf-8"))
    print("begin recv data \n")
    # Receive data from the server and shut down
    received = str(sock.recv(1024), "utf-8")

print("Sent:     {}".format(data))
print("Received: {}".format(received))

3. 取代netcat的工具软件

nc功能强大,可以参考:Linux Netcat 命令——网络工具中的瑞士军刀 - OSCHINA - 中文开源技术交流社区
引入了一个新的第三方库 chardet 来判断 字符编码

import sys
import socket 
import getopt
import threading
import subprocess
from chardet import detect
listen = False
command = False
upload = False
execute = ""
target = ""
upload_destination = ""
port = ""
def run_command(command):
    command = command.rstrip()
    try:
        command = bytes.decode(command)
        print (command)
        output = subprocess.check_output(command, stderr = subprocess.STDOUT, shell = True )
    except Exception as b:
        print (b)
        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(str.encode("Successfully saved file to %s\r\n" % upload_destination))
        except:
            client_socket.send(str.encode("Failed to save file to %s\r\n" % upload_destination))
    if len(execute):
        output = run_command(execute)
        client_socket.send(str.encode(output))
    if command:
        while True:
            client_socket.send(str.encode("<BHP:#>"))
            cmd_buffer = ""
            cmd_buffer = str.encode(cmd_buffer)
            while "\n" not in bytes.decode(cmd_buffer):
                cmd_buffer += client_socket.recv(4096)
            response = run_command(cmd_buffer)
            bytestype = detect(response)
            if bytestype["encoding"] == "GB2312": #我在这里加了一个字符编码判断当编码为 gbk时 先解码 因为py3 默认是utf-8
                response = response.decode('gbk')
                response = str.encode(response)     
            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(str.encode(buffer))
        while True:
            recv_len = 1
            response = ""
            while recv_len:
                data = client.recv(4096)
                recv_len = len(data)
                data = bytes.decode(data)
                response += data
                if recv_len < 4096:
                    break
            print (response)
            buffer = input("")
            buffer += "\n"
            client.send(str.encode(buffer))
    except Exception as e:
        print (e)
        print ("[*] Exception! Exiting.")
        client.close()
def  usage():
    print ("BHP Net Tool")
    print ()
    print ("Usage:netcat.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 ("netcat.py -t 192.168.0.1 -p 5555 -l -c")
    print ("netcat.py -t 192.168.0.1 -p 5555 -l -u=c:\\target.exe"  )
    print ("netcat.py -t 192.168.0.1 -p 5555 -l -e=\"cat /etc/passwd")
    print ("echo 'ABCDEFGHI' | python ./netcat.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:
        opts, args = getopt.getopt(sys.argv[1:],"hle:t:p:cu",["help","listen","execute","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 Optin"
    if not listen and len(target) and port > 0:
            buffer = sys.stdin.read()
            client_sender(buffer)
    if listen:
            server_loop()
main()

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

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

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

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

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

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


客户端发起 HTTP 请求:

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

4. 改进后的netcat --- black hat 第2版(python3.x)

import argparse
import socket
import shlex
import subprocess
import sys
import textwrap
import threading


#生成一个新的进程执行命令,用到了 subprocess模块
def execute(cmd):
    cmd = cmd.strip()
    if not cmd:
        return
    output = subprocess.check_output(shlex.split(cmd),
                                     stderr=subprocess.STDOUT)
    return output.decode()


class NetCat:
    def __init__(self, args, buffer=None):
        self.args = args
        self.buffer = buffer
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    def run(self):
        if self.args.listen:
            self.listen()
        else:
            self.send()

    #循环的发送读取数据
    def send(self):
        self.socket.connect((self.args.target, self.args.port))
        if self.buffer:
            self.socket.send(self.buffer)

        try:
            while True:
                recv_len = 1
                response = ''
                while recv_len:
                    data = self.socket.recv(4096)
                    recv_len = len(data)
                    response += data.decode()
                    if recv_len < 4096:
                        break
                if response:
                    print(response)
                    buffer = input('> ')
                    buffer += '\n'
                    self.socket.send(buffer.encode())
        except KeyboardInterrupt:
            print('User terminated.')
            self.socket.close()
            sys.exit()

    
    #在监听模式下的主循环函数,每当有新的连接进来,创建新线程
    def listen(self):
        print('listening')
        self.socket.bind((self.args.target, self.args.port))
        self.socket.listen(5)
        while True:
            client_socket, _ = self.socket.accept()
            client_thread = threading.Thread(target=self.handle, args=(client_socket,))
            client_thread.start()

    #线程的功能代码
    def handle(self, client_socket):
        if self.args.execute:
            output = execute(self.args.execute)
            client_socket.send(output.encode())

        elif self.args.upload:
            file_buffer = b''
            while True:
                data = client_socket.recv(4096)
                if data:
                    file_buffer += data
                    print(len(file_buffer))
                else:
                    break

            with open(self.args.upload, 'wb') as f:
                f.write(file_buffer)
            message = f'Saved file {self.args.upload}'
            client_socket.send(message.encode())

        elif self.args.command:
            cmd_buffer = b''
            while True:
                try:
                    client_socket.send(b' #> ')
                    while '\n' not in cmd_buffer.decode():
                        cmd_buffer += client_socket.recv(64)
                    response = execute(cmd_buffer.decode())
                    if response:
                        client_socket.send(response.encode())
                    cmd_buffer = b''
                except Exception as e:
                    print(f'server killed {e}')
                    self.socket.close()
                    sys.exit()


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='BHP Net Tool',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=textwrap.dedent('''Example:
          netcat.py -t 192.168.1.108 -p 5555 -l -c # command shell
          netcat.py -t 192.168.1.108 -p 5555 -l -u=mytest.whatisup # upload to file
          netcat.py -t 192.168.1.108 -p 5555 -l -e=\"cat /etc/passwd\" # execute command
          echo 'ABCDEFGHI' | ./netcat.py -t 192.168.1.108 -p 135 # echo local text to server port 135
          netcat.py -t 192.168.1.108 -p 5555 # connect to server
          '''))
    parser.add_argument('-c', '--command', action='store_true', help='initialize command shell')
    parser.add_argument('-e', '--execute', help='execute specified command')
    parser.add_argument('-l', '--listen', action='store_true', help='listen')
    parser.add_argument('-p', '--port', type=int, default=5555, help='specified port')
    parser.add_argument('-t', '--target', default='192.168.1.203', help='specified IP')
    parser.add_argument('-u', '--upload', help='upload file')
    args = parser.parse_args()
    if args.listen:
        buffer = ''
    else:
        buffer = sys.stdin.read()

    nc = NetCat(args, buffer.encode('utf-8'))
    nc.run()

其中, shlex模块为基于Uninx shell语法的语言提供了一个简单的lexer(也就是tokenizer)

看一个示例:

quotes.txt的内容如下

This string has embedded "double quotes" and 'single quotes' in it,
and even "a 'nested example'".
#!/usr/bin/env python

import shlex
import sys

if len(sys.argv) != 2:
    print 'please input'
    sys.exit(1)

filename = sys.argv[1]
body = file(filename,'rt').read()

#函数str() 用于将值转化为适于人阅读的形式,而repr() 转化为供解释器读取的形式。

print 'ORIGINAL:',repr(body)
print

print 'TOKENS:'
lexer = shlex.shlex(body)
for token in lexer:
    print repr(token)

./test.py quotes.txt

ORIGINAL: 'This string has embedded "double quotes" and \'single quotes\' in it,\nand even "a \'nested example\'".\n'

TOKENS:
'This'
'string'
'has'
'embedded'
'"double quotes"'
'and'
"'single quotes'"
'in'
'it'
','
'and'
'even'
'"a \'nested example\'"'
'.'

shlex.split方法

decode() 方法用于将 bytes 类型的二进制数据转换为 str 类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值