Node.js进程注入

前言

上篇文章实现了对Python进程的代码注入,今天接着来尝试Node.js的注入。

Inspector

根据Node.js的官方文档得知,在Node.js 8之后加入了新的调试机制(Inspector API),在启动时加入”–inspect”参数或者向进程发送SIGUSR1信号,就会激活检查器。

1
2
$ node
$ kill -USR1 $(pidof node)

激活检查器后,终端会打印信息:

Debugger listening on ws://127.0.0.1:9229/f1f12ee0-4f35-4e61-836c-71d175a607e3

检查器监听本地端口9929,使用websocket协议,协议约定可见文档,连接检查器可以使用node自带的inspect client:

1
$ node inspect -p $(pidof node)

连接后可以通过”exec(‘console.log(123)’)”在目标进程中执行node代码,或者执行”repl”开启交互模式。但是自带的inspect client功能简单,如果需要更好的体验,可以使用chrome的调试模块,在chrome中访问”chrome://inspect”即可。

协议

node-inspect就是检查器客户端的官方代码仓库,通过阅读inspect_client.js发现,交互协议就是简单的json字符串,每个请求和响应通过id字段一一对应。
例如请求开启调试时,通过websocket协议发送字符串:

1
2
3
4
{
"id": 1,
"method": "Debugger.enable"
}

检查器返回响应:

1
2
3
4
5
6
{
"id": 1,
"result": {
"debuggerId": "(D750AD89818A150E3155AC1D6ECB7BB)"
}
}

如果你想在目标进程中执行代码,类似于”exec(‘console.log(123)’)”命令,你只需要使用Runtime.evaluate,发送请求:

1
2
3
4
5
6
7
8
{
"id": 2,
"method": "Runtime.evaluate",
"params": {
"expression": "console.log(123)",
"includeCommandLineAPI": true
}
}

参数需要设置”includeCommandLineAPI”,否则注入的代码无法使用require函数。