MyException - 我的异常网
当前位置:我的异常网» 互联网 » ElasticSearch及Kibana的X-pack破译

ElasticSearch及Kibana的X-pack破译

www.MyException.Cn  网友分享于:2013-09-10  浏览:0次
ElasticSearch及Kibana的X-pack破解

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

 

文章采用的ELK版本为5.4.3,其他版本没有做过验证。本文参考了博文http://blog.csdn.net/u013066244/article/details/73927756的破解方法,并解决了破解后空指针问题。

 

首先需要正常安装Kibana 5.4.3和ElasticSearch 5.4.3及其x-pack组件。

 

ElasticSearch 破解步骤如下:

1.下载ElasticSearch 目录中的/plugins/x-pack/x-pack-5.4.3.jar,并反编译。

    注:此处要用 Luyten 来进行反编译,jd-gui有些文件反编译不出来。

主要需要反编译的两个文件:

org/elasticsearch/license/LicenseVerifier.class
org/elasticsearch/xpack/XPackBuild.class

反编译后,将这两个文件做如下修改,并保存问java文件。

 

LicenseVerifier.java,跳过校验部分,直接返回true

package org.elasticsearch.license;

public class LicenseVerifier
{
    public static boolean verifyLicense(final License license, final byte[] array) {
        return true;
    }
    
    public static boolean verifyLicense(final License license) {
        return true;
    }
} 

 

XPackBuild.java,主要修改static部分,获取hash和date,这两个值需要跟“curl XGET ${es_host}/_xpack”这个命令执行结果中的build的值一样,如果有需要,可以直接sysout输出到控制台,然后update到es中

package org.elasticsearch.xpack;

import org.elasticsearch.common.io.*;
import java.net.*;
import org.elasticsearch.common.*;
import java.nio.file.*;
import java.io.*;
import java.util.jar.*;

public class XPackBuild
{
    public static final XPackBuild CURRENT;
    private String shortHash;
    private String date;
    
    @SuppressForbidden(reason = "looks up path of xpack.jar directly")
    static Path getElasticsearchCodebase() {
        final URL url = XPackBuild.class.getProtectionDomain().getCodeSource().getLocation();
        try {
            return PathUtils.get(url.toURI());
        }
        catch (URISyntaxException bogus) {
            throw new RuntimeException(bogus);
        }
    }
    
    XPackBuild(final String shortHash, final String date) {
        this.shortHash = shortHash;
        this.date = date;
    }
    
    public String shortHash() {
        return this.shortHash;
    }
    
    public String date() {
        return this.date;
    }
    
    static {
        final Path path = getElasticsearchCodebase();
        String shortHash = null;
        String date = null;
        if (path.toString().endsWith(".jar")) {
            try {
//                JarInputStream jar = new JarInputStream(Files.newInputStream(path));
                JarFile jar = new JarFile(path.toString());
                Manifest manifest = jar.getManifest();
                shortHash = manifest.getMainAttributes().getValue("Change");
                date = manifest.getMainAttributes().getValue("Build-Date");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            shortHash = "Unknown";
            date = "Unknown";
        }
        // System.out.println("hash:"+ shortHash);
        // System.out.println("date:"+ date);
        CURRENT = new XPackBuild(shortHash, date);
    }
}

 

2. 将这两个java上传到服务器中,进行javac编译,我的es安装路径:/usr/local/elastic/elasticsearch-node1,以下用${es_dir}代替

javac -cp "${es_dir}/lib/elasticsearch-5.4.3.jar:${es_dir}/lib/lucene-core-6.5.1.jar:${es_dir}/plugins/x-pack/x-pack-5.4.3.jar" LicenseVerifier.java

javac -cp "${es_dir}/lib/elasticsearch-5.4.3.jar:${es_dir}/lib/lucene-core-6.5.1.jar:${es_dir}/plugins/x-pack/x-pack-5.4.3.jar" XPackBuild.java

 

3. 将编译好的两个class下载到本地,用压缩工具将其打包覆盖到x-pack-5.4.3.jar中。

 

4. 将修改好的x-pack-5.4.3.jar上传到${es_host}/plugins/x-pack/中,将原来的覆盖掉,如果是集群,则每个节点都需要覆盖。

 

5. 更新之后,启动ES。

 

6. 去官网申请license,将得到一个类似如下json格式的文件

{
  "license": {
    "uid": "fd2deee3-*****-4fd959056bea", 
    "type": "platinum", 
    "issue_date_in_millis": 1504051200000, 
    "expiry_date_in_millis": 1598922000000, 
    "max_nodes": 100, 
    "issued_to": "hong king", 
    "issuer": "Web Form", 
    "signature": "AAAAAwAAA.......N长的一串.......zdGJHVbnD3yd", 
    "start_date_in_millis": 1504051200000
  }
}

   将其中的type修改为“platinum”,过期时间(expiry_date_in_millis)随便设置一个将来的日期,其他数据视实际情况修改。将文件保存为license.json

 

7. 将license.json文件上传到服务器,并执行以下命令

curl -XPUT -u elastic:changeme 'http://192.168.1.115:9200/_xpack/license' -d @license.json

    注:如果有多个节点,则每个节点都需要按这个命令进行license更新

 

8. 再次重启ES就OK了。

 

Kibana的破解:

如果这端不做修改,目前也没有问题,不过我不知道在expiry_date_in_millis时间之后会不会有什么问题,为了保险起见可以按如下步骤处理。

 

1. 修改${kibana}/plugins/x-pack/server/lib/_xpack_info.js文件,将其中需要验证的函数方法都返回true,修改后的文件如下

import { createHash } from 'crypto';
import moment from 'moment';
import { get, set, includes, forIn } from 'lodash';
import Poller from './poller';
import { LICENSE_EXPIRY_SOON_DURATION_IN_DAYS } from './constants';

export default function _xpackInfo(server, pollFrequencyInMillis, clusterSource = 'data') {
  if(!pollFrequencyInMillis) {
    const config = server.config();
    pollFrequencyInMillis = config.get('xpack.xpack_main.xpack_api_polling_frequency_millis');
  }

  let _cachedResponseFromElasticsearch;

  const _licenseCheckResultsGenerators = {};
  const _licenseCheckResults = {};
  let _cachedXPackInfoJSON;
  let _cachedXPackInfoJSONSignature;

  const poller = new Poller({
    functionToPoll: _callElasticsearchXPackAPI,
    successFunction: _handleResponseFromElasticsearch,
    errorFunction: _handleErrorFromElasticsearch,
    pollFrequencyInMillis,
    continuePollingOnError: true
  });

  const xpackInfoObject = {
    license: {
      getUid: function () {
        return get(_cachedResponseFromElasticsearch, 'license.uid');
      },
      isActive: function () {
        // return get(_cachedResponseFromElasticsearch, 'license.status') === 'active';
        return true;
      },
      expiresSoon: function () {
        // const expiryDateMillis = get(_cachedResponseFromElasticsearch, 'license.expiry_date_in_millis');
        // const expirySoonDate = moment.utc(expiryDateMillis).subtract(moment.duration(LICENSE_EXPIRY_SOON_DURATION_IN_DAYS, 'days'));
        // return moment.utc().isAfter(expirySoonDate);
        return false;
      },
      getExpiryDateInMillis: function () {
        return get(_cachedResponseFromElasticsearch, 'license.expiry_date_in_millis');
      },
      isOneOf: function (candidateLicenses) {
        if (!Array.isArray(candidateLicenses)) {
          candidateLicenses = [ candidateLicenses ];
        }
        return includes(candidateLicenses, get(_cachedResponseFromElasticsearch, 'license.mode'));
      },
      getType: function () {
        return get(_cachedResponseFromElasticsearch, 'license.type');
      }
    },
    feature: function (feature) {
      return {
        isAvailable: function () {
          // return get(_cachedResponseFromElasticsearch, 'features.' + feature + '.available');
          return true;
        },
        isEnabled: function () {
          // return get(_cachedResponseFromElasticsearch, 'features.' + feature + '.enabled');
          return true;
        },
        registerLicenseCheckResultsGenerator: function (generator) {
          _licenseCheckResultsGenerators[feature] = generator;
          _updateXPackInfoJSON();
        },
        getLicenseCheckResults: function () {
          return _licenseCheckResults[feature];
        }
      };
    },
    isAvailable: function () {
      // return !!_cachedResponseFromElasticsearch && !!get(_cachedResponseFromElasticsearch, 'license');
      return true;
    },
    getSignature: function () {
      return _cachedXPackInfoJSONSignature;
    },
    refreshNow: function () {
      const self = this;
      return _callElasticsearchXPackAPI()
      .then(_handleResponseFromElasticsearch)
      .catch(_handleErrorFromElasticsearch)
      .then(() => self);
    },
    stopPolling: function () {
      // This method exists primarily for unit testing
      poller.stop();
    },
    toJSON: function () {
      return _cachedXPackInfoJSON;
    }
  };

  const cluster = server.plugins.elasticsearch.getCluster(clusterSource);

  function _callElasticsearchXPackAPI() {
    server.log([ 'license', 'debug', 'xpack' ], 'Calling Elasticsearch _xpack API');
    return cluster.callWithInternalUser('transport.request', {
      method: 'GET',
      path: '/_xpack'
    });
  };

  function _updateXPackInfoJSON() {
    const json = {};

    // Set response elements common to all features
    set(json, 'license.type', xpackInfoObject.license.getType());
    set(json, 'license.isActive', xpackInfoObject.license.isActive());
    set(json, 'license.expiryDateInMillis', xpackInfoObject.license.getExpiryDateInMillis());

    // Set response elements specific to each feature. To do this,
    // call the license check results generator for each feature, passing them
    // the xpack info object
    forIn(_licenseCheckResultsGenerators, (generator, feature) => {
      _licenseCheckResults[feature] = generator(xpackInfoObject); // return value expected to be a dictionary object
    });
    set(json, 'features', _licenseCheckResults);

    _cachedXPackInfoJSON = json;
    _cachedXPackInfoJSONSignature = createHash('md5')
    .update(JSON.stringify(json))
    .digest('hex');
  }

  function _hasLicenseInfoFromElasticsearchChanged(response) {
    const cachedResponse = _cachedResponseFromElasticsearch;
    return (get(response, 'license.mode') !== get(cachedResponse, 'license.mode')
      || get(response, 'license.status') !== get(cachedResponse, 'license.status')
      || get(response, 'license.expiry_date_in_millis') !== get(cachedResponse, 'license.expiry_date_in_millis'));
  }

  function _getLicenseInfoForLog(response) {
    const mode = get(response, 'license.mode');
    const status = get(response, 'license.status');
    const expiryDateInMillis = get(response, 'license.expiry_date_in_millis');

    return [
      'mode: ' + mode,
      'status: ' + status,
      'expiry date: ' + moment(expiryDateInMillis, 'x').format()
    ].join(' | ');
  }

  function _handleResponseFromElasticsearch(response) {

    if (_hasLicenseInfoFromElasticsearchChanged(response)) {
      let changed = '';
      if (_cachedResponseFromElasticsearch) {
        changed = 'changed ';
      }

      const licenseInfo = _getLicenseInfoForLog(response);
      const logMessage = `Imported ${changed}license information from Elasticsearch for [${clusterSource}] cluster: ${licenseInfo}`;
      server.log([ 'license', 'info', 'xpack'  ], logMessage);
    }

    _cachedResponseFromElasticsearch = response;
    _updateXPackInfoJSON();
  }

  function _handleErrorFromElasticsearch(error) {
    server.log([ 'license', 'warning', 'xpack' ], 'License information could not be obtained from Elasticsearch. ' + error);
    _cachedResponseFromElasticsearch = null;
    _updateXPackInfoJSON();

    // allow tests to shutdown
    error.info = xpackInfoObject;

    throw error;
  }

  // Start polling for changes
  return poller.start()
  .then(() => xpackInfoObject);
}

 

2. 删除${kibana}/optimize下的所有编译文件

 

 3. 启动kibana

 

完工,附件为破解后的jar包和license文件。

 

补充:另一破解思路是,自己生成RSA的公钥私钥,然后按照 LicenseVerifier里的验证方法,自己写一个加密方法计算license.signature,然后替换jar中的public.key,上传后,再导入license.json,该方法没有验证,等后期验证完再详细说明。

 

在整个破解过程中,在按照参考博文进行破解时也碰到空指针错误,经排查是XPackBuild用JarInputStream读取jar包后,获取不到Manifest 对象,所以改用JarFile来读取jar包文件。

参考链接:http://blog.csdn.net/u013066244/article/details/73927756

 

 

 

 

文章评论

看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
编程语言是女人
编程语言是女人
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
每天工作4小时的程序员
每天工作4小时的程序员
中美印日四国程序员比较
中美印日四国程序员比较
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
一个程序员的时间管理
一个程序员的时间管理
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
10个调试和排错的小建议
10个调试和排错的小建议
程序员和编码员之间的区别
程序员和编码员之间的区别
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
程序员必看的十大电影
程序员必看的十大电影
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
老程序员的下场
老程序员的下场
我的丈夫是个程序员
我的丈夫是个程序员
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
代码女神横空出世
代码女神横空出世
程序员的鄙视链
程序员的鄙视链
旅行,写作,编程
旅行,写作,编程
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
程序员都该阅读的书
程序员都该阅读的书
如何成为一名黑客
如何成为一名黑客
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
我是如何打败拖延症的
我是如何打败拖延症的
那些争议最大的编程观点
那些争议最大的编程观点
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
为什么程序员都是夜猫子
为什么程序员都是夜猫子
 程序员的样子
程序员的样子
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
程序员应该关注的一些事儿
程序员应该关注的一些事儿
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
漫画:程序员的工作
漫画:程序员的工作
鲜为人知的编程真相
鲜为人知的编程真相
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
Java程序员必看电影
Java程序员必看电影
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有