Jython
Jython 是 Python 编程语言的一个实现,它是用 Java 编写的,并且运行在 Java 平台上。因此可以在 Jython 中使用与标准 Python 相同的语法和标准库来执行系统命令,并且可以利用 Java 平台的特性和库,可以通过这个代码执行命令
public static void main(String[] args) {
PythonInterpreter pythonInterpreter = new PythonInterpreter();
String pythonCode = "__import__('os').system('open -a Calculator.app')";
PyFunction pyFunction = (PyFunction) pythonInterpreter.eval(pythonCode);
pyFunction.__call__();
}
Jython1
0x01 PyFunction
org.python.core.PyFunction
是 Jython 中的一个类,用于表示 Python 中的函数对象。PyFunction
类提供了访问和操作 Python 函数的方法和属性。
PyFunction
类中有几个关键的类和方法
__call__(PyObject[] args, String[] keywords)
:调用 Python 函数,传递参数和关键字参数。__getattr__(String name)
:获取函数的属性。__code__
:函数的字节码对象,包含函数的代码、参数列表等信息。__name__
:函数的名称。__doc__
:函数的文档字符串。
所以我们要代码执行实际上就是要调用其 __call__
方法,而 PyFunction
类还实现了 java.lang.reflect.InvocationHandler
接口,好巧不巧 invoke()
方法中就调用了 __call__
,这代表可以用这个类来动态代理获取真正的执行结果。
0x02 PyCode
org.python.core.PyCode
用于表示 Python 中的代码对象,包括函数、模块、类等的字节码表示。我们可以看到 org.python.core.PyFunction#__call__()
方法最终会调用 org.python.core.PyCode#call()
方法来执行 Python 代码。
org.python.core.PyBaseCode
是 PyCode
的基础抽象类,org.python.core.PyBytecode
和 org.python.core.PyTableCode
对其进行了具体实现。
跟进最开始给出的执行代码的 demo 可以看到调用了 org.python.core.PyBaseCode.call()
方法来执行命令。
通过最开始的 PythonInterpreter
创建的 PyFunction
的 PyCode
是 PyTableCode
,其执行命令的是 funcs
是一个 org.python.core.PyFunctionTable
抽象类是在运行时动态生成的没办法直接使用,所以用 PyTableCode
来实现的恶意 org.python.core.PyFunction
的创建。
PyBytecode
构建信息可以通过 python -m dis exec.py
来生成,这里以 Jython1 为例。
def execEvil(a, b):
f = open(a, 'w')
f.write(b)
f.close()
execfile(a)
if __name__ == '__main__':
print(execEvil.__code__.co_code.encode('hex'))
print(execEvil.__code__.co_name)
print(execEvil.__code__.co_names)
print(execEvil.__code__.co_consts)
print(execEvil.__code__.co_varnames)
print(execEvil.__code__.co_filename)
print(execEvil.__code__.co_argcount)
print(execEvil.__code__.co_stacksize)
print(execEvil.__code__.co_nlocals)
print(execEvil.__code__.co_flags)
print(execEvil.__code__.co_lnotab)
print(execEvil.__code__.co_firstlineno)
print(dis.dis(execEvil.__code__))
Jython2 和 Jython1 一样,只不过换成 os.system() 来执行,避免写文件。
Jython3
0x01 PyMethod
org.python.core.PyMethod
这个类同样实现了动态代理,其 invoke()
方法调用了 __call__()
方法,构造的时候满足 PyMethod
的判断即可:
__self__
类型与 args 保持一致,org.python.core.PyMethod.checkSelf()
方法会有个判断。
index
为 18 触发真正的 eval()
Jython3 用的是 org.python.core.BuiltinFunctions
这个类来触发
Jython4
Jython4 这条链用的 com.ziclix.python.sql.connect.Lookup#__call__()
来触发,这个利用比较简单,将参数 1 设置为远程调用地址就行。