首页 > 编程语言 >【JAVA系列】java命令注入科普

【JAVA系列】java命令注入科普

时间:2024-09-01 19:36:04浏览次数:13  
标签:执行 JAVA String .. exec sh java Runtime 科普

名词科普

原理科普

注入科普

原创 medi0cr1ty Medi0cr1ty

这里只讨论使用java执行命令的情况(Runtime/ProcessBuilder),结合之前挖过过的一些case或者群里见到过的case来讲。

名词科普

命令解释器shell:是一种软件程序(可视作一门编程语言的代码解释器),它接收用户在命令行界面输入的指令和参数,并将其转换为计算机可理解和执行的操作。如unix系统常见的sh,bash,dash,zsh,windows常见的cmd.exe

命令注入:是指攻击者通过在输入字段中恶意插入系统命令,利用应用程序对用户输入的不当处理,从而让系统执行这些恶意命令,达到获取敏感信息、控制服务器等非法目的。

原理科普

Java的命令执行之所以“特殊”,根本原因jdk中提供的命令执行的接口Runtime或ProcessBuilder默认没有套命令解释器。
所以输入& | ; $()``这类shell的表达式语法并不会被解释并执行,因为java并没有去解释这些表达式。

这个怎么理解呢,就好比下面的python代码你在终端你加了python3这个代码解释器去执行他能执行,你不加,直接丢给shell去执行,他也没法执行。
是一样的道理。

python3 -c "import sys;print(sys.version)"

那为什么像php,python这类语言的命令执行就可以默认拼接呢?
因为他底层默认就套了命令解释器。是不是除了java其他的都套了解释器?
当然也不是,比如golang就没有,所以大胆预测一波,等golang真正大面积走进这些安全专家的视线里,同样的问题还会被重复提及。

回到Java命令注入的科普上,Runtime.exec的入参可以是一个字符串或者字符串数组作。
ProcessBuilder则是数组或可变参数。
Runtime.exec实际上是调的ProcessBuilder,ProcessBuilder只要不套解释器的情况下,命令注入的可能性会非常低,所以这里重点说Runtime.exec。

Runtime.exec的入参有下面这些:

入参为String的时候会使用空格以及\t\n\r\f做切割成数组:

public Process exec(String command,String[] envp,File dir)
throwsIOException{
if(command.length()==0)
thrownewIllegalArgumentException("Empty command");

StringTokenizer st =newStringTokenizer(command);
String[] cmdarray =newString[st.countTokens()];
for(int i =0; st.hasMoreTokens(); i++)
            cmdarray[i]= st.nextToken();
returnexec(cmdarray, envp, dir);
}


public StringTokenizer(String str){
this(str," \t\n\r\f",false);
    }

然后交ProcessBuilder继续执行,最终根据不同环境调不同的原生方法启动,其中cmdarray[0]也就是数组中第一个的作为真正需要执行的程序来执行。

public Process exec(String[] cmdarray,String[] envp,File dir)
throwsIOException{
returnnewProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
}



#pb.start()    
static Process start(String[] cmdarray,
                         java.util.Map<String,String> environment,
String dir,
ProcessBuilder.Redirect[] redirects,
boolean redirectErrorStream)
throwsIOException
{

...


return new UNIXProcess
(toCString(cmdarray[0]),
             argBlock, args.length,
             envBlock, envc[0],
             toCString(dir),
                 std_fds,
             redirectErrorStream);
}finally{

...

}
}




UNIXProcess(finalbyte[] prog,
finalbyte[] argBlock,finalint argc,
finalbyte[] envBlock,finalint envc,
finalbyte[] dir,
finalint[] fds,
finalboolean redirectErrorStream)
throwsIOException{

        pid = forkAndExec(launchMechanism.ordinal()+1,
                          helperpath,
                          prog,
                          argBlock, argc,
                          envBlock, envc,
                          dir,
                          fds,
                          redirectErrorStream);

try{
            doPrivileged((PrivilegedExceptionAction<Void>)()->{
                initStreams(fds);
returnnull;
});
}catch(PrivilegedActionException ex){
throw(IOException) ex.getException();
}
    }

所以如果你传入的是sh -c "whoami;ls"那么java执行的第一个程序实际上sh而不是whoamils

sh执行后再根据自己的逻辑将whoami;ls切割并顺序启动,可以理解为whoamilssh的子进程,sh是java的子进程。

如果传入的是"whoami&&ls",java无法切割也不做解析,那么ls则不会作为第二个程序去执行,而是"whoami&&ls"这整个字符串作为一个程序去执行,环境中找不到这个文件,自然就会无法执行,进而一条都执行不成功。

注入科普

前面基础科普讲完了,那么就是注入技巧的问题了。在无前置过滤的情况下:

套了命令解释器的拼接可执行

String cmd = "whoami;id";
Runtime.getRuntime().exec(String.format("bash -c %s",cmd));

不套的拼接不可执行。

String cmd = "whoami;id";
Runtime.getRuntime().exec(String.format("xxxx %s",cmd));

但可以考虑污染前面的xxx程序的参数,间接实现rce。比如执行程序是curl的时候可以通过-o参数写文件实现间接rce

cmd = "http://www.baidu.com -o /tmp/baidu";
Runtime.getRuntime().exec(String.format("curl %s",cmd));

再比如find的-exec参数,玩法比较多样,也有没得玩的时候。

遇到的大多数情况类似,这种直接在host中拼接执行的,可控的部分不作为sh的参数来输入,而是作为deploy.sh这个程序的参数来输入,这个但凡写过几行python就不用说也能理解。
所以有没有可能rce取决于你的程序本身(deploy.sh),而不是sh

String deployCmd = "sh deploy.sh " + host ;
Runtime.getRuntime().exec(deployCmd);

再讲个特殊情况,某群里看到的case,群友用来面试别人的面试题,猜测他预期的答案就是上面这种情况,让别人回答去审计"login.sh"这个程序。

可如果代码真如图所示的话,真的是这么做吗?能rce吗?需要审计login.sh吗?

我认为不需要,因为login.sh后面没有空格就直接拼接了,拼接完后的文件名复杂化,大概率不存在,或文件内容不可控,审计个der。后面的参数又没办法作为sh的参数进行污染。

怎么rce呢?很简单,想办法控制sh执行的文件指向一个存在“漏洞”或者说命令执行行为的sh文件,再污染他的参数即可。

find / -type f -exec file {} + | grep "shell script"

很容易就看到/usr/bin/command这条命令实际上是一个bash脚本,语句做下简单的闭合即可完成命令注入。

String payload = "/../../../../../../../../../../../../../../../../../../../usr/bin/command bash -c 'id";
String cmd = "sh login.sh'" + payload + "'";
Runtime rt = Runtime.getRuntime();
rt.exec(cmd);

嗯,没错,有限制条件,就是得找个可以创建文件夹的点配合利用,在当前文件夹下创建login.sh'这个目录,否则unix下../是没办法跨域过一个不存在的文件夹的。
写在最后

这个有问题隔三差五就会在各个安全的群里看到有人问,成月经问题了。

它很基础吗? 这个但凡挖过几次实战使用洞的人都肯定会知道。

它不基础吗? 见过一堆搞了好多年了sdl的人讨论的时候将拼接后不能执行归咎于沙箱,归咎于rasp(环境中其实没这两因素); 也见过某些大厂的安全中台给别人出的考试题目里告诉研发没命令解释器执行ping命令也存在命令注入的风险。更别说群里问的新手(这种勉强可以理解)

我的总结是,大部分人没有挖洞不需要实战,唬住研发和leader就行,不需要验证,自然就不会知道。

标签:执行,JAVA,String,..,exec,sh,java,Runtime,科普
From: https://www.cnblogs.com/o-O-oO/p/18391551

相关文章

  • JavaSE-递归法解决二分查找、快速排序
    704.二分查找https://leetcode.cn/problems/binary-search/packagedemo;publicclassBinarySearch{publicstaticvoidmain(String[]args){BinarySearchbr=newBinarySearch();System.out.println(br.search(newint[]{1,2,3,4,5,6,7......
  • 为什么Java仍旧生机盎然——对“为什么Java正在消亡”的回应
    [图片上传失败...(image-599293-1649288200226)]0.阅读完本文你将会了解Java作为热门语言之一所面临的争议了解Java的生态环境和未来1.前言原文标题:WhyJavaIsPerfectlyAlive——Aresponseto"WhyJavaIsDying"原文地址:https://betterprogramming.pub/why-......
  • 互联网 Java 工程师面试题(Java 面试题四)
    下面列出这份Java面试问题列表包含的主题多线程,并发及线程基础数据类型转换的基本原则垃圾回收(GC)Java集合框架数组字符串GOF设计模式SOLID抽象类与接口Java基础,如equals和hashcode泛型与枚举JavaIO与NIO常用网络协议Java中的数据结构和算法正则表达式JVM底......
  • 学JAVA的第七周
    变量和方法成员变量与局部变量的区别有哪些变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上讲,变量其实是内存中的一小块区域成员变量:方法外部,类内部定义的变量局部变量:类的方法中的变量。成员变量和局部变量的区别作用域成员变量:针对整个类有效。局部......
  • 学JAVA的第八周
    内部类可以分为四种:成员内部类、局部内部类、匿名内部类和静态内部类。静态内部类定义在类内部的静态类,就是静态内部类。静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量成员内部类定义在类内部,成员位置上的非静态类,就是成员内部类。成员内部类可以访......
  • Java的GRPC
    环境配置<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://m......
  • Java:有效括号字符串验证器
    Java实现的有效括号字符串验证器引言在编程中,经常需要验证一组字符串中的括号是否正确配对。例如,检查一段代码或表达式中的圆括号、方括号和花括号是否成对出现。这类问题不仅在编程语言解析器中非常重要,也是许多软件开发场景中的基础需求。本文将介绍一种基于Java语言实......
  • Java反射
    1.反射1.1.反射引入编译时知道类或对象的具体信息,此时直接对类和对象进行操作即可,无需反射如果编译不知道类或对象的具体信息,就使用反射来实现。比如类名、属性和属性值放在XML文件中,需要在运行时读取XML文件,动态获取类的信息publicclassTest{publicstaticvo......
  • 2025毕业设计精选:如何用Java SpringBoot+Vue构建受灾救援物资管理系统,实现实时监控,提
    ✍✍计算机毕业编程指导师⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、微信小程序、大数据实战项目集⚡⚡文......
  • JAVA之JVM入门
    Java虚拟机(JVM)是Java平台的核心部分之一,它为Java程序提供了运行环境。一、历史背景1.SunClassicVM发布时间:1996年重要功能:Java1.0的默认JVM。支持基本的字节码执行。简单的垃圾回收机制。2.HotSpotVM发布时间:1999年重要功能:JDK1.3开始成为默认JVM。引入了......