[<prev] [next>] [day] [month] [year] [list]
Message-ID: <200503020341.j223fqpv057571@mailserver3.hushmail.com>
From: phantasmal at hush.ai (Phantasmal Phantasmagoria)
Subject: Irony in the Otherworld
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
[------------------------------------
Irony in the Otherworld
by Phantasmal Phantasmagoria
phantasmal@...h.ai
[------------------------------------
The Linux Security Module [1] provides a framework for access
control models to be hooked in to the Linux kernel. The standard
Discretionary Access Control found in a traditional Unix system has
long been considered insufficient and various alternatives [2][3]
have been developed. It is for these alternative projects that LSM
was designed for.
This text examines the potential misuse of an LSM system,
specifically the insertion of rootkit and backdoor code in to the
kernel through the abuse of LSM hooks. The techniques developed
below manifest themselves when an LSM system does not explicitly
disallow the writing of kernel memory by kernel modules and the
kmem/mem devices. It should be stressed that the methods presented
here do not constitute a vulnerability or flaw in LSM itself. This
should hopefully be evident after having read the entire document.
The official stance from the LSM developers is that any policy that
does not disallow the writing of kernel memory is equivalent to a
misconfiguration. I don't completely agree with this sentiment, but
the important thing to note is that LSM does provide all the
necessary hooks to prevent the techniques discussed. It should also
be noted that a system is not significantly less secure for having
an LSM setup which is affected by the presented methods, simply
because there are alternative ways to achieve the same results
without using LSM hooks.
We need to start by looking at how LSM works in a general sense. In
its technical essence LSM inserts a number of kernel level hooks in
order to provide the ability to check system call permissions.
These hooks are referenced off a globally defined pointer: "struct
security_operations *security_ops;". The security_operations
structure is defined in include/linux/security.h and is essentially
a series of predefined function pointers.
In order for an access control model to hook into the system a
security_operations structure must be registered with the LSM
function register_security(). The requesting module sets the
function pointer entries of the structure to the location of the
desired hook function, or NULL if the default hook is to be used.
The register_security() function simply points the security_ops
global to the security_operations structure passed as an argument.
The default security_operations structure points to a series of
dummy hook functions (which are the same dummy hook functions used
if register_security() finds a NULL function pointer):
c0327320 B security_ops
c0327340 B dummy_security_ops
(gdb) x/wx 0xc0327320
0xc0327320: 0xc0327340
The security_ops pointer and the hook functions it contains are the
focus of the redirection technqiues presented below. Given an
appropriately misconfigured system, the only barrier for a rootkit
is a check in register_security() that prevents more than one
security_operations structure from being registered. However, this
check was not designed to be a security measure and is thus trivial
to bypass. The actual reason for this check, LSM module "stacking",
is a significant point of contention in the design of LSM. Stacking
essentially means the functionality of having multiple LSM modules
is offloaded to the LSM modules themselves, and is an important
concept for a successful LSM rootkit.
Assuming that a system is appropriately misconfigured we are left
with three scenarios to consider in regards to the insertion of a
malicious LSM hook. Firstly, an LSM enabled kernel with module
support and no alternative access models registered. Secondly, an
LSM enabled kernel with module support and a previously registered
access model. Lastly, an LSM enabled kernel with a previously
registered access model and no module support (and thus no exported
symbols). The first scenario will not be covered here due to its
triviality: simply insert a module that registers a malicious
hooking function in the standard LSM manner.
So let us assume we have a kernel with both LSM and an LSM enabled
module. The only prerequisite for this technique is the ability to
use the init_module syscall. As mentioned previously, the only
problem we are faced with is the register_security() checks. To
circumvent these checks we simply need to modify the
security_operations structure of the currently registered module
directly. This is made relatively easy by the fact that the
security_ops pointer is an exported symbol (see
security/security.c).
The implementation of a local backdoor LKM using security_ops to
locate the currently registered structure is attached at the end of
this document (lsm_local.c). In practice the implementation
resembles the hook stacking discussed above. There is, however, a
significant chance that modules will be disabled, either by
configuration at compile time or by the use of linux capabilities,
specifically CAP_SYS_MODULE. In this circumstance a different
approach can be taken to achieve the same result as using the
exported security_ops pointer. In order to modify kernel memory we
have to use the /dev/kmem device.
Lets assume the worst, and state that the System.map file is
unavailable, meaning we have no knowledge of the location of the
system_ops pointer. In this circumstance we can use the sidt
technique [4] to find the location of one of the system calls that
contains an LSM hook, and then use opcode pattern matching to find
the reference to system_ops. This is made possible as the hooking
procedure is compiled inline to each of the hooked system calls. It
looks like this:
mov sys_op,%eax
call ref(%eax)
Where "sys_op" represents the location of the system_ops pointer
and "ref" is a reference to the appropriate function pointer within
the registered security_operations structure. A proof of concept
for this technique (lsmkmem_local.c) is attached at the end of this
document, providing backdoor functionality similar to the LKM
described above.
So it has been clearly established that under certain circumstances
we can use LSM hooks for some less than legitimate purpose. The
last thing that needs to be considered is the total effect that may
leveraged. The examples provided at the end of this document both
demonstrate covert local privilege escalation, but there is
potential to do much more. Firstly, if compiled with
CONFIG_SECURITY_NETWORK=y the attacker is given access to a series
of socket related hooks. It is possible to use one of these hooks,
socket_sock_rcv_skb, to remotely trigger an arbitrary execution
flow. The idea of pure kernel-space remote backdoors under Linux
has not received much attention in public research, but a number of
potential implementations have been discussed [5].
The final hook I'd like to mention, file_permission, can be used to
hide processes and files. This hook is called from readdir()'s VFS
layer handler. There are two techniques that may be applied to this
hook, the first of which is only relevant when hiding a procfs pid
directory. These pid directories are handled specially by the proc
filesystem function proc_pid_readdir() which fills the userspace
callback buffer with every pid in the task_struct list. Since the
file_permission hook is called before the VFS layer passes control
to this function we can not directly affect the contents of the
callback buffer. Fortunately, we can prevent a target pid from
being included in this buffer by abusing get_tid_list()'s error
checking:
if (pid_alive(task)) do {
int tid = task->pid;
...
tids[nr_tids] = tid;
nr_tids++;
...
} while ((task = next_thread(task)) != leader_task);
The get_tid_list() function is used by proc_pid_readdir() to
extract the list of pid's from the current task_struct. By
temporarily marking our target process as "stale" the pid_alive()
check will fail and our pid will be exempt from the callback
buffer. This technique is ideal for hiding a process, but hiding
regular files with the file_permission hook is unfortunately more
difficult. The solution for hiding regular files I present here is
only conceptual, it has not been tested.
The general idea is to intercept the "VFS to filesystem specific"
translation by examing vfs_readir()'s stack. This puts the
file_permission hook in charge of the translation, and allows the
hook to modify the userland callback buffer after it has been
filled. It should be possible to work backwards from the stack
pointer in the file_permission hook to the arguments passed to
vfs_readdir(), specifically the filldir_t function pointer and the
userland callback buffer. Our hook would then need to reference the
relevant readdir() operation from the file structure passed to it,
supplying the arguments lifted from vfs_readdir(). From there we
can remove the target file from the callback buffer.
However, there are a couple of problems to be overcome if this idea
were to be implemented. Firstly, the differentiation of a
file_permission hook from vfs_readdir() and a file_permission hook
in vfs_read/write(). In general this can be done by checking that
the type of the file structure passed to the hook is a directory,
but this is not always going to work (for instance, it is perfectly
legitimate to read from a directory). Secondly, we have to modify
the return location of our hook to prevent vfs_readdir() from
continuing with the filesystem specific reference that we have
already handled. There are two ways of doing this. The first is to
return directly to the original system call by lifting the saved
return address from vfs_readdir()'s stack. The second is to take
advantage of the code succeeding the file_permission hook:
if (res)
goto out;
...
out:
return res;
Unfortunately, it is not an option to return a non-zero res as that
would indicate a failure to the original system call. Instead, we
can advance our hook's saved return address past the comparison
operation to the near jump of the goto. This has the same effect as
returning directly to the original syscall, but is perhaps the
safer method of the two. If necessary we may have to adjust the
relevant status flags in the EFLAGS register.
It was always inevitable that the Linux Security Module would be
utilized in a less than honest way, so I don't think much of a
conclusion is in order. For a full list of LSM hooks consult
include/linux/security.h as there are many other potential targets
that have not been mentioned here. Finally, I'm going to save my
usual rhetoric on the hacking community for another day, but I
promise a return to my overly socratic style within the next half
year.
Phantasmal Phantasmagoria
[------------------------------------
[1] http://lsm.immunix.org/
[2] http://www.nsa.gov/selinux/
[3] http://www.rsbac.org/
[4] http://www.phrack.org/show.php?p=58&a=7
[5] http://www.phrack.org/show.php?p=61&a=13
[6] http://www.grsecurity.net/lsm.php
[7] http://www.rsbac.org/documentation/lsm.php
[------------------------------------
begin 644 irony.tar.gz
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
ET2_YW:JAAAIJJ*&&&FJHH88::JBAAAIJJ*&'T3^29G2F`"@`````
`
end
[------------------------------------
-----BEGIN PGP SIGNATURE-----
Note: This signature can be verified at https://www.hushtools.com/verify
Version: Hush 2.4
wkYEARECAAYFAkIlNgMACgkQImcz/hfgxg2dkQCfSE9n7cV5VoaUWWlgpgZ+eApsDk8A
n1md8ECuTcDX1W2vKaC2/NQKwp/g
=WISz
-----END PGP SIGNATURE-----
Concerned about your privacy? Follow this link to get
secure FREE email: http://www.hushmail.com/?l=2
Free, ultra-private instant messaging with Hush Messenger
http://www.hushmail.com/services-messenger?l=434
Promote security and make money with the Hushmail Affiliate Program:
http://www.hushmail.com/about-affiliate?l=427
Powered by blists - more mailing lists