X-pack cracking of ElasticSearch and Kibana

Disclaimer: This article is only for learning and communication, please do not use it for commercial purposes, otherwise you will be responsible for the consequences. If you want to use the gold or platinum version of the X-Pack, please buy the genuine version.

 

The ELK version used in this article is 5.4.3, and other versions have not been verified. This article refers to the cracking method of the blog post http://blog.csdn.net/u013066244/article/details/73927756 , and solves the problem of null pointers after cracking.

 

First, you need to install Kibana 5.4.3 and ElasticSearch 5.4.3 and their x-pack components normally.

 

The steps to crack ElasticSearch are as follows:

1. Download /plugins/x-pack/x-pack-5.4.3.jar in the ElasticSearch directory and decompile it.

    Note:  Luyten  is used for decompilation here. Some files in jd-gui cannot be decompiled.

There are mainly two files that need to be decompiled:

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

After decompiling, modify these two files as follows, and save the java file.

 

LicenseVerifier.java, skip the verification part and return true directly

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 mainly modifies the static part to get the hash and date. These two values ​​need to be the same as the build value in the execution result of the command "curl XGET ${es_host}/_xpack". If necessary, it can be directly output to sysout to console, then update to 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. Upload these two javas to the server and compile javac. My es installation path: /usr/local/elastic/elasticsearch-node1, the following is replaced by ${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. Download the two compiled classes to the local, and use the compression tool to package and cover them into x-pack-5.4.3.jar.

 

4. Upload the modified x-pack-5.4.3.jar to ${es_host}/plugins/x-pack/ and overwrite the original one. If it is a cluster, each node needs to be overwritten.

 

5. After the update, start the ES.

 

6. Go to the official website to apply for a license, and you will get a file similar to the following json format

{
  "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 long string......zdGJHVbnD3yd",
    "start_date_in_millis": 1504051200000
  }
}

   Change the type to "platinum", set the expiration time (expiry_date_in_millis) to a future date, and modify other data according to the actual situation. Save the file as license.json

 

7. Upload the license.json file to the server and execute the following commands

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

 

 

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326443282&siteId=291194637