beacon生成原理
beacon生成主要有3个步骤,首先是将C2Patch的相关数据patch到beacon中,便于beacon使用,第二步,处理beacon的PE数据和添加引导shellcode,这段shellcode是引导执行ReflectiveLoader。第三步将beacon加密,并和一些数据patch到loader中。
在beacon生成这块,主要涉及到4个java文件。BeaconPayload.java主要是对beacon进行C2Profile相关的处理,主要涉及的函数为exportBeaconStage。MalleablePE.java,主要用于对beacon进行一些PE相关的处理,主要涉及的函数为process函数。而BeaconLoader.java主要是patch beacon的开头那段shellcode。主要涉及到patchDOSHeader函数。BaseArtifactUtils主要是将加密beacon数据和一些加密beacon的key之类的数据patch到loader模板上,
CobaltStrike服务端,通过()生成beacon,经过分析,将断点分别下在WindowsExecutableStageDialog.dialogAction和WindowsExecutableStageDialog.dialogResult这两个函数处。通过 dialogAction函数,选择需要保存的文件的内容或者格式。然后调用SafeDialogs.saveFile函数,弹出保存文件的选择框。
接着调用dialogResult函数,dialogResult函数是生成beacon的主要流程,参数的参数var1表示保存beacon的路径。
依次获取架构类型(x86或者x64),然后监听器这里选的是reverse_http。
然后调用ScListener.export函数,export函数的作用是通过不同的监听器,选择不同的Stage。本例中是调用eaconPayload.exportBeaconStageHTTP函数。exportBeaconStageHTTP的参数分别是(var1)端口,(var2)链接地址,var3,var4分别是false,var5是架构。通过不同的架构选择不同的BeaconStage数据。
在exportBeaconStage函数中,首先调用SleevedResource.readResource加载指定的beacon原始文件
然后读取C2Profile中的uri等C2Profile信息。我曾经根据这些默认的C2Profile的URI信息,捞到过一批有价值的CobaltStrike样本。
在解析完C2Profile数据之后,就会按照一定的顺序将这些C2Profile的参数拼装起来,并patch到beacon中,以供beacon使用。
在beacon\BeaconConstants.java这个文件中,可以看到C2Profile数据拼接序号的含义。在之前分析exportBeaconStageHTTP参数的时候,var1为端口。可以看到这里第二个处理的就是端口。而beacon\BeaconConstants.java文件的第二项的内容也是端口。
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke
beacon生成主要有3个步骤,首先是将C2Patch的相关数据patch到beacon中,便于beacon使用,第二步,处理beacon的PE数据和添加引导shellcode,这段shellcode是引导执行ReflectiveLoader。第三步将beacon加密,并和一些数据patch到loader中。
在beacon生成这块,主要涉及到4个java文件。BeaconPayload.java主要是对beacon进行C2Profile相关的处理,主要涉及的函数为exportBeaconStage。MalleablePE.java,主要用于对beacon进行一些PE相关的处理,主要涉及的函数为process函数。而BeaconLoader.java主要是patch beacon的开头那段shellcode。主要涉及到patchDOSHeader函数。BaseArtifactUtils主要是将加密beacon数据和一些加密beacon的key之类的数据patch到loader模板上,
CobaltStrike服务端,通过()生成beacon,经过分析,将断点分别下在WindowsExecutableStageDialog.dialogAction和WindowsExecutableStageDialog.dialogResult这两个函数处。通过 dialogAction函数,选择需要保存的文件的内容或者格式。然后调用SafeDialogs.saveFile函数,弹出保存文件的选择框。
接着调用dialogResult函数,dialogResult函数是生成beacon的主要流程,参数的参数var1表示保存beacon的路径。
依次获取架构类型(x86或者x64),然后监听器这里选的是reverse_http。
然后调用ScListener.export函数,export函数的作用是通过不同的监听器,选择不同的Stage。本例中是调用eaconPayload.exportBeaconStageHTTP函数。exportBeaconStageHTTP的参数分别是(var1)端口,(var2)链接地址,var3,var4分别是false,var5是架构。通过不同的架构选择不同的BeaconStage数据。
在exportBeaconStage函数中,首先调用SleevedResource.readResource加载指定的beacon原始文件
然后读取C2Profile中的uri等C2Profile信息。我曾经根据这些默认的C2Profile的URI信息,捞到过一批有价值的CobaltStrike样本。
在解析完C2Profile数据之后,就会按照一定的顺序将这些C2Profile的参数拼装起来,并patch到beacon中,以供beacon使用。
在beacon\BeaconConstants.java这个文件中,可以看到C2Profile数据拼接序号的含义。在之前分析exportBeaconStageHTTP参数的时候,var1为端口。可以看到这里第二个处理的就是端口。而beacon\BeaconConstants.java文件的第二项的内容也是端口。
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke
拼接C2Profile数据的是和,CobaltStrike使用addShort,addInt,addData,addString四个函数添加数据。其中前三个为基本函数,addString底层是通过addData实现的。以addData为例子,通过分析参数,可知依次添加了index,type,length,和value。且如果是short类型,type为1,如果是int类型,type为2,如果是Data或者string类型呢,type就为3了。
然后将这些数据转化为byte类型,然后将其与46进行进行异或运算。
将读取的原始beacon文件的byte转化为string类型,并定位其中的“AAAABBBBCCCCDDDDEEEEFFFF”字符串。然后用C2Profile数据替换掉。
当C2Profile的数据patch到beacon之后呢,开始处理PE数据,CobaltStrike在处理PE数据的时候分为两部,首先会对PE数据进行预处理,也就是从C2Profile中读取关于PE处理的相关数据,例如image_size,compile_time等等,然后对这些PE的基础数据进行处理。
在对PE数据进行预处理之后呢,根据所选择的架构不同,patch DOS头,也就是前面那段shellcode。首先调用findReflectiveLoader函数,通过导出表获取ReflectiveLoader导出函数地址。然后将该地址填充到shellcode中,其实分析过这种stage类型的beacon会发现,这种payload本质就是一个PE文件,只不过PE头被修改成一段可以执行的shellcode,这个shellcode的目的就是引导至ReflectiveLoader函数。
构造合适的Loader,在_patchArtifact函数中,首先读取指定的Loader的模板,该模板位于resources/目录下面,然后生成一组随机的byte数组,并用这些数组对beacon进行异或加密,这也是为什么每个生成的beacon都是不一样的原因。
然后依次保存1024个A所在地址偏移+16这个地址,beacon的长度,异或加密的随机数组,GetModuleHandleA,GetProcAddress函数地址(如果可以的话),保存加密之后的beacon数据,将上述数据替换到那1024个A处。然后将byte[]写入指定文件即完成beacon的生成。
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke
然后将这些数据转化为byte类型,然后将其与46进行进行异或运算。
将读取的原始beacon文件的byte转化为string类型,并定位其中的“AAAABBBBCCCCDDDDEEEEFFFF”字符串。然后用C2Profile数据替换掉。
当C2Profile的数据patch到beacon之后呢,开始处理PE数据,CobaltStrike在处理PE数据的时候分为两部,首先会对PE数据进行预处理,也就是从C2Profile中读取关于PE处理的相关数据,例如image_size,compile_time等等,然后对这些PE的基础数据进行处理。
在对PE数据进行预处理之后呢,根据所选择的架构不同,patch DOS头,也就是前面那段shellcode。首先调用findReflectiveLoader函数,通过导出表获取ReflectiveLoader导出函数地址。然后将该地址填充到shellcode中,其实分析过这种stage类型的beacon会发现,这种payload本质就是一个PE文件,只不过PE头被修改成一段可以执行的shellcode,这个shellcode的目的就是引导至ReflectiveLoader函数。
构造合适的Loader,在_patchArtifact函数中,首先读取指定的Loader的模板,该模板位于resources/目录下面,然后生成一组随机的byte数组,并用这些数组对beacon进行异或加密,这也是为什么每个生成的beacon都是不一样的原因。
然后依次保存1024个A所在地址偏移+16这个地址,beacon的长度,异或加密的随机数组,GetModuleHandleA,GetProcAddress函数地址(如果可以的话),保存加密之后的beacon数据,将上述数据替换到那1024个A处。然后将byte[]写入指定文件即完成beacon的生成。
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke
BeaconEye使用C#开发,通过使用yara规则,检测beacon解析之后的C2Profile数据分布实现的。因为libyaraNET库没有x86版本,所以BeaconEye务必编译成X64版本,才可以通过。
以x86的yara规则举例子,yara第一段为全0,因为C2Profile数据是从+0x08处开始复制的,所以前八个字节没有数据为全0,剩下的数据就很简单了,根据解析C2Profile的变量类型来看,前六个数据类型分别是short,short,int,int,short,short对应的type分别是01,01,02,02,01,01。这样就是检测的原理。
在dwReason为1的时候初始化C2Profile数据,在Sub_339762_Parse_C2Profile函数中,很显然,可以看到将C2Profile进行了解密。在内存中,大概还是以 index,type,length,value的顺序进行分布。
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke
以x86的yara规则举例子,yara第一段为全0,因为C2Profile数据是从+0x08处开始复制的,所以前八个字节没有数据为全0,剩下的数据就很简单了,根据解析C2Profile的变量类型来看,前六个数据类型分别是short,short,int,int,short,short对应的type分别是01,01,02,02,01,01。这样就是检测的原理。
在dwReason为1的时候初始化C2Profile数据,在Sub_339762_Parse_C2Profile函数中,很显然,可以看到将C2Profile进行了解密。在内存中,大概还是以 index,type,length,value的顺序进行分布。
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke
虚拟机逃逸初探----2018rwctf_station-escape
这里从头开始,一般出现在ctf的虚拟机逃逸会有俩个vmx,一个是原来正常的,另一个是patch过的
使用010editor比较俩个文件的异同
有俩处不同,拖进ida,找到对应的地址看看改了啥
查看被patch过的地址
在0x1893c9(379)指针置null的操作被nop掉了
另一个在0x1893e6(383)处的函数调用中,replay_type&1变成了v7&0x21
+7对应的成员out_msg_buf
如果该句被nop掉,out_msg_buf指针没有被置NULL,其次在第二处patch中,原先被限制的reply type(&0x1)变成了&0x21,也就是说在finish_recv_func(sub_177700)中可以存在free部分再次释放out_msg_buf
这个patch会导致UAF:如果我们在接收完成之后设置了0x21这个位,那么output buffer就会被释放掉,但由于它没有被清零,所以理论上我们可以无限次的将它free掉。可以通过 多次执行 case 5释放 输出缓冲区,最后制造一个 double free的漏洞。然后利用 info-get和 info-set命令,实现堆块的分配。利用RPC的发送命令和接受返回来实现堆块布局
这里的思路借鉴长亭师傅
利用思路
Leak:
1. 开两个channel:A和B,A的output buffer为buf_A,然后A释放buf_A
2. 这时让B准备给guest发output,B会分配一个buffer,我们利用info-set和info-get来控制我们分配的buffer大小,使得B的output buffer: buf_B=buf_A。
3. A再次释放buf_A,这也导致了buf_B被释放。这个时候我们就可以leak出buf_B的fd了,但是这个指针没有什么用,我们想要的是text base。
4. 因此我们再执行命令vmx.capability.dnd_version,这会让host分配一块内存来存放一个obj,通过控制buffer大小我们可以刚好让buf_B被用来存放一个obj。而这个obj里面有vtable,我们可以leak出来计算text base。注意我们一直没有接受B的输出,只是让它做好准备(分配output buffer)。直到这个时候我们才接受它的输出,完成leak
Exploit
有了leak的方法,exploit的也是类似的了。简单来说就是UAF,把tcache的fd改到bss段,然后改函数指针为system,最后弹calculator
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke
这里从头开始,一般出现在ctf的虚拟机逃逸会有俩个vmx,一个是原来正常的,另一个是patch过的
使用010editor比较俩个文件的异同
有俩处不同,拖进ida,找到对应的地址看看改了啥
查看被patch过的地址
在0x1893c9(379)指针置null的操作被nop掉了
另一个在0x1893e6(383)处的函数调用中,replay_type&1变成了v7&0x21
+7对应的成员out_msg_buf
如果该句被nop掉,out_msg_buf指针没有被置NULL,其次在第二处patch中,原先被限制的reply type(&0x1)变成了&0x21,也就是说在finish_recv_func(sub_177700)中可以存在free部分再次释放out_msg_buf
这个patch会导致UAF:如果我们在接收完成之后设置了0x21这个位,那么output buffer就会被释放掉,但由于它没有被清零,所以理论上我们可以无限次的将它free掉。可以通过 多次执行 case 5释放 输出缓冲区,最后制造一个 double free的漏洞。然后利用 info-get和 info-set命令,实现堆块的分配。利用RPC的发送命令和接受返回来实现堆块布局
这里的思路借鉴长亭师傅
利用思路
Leak:
1. 开两个channel:A和B,A的output buffer为buf_A,然后A释放buf_A
2. 这时让B准备给guest发output,B会分配一个buffer,我们利用info-set和info-get来控制我们分配的buffer大小,使得B的output buffer: buf_B=buf_A。
3. A再次释放buf_A,这也导致了buf_B被释放。这个时候我们就可以leak出buf_B的fd了,但是这个指针没有什么用,我们想要的是text base。
4. 因此我们再执行命令vmx.capability.dnd_version,这会让host分配一块内存来存放一个obj,通过控制buffer大小我们可以刚好让buf_B被用来存放一个obj。而这个obj里面有vtable,我们可以leak出来计算text base。注意我们一直没有接受B的输出,只是让它做好准备(分配output buffer)。直到这个时候我们才接受它的输出,完成leak
Exploit
有了leak的方法,exploit的也是类似的了。简单来说就是UAF,把tcache的fd改到bss段,然后改函数指针为system,最后弹calculator
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke
主要看的部分主要是leak()和 expilot()部分,channel_recv_finish2()函数就是把rbx改为0x21最后会执行到free操作
Run_cmd()
发送命令进行执行
Leak()
初始化操作,这里使用 info-set命令发送了0x100的信息,在后续只要使用info-get命令就可以执行malloc(0x100)的操作,这里0x100是因为dnd_version为4时会分配一个0x100的Obj。
第一步:开启通道0,此时通道0分配了buf为0x100
第二步:开启通道1,发送指令分了俩部分,在俩个发送指令之间释放了通道0的内存,此时再发送完指令后,通道1的内存块为buf
第三步,再次通过通道0释放buf(因为指针一直没有置0,就可以一直释放),执行"vmx.capability.dnd_version",在发送“vmx.capability.dnd_version” 命令的时候,对应的处理函数中如果发现当前版本和设置的版本不一致,就会调用函数创建新的 object,把原来的版本的object销毁。再开始时发送指令tools.capability.dnd_version 4,会使得这个分配的大小为0x100。此时的object就会到buf的位置。object里包含vtable的地址,再次通过通道1进行数据的返回(之前一直没有),进而得到数据的基地址
Expilt()
类似于leak,此时的buf安排的大小是0x150
开启四个通道,通道0先malloc出0x150的空间
此时通道0指向buf,第一次0释放,分配1通道,此时1指向buf,buf存在
第二次0释放,buf不存在,此时1通道进行写操作,当内存块不存在时,此时1通道写的位置其实是下一块的地址,pay1是一个在bss段上,且一定存在call的一个地址
Exp中的是FE95C8,可以对应下列的位置
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke
Run_cmd()
发送命令进行执行
Leak()
初始化操作,这里使用 info-set命令发送了0x100的信息,在后续只要使用info-get命令就可以执行malloc(0x100)的操作,这里0x100是因为dnd_version为4时会分配一个0x100的Obj。
第一步:开启通道0,此时通道0分配了buf为0x100
第二步:开启通道1,发送指令分了俩部分,在俩个发送指令之间释放了通道0的内存,此时再发送完指令后,通道1的内存块为buf
第三步,再次通过通道0释放buf(因为指针一直没有置0,就可以一直释放),执行"vmx.capability.dnd_version",在发送“vmx.capability.dnd_version” 命令的时候,对应的处理函数中如果发现当前版本和设置的版本不一致,就会调用函数创建新的 object,把原来的版本的object销毁。再开始时发送指令tools.capability.dnd_version 4,会使得这个分配的大小为0x100。此时的object就会到buf的位置。object里包含vtable的地址,再次通过通道1进行数据的返回(之前一直没有),进而得到数据的基地址
Expilt()
类似于leak,此时的buf安排的大小是0x150
开启四个通道,通道0先malloc出0x150的空间
此时通道0指向buf,第一次0释放,分配1通道,此时1指向buf,buf存在
第二次0释放,buf不存在,此时1通道进行写操作,当内存块不存在时,此时1通道写的位置其实是下一块的地址,pay1是一个在bss段上,且一定存在call的一个地址
Exp中的是FE95C8,可以对应下列的位置
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我 @MoA_Ke