声明:本文仅作为学习交流,请勿用于商业用途,否则后果自负。如需使用黄金或白金版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,也可以方便控制版本及年限,对原包改动最小。