为什么setuid 调用systemphp 函数调用有漏洞

1374人阅读
SystemServer进程名称为System_Server,在一文中介绍了zygote进程通过startSystemServer函数调用将启动一个SystemServer子进程:
创建该进程的核心是通过调用forkSystemServer函数来完成的,这是应该native函数
在dalvik_system_Zygote.c文件中实现:
新创建的进程会执行handleSystemServerProcess函数,来完成自己的使命。
由于由Zygote进程创建的子进程会继承Zygote进程在前面创建的Socket文件描述符,而这里的子进程又不会用到它,因此,这里就调用closeServerSocket函数来关闭它。这个函数接着调用RuntimeInit.zygoteInit函数来进一步执行启动SystemServer组件的操作。
RuntimeInit.java&&
这个函数会执行两个操作:
一个是调用zygoteInitNative函数来执行一个Binder进程间通信机制的初始化工作;
一个是调用com.android.server.SystemServer类的main函数;
由于SystemServer 是由zygote fork出来,因此它也拥有zygote进程中的gCurRuntime,也就是AppRuntime
因此通过调用zygoteInitNative函数,将建立Binder通信。
调用invokeStaticMain函数:
抛出的MethodAndArgsCaller异常会在ZygoteInit.java 中的main函数捕获:
SystemServer.java
抛出MethodAndArgsCaller异常会导致com.android.server.SystemServer类的main函数被调用。为什么采用这种方式来调用呢,读者可以自行研究!
com_android_server_SystemServer.cpp
System_init.cpp
这里的main函数首先会执行JNI方法init1,然后init1会调用这里的init2函数,在init2函数里面,会创建一个ServerThread线程对象来执行一些系统关键服务的启动操作:
init2只是简单创建一个线程,在该ServerThread线程中启动各种系统服务:
在run函数中启动Java中的各种Service。至此SystemServer进程启动过程分析完毕!启动过程序列图如下所示:
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:168794次
积分:2562
积分:2562
排名:第7058名
原创:54篇
转载:240篇
评论:15条
(9)(1)(4)(2)(2)(6)(8)(7)(4)(5)(1)(1)(7)(3)(5)(2)(1)(1)(2)(6)(7)(4)(1)(3)(14)(56)(33)(18)(21)(14)(9)(30)(7)扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
【原创】Android adb setuid提权漏洞的分析
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口Android adb setuid提权漏洞的分析 | i, Claud | 第3页
去年的Android adb setuid提权漏洞被用于各类root刷机,漏洞发现人公布的利用工具RageAgainstTheCage(rageagainstthecage-arm5.bin)被用于z4root等提权工具、Trojan.Android.Rootcager等恶意代码之中。下面我们来分析这一漏洞的产生原因。
The Android Exploid Crew小组在后来发布了一份PoC代码:。从这份代码开始着手。
在main(:72)函数中,首先获取了RLIMIT_NPROC的值(:83),这个值是Linux内核中定义的每个用户可以运行的最大进程数。
然后,调用find_adb()函数(:94)来搜索Android系统中adb进程的PID,具体而言,该函数读取每个进程对应的文件的/proc/&pid&/cmdline,根据其是否等于”/sbin/adb”来判断是否adb进程。
接下来,fork了一个新的进程(:109),父进程退出,而子进程继续。接下来,在113行创建一个管道。
if (fork() & 0)
pipe(pepe);
重头戏发生在下面的122到138行,代码如下:
if (fork() == 0) {
close(pepe[0]);
for (;;) {
if ((p = fork()) == 0) {
} else if (p & 0) {
if (new_pids) {
printf(&\n[+] Forked %d childs.\n&, pids);
new_pids = 0;
write(pepe[1], &c, 1);
close(pepe[1]);
新建一个进程后,在子进程之中,exploit代码不断地fork()(:125),而新的子进程不断退出,从而产生大量的僵尸进程(占据shell用户的进程数)。最终,进程数达到上限,fork()返回小于0,于是打印当前已经创建多少子进程,并向管道输入一个字符(:131)。
在这里,管道的作用是和(:122)fork出来的父进程同步,该进程在141行read这一管道,因而阻塞直至僵尸进程已经达到上限(:131)。
进一步的,exploit杀掉adb进程,并在系统检测到这一现象并重启一个adb之前,再一次fork(),将前一个adb留下的进程空位占据。最后,在152行,exploit调用wait_for_root_adb(),等待系统重启一个adb,这个新建的adb就会具有root权限。
为什么在shell用户的进程数达到上限RLIMIT_NPROC以后,新建的adb会具有root权限?我们来看adb的源码。
在&android_src&/system/core/adb/adb.c的第918行,我们可以看到如下代码:
/* then switch user and group to &shell& */
if (setgid(AID_SHELL) != 0) {
if (setuid(AID_SHELL) != 0) {
这已经是漏洞修补以后的代码。在漏洞最初被发现时,代码如下:
/* then switch user and group to &shell& */
setgid(AID_SHELL);
setuid(AID_SHELL);
简而言之,原来没有检查setuid()函数的返回值。事实上,在此之前,adb.c中的代码都是以root权限运行,以完成部分初始化工作。在这一行,通过调用setuid()将用户从root切换回shell,但setuid()在shell用户进程数达到上限RLIMIT_NPROC时,会失败,因此adb.c继续以root身份运行,而没有报错。
我们来看setuid()的man手册(man 2 setuid),其中有如下说明:
RETURN VALUE
zero is returned.
On error, -1 is returned, and errno is
set appropriately.
EAGAIN The uid does not match the current uid and
over its RLIMIT_NPROC resource limit.
可以看到,setuid是可能发生错误的,并且在uid的进程数超过RLIMIT_NPROC极限时,发生EAGAIN错误。
在android的源码中,setuid()定义于&android_src&/bionic/libc/unistd/setuid.c,实际上引用了一个外部符号__setuid,这个符号在&android_src&/bionic/libc/arch_xxx/syscalls/__setuid.S中定义,最终是一个%eax=$__NR_setuid32,%ebx=uid的int 0×80中断。
因为只是要分析原理,我们不再鏖战于Android,转而看向Linux内核。
在最新的kernel2.6中,setuid()位于kernel/sys.c的682行,其中,在697行,一切正常的情况下,它会调用set_user()来完成用户切换。
set_user()实现于同一文件的587行,其中一部分代码如下:
if (atomic_read(&new_user-&processes) &= rlimit(RLIMIT_NPROC) &&
new_user != INIT_USER) {
free_uid(new_user);
return -EAGAIN;
含义很明显,当目标用户的进程数达到上限,那系统就不能再将一个进程分配给它,因而返回-EAGEIN。然后再setuid()中,直接跳过后面的代码,而返回错误。
至此,整个漏洞的原理已经分析完毕。整理如下:
1、在Android的shell用户下,制造大量的僵尸进程,直至达到shell用户的进程数上限RLIMIT_NPROC;
2、kill当前系统中的adb进程,并再次占据其进程位置以保持达到上限;
3、系统会在一段时间后重启一个adb进程,该进程最初是root用户,在完成少许初始化工作后,调用setuid()切换至shell用户;
4、此时shell用户的进程数已经达到上限,所以setuid()失败,返回-1,并且用户更换没有完成,adb还是root权限;
5、adb没有检查setuid()的返回值,继续后续的工作,因此产生了一个具有root权限的adb进程,可以被用于与用户的下一步交互。
实际上,setuid在目标用户进程数达到RLIMIT_NPROC极限时返回错误,这一问题可能产生的安全隐患最早可以追溯到。而在2006年,出现了真正利用这一编码问题的漏洞()。
因此,这并不是一个全新的漏洞。我们可以得出几点结论:
1、函数返回值一直是忽略的对象,因为getuid()永远不会失败,程序员可能会认为setuid()也不会失败——至少没有遇到过,因此忽略了对返回值的检查。检查一个系统函数是否调用失败是一个常识,但又是很麻烦的事,如果为了省事而忽略,问题就可能产生了。
2、Android下的安全问题,很多并非全新的,而且个人判断将来还会有大量漏洞、恶意代码产生于传统思路,而作用于新的平台。面对这一新的平台,我们是否能抢先于攻击者做好防范准备,是一个需要我们思考和实践的问题。
本条目发布于。属于分类。作者是。
老博客“格物致知”的存档在。ARM Exploitation | WooYun知识库
ARM Exploitation
原文:Learning Pentesting for Android Devices
本文主要带大家了解ARM处理器的基础知识和ARM世界中不同种类的漏洞.我们会进一步分析这些漏洞来搞清楚它的具体利用场景.此外,我们还会研究不同的安卓rooting利用脚本用于挖掘潜在的漏洞.考虑大世面上大多数android智能手机都是基于ARM架构处理器,因此了解ARM以及ARM中存在的安全隐患是非常有价值的.
0x01 Introduction to ARM architecture
ARM架构基于精简指令集(Reduced Instruction Set Computing ),这意味着它具有比基于复杂指令集(Complex Instruction Set Computing)少得多的指令架构.使用ARM处理器的设备几乎无处不在,比如智能手机,电视,电子书,嵌入式设备等等.
ARM共有16个通用寄存器从R0到R15.(R0-R7,8个通用寄存器)其中5个有特?殊意义:
R11: Frame Pointer (FP)
R12: 内部过程调用暂时寄存器 Intra-procedure Register (IP)
R13: 栈指针 Stack Pointer (SP)
R14: 链接寄存器 Link Register (LR)
R15: 程序计数器 Program Counter (PC)
下图显示了ARM架构:
这五个寄存器中我们应重点关注如下三个:
栈指针 Stack Pointer (SP-R13):存储栈顶指针
链接寄存器 Link Register (LR-R14):存储被调用函数返回地址
程序计数器 Program Counter (PC-R15):存储着下一条执行指令的地址.每条执行被执行后,该计数器会进行自增.
0x02 Execution modes
ARM有两种执行模式:
ARM 模式: In the ARM mode, 32位指令集
Thumb 模式: In the Thumb mode, 16位指令集
执行模式取决于程序状态寄存器(CPSR)的状态.其实存在第三种模式: Thumb-2模式,就是将arm模式和Thumb模式混合.我们不会去分析这两种模式的区别,因为这样就超出本文的范围了.即使是Android SDK中的模拟器也是arm平台的,其他大多数的智能手机也是基于arm.但是我们还是选择从开源硬件模拟器开始进行ARM exploitation的训练.
0x03 Setting up the environment
在我们开始基于ARM平台设备的exploiting前建议先安装好对应的环境.尽管Android SDK的模拟器也能基于arm运行,而且大多数的智能手机也是基于arm.我们还是选择用QEMU(开源硬件虚拟机和模拟器)开始ARM exploitation.
为了在android设备上执行接下来的操作,我们需要下载和配置Android NDK环境.如果你正使用Mac,那么安装QEMU是非常简单的,只需要输入:brew install qemu
如果系统是Ubuntu需要执行如下操作:
1.第一步下载安装QEMU依赖包
sudo apt-get build-dep qemu
wget http://wiki.qemu-project.org/download/qemu-
1.7.0.tar.bz2
2.下一步配置QEMU,指定目标为ARM最后make.只需要进入解压后的目录输入如下命令.
./configure --target-list=arm-softmmu
make && make install
3.一但QEMU安装成功,我们就可以下载ARM平台的Debian镜像运行exploitation习题.下载列表:
4.这里我们下载格式为qcow2的镜像,debian_squeeze_armel_ standard是基于QUME的系统镜像.qcow2 for our OS.内核文件是 vmlinuz-2.6.32- 5-versatile ,RAM磁盘文件是initrd.img-2.6.32-5- versatile.下载完必须文件后就可以通过以下指令启动QEMU实例.
qemu-system-arm -M versatilepb -kernel vmlinuz-2.6.32-5-versatile -initrd initrd.img-2.6.32-5-versatile -hda debian_squeeze_armel_standard.qcow2 -append "root=/dev/sda1" --redir tcp:2222::22
5.上述所有操作成功就可以通过以下命令ssh登录QEMU:
ssh root@[ip address of Qemu] -p 2222
6.默认帐号密码是root:root.
到此我们已经成功配置好环境,是时候开始exploiting存在漏洞的应用
0x04 Simple stack-based buffer overflow
简单来讲,缓存(buffer)是用于存储任意数据的地方.当缓存的数据超过了缓存区的大小就会发生溢出(overflow).攻击者可以利用溢出攻击来控制程序执行恶意代码.
下面就用一个简单的程序来演示如何利用溢出攻击.下图中显示程序有三个函数:vulnerable, ShouldNotBeCalled以及 main.
执行程序的时候函数 ShouldNotBeCalled 一直没有被调用.
函数vulnerable只有一个操作就是将成员变量拷贝到只有10bytes大小的缓存buff中.
写完此程序后通过gcc编译(arm虚拟机中编译).此外我们还将禁用空间格局随机化Address Space Layout Randomization (ASLR)让利用场景变得更简单些.ASLR是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的.据研究表明ASLR可以有效的降低缓冲区溢出攻击的成功率,如今Linux、FreeBSD、Windows等主流操作系统都已采用了该技术.Android 4.0之后也实现了该方案.
echo 0 & /proc/sys/kernel/randomize_va_space //禁用ASLR
gcc -g buffer_overflow.c -o buffer_overflow
//编译example
下一步,用gdb调试二进制文件.
gdb -q buffer_overflow
使用disass命令反编译一部分函数,下图为反编译ShouldNotBeCalled
正如截图中说看到的,函数ShouldNotBeCalled从内存地址0x开始.如果我们查看反编译的main函数,将会发现vulnerable函数是从0x开始调用,在0x返回.当程序进入存在漏洞的函数,使用有漏洞的指令strcpy,函数并不会检查拷贝字符串的大小.如果程序进入存在漏洞的子程序,我们就能够通过控制LR控制整个程序流程.
这里目标是估算LR何时被重写之后插入ShouldNotBeCalled地址来调用函数ShouldNotBeCalled.用一个较长的参数运行程序,比如下面的命令,观察发生了啥.在此之前先在调用strcpy地址处设置断点.
b vulnerable
b *&address of the strcpy call&
通过设置断点,我们可以将参数改成AAAABBBBCCCC运行程序观察他如何被覆盖.观察发现在vulnerable和strcpy函数被调用时触发断点.一但断点触发,我们就可以通过x命令指定sp操作堆栈.如下图
如图所示,堆栈已经被我们输入(ASCII: 41 for A, 42 for B, and so on)的buffer重写.分析截图,发现0x这种情况我们需要多于4个字节去覆盖返回地址.
最终输入的字符串为16字节的垃圾数据和函数ShouldNotBeCalled的地址
r `printf "AAAABBBBCCCCDDDD\x38\x84"`
如图所示,我们将IShouldNeverBeCalled起始地址插入参数中
请注意,因为框架原因这里字节顺序是相反的.这样就能看到程序调用函数ShouldNotBeCalled了.如下图
0x05 Return-oriented programming
大多数情况下,我们并不需要调用程序自身的其他函数.相反,我们需要在攻击向量中插入shellcode,这样就可以通过shellcode达到任意目的.但是,再大多数基于arm平台的设备中内存区域是不可执行的,这样就阻止了我们插入和执行shellcode.
所以,攻击者必须依赖一项技术返回导向编程 return-oriented programming .所谓ROP,简单的说就是把原来内存已经存在的代码块拼接起来,拼接的方式是通过一个预先准备好的特殊的返回栈,里面包含了各条指令结束后下一条指令的地址.最终执行我的shellcode.在一般程序里面,都包含着大量的返回指令(ret),他们基本位于函数的尾部,或是函数中部需要返回的地方.而从函数开始的地方到ret指令之间的这一段序列称为二进制指令代码块(gadgets).我们需要在整个内存空间中搜索我们需要的gadgets
举个例子,如果我们在调试程序的时候反编译seed48(),得到如下输出:
分析反编译代码,代码包含一个ADD指令接着是POP和BX指令,这就是完美的 ROP gadget.这里攻击者可以想到为了利用 ROP gadget 首先跳到POP指令控制R4(which will be six less than the address of /bin/sh)之后在LR中输入ADD指令的值.最后我们得到 /bin/sh 的地址,当我们跳会ADD (R0 = R4 + 6 ),之后我们可以在R4中指定任意垃圾数据以及LR中指定 system() 的地址.
这意味着我们最终讲跳到 system() 并且参数为 /bin/sh , 这样就可以执行shell命令了.用同样的方式,我们可以创建任意ROP gadget 来达到执行任意命令的效果.因为ROP是个非常复杂的话题,强烈建议自己动手尝试分析反编译代码,然后构造exploit.
0x06 Android root exploits
在早期android版本中,各种android版本的各种设备都遇到Android root exploits .Android rooting就是获取设备的最高权限而不是手机制造厂商给用户的默认权限.这些root exploits利用了各种Android系统漏洞.下面是一些漏洞列表和漏洞原理简介:
Exploid: CVE- 影响android2.1及之前版本,此exploit基于udev漏洞CVE-,udev是一个android组件负责USB连接,进程应该只处理kernel发送的device的NETLINK的socket消息,但实际上并未检测NETLINK的socket消息的来源,这样可以广播add device的socket信息,触发硬件处理事件,将恶意代码传入kernel,由其写入设备文件.这样,攻击者只需发送一条构造好的udev消息就可以提权了.
Gingerbreak:CVE-,此exploit利用vold的漏洞,原理类似上一个.(android并没有实现linux的udev,其功能由vold进程实现,其包含VolumeManager,NetlinkManager,CommandListener等modules).Android 2.3.4之前版本的 volume 守护进程(vold)由于信任从 PF_NETLINK socket 接收到的消息,因此允许以 root 权限执行任意代码,利用方法是通过一个负数索引绕过指针对最大值的有符号整数检查.
RageAgainstTheCage:此exploit基于RLIMIT_NPROC,RLIMIT_NPROC用于指定用户调用setuid()函数的时候能创建的最大进程数.adb 后台是root权限,之后会调用 setuid() 自行降权.android 2.2 以及之前版本如果进程数达到RLIMIT_NPROC的阈值,程序就不会调用setuid()降权,这样adb就会以root权限运行了.
Zimperlich:与RageAgainstTheCage原理类似,不一样的是此处依赖的zygote进程的降权.所有的android应用是由Zygote进程fork分支后启动的.Zygote是由root权限运行的.在fork之后新的进程将使用setuid调用降权至目标应用的uid.Android2.2以及之前版本的Zygote没有对降权时setuid调用的返回值进行检查.同样,在耗尽目标程序uid的最大进程数之后,Zygote就无法降低它的权限,然后就以root权限启动应用了.
KillingInTheNameOf: CVE- 此expolit利用了ashmem (the shared memory manager) 接口漏洞,用于修改ro.secure的值,ro.secure决定了设备的root状态.Android 的共享内存(Ashmem)子系统是一个共享内存分配器.共享内存可以通过 mmap 或者文件 I/O 进行访问.在android 2.3之前,ashmem 允许任何用户重新映射属于 init 进程的共享内存,将包括系统属性地地址空间的内存进行共享,KillingInTheNameOf 利用程序将系统属性空间重新映射为可写,并将 ro.secure 属性设置为0.在重启 adbd 后,ro.secure 属性的修改会允许 adb shell 取得 root 权限访问.
这些都是比较出名的用户root安卓设备的exploits.
数据处理指令-指令编码
操作码功能表
分支指令B/BL-指令编码
分支指令BX-指令编码
分支指令功能表
B 跳转指令。
BL 带返回的跳转指令。
BLX 带返回和状态切换的跳转指令。
BX 带状态切换的跳转指令。
数据处理指令
MOV 数据传送指令
MVN 数据取反传送指令
CMP 比较指令
CMN 反值比较指令
TST 位测试指令
TEQ 相等测试指令
ADD 加法指令28
ADC 带进位加法指令
SUB 减法指令
SBC 带借位减法指令
SUB 减法指令
SBC 带借位减法指令
RSB 逆向减法指令
RSC 带借位的逆向减法指令
AND 逻辑与指令
ORR 逻辑或指令
EOR 逻辑异或指令
BIC 位清除指令
乘法指令与乘加指令
MUL 32 位乘法指令
MLA 32 位乘加指令
SMULL 64 位有符号数乘法指令
SMLAL 64 位有符号数乘加指令
UMULL 64 位无符号数乘法指令
UMLAL 64 位无符号数乘加指令
程序状态寄存器存取指令
MRS 程序状态寄存器到通用寄存器的数据传送指令。
MSR 通用寄存器到程序状态寄存器的数据传送指令。
寄存器加载/存储指令
LDR 字数据加载指令
LDRB 字节数据加载指令
LDRH 半字数据加载指令
STR 字数据存储指令
STRB 字节数据存储指令
STRH 半字数据存储指令
LDM 连续数据加载指令
STM 连续数据存储指令
数据交换指令 :
SWP 字数据交换指令
SWPB 字节数据交换指令
移位元指令:
LSL 逻辑左移
ASL 算术左移
LSR 逻辑右移
ASR 算术右移
ROR 循环右移
RRX 带扩充的循环右移
协处理器指令
CDP 协处理器数据操作指令
LDC 协处理器数据加载指令
STC 协处理器数据存储指令
MCR ARM处理器寄存器到协处理器寄存器的数据传送指令
MRC 协处理器寄存器到ARM处理器寄存器的数据传送指令
arm架构完整版
@瘦蛟舞 你老板让你赶快掏干货,再不写,就让你捡肥皂……
@我是壮丁 我就不写,我就 BB
@error 快来写啊
表示没有干货
感谢知乎授权页面模版

我要回帖

更多关于 调用iframe中的函数 的文章

 

随机推荐