读书笔记系列文章
一直都在读书,读了忘,忘了再读。不如把每次学到的东西都写下来
简介
内容不错,大部分领域都是浅尝而止,有种师傅领进门,修行看个人的感觉。就是书的排版有点问题,书一共不到200页,粘贴了大量代码,代码行间距太大。
书中用到的所有代码都可以从 http://nostarch.com/blackhatpython/ 下载
第一章 设置 python 环境
其实这一章没什么收获,一直在用 kali 操作系统,喜欢的 IDE 是 pycharm 而不是 WingIDE。所以没什么可以做的
第二章 网络基础
前几节(Python 网络编程简介,TCP 客户端,UDP 客户端,TCP 服务器)都比较简单,是最基础的 socket 编程,都是模板式的编程,比较基础。除非从来没写过网络程序,否则应该是一眼就知道在做什么
取代 netcat
这一节开始变的有意思起来了。 netcat(nc) 网络界的瑞士军刀,可以做端口扫描,可以作为聊天工具,可以上传下载文件,可以执行 shell 做后门程序,总之用处多多。
本节内容,作者试图使用简单的 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()