Debug端口开放存在被攻击的可能性,本次针对Node.js、Headless Chrome 、Java、Golang 、Flask,Django六类语言或框架利用debug端口进行检测及简单利用。
本篇文章介绍Node.js、Headless Chrome 、Java三类远程调试器的攻击面和检测方式,Golang 、Flask,Django待下一篇分享介绍。
Node.js内置了调试功能,Node.js7之前的版本使用--debug启动,默认端口是5858。Node.js调试器允许执行任意JS代码,可以使用Metasploit的exploit/multi/misc/nodejs_v8_debugger/模块。
Node.js8之后调试器使用--inspect启动,默认端口是9229。
使用 node --inspect 启动,默认情况下 --inspect 绑定的是127.0.0.1,这样就只允许本地程序访问,可以指明本机的外网IP或者0.0.0.0,这样就可以进行远程调试了
然而,我们会发现,程序直接执行完成了,没有中断,导致我们无法使用 Chrome DevTools 进行调试。对于这种直接执行的代码,我们可以使用 --inspect-brk 参数,在应用程序代码的第一行中断,然后再进行调试。
可以使用Chrome DevTools远程调试Node.js,访问http://127.0.0.1:9229/json和http://127.0.0.1:9229/json/version
如上图中devtoolsFrontendUrl,其就是
通过将ip:port与id拼接到 devtools里,如果Chrome浏览器低于66.0.3345.0,请在上述URL中使用inspector.html代替js_app.html,devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=x.x.x.x:9229/800765f6-4de6-4a9f-a670-12b49eec4f84可以获取一个远程调试的端口。
child_process模块是Nodejs的一个子进程模块,可以用来创建一个子进程,并可以直接在js里面调用shell命令去执行任务。
除此之外,webSocketDebuggerUrl 属性就是我们需要websocket 通信地址。检测脚本可以通过连接webSocketDebuggerUrl来连接目标调试端口执行命令,可以通过dnslog来判断是否执行成功。
Headless Chrome是Chrome 浏览器的无界面形态,由Chromium和Blink渲染引擎提供的网页平台的特征都转化成了命令行。Headless Chrome 更加方便测试 web 应用,做爬虫抓取信息、截图等。
开启headless模式的chrome的最简单的命令:
chrome --headless --remote-debugging-port=9222 https://www.iqiyi.com
参数说明:
--headless:无头模式
--remote-debugging-port:开启远程调试,端口9222。后面为要访问的url,打开http://127.0.0.1:9222/json,发现和刚刚的nodejs差不多,一般每个tab 就是一个可调试目标。
devtoolsFrontendUrl是开发者工具的前端地址,里面含有WebSocket调试地址,打开这个地址既可以看到远程chrome上的页面,也可以devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=10.17.80.41:31413/ba897daa-338d-4426-bb7c-25d11324c43a获取一个远程调试的端口,执行js代码。
通过远程连接websocket,使用Page.navigate让其访问页面进行爬取页面,再通过Runtime.evaluate执行js
command结构如下:
request: {
"id": <number>,
"method": <method>,
"params": {
"url": <string>
}
}
response: {
"id": <number>,
"error": <object>
}
执行 Page.navigate 操作,需要参数 url,id 可以随意指定,不过要确认全局的唯一性,因为需要通过 id 关联 request 和 response。
检测代码大致如下:
def command(conn, method, **kwargs):
global request_id
request_id += 1
command = {'method': method,
'id': request_id,
'params': kwargs}
conn.send(json.dumps(command))
while True:
msg = json.loads(conn.recv())
if msg.get('id') == request_id:
return msg
url = 'https://www.iqiyi.com'
command(conn, 'Page.navigate', url=url)
js = """ $("#container").find(".nums").text()"""
result = command(conn, 'Runtime.evaluate', expression=js)
value= json.loads(result['result']['result']['value'])
最后判断value值是否是预期的值,来判断Headless Chrome是否存在远程调试,
除此之外,与Chrome –no-sandbox远程命令执行漏洞结合起来,用Headless Chrome执行poc,shellcode访问dnslog来判断漏洞是否存在。
JDWP 是 Java Debug Wire Protocol 的缩写,它定义了调试器(debugger)和被调试的 Java 虚拟机(target vm)之间的通信协议。
要使用JDWP调试Java应用,首先需要以debugging模式启动应用(假设应用启动类名为javaTest):
java -Xdebug -Xrunjdwp:transport=dt_socket,address=8888,server=y,suspend=y javaTest
参数说明:
-
-Xdebug:运行运行时调试。必须与 -Xrunjdwp 选项配合使用,才能实现调试功能。
-
-Xrunjdwp:debug-settings:按指定的调试设置参数,开启一个JDWP会话。必须与 -Xdebug 选项配合使用,才能实现调试功能。
JDWP 大致分为两个阶段:握手和应答。
建立传输连接之后,在发送任何数据包之前,连接的两侧之间会发生握手:
握手过程包括以下步骤:
-
Debugger向VM端发送14 bytes字符串“ JDWP-Handshake”的14个ASCII字符。
-
VM端使用相同的14个字节进行回复:JDWP-Handshake
检测脚本可以利用:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, port))
client.send("JDWP-Handshake")
if client.recv(14)=="JDWP-Handshake":
print("[*] Detected JDWP service")
client.close()
可以使用telnet ip port 然后快速发送JDWP-Handshake来进行简单验证是否存在漏洞,如果服务器也返回了JDWP-Handshake那么可能就存在该漏洞了
还可以用nmap探测 JDWP 服务,JDWP并无固定的端口,当未指定调试端口时,则会随机指定一个空闲端口。
可以利用github上的脚本执行命令:https://github.com/IOActive/jdwp-shellifier
python jdwp-shellifier.py -t 127.0.0.1 -p 8088 --break-on java.lang.String.indexOf --cmd "touch /tmp/demo.txt"
以上的三类debug端口调试所导致的漏洞你了解了吗?
另外三类请关注下一期分享哦~
原文始发于微信公众号(爱奇艺安全应急响应中心):六类常见远程调试安全分析之第一弹
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论