python编写简单netcat

之前ke推送的netcat的用法相信大家已经熟悉了,今天我来分享一下如何使用python去编写一个简单的netcat。当然了,实际使用的话,因为要依赖python环境,所以不免有点鸡肋,因此这篇文章更侧重于分享简单的python安全工具的写法。

以下为要用到的python库。

  • socket
  • subprocess
  • argparse

    同样的,本篇文章不对这些库做过多介绍,有兴趣的自行阅读官方文档。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import socket
    import argparse
    import subprocess
    import traceback
    class netcat:
    def __init__(self):
    self.parser = argparse.ArgumentParser()
    self._init_args_parser()
    self.args = self.parser.parse_args()
    self.client_socket = None
    self.server_socket = None
    if self.args.l:
    self.listen_mode()
    elif self.args.c:
    self.client_mode()

构造一个netcat类,一些常用变量直接设置为类变量方便访问。netcat的主程序即为init(),包括初始化以及后续执行阶段。client_socket为服务器被连接是的socket,server_socket则为客户端连接时获得的socket。argparse.ArgumentParser()返回一个操作命令行参数的对象,调用parse_args()获得参数。

1
2
3
4
5
6
7
8
def _init_args_parser(self):
self.parser.add_argument('-l', help='listen mode', required=False, action='store_true')
self.parser.add_argument('-e', help='execute command', required=False, action='store_true')
self.parser.add_argument('-a', help='address', required=False, default='127.0.0.1')
self.parser.add_argument('-p', type=int, help='port', required=False)
self.parser.add_argument('-u', help='upload file', required=False)
self.parser.add_argument('-c', help='client mode', required=False, action='store_true')
self.parser.add_argument('-f', help='select file upload', required=False)

这是具体的参数设置,-l表示参数前缀,help指定帮助display字段,required表示字段是否必须, action='store_true'表示只要有前缀就返回True。其他字段以此类推。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def listen_mode(self):
address = self.args.a
port = self.args.p
if not port or not address:
print('not port or address')
else:
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((address, port))
server_socket.listen(1)
while True:
client_socket, addr = server_socket.accept()
self.client_socket = client_socket
self.server_handler()

监听模式,首先从命令行参数当中获取地址和端口,然后通过socket进行绑定。绑定后调用accept建立连接。然后将client_socket赋予到类变量当中。后续动作则交由server_handler()处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def server_handler(self):
if self.client_socket:
if self.args.e:
while True:
cmd_buffer = self.get_client_input_buffer()
response = self.run_command(cmd_buffer)
self.client_socket.send(response)
elif self.args.u:
while True:
try:
file_buffer = self.get_client_input_buffer()
file_buffer = file_buffer.decode('utf-8')
dest = self.args.u
with open(dest, 'a') as f:
f.write(file_buffer)
f.close()
except Exception as err:
err_message = traceback.format_exc()
err_message.encode('utf-8')
self.client_socket.send(err_message)

如果存在e参数,则为执行命令模式。从客户端接收命令,然后调用run_command()处理。如果存在u参数,则为文件上传模式,从客户端接收文件,定义文件路径(包括文件名),然后写入。

1
2
3
4
5
6
7
def run_command(self, command):
try:
output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True)
return output
except Exception as err:
error_message = traceback.format_exc()
return error_message.encode('utf-8')

这里执行命令,调用了subprocess模块的check_output方法,第一个参数为执行的命令。

1
2
3
4
5
6
7
8
9
10
11
def client_mode(self):
address = self.args.a
port = self.args.p
try:
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.connect((address, port))
except Exception as err:
print(err)
return 0
self.server_socket = server_socket
self.client_handler()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def client_handler(self):
if self.args.f:
file_name = self.args.f
file_buffer = ''
with open(file_name, 'r') as f:
for line in f:
file_buffer += line
file_buffer.encode('utf-8')
f.close()
self.server_socket.send(file_buffer.encode('utf-8'))
elif self.args.e:
while True:
cmd = input()
self.server_socket.send(cmd.encode('utf-8'))
data = self.server_socket.recv(1024)
print(data.decode('utf-8'))

客户端的实现也是类似,理解应该不是问题。

1
test = netcat()

当然,当然,最后,还得调用一下。
至此,一个相当的简陋的netcat算是完工了,我们跑起来测试一下。
测试截图

提醒一下,py3当中socket不管收发都是用的bytes而非str,所以编写的时候要注意了。
代码还有很多问题,并且功能非常简陋,这个只是作为demo展示。如果你有更好的想法,欢迎在我的github上留言。(别太care头像..)
最后,这段代码的思路参考了《python黑帽子:黑客与渗透测试编程之道》,目前中文版好像没有电子版,大家有兴趣可以买来阅读,当然,英语好的直接阅读原版就好。