ElasticSearch及Kibana的X-pack破解2

声明:本文仅作为学习交流,请勿用于商业用途,否则后果自负。如需使用黄金或白金版X-Pack请购买正版。

接上篇 http://fishboy.iteye.com/blog/2391750 ,该文章是采用自己生成RSA的公钥私钥来进行破解的。准备工作与前篇一致,只需要按照以下代码自己生成RSA密钥对,然后计算出签名数据即可

package com.uoquo.xpack.crack;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;

import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.CryptUtils;
import org.elasticsearch.license.License;
import org.elasticsearch.license.LicenseVerifier;

public class Crack {
    private static String KEY_FILE_PATH = ""; // 存放key的目录,为空时表示存放到编译的根目录下
    private static String path = "";// 运行时的绝对路径
    static {
        path = Crack.class.getResource("/").toString();
        path = path.replaceFirst("file:/", "") + KEY_FILE_PATH;
    }

    /**
     * 生成RSA密钥对
     */
    public static void generateKey() {
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();
        }
        // 初始化密钥对生成器,密钥大小为96-1024位
        keyPairGen.initialize(2048, new SecureRandom());
        // 生成密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 保存私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        byte[] prvData = CryptUtils.writeEncryptedPrivateKey(privateKey);
        save2File(prvData, "private.key");
        // 保存公钥
        RSAPublicKey  publicKey  = (RSAPublicKey)  keyPair.getPublic();
        byte[] pubData = CryptUtils.writeEncryptedPublicKey(publicKey);
        save2File(pubData, "public.key");
    }
    
    /**
     * 保存密钥到文件 
     */
    private static void save2File(byte[] data, String fileName) {
        try {
            FileOutputStream   fos = new FileOutputStream(path +"/"+ fileName);
            BufferedOutputStream oos = new BufferedOutputStream(fos);
            oos.write(data); // 写入文件
            oos.close();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 获取文件内容
     */
    private static byte[] read4File(String fileName) {
        try {
            InputStream is = Crack.class.getResourceAsStream(KEY_FILE_PATH +"/"+ fileName);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            Streams.copy(is, (OutputStream)out);
            byte[] bytes = out.toByteArray();
            return bytes;
        } catch (IOException ex) {
            throw new IllegalStateException(ex);
        }
    }

    /**
     * 数据签名
     */
    public static String signed(License license) {
        try {
            // 原始数据
            XContentBuilder   builder = XContentFactory.contentBuilder(XContentType.JSON);
            ToXContent.Params params  = new ToXContent.MapParams(Collections.singletonMap("license_spec_view", "true"));
            license.toXContent(builder, params);
            byte[] data = BytesReference.toBytes(builder.bytes());
            
            // RSA 签名对象
            PrivateKey key = CryptUtils.readEncryptedPrivateKey(read4File("private.key"));
            Signature  rsa = Signature.getInstance("SHA512withRSA");
            rsa.initSign(key);
            rsa.update(data);
            // 数字签名
            byte[] sigContent = rsa.sign();
            int contentLen = sigContent.length;
            // 公钥信息
            byte[] pubKeyData = read4File("public.key");
            byte[] sigHash = Base64.getEncoder().encode(pubKeyData);
            int hashLen = sigHash.length;
            // 随机数据
            byte[] magic = "1234567890123".getBytes();
            int magicLen = magic.length;
            // 签名数据拼接
            int capacity = 4*4 + magicLen + hashLen + contentLen;
            ByteBuffer byteBuffer = ByteBuffer.allocate(capacity);
            byteBuffer.putInt(license.version());
            byteBuffer.putInt(magicLen);
            byteBuffer.put(magic);
            byteBuffer.putInt(hashLen);
            byteBuffer.put(sigHash);
            byteBuffer.putInt(contentLen);
            byteBuffer.put(sigContent);
            // 最终签名数据
            return Base64.getEncoder().encodeToString(byteBuffer.array());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    /**
     * 签名校验
     */
    public static boolean verify(License license) {
        try {
            // 签名数据
            byte[] signed = Base64.getDecoder().decode(license.signature());
            ByteBuffer byteBuffer = ByteBuffer.wrap(signed);
            int version  = byteBuffer.getInt();
            
            int magicLen = byteBuffer.getInt();
            byte[] magic = new byte[magicLen];
            byteBuffer.get(magic);
            
            int hashLen = byteBuffer.getInt();
            byte[] sigHash = new byte[hashLen];
            byteBuffer.get(sigHash);
            
            int contentLen = byteBuffer.getInt();
            byte[] sigContent = new byte[contentLen];
            byteBuffer.get(sigContent);
            
            // 原始数据
            XContentBuilder   builder = XContentFactory.contentBuilder(XContentType.JSON);
            ToXContent.Params params  = new ToXContent.MapParams(Collections.singletonMap("license_spec_view", "true"));
            license.toXContent(builder, params);
            byte[] data = BytesReference.toBytes(builder.bytes());

            // RSA 校验对象
            byte[] pubKeyData = read4File("public.key");
            PublicKey key = CryptUtils.readEncryptedPublicKey(pubKeyData);
            Signature rsa = Signature.getInstance("SHA512withRSA");
            rsa.initVerify(key);
            rsa.update(data);

            // 校验
            return rsa.verify(sigContent) && Arrays.equals(Base64.getEncoder().encode(pubKeyData), sigHash);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } 
    }
    
    /**
     * license数据
     * @param sige
     * @return
     */
    public static License getLicense(String sige) {
        // 手动设置
        License.Builder builder = License.builder();
        builder.uid("fd2deee3-******-4fd959056bea");
        builder.type("platinum");// trial,basic,standard,gold,platinum
        builder.issueDate(1504051200000L);
        builder.expiryDate(1535673599999L);
        builder.issuedTo("hong king");
        builder.issuer("Web Form");
        builder.maxNodes(100);
        builder.startDate(1504051200000L);
        builder.signature(sige);
        // 以下三个字段不知道干啥的,可以不填
//        builder.version(1); // 默认为3
//        builder.subscriptionType("platinum");
//        builder.feature(feature);
        return builder.build();
    }
    
    public static void main(String[] args) {
        // 生成RSA密钥对
//        generateKey();
//        byte[] d1 = read4File("private.key");
//        System.out.println(d1.length);
//        byte[] d2 = read4File("public.key");
//        System.out.println(d2.length);
        
        // license对象
        License license = getLicense(null);
        System.out.println(license.toString());
        // 签名
        String sige = signed(license);
        System.out.println(sige);
        System.out.println(sige.length());
//        // 将签名数据放到license中
        license = getLicense(sige);
        System.out.println(license.toString());
        // 校验
        boolean flag = verify(license);
        System.out.println(flag);
        
        // 用x-pack自身的校验方法校验,此时public.key需要放到src的根目录下
        flag = LicenseVerifier.verifyLicense(license);
        System.out.println(flag);
    }
}

 在eclipse中创建一个java项目,lib包中引入x-pack的所有包,以及elasticsearch安装后的lib/elasticsearch-5.4.3.jar包,然后运行即可。

1. 修改getLicense中的相关数据

2.去掉main中generateKey();前面的注释,用于生成自己的RSA密钥对

3.将生成的pulic.key打包覆盖到x-pack-5.4.3.jar中,将控制台输出的license数据“{"uid":.....}”复制后,新建一个license.json文件,内容如下:

{"license":
  {"uid":......} // 控制台输出的uid那整行信息
}

4. 上传x-pack-5.4.3.jar和license.json

5.启动ES,执行更新license命令。

  注:如果也抛出空指针异常,则采用前一篇文章中的方法,更新XPackBuild.class即可

采用这种方式,可以不用改动前端kibana,也可以方便控制版本及年限,对原包改动最小。

猜你喜欢

转载自fishboy.iteye.com/blog/2392060