最近在吾爱上看到一篇文章,大佬把shellcode调用的函数都写出来了
通过这些函数写一个免杀,这样就不会出现shellcode的特征码了
文章地址:https://www.52pojie.cn/thread-1334525-1-1.html
先说一下CS上线的过程,正常生成的shellcode只有下载功能,会从攻击机下载一个200多KB的shellcoode,那个shellcode是主要功能
之前看到过一些文章说是把shellcode放到网上再下载下来,其实是没必要的直接下载主要功能的shellcode就行了
本来也是不知道的抓了流量才知道
在攻击->生成后门里面有一个Windows Executable(S)选项,本来以为这个S是代表super的意思,生成的可以直接弹出uac
后来看翻译说是什么无状态,当时也不明白,其实就是不经过向攻击机下载shellcode那个步骤,直接生成主要shellcode代码
扯远了,看看用了什么函数
1 | InternetOpenA |
开辟一块0x40000字节的内存,读到的shellcode以每次0x2000字节放入开辟的内存中,之后执行shellcode
1 | HINTERNET InternetOpenA( |
感觉像以前一样每个参数解释过去还是有点吃力的,毕竟用法太多了,所以这次只写用的到实参
lpszAgent 就是User-Agent随便设置啥都行,有些机翻真的看不懂
dwAccessType 访问类型,写这个用INTERNET_OPEN_TYPE_DIRECT参数就行,另外几个参数都是和代理有关的,这个参数就是本地解析所有主机名
lpszProxy 和代理有关,上一个参数设置INTERNET_OPEN_TYPE_PROXY才需要,不然直接NULL就行
lpszProxyBypass 和上面一样没设置代理直接NULL就行
dwFlags 就三个宏定义,一个是发出网络请求的,另外两个是不发出网络请求从缓存中取数据的,什么异步什么的不用管就这么想就行
这个函数返回值是一个句柄
官方文档:https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopena
1 | HINTERNET InternetConnectA( |
hInternet 上一个函数返回的句柄
lpszServerName 要连接的服务器IP(域名可以不可以不清楚没试过)
nServerPort 要连接的服务器的端口(宏定义就定义了几个,不在宏定义里面的端口输个数字就行)
lpszUserName 用户名,因为这个函数FTP也可以使用,这个用户名可以用来登录FTP,用不到NULL就行了
lpszPassword 密码,同上
dwService 服务类型,有三个宏定义,选INTERNET_SERVICE_HTTP就行,另外两个是FTP和GOPHER
dwFlags 上一个参数是FTP才有用,不是的话直接NULL就行
dwContext 这翻译也看不懂,不知道干啥用的直接NULL,这个有师傅知道的话希望可以告知一下提前谢谢
这个函数返回的是句柄
官方文档:https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetconnecta
这个参数和HttpSendRequestA合用
感觉就是一个构建一个发送
1 | HINTERNET HttpOpenRequestA( |
hConnect InternetConnectA返回的句柄
lpszVerb 请求方法,就是一个字符串,常用的就GET,当然改成别的CS服务器也是可以认出来的
lpszObjectName 就是URL后面的路径
lpszVersion 协议版本,写个NULL默认HTTP/1.0或者HTTP/1.1,写个100CS服务器也是可以解析的
lpszReferrer 接收的MIME类型,写为NULL默认只接收文本类型不接收别的东西..图片啥的,这里接收文本类型就行这个参数直接NULL
dwFlags 这参数有好多宏定义,看了一眼就是要不要缓存啥的,选择INTERNET_FLAG_NO_CACHE_WRITE不将返回值添加到缓存,别的暂时用不到
dwContext 一样不知道什么意思直接NULL..
这个函数返回一个句柄
官方文档:https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-httpopenrequesta
1 | BOOL HttpSendRequestA( |
上面函数构建好了请求报文,这个函数发送
hRequest HttpOpenRequestA函数返回的句柄
lpszHeaders 请求头,这次用不到直接NULL就行
dwHeadersLength 请求头的长度,如果为-1会默认以\x00结尾并计算长度
lpOptional 看意思是POST请求参数,试一下就知道
dwOptionalLength POST请求长度
函数成功返回TRUE失败返回FALSE
给个位置不然顺序不对看着不舒服..
参数和ReadFile差不多
1 | BOOL InternetReadFile( |
hFile HttpOpenRequestA函数返回的句柄
lpBuffer 读取出来的数据存放的起始位置的指针
dwNumberOfBytesToRead 读取数据的大小
lpdwNumberOfBytesRead 实际读出的大小
返回TRUE或FALSE
到这里基本的函数都已经了解了
首先还是尝试这两个函数可以构建怎么样的HTTP请求报文
HttpOpenRequestA
HttpSendRequest
如果需要构建多个请求头需要用到
HttpAddRequestHeadersA
1 | BOOL HttpAddRequestHeadersA( |
hRequest HttpOpenRequestA返回的句柄
lpszHeaders 和上一个函数一样
dwHeadersLength 和上一个函数一样
dwModifiers 这个主要是判断请求头有无重复,有重复该怎么继续,是替换还是报错,就用HTTP_ADDREQ_FLAG_ADD_IF_NEW,只有不存在的请求头才添加,如果请求头不存在就报错
别的参数直接看官方文档:https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-httpaddrequestheadersa
被某些教程误导了一波
本以为HttpSendRequest的第二个参数直接用\r\n就可以接上第二个请求头
后来才发现需要一个个添加
下面看一下代码
1 |
|
发送的数据包是这样的
1 | dsahdjaks /K8sf HTTP/2 |
和上面代码对应就可以知道什么函数对应了请求头什么地方
最后贴上模仿shellocde的代码
1 |
|
还有一点就是shellcode的URL,首先生成一个payload.bin,用010Editor打开,找到130h-140h这两行,看一下又没有 “/四个字符串”这样的格式,找到了贴在ip后面就是完整URL了
放到VT上查了一下有二十多个杀软查出来了,但是实际测试火绒和windowsdefender都是可以过的
用动态加载写一个估计就不会被这么多查杀了
最后再贴一个简单版本的
1 |
|