Malware Dev 03 - 隐匿之 Command Line Spoofing 原理解析

news2024/12/22 17:35:27

写在最前

如果你是信息安全爱好者,如果你想考一些证书来提升自己的能力,那么欢迎大家来我的 Discord 频道 Northern Bay。邀请链接在这里:

https://discord.gg/9XvvuFq9Wb

我拥有 OSCP,OSEP,OSWE,OSED,OSCE3,CRTO,CRTP,CRTE,PNPT,eCPPTv2,eCPTXv2,KLCP,eJPT 证书。

所以,我会提供任一证书备考过程中尽可能多的帮助,并分享学习和实践过程中的资源和心得,大家一起进步,一起 NB~


背景

红队/渗透测试离不开命令行,在命令行执行命令的时候,执行的命令以及命令的参数,会被系统日志记录。那么我们的真实目的,就会被一览无余。

为了进一步隐藏我们的真实目的,混淆视听,我们可以使用 Command Line Spoofing 这个技巧,修改进程的 PEB,来达到隐藏真实命令的效果。

这篇文章,我们就来看一下 Command Line Spoofing 是如何实现的。

Command Line Spoofing

概述

Command Line Spoofing 是通过修改进程 PEB(Process Environment Block) 中的 RTL_USER_PROCESS_PARAMETERS 结构来达成的。原理就是这样,我们实践一下,看一下具体如何实现。

RTL_USER_PROCESS_PARAMETERS 结构

在命令行用 notepad 随便打开一个文件。

在这里插入图片描述

WinDBG hook 进程。

在这里插入图片描述

查看一下 PEB。

dt !_PEB

在这里插入图片描述

在 offset 0x20 的地方可以看到 RTL_USER_PROCESS_PARAMETERS 结构。

看一下官方的结构原型。

typedef struct _RTL_USER_PROCESS_PARAMETERS {
  BYTE           Reserved1[16];
  PVOID          Reserved2[10];
  UNICODE_STRING ImagePathName;
  UNICODE_STRING CommandLine;			// 重点在这里
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

第四个参数,CommandLine 是我们关注的重点。

我们看一下当前 _RTL_USER_PROCESS_PARAMETERS 的数据。

dt _RTL_USER_PROCESS_PARAMETERS

在这里插入图片描述

CommandLine 参数在 0x70 的位置上。

查看一下 _RTL_USER_PROCESS_PARAMETERS 结构在内存中的地址。

dt _peb @$peb

在这里插入图片描述

查看一下内存中的内容。可以直接点击 ProcessParameters

dx -r1 ((wintypes!_RTL_USER_PROCESS_PARAMETERS *)0x16c2c0f2b60)

在这里插入图片描述

查看 CommandLine 成员的内容。直接点击即可。

dx -r1 (*((wintypes!_UNICODE_STRING *)0x16c2c0f2bd0))

在这里插入图片描述

我们可以看到,整个命令被保存在 CommandLine 成员的 Buffer 属性中。

我们跟 Process Hacker 对比一下。一致。

在这里插入图片描述

看到了 _RTL_USER_PROCESS_PARAMETERS 结构的内部,下面我们就需要在运行时更改这个结构中 CommandLine 成员的值。

_RTL_USER_PROCESS_PARAMETERS Runtime Patch

整体步骤如下:

  1. 创建一个挂起(suspend)进程,使用假的命令及参数作为 CreateProcess 的 commandline 参数;
  2. 找到当前进程的 _RTL_USER_PROCESS_PARAMETERS 结构;
  3. 修改 _RTL_USER_PROCESS_PARAMETERS 结构的 CommandLine 成员为真实的命令及参数;
  4. 恢复(resume)进程运行,以修改之后的命令及参数执行;

一步一步实现。

  1. 创建一个挂起(suspend)进程,使用假的命令及参数作为 CreateProcess 的 commandline 参数;

    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    
    WCHAR goodArgs[] = L"notepad all-good.txt";
    
    if (CreateProcess(
        L"C:\\Windows\\System32\\notepad.exe",
        goodArgs,										// 使用假的参数创建这个进程
        NULL,
        NULL,
        FALSE,
        CREATE_SUSPENDED,								// 创建挂起状态的进程
        NULL,
        L"C:\\",
        &si,
        &pi))
    {
        _tprintf(L"Process created: %d", pi.dwProcessId);
    }
    

    我们在 88 行打个断点,debug 一下。

    在这里插入图片描述

    WinDBG hook 重复以上步骤查看 _RTL_USER_PROCESS_PARAMETERS 中的 CommandLine 成员。

    在这里插入图片描述
    在这里插入图片描述

    看到了当前的虚假参数。接下来我们要找到 _RTL_USER_PROCESS_PARAMETERS,以便修改 CommandLine 成员。

  2. 找到当前进程的 _RTL_USER_PROCESS_PARAMETERS 结构;

    我们继续分解成几个小步骤来完成。

    • 1)获取 NtQueryInformationProcess 函数在 ntdll 中的地址以调用;

    • 2)使用 NtQueryInformationProcess 函数获取 PROCESS_BASIC_INFORMATION,PEB 的地址包含在这个结构中;

    • 3)使用 ReadProcessMemory 函数,从 PROCESS_BASIC_INFORMATION 中获取 PebBaseAddress 地址;

    • 4)使用 ReadProcessMemory 函数,从 PebBaseAddress 中获取 ProcessParameters 地址,读取 RTL_USER_PROCESS_PARAMETERS 结构;

      下面我们一步一步来实现。

      1)获取 NtQueryInformationProcess 函数在 ntdll 中的地址以调用;

      要查看进程的信息,会使用到 NtQueryInformationProcess

      函数原型。

      __kernel_entry NTSTATUS NtQueryInformationProcess(
        [in]            HANDLE           ProcessHandle,
        [in]            PROCESSINFOCLASS ProcessInformationClass,
        [out]           PVOID            ProcessInformation,
        [in]            ULONG            ProcessInformationLength,
        [out, optional] PULONG           ReturnLength
      );
      

      NtQueryInformationProcess 这个函数不能直接使用,必须在运行时通过 GetProcAddress 函数获取其在 ntdll 中的地址。

      因此我们先定义一个函数原型。然后在运行时解析他的地址。

      typedef NTSTATUS(*QueryInformationProcess)(IN HANDLE, IN PROCESSINFOCLASS, OUT PVOID, IN ULONG, OUT PULONG);
      
      // 运行时解析地址
      HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
      QueryInformationProcess NtQueryInformationProcess = (QueryInformationProcess)GetProcAddress(ntdll, "NtQueryInformationProcess");
      

      至此,我们就可以调用 NtQueryInformationProcess 函数来获取

      2)使用 NtQueryInformationProcess 函数获取 PROCESS_BASIC_INFORMATION,PEB 的地址包含在这个结构中;

      PROCESS_BASIC_INFORMATION pbi;
      DWORD length;
      
      NtQueryInformationProcess(
          pi.hProcess,
          ProcessBasicInformation,		// 从 ProcessBasicInformation 中读取 PROCESS_BASIC_INFORMATION
          &pbi,							// 读取结果存放在 pbi 变量中
          sizeof(pbi),
          &length);
      

      3)使用 ReadProcessMemory 函数,从 PROCESS_BASIC_INFORMATION 中获取 PebBaseAddress 地址;

      PEB peb;
      SIZE_T bytesRead;
      
      ReadProcessMemory(
          pi.hProcess,
          pbi.PebBaseAddress,				// 从 pbi 中获取 PEB 的基地址
          &peb,							// PEB 的基地址存放在 peb 变量中
          sizeof(PEB),
          &bytesRead);
      

      4)使用 ReadProcessMemory 函数,从 PebBaseAddress 中获取 ProcessParameters 地址,读取 RTL_USER_PROCESS_PARAMETERS 结构;

      RTL_USER_PROCESS_PARAMETERS rtlParams;
      
      ReadProcessMemory(
          pi.hProcess,
          peb.ProcessParameters,					// 从 PEB 的 ProcessParameters 中读取 RTL_USER_PROCESS_PARAMETERS 结构
          &rtlParams,								// 读取结果存放在 rtlParams 变量中
          sizeof(RTL_USER_PROCESS_PARAMETERS),
          &bytesRead);
      

      至此,RTL_USER_PROCESS_PARAMETERS 结构我们已经找到。接下来就是用真实的命令及参数,覆盖掉原来的虚假参数。

  3. 修改 _RTL_USER_PROCESS_PARAMETERS 结构的 CommandLine 成员为真实的命令及参数;

    使用 WriteProcessMemory 函数写入新的命令及参数到 RTL_USER_PROCESS_PARAMETERS 的 CommanLine 成员中。

    WCHAR evilArgs[] = L"notepad C:\\Users\\opr\\Desktop\\target-file.txt";
    SIZE_T bytesWritten;
    
    WriteProcessMemory(
        pi.hProcess,
        rtlParams.CommandLine.Buffer,		// 写入到 RTL_USER_PROCESS_PARAMETERS -> CommandLine -> Buffer 中,修改原有的值
        evilArgs,							// 使用 evilArgs 覆盖 goodArgs
        sizeof(evilArgs),
        &bytesWritten);
    
  4. 恢复(resume)进程运行,以修改之后的命令及参数执行最终命令;

    ResumeThread(pi.hThread);
    

我们运行起来看一看是否能打开用户桌面的指定文件,并且配置 Sysmon 来查看日志记录的命令行。Sysmon 在这里下载。

这里抓取 notepad 进程的最简单 Sysmon config.xml 配置文件如下,保存到任意位置即可(这里我保存在了 \Windows\config.xml)。

<Sysmon schemaversion="4.60">
  <EventFiltering>
    <!-- Event ID 1 == Process Creation - Includes -->
    <RuleGroup groupRelation="or">
      <ProcessCreate onmatch="include">
		<OriginalFileName condition="is">notepad.exe</OriginalFileName>
		<CommandLine name="technique_id=T9999,technique_name=whatever" condition="contains all">notepad.exe</CommandLine>
      </ProcessCreate>
    </RuleGroup>
  </EventFiltering>
</Sysmon>

启动 Sysmon。

sysmon64.exe -i c:\windows\config.xml

在这里插入图片描述

确认 Sysmon 服务已经运行。

在这里插入图片描述

打开 Event Viewer,找到 Applications and Services Log > Microsoft > Windows > Sysmon Operational。

创建一个 Filter,过滤 Event ID 为 1 的事件,也就是 Process Creation 事件。

在这里插入图片描述

然后运行 CommandLineSpoofing.exe。之后查看 Event Viewer。

在这里插入图片描述

可以看到 Sysmon 抓到的 CommandLine 日志是 notepad all-good.txt,但是我们成功偷换了参数,打开了指定的 target-file.txt 文件。

在这里插入图片描述

Command line spoofing 成功。

发现的问题

Process Hacker 会在我们打开一个进程的属性菜单的时候重新读取该进程的 PEB 数据,因此 Command Line Spoofing 对于 Process Hacker 看似无效。

我们在 Process Hacker 看一下这个进程,发现 Command line 被截掉了一部分。

在这里插入图片描述

还记得我们之前在 WinDBG 中看到的,每个 CommandLine 成员有一个 Length 属性,这个就是当前整个命令的长度。

在这里插入图片描述

这个值是 0x2a,转换成十进制是 42 个 byte。
在这里插入图片描述

而 notepad all-good.txt 长度是 20 个字节(外加 1 个字节的 null-byte),共 21 字节。

在这里插入图片描述

这是因为 CommandLine 中用于存放命令的 Buffer 是 wchar_t 类型,一个字母占 2 个字节。

在这里插入图片描述

所以一共是 42 个字节。

这就是问题所在,这个 Buffer 只能放下 21 个字母,我们替换进去的命令,只有黑体部分 notepad C:\Users\opr\target-file.txt 被显示出来。

所以我们在使用 Command Line Spoofing 的时候,我们可以计算一下虚假参数的长度,配合真实参数的长度做截取,达到目的。

总结

这篇文章解释了 Command Line Spoofing 的原理,就是通过修改进程 PEB(Process Environment Block) 中的 RTL_USER_PROCESS_PARAMETERS 结构,来达到隐藏真实命令参数的效果。

不过 Command Line Spoofing 并不是全能。我们必须考虑多层的防护机制。比如,就算命令行参数隐藏了,但是如果命令会创建进程,那么创建进程的事件,依然会被 Sysmon 等日志系统记录。

因此, Command Line Spoofing 最好使用在不会创建额外进程的情况下。对于 Malware 或者 C2 开发来说,是一个很好的隐藏行为轨迹的思路。

参考链接

  • https://stackoverflow.com/questions/12760878/contains-function-for-lpctstr
  • https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessid
  • https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulefilenameexa
  • https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getmodulebasenamea?redirectedfrom=MSDN
  • https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-rtl_user_process_parameters
  • https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/exploring-process-environment-block
  • https://www.codeproject.com/Articles/19685/Get-Process-Info-with-NtQueryInformationProcess
  • https://stackoverflow.com/questions/766126/representation-of-wchar-t-and-char-in-windbg
  • https://www.blumira.com/enable-sysmon/
  • https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/386822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅分析BIG-建筑展示系统

一、主页&#xff08;主要界面&#xff09;重点疑点&#xff08;需要解决&#xff09;1.云平台实时同步。是否可以电脑与hololens2同步或链接&#xff1f;并可以传输信息提醒&#xff1f;一级界面&#xff08;启动界面&#xff09;1.交互式启动激活效果&#xff08;触发按钮旋转…

TCP协议三次握手的原因是什么?为什么不用两次握手和4次握手?

今天复习了TCP协议的三次握手&#xff0c;对上一篇C网络编程有了更深的理解。当时考研的时候计网学过&#xff0c;这里再总结一下分享。网图都是截图来的&#xff0c;侵删。TCP协议属于传输层协议&#xff0c;上面的应用层协议包括HTTP、FTP之类&#xff0c;应用层协议是最接近…

Prometheus 监控云Mysql和自建Mysql(多实例)

本文您将了解到 Prometheus如何配置才能监控云Mysql(包括阿里云、腾讯云、华为云)和自建Mysql。 Prometheus 提供了很多种Exporter&#xff0c;用于监控第三方系统指标&#xff0c;如果没有提供也可以根据Exporter规范自定义Exporter。 本文将通过MySQL server exporter 来监控…

通达信波段主图指标公式,源码简洁原理却不简单

通达信波段主图指标公式的核心语句也就4句&#xff0c;后面的语句都是为了画图的。公式看起来比较简单&#xff0c;原理也比较巧妙&#xff0c;但是理解起来有些困难。 直接上源码&#xff1a; HH:HHV(H,5); LL:LLV(L,5); TH:BARSLAST(H>REF(HH,1)); TL:BARSLAST(L<REF(…

K8s(v1.25.1) 高可用集群(3 Master + 5 Node) Ansible 剧本部署(CRI使用docker,cri-docker)

写在前面 分享一个 k8s 高可用集群部署的 Ansible 剧本以及涉及到的一些工具的安装博文内容涉及&#xff1a;从零开始 一个 k8s 高可用 集群部署 Ansible剧本编写&#xff0c;编写后搭建 k8s 高可用 集群一些集群常用的 监控&#xff0c;备份工具安装&#xff0c;包括&#xff…

边缘计算:万字长文详解高通SNPE inception_v3推理实战

本文主要讲解利用高通SNPE进行神经网络推理&#xff0c;主要参考&#xff1a; 上手SNPE&#xff0d;推理inception_v3 - 知乎 文中是容器做的&#xff0c;在conda环境下做一样的&#xff0c;没问题&#xff0c;已跑通。 在anaconda环境中使用conda命令安装cuda、cudnn、tens…

数据结构与算法系列之单链表

&#x1f497; &#x1f497; 博客:小怡同学 &#x1f497; &#x1f497; 个人简介:编程小萌新 &#x1f497; &#x1f497; 如果博客对大家有用的话&#xff0c;请点赞关注再收藏 &#x1f31e; 这里写目录标题test.hSList.h注意事项一级指针与二级指针的使用assert的使用空…

内大892复试真题19年

内大892复试真题19年 1. 统计低于平均分的人数2. 输出数组中最大值3. 一元二次方程求根4. 字符串数组平移(反转法)5. 矩阵乘法(分治+strassen思想)1. 统计低于平均分的人数 问题 代码 #include <iostream>using namespace std;// 函数声明 double avgFunc

0098 Mysql01

1.登录Mysql mysql -uroot -p密码 2.Mysql常用命令 退出:exit 查看mysql有哪些数据库&#xff1a;show databases;(以分号结尾) 选择使用某个数据库&#xff1a;use sys; (表示正在使用一个名叫sys得数据库) 创建数据库&#xff1a;create database bjpowernode; 查看某个数…

FFmpeg入门 - 格式转换

1、音频分⽚(plane)与打包(packed)解码出来的AVFrame,它的data字段放的是视频像素数据或者音频的PCM裸流数据,linesize字段放的是对齐后的画面行长度或者音频的分片长度:/*** For video, size in bytes of each picture line.* For audio, size in bytes of each plane.** For …

Python3 入门教程||Python3 条件控制||Python3 循环

Python3 条件控制 if语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。 Python 中 if 语句的一般形式如下所示&#xff1a; if condition_1:statement_block_1 流程图如下所示&#xff1a; 这种if语句只有在符合条件的时候才会执行代…

华大Flash檫写导致重启异常问题

一、华大Flash写入注意事项由Flash操作说明我们可以看出重要一点&#xff0c;就是檫写Flash函数地址需要定义在32K之前&#xff08;即0x8000之前&#xff09;&#xff0c;否则将写入失败。二、先上的错误的源代码这个代码是我应用中导致硬件卡死重启的&#xff0c;其实也不算错…

FreeSWITCH 呼入系统的简要设计

文章目录1. 呼入处理方案2. 细节处理1. a-leg 的拨号计划2. originate 呼叫坐席1. 呼入处理方案 使用 FreeSWICTH 的 ESL 模块&#xff0c;一个简单的呼入处理时序如下图所示&#xff0c;关键步骤做如下补充: 用户呼入到 FreeSWITCH 实例&#xff0c;a-leg 创建FreeSWITCH 根据…

DC真实数据都有哪些?Filecoin为DC数据存储的解决方案又是什么?

对于生活在数字时代的我们而言&#xff0c;数据或许就和平日呼吸的空气一样&#xff0c;已经不需要我们再去思考其概念。我们的日常生活中无时无刻都有数据的身影&#xff0c;日常的购物消费、出行、学习、记录&#xff0c;当我们每天生活有数字化加持的小区里&#xff0c;工作…

网上图书资料管理系统

技术&#xff1a;Java、JSP等摘要&#xff1a;Internet带给我们的不仅是无穷的信息&#xff0c;更为我们带来了很多的便利。在这个科技高速发展的时代&#xff0c;网络应用十分广泛&#xff0c;所以许多人愿意通过网络来使他们的生活变得更加的方便。网上图书资料管理系统的出现…

Spring Cloud(微服务)学习篇(五)

Spring Cloud(微服务)学习篇(五) 1 nacos配置文件的读取 1.1 访问localhost:8848/index.html并输入账户密码后进入nacos界面并点击配置列表 1.2 点击右侧的号 1.3 点击加号后,进入新建配置界面,并做好如下配置 1.4 往下翻动,点击发布按钮 1.5 发布成功后的界面 1.6 在pom.xml…

ChatGPT解答:PYQT5 的mwindow源码文件里面写了很多的函数方法,随着时间的推移越来越多,代码行数太多,影响了性能,如何解决

ChatGPT解答&#xff1a; PYQT5 的mwindow源码文件里面写了很多的函数方法&#xff0c;随着时间的推移越来越多&#xff0c;代码行数太多&#xff0c;影响了性能&#xff0c;如何解决 以下为可复制的内容与实例&#xff1a; PYQT5 的mwindow源码文件里面写了很多的函数方法&a…

第一道pwn栈溢出题

代码和解题思路来自启明星辰的《ctf安全竞赛入门》&#xff0c;当然还有好多热心的师傅们的指导。1.代码&#xff1a;#include "stdio.h" void shell() {system("/bin/sh"); } void vuln() {printf("Please input your name:\n");char s[8];gets…

实现pdf文件预览

前言 工作上接到的一个任务&#xff0c;实现pdf的在线预览&#xff0c;其实uniapp中已经有对应的api&#xff1a;uni.openDocument(OBJECT)&#xff08;新开页面打开文档&#xff0c;支持格式&#xff1a;doc, xls, ppt, pdf, docx, xlsx, pptx。&#xff09;**实现了相关功能…

冬奥会信息管理系统

摘 要伴随着社会以及科学技术的发展&#xff0c;互联网已经渗透在人们的身边&#xff0c;网络慢慢的变成了人们的生活必不可少的一部分&#xff0c;紧接着网络飞速的发展&#xff0c;系统管理这一名词已不陌生&#xff0c;越来越多的体育馆等机构都会定制一款属于自己个性化的管…