【代码审计】命令执行漏洞分析

admin 2025年5月19日11:31:34评论19 views字数 4801阅读16分0秒阅读模式
【代码审计】命令执行漏洞分析

点击上方蓝字关注我们

【代码审计】命令执行漏洞分析
【代码审计】命令执行漏洞分析

    请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。如有侵权烦请告知,我们会立即删除并致歉。谢谢!

【代码审计】命令执行漏洞分析
【代码审计】命令执行漏洞分析

01

漏洞简介

       在Java代码审计中,命令执行漏洞指应用程序未对用户输入进行严格过滤,直接将外部可控参数拼接到系统命令中执行,导致攻击者可注入恶意命令并获取服务器控制权。其核心原理是开发者误用危险函数执行系统命令时,未对用户输入的参数进行安全校验或转义,导致用户可通过构造特殊字符(如管道符|、命令分隔符;)或参数注入(如${}表达式)将恶意指令与原始命令拼接。该漏洞常出现在参数动态拼接的场景,且受操作系统特性影响。

Windows系统命令注入表

【代码审计】命令执行漏洞分析

Linux系统命令注入表

【代码审计】命令执行漏洞分析

02

Java原生命令执行方式

【代码审计】命令执行漏洞分析

Runtime.exec()

【代码审计】命令执行漏洞分析

Runtime.exec() 是Java中执行系统命令的核心方法,提供多种重载形式,本质是启动子进程执行外部命令。直接拼接用户输入会导致命令注入漏洞,需使用参数数组形式并严格校验输入。Java中命令执行用到最多的方法就是java.lang.Runtime#exec()

// 方法1: 直接执行字符串命令Process exec(String command);// 方法2: 通过字符串数组传递命令和参数Process exec(String[] cmdarray);// 方法3: 指定环境变量执行字符串命令Process exec(String command, String[] envp);// 方法4: 通过数组传递命令并自定义环境变量Process exec(String[] cmdarray, String[] envp);// 方法5: 指定环境变量和工作目录执行字符串命令Process exec(String command, String[] envp, File dir);// 方法6: 通过数组传递命令,并指定环境变量、工作目录Process exec(String[] cmdarray, String[] envp, File dir);

【代码审计】命令执行漏洞分析

从上面可知exec()方法在执行命令的时候,传入的参数有字符串和字符串数组两种形参,将这种方法封装到靶场上且限制必须包含ping来执行观察其效果,分析可利用的方式。

【代码审计】命令执行漏洞分析

首先使用exec(String)执行ping命令,正常返回结果,执行其他命令则异常

【代码审计】命令执行漏洞分析

【代码审计】命令执行漏洞分析

使用&进行命令拼接,但是发现也异常了

【代码审计】命令执行漏洞分析

切换为exec(String[])时,直接使用&拼接,发现两条命令都可以被执行。

【代码审计】命令执行漏洞分析

思考下,为什么exec(String)使用了&会异常,而exec(String[])不会呢?来动态调试exec(String)的调用链加深理解,开始断点调试,发现调用的是exec(command, null, null);

【代码审计】命令执行漏洞分析

【代码审计】命令执行漏洞分析

继续跟进,发现这里最终也去调用的是exec(cmdarray, envp, dir),那为什么最终的命令执行的结果不一样呢,分析下面的代码可以发现,传入的command是经过了StringTokenizer进行处理的,那么问题的关键就是StringTokenizer是怎么去处理的

【代码审计】命令执行漏洞分析

跟进StringTokenizer,发现这里对传入的命令做了一个分割,将传入的字符串 str 按照默认的空白分隔符(包括空格、制表符 t、换行符 n、回车符 r 和换页符 f)进行分割,将字符串拆解为一系列连续的子字符串

【代码审计】命令执行漏洞分析

String[] cmdarray = new String[st.countTokens()]; 的作用是创建一个字符串数组 cmdarray,其长度等于 StringTokenizer 对象 st 中分割后的子字符串数量,最终命令变成了["calc&ping","baidu.com"] 传入了exec(cmdarray, envp, dir)

【代码审计】命令执行漏洞分析

最终交给ProcessBuilder去执行,命令被错误的分割成["calc&ping", "baidu.com"] ,Java会尝试执行第一个参数 calc&ping,视为可执行程序名,calc&ping 不是一个有效程序,因此抛出 IOException: Cannot run program "calc&ping"

【代码审计】命令执行漏洞分析

如果是exec(String[])呢?最终命令是["cmd", "/c", "calc&ping", "baidu.com"],Java调用 cmd.exe,并传递参数 /c 和后续参数 calc&ping baidu.com。 cmd.exe 会将 calc&ping baidu.com 整体视为一个字符串,并按照 Shell 规则解析其中的 & 符号,将 calc&ping baidu.com 解析为两条命令,故而执行成功。

【代码审计】命令执行漏洞分析

exec(String)怎么去进行漏洞利用呢?可以利用Shell的解析逻辑实现命令注入,直接拼接cmd /c即可

【代码审计】命令执行漏洞分析

【代码审计】命令执行漏洞分析

ProcessBuilder

【代码审计】命令执行漏洞分析

ProcessBuilder命令执行漏洞的核心在于通过ProcessBuilder类直接构造并执行系统命令时,若未对用户输入参数进行严格过滤或拆分,攻击者可注入恶意命令实现任意代码执行,ProcessBuilder不支持以字符串形式传入命令,只能拆分成List或者数组的形式传入。

【代码审计】命令执行漏洞分析

从靶场漏洞代码中可知道,是直接将用户输入的参数传入到ProcessBuilder进行命令执行,从而攻击者可以拼接恶意命令造成漏洞

【代码审计】命令执行漏洞分析

跟进ProcessBuilder.start()方法,ProcessBuilder.start() 是Java中启动外部进程的核心方法,其底层实现最终通过调用 ProcessImpl.start() 完成操作系统级别的进程创建。

【代码审计】命令执行漏洞分析

【代码审计】命令执行漏洞分析

ProcessImpl

【代码审计】命令执行漏洞分析

ProcessImpl 是 Java 中 Process 抽象类的具体实现类 ,其设计目的是为 ProcessBuilder.start() 方法提供底层支持,用于创建和管理操作系统进程 。由于 ProcessImpl 的构造函数被声明为 private,无法直接通过 new 实例化,开发者通常需通过 ProcessBuilder 或 Runtime.exec() 间接调用其功能 。若需直接操作ProcessImpl,必须通过反射技术绕过访问限制。ProcessImpl 的 start() 方法是静态的,可通过反射获取该方法并传入参数(如命令数组、环境变量等)创建进程。

package com.xmsec.controller.rce;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Map;public class ProcessImplExamples {    public static void main(String[] args) throws ClassNotFoundExceptionNoSuchMethodExceptionInvocationTargetExceptionIllegalAccessException {        String[] cmdarray = new String[]{"cmd""/c""calc"};        Class clazz = Class.forName("java.lang.ProcessImpl");        Method method = clazz.getDeclaredMethod("start"String[].classMap.classString.classProcessBuilder.Redirect[].classboolean.class);        method.setAccessible(true);        Process p = (Process) method.invoke(null, cmdarray, nullnullnullfalse);    }}

靶场效果

【代码审计】命令执行漏洞分析

03

代码审计思路

学习完Java命令执行的一些方式,就可以知道需要审计哪些危险函数了,是否手动创建了shell,然后关注参数是否可控,若不可控则无法命令注入,若参数可控注意空格等会导致分割,可编码绕过(如${IFS}代替空格)。核心思路是识别所有可能导致命令注入的代码路径,重点围绕“参数可控性”和“Shell调用方式”两个维度进行分析:

1、定位危险入口点,识别所有可能执行系统命令的代码位置

  • Runtime.getRuntime().exec()

  • ProcessBuilder.start()

  • 反射调用 ProcessImplUNIXProcess 等底层类的方法

审计技巧:

  • 使用IDE全局搜索关键词:exec(ProcessBuilderstart(getRuntime()

  • 检查反射调用:搜索 Class.forName()Method.invoke() 等代码块,确认是否操作危险类(如ProcessImpl)。

2、分析参数来源,判断命令参数是否完全或部分可控。

  • HTTP请求参数(GET/POST)、Headers、Cookies

  • 文件上传内容、数据库查询结果

  • 配置文件(如YAML/Properties)中的动态值

  • 是否存在字符串拼接(如 "sh -c " + userInput

  • 是否通过 String.format()StringBuilder 动态生成命令

3、验证调用方式与参数解析,确认是否通过Shell环境执行命令,以及参数解析是否安全,Shell会解析命令中的特殊符号(如;&&$()),导致命令注入。

  • 检查是否显式调用Shell,如使用 sh -cbash -ccmd.exe /c 等Shell解释器,如new ProcessBuilder("sh", "-c", userCmd)

  • 检查参数分割逻辑,如使用 exec(String command) 传递单个字符串命令

  • 检查反射绕过,通过反射直接调用ProcessImpl.start(),绕过参数安全检查。

04

防御与修复

1、避免执行系统命令

优先使用Java原生API替代直接执行系统命令。例如:删除文件使用File.delete()而非rm命令 ,网络请求使用通过HttpClient而非curl命令等等,规避命令注入风险,同时提升跨平台兼容性。

2、无法避免系统命令执行时,优先使用Runtime.exec(String[] cmdarray)ProcessBuilder的数组传参方式,避免将命令与参数拼接为字符串

exec("cmd /c " + userInput)  // 容易被注入exec(new String[]{"cmd""/c", fixedCommand})  // 如果命令有白名单限制,相比上面安全

3、避免shell调用,禁止通过sh -ccmd.exe /c等方式创建Shell环境,直接调用可执行文件路径

exec("sh -c ls " + dir);   // 不安全的Shell调用  exec(new String[]{"/bin/ls", dir});   // 安全

4、危险字符过滤,过滤|&;$()等Shell元字符,以及路径遍历符号(../),可使用OWASP ESAPI等安全库进行编码处理

String safeInput = ESAPI.encoder().encodeForOS(new WindowsCodec(), userInput);  
【代码审计】命令执行漏洞分析
【代码审计】命令执行漏洞分析

陪伴是最长情的告白

为你推送最实用的网安知识

识别二维码

关注我们

【代码审计】命令执行漏洞分析

原文始发于微信公众号(Sec探索者):【代码审计】命令执行漏洞分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月19日11:31:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【代码审计】命令执行漏洞分析https://cn-sec.com/archives/4079622.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息