freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

java下exec命令执行问题
Notadmin 2023-02-07 14:29:49 136489
所属地 上海

简介

在java中执行系统命令,一定会用到​​Runtime.getRuntime().exec​​,在做代码审计的过程中,遇到了传入的是一个数组的情况,第三个元素可控,这种情况下是否可以执行系统命令?

使用方法

使用exec一般有下面的两种方式

exec(java.lang.String)

只传递一个字符串,字符串代表一个没有参数的纯命令,如hostname、pwd、ll等。

exec(java.lang.String[])

字符串数组,第一个元素是命令,和​​exec(java.lang.String)​​中的一个字符串代表的概念一样,​后面的元素都是命令的参数​。传递数组时,第二个元素开始就是参数,因此不能直接通过&,|等连接符执行复杂的系统命令。

例如下面的字符串数组,第一个元素是执行bash文件的命令​​/bin/sh​​​,也可以是​​bash​​,第二个元素是bash文件路径,第三个元素是bash文件内命令执行需要的参数。

String[] cmds = {"/bin/sh", "/root/tmp/xxx.sh", "xxx"};


不创建脚本文件执行复杂命令

如果执行的命令是一个完整的命令,不需要传参,可以直接使用​​exec(java.lang.String)​​​;如果执行的命令需要传递参数,则需要使用​​exec(java.lang.String[])​​。

​​exec(java.lang.String[])​​数组参数的第二个元素是可执行脚本文件路径,对于bash命令,可以不用创建文件也可以执行复杂的命令,例如:

// ps -ef | grep xxx | grep -v grep | awk '{ print $2 }'

// 过滤xxx进程并输出其pid,-v是取反过滤,排除当前命令的影响

String[] cmds = {"/bin/sh", "-c", "ps -ef | grep xxx | grep -v grep | awk '{ print $2 }'"};

Runtime.getRuntime().exec(cmds);

​​/bin/sh -c​​可将一个多操作命令合并成一个完整命令执行。


问题分析

回到最开始的那个问题,如下的代码

import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
class Main {
    public static void main(String[] args) throws IOException {

        // 创建一个动态数组
        ArrayList<String> sites = new ArrayList<>();

        sites.add("ffmpeg-amd64-3.0.0.exe");
        sites.add("-i");
        sites.add("D:\\test.txt | mkdir E:\\xixihaha111222222");
        sites.add("-hide_banner");
        
        Runtime runtime = Runtime.getRuntime();
        runtime.exec((String[])sites.toArray(new String[0]));
        
    }
}

调用ffmpeg-amd64-3.0.0.exe去操作文件,文件的路径可控,从exec函数的说明可以知道从第二个元素开始就被当做参数来对待,并不能去执行系统命令。实际运行下来发现也没有成功执行系统命令。


因此发现对于Java环境中的命令注入,连接符的使用存在一些局限。例如如下示例代码,使用ping命令来诊断网络。其中url参数为用户可控,当恶意用户输入“www.baidu.com&ipconfig”时,拼接出的系统命令为“ping www.baidu.com&ipconfig”,该命令在命令行终端可以成功执行。然而在Java运行环境下,却执行失败。在该Java程序的处理中,“www.baidu.com&ipconfig ”被当作一个完整的字符串而非两条命令。因此以下代码片段不存在命令注入漏洞。

protected ByteArrayOutputStream ping(String url) throws IOException {
    Process process = Runtime.getRuntime().exec("ping "+ url);
    InputStream in = process.getInputStream();
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    byte[] b = new byte[1024];
    int i = -1;
 
    while ((i = in.read(b)) != -1) {
        byteArrayOutputStream.write(b, 0, i);
    }
    return byteArrayOutputStream;
}

总结

对于java环境的命令执行,如果传入的是一个字符串,一般要能控制字符串的开始位置才能执行,如果传入的是一个字符数组,要能控制第一个元素。

# web安全
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 Notadmin 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
Notadmin LV.6
微信公众号:信安路漫漫
  • 87 文章数
  • 153 关注者
浅谈SSO认证原理及常见安全问题
2025-03-25
微信小程序测试技巧总结
2025-03-13
验证机制常见的问题
2025-03-10
文章目录