Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
paracosme — Paracosme 是一个零点击远程内存破坏漏洞利用程序,可攻陷 ICONICS Genesis64,该漏洞利用已在 Pwn2Own Miami 2022 竞赛期间于舞台上成功演示。 | Kitploit
工具/GitHubGitHub/0vercl0k/paracosme
漏洞分析漏洞利用SCADA/ICS安全渗透测试Payload 开发二进制利用Archived
GitHub0vercl0k/paracosme

paracosme

Paracosme 是一个零点击远程内存破坏漏洞利用程序,可攻陷 ICONICS Genesis64,该漏洞利用已在 Pwn2Own Miami 2022 竞赛期间于舞台上成功演示。

查看仓库
9022283年前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

Paracosme - CVE-2022-33318 - ICONICS Genesis64 中的远程代码执行

Paracosme 是我编写的一个内存破坏漏洞利用程序,用于攻击由 ICONICS 开发的 Genesis64 套件 v10.97.1,以实现远程代码执行。

该漏洞利用程序是在 S4x22 Conference 期间举行的 Pwn2Own 2022 Miami 竞赛上演示的。你可以通过 参加 Pwn2Own ICS 2022 Miami:利用 ICONICS Genesis64 中的零点击远程内存破坏 了解详情。

该问题在 CVSS 中评分为 9.8,并被分配为 CVE-2022-33318 / ZDI-22-1041。它已被修复,并在 Genesis64 10.97.2 中修复。你也可以阅读 ICSA-22-202-04 公告以及 ICONICS 的 关于 ICONICS Suite 安全漏洞的白皮书。

你可以在 src/paracosme.py 中找到漏洞利用代码,在 src/paracosme-poc.py 中找到用于触发崩溃/验证你是否受影响的 PoC,在 src/payload 中找到目标机器上执行的 payload。

我是否受影响?

判断你是否受影响的最佳方法是为 GenBroker64.exe 启用 Page Heap,重启服务,将调试器附加到 GenBroker64.exe,针对你的服务器运行 paracosme-poc.py,然后你应该会看到类似下面的崩溃:

你需要将调试器附加到目标进程才能看到崩溃,否则应用程序会忽略它。

运行漏洞利用程序

该漏洞利用程序只在 Windows 上测试过,但应该也能在 Linux 平台上运行:

  1. 使用以下命令安装 impacket:pip3 install impacket
  2. 使用 sc config lanmanserver start=disabled 关闭机器上运行的任何 SMB 服务器,然后重新启动
  3. 使用 smbserver.py(impacket 示例的一部分)启动 smbserver:python src\smbserver.py -smb2support x bin
  4. 使用 python src\paracosme.py --target <ip> 启动漏洞利用程序

漏洞利用

更多细节,请参阅 参加 Pwn2Own ICS 2022 Miami:利用 ICONICS Genesis64 中的零点击远程内存破坏。

漏洞概述

Paracosme 利用在 GenBroker64 进程中发现的释放后使用(use-after-free)问题,在 Windows 21H2 x64 系统上实现远程代码执行。

从高层次来看,GenBroker64 进程监听 TCP 端口 38080,并在与客户端完成握手后能够反序列化各种数据包。我发现的 bug 出在从网络套接字读取 VARIANT 的代码中。基本上,一个 variant 由一个类型和一个值组成。该函数乍一看写得不错,并且尽力只解包某些类型。其代码如下:

bool CheckVariantType(VARTYPE VarType) {
  if((VarType & 0x2FFF) != VarType) {
    return false;
  }

  switch(VarType & 0xFFF) {
    case VT_EMPTY:
    case VT_NULL:
    case VT_I2:
    case VT_I4:
    case VT_R4:
    case VT_R8:
    case VT_CY:
    case VT_DATE:
    case VT_BSTR:
    case VT_ERROR:
    case VT_BOOL:
    case VT_VARIANT:
    case VT_I1:
    case VT_UI1:
    case VT_UI2:
    case VT_UI4:
    case VT_I8:
    case VT_UI8:
    case VT_INT:
    case VT_UINT:
    case VT_HRESULT:
    case VT_FILETIME:
      return true;
      break;
    default:
      return false;
  }
}

size_t VariantTypeToSize(VARTYPE VarType) {
  switch(VarType) {
    case VT_I1: return 1;
    case VT_UI2: return 2;
    case VT_UI4:
    case VT_INT:
    case VT_UINT:
    case VT_HRESULT:
      return 4;
    case VT_I8:
    case VT_UI8:
    case VT_FILETIME:
      return 8;
    default:
      return 0;
  }
}

void Utils::ReadVariant(tagVARIANT *Variant, Archive_t *Archive, int Level) {
    TRY {
        return ReadVariant_((CArchive *)Archive, (COleVariant *)Variant);
    } CATCH_ALL(e) {
        VariantClear(Variant);
    }
}

HRESULT Utils::ReadVariant_(tagVARIANT *Variant, Archive_t *Archive, int Level) {
  VARTYPE VarType = Archive.ReadUint16();
  if((VarType & VT_ARRAY) != 0) {
      // Special logic to unpack arrays..
      return ..;
  }

  Size = VariantTypeToSize(VarType);
  if (Size) {
      Variant->vt = VarType;
      return Archive.ReadInto(&Variant->decVal.8, Size);
  }

  if(!CheckVariantType(VarType)) {
      // ...
      throw Something();
  }

  return Archive >> Variant;
}

该函数自己实现了数组解包,以及读取简单的 variant 类型,但如果收到的是不属于这两类的东西,它就会转交给 archive 实例的 operator>>。这个 archive 实例是由 Microsoft Foundation Class 框架提供的对象,负责各种对象的序列化和反序列化。这段代码实际上是开源的,你可以在 C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\atlmfc\src\mfc\olevar.cpp 中找到它,其内容如下:

CArchive& AFXAPI operator>>(CArchive& ar, COleVariant& varSrc) {
  LPVARIANT pSrc = &varSrc;
// ...
  switch(pSrc->vt) {
// ...
    case VT_DISPATCH:
    case VT_UNKNOWN: {
      LPPERSISTSTREAM pPersistStream = NULL;
      CArchiveStream stm(&ar);
      CLSID clsid;
      ar >> clsid.Data1;
      ar >> clsid.Data2;
      ar >> clsid.Data3;
      ar.EnsureRead(&clsid.Data4[0], sizeof clsid.Data4);
      SCODE sc = CoCreateInstance(clsid, NULL,
        CLSCTX_ALL | CLSCTX_REMOTE_SERVER,
        pSrc->vt == VT_UNKNOWN ? IID_IUnknown : IID_IDispatch,
        (void**)&pSrc->punkVal);
      if(sc == E_INVALIDARG) {
        sc = CoCreateInstance(clsid, NULL,
          CLSCTX_ALL & ~CLSCTX_REMOTE_SERVER,
          pSrc->vt == VT_UNKNOWN ? IID_IUnknown : IID_IDispatch,
          (void**)&pSrc->punkVal);
      }
      AfxCheckError(sc);
      TRY {
        sc = pSrc->punkVal->QueryInterface(
          IID_IPersistStream, (void**)&pPersistStream);
        if(FAILED(sc)) {
          sc = pSrc->punkVal->QueryInterface(
            IID_IPersistStreamInit, (void**)&pPersistStream);
        }
        AfxCheckError(sc);
        AfxCheckError(pPersistStream->Load(&stm));
      } CATCH_ALL(e) {
        if(pPersistStream != NULL) {
          pPersistStream->Release();
        }
        pSrc->punkVal->Release();
        THROW_LAST();
      }
      END_CATCH_ALL
      pPersistStream->Release();
    }
    return ar;
  }
}

这个函数大部分内容都很无聊,因为它也有解包普通类型的逻辑,但引起我注意的是 VT_DISPATCH / VT_UNKNOWN。

这是什么情况?你可以发送一个实现了 IPersistStream 或 IPersistStreamInit 的任意 COM 对象类 ID,它会通过调用 IPersistream::Load 来加载并初始化该对象。虽然这令人惊讶,而且是个奇怪的功能,但从安全角度来看,我并不觉得这多有趣,因为我需要在 Windows 10 自带的 COM 对象中找到另一个 bug。

现在,让我们仔细看看下面的代码:

SCODE sc = CoCreateInstance(clsid, NULL,
  CLSCTX_ALL | CLSCTX_REMOTE_SERVER,
  pSrc->vt == VT_UNKNOWN ? IID_IUnknown : IID_IDispatch,
  (void**)&pSrc->punkVal); <-------------- [[0]]

if(sc == E_INVALIDARG) {
  sc = CoCreateInstance(clsid, NULL,
    CLSCTX_ALL & ~CLSCTX_REMOTE_SERVER,
    pSrc->vt == VT_UNKNOWN ? IID_IUnknown : IID_IDispatch,
    (void**)&pSrc->punkVal);
}
下载工具