关联漏洞
标题:
Tp-link Tapo C200 命令注入漏洞
(CVE-2021-4045)
描述:Tp-link Tapo C200是中国普联(Tp-link)公司的一款网络摄像头设备。 Tp-link Tapo C200 网络摄像头 1.1.15及其之前的固件版本存在安全漏洞,该漏洞源于软件中存在默认以root身份运行的uhttpd二进制文件,该文件缺少对于命令参数的过滤和转义。未经身份验证的攻击者可以通过特殊的命令请求利用该漏洞在系统上执行系统命令。
描述
Exploit for command injection vulnerability found in uhttpd binary from TP-Link Tapo c200 IP camera
介绍
# CVE-2021-4045 PoC
CVE-2021-4045 is a Command Injection vulnerability that allows Remote Code Execution in the TP-Link Tapo c200 IP camera. It affects all firmware versions prior to 1.1.16 Build 211209 Rel. 37726N due to insufficient checks on user input in `uhttpd`, which is one of the main binaries of the device. Full write up can be found [here](https://hacefresko.github.io/posts/tp-link-tapo-c200-unauthenticated-rce).
## Proof of Concept ([pwnTapo.py](pwntapo.py))
This is an extended version of the PoC made to show the vulnerability at the [CryptoParty Madrid 2022](https://cryptoparty.ucm.es/). It has 2 modes:
* **shell**: Spawns a root shell on the target

* **rtsp**: Gives access to the live video stream over RTSP

## Binary analysis
Function `exec_and_read_json` uses `popen` to execute commands:

`exec_and_read_json` is used by 2 unnamed functions, which I named `set_language` and `wifi_connect`. They respectively deal with language and wifi configuration (obviously). `wifi_connect` seems to parse single quotes (`'`), however, `set_language` doesn't. This means that if we can control the input for `set_language` function, we can successfully inject our own commands.


Function `set_language` is used by `uh_slp_proto_request`, the function I mentioned before, which passes as input some parsed data received from the user.


To parse the user data, `uh_slp_proto_request` checks if it is a valid JSON object. Then, it gets a string value identified by key `"method"` and a dictionary value identified by `"params"` (at least that is what I think, since function call could not be resolved by Ghidra but seemed to work this way). Depending on the selected method, `uh_slp_proto_request` selects the function which will be called.
So, by sending `{"method": "setLanguage", "params":{}}` we successfully call `set_language` function and pass `{}` as `language_json` parameter. Then, inside `set_language`, `language_json` object is converted to string and inserted directly into `"ubus call system_state_audio set_language \'%s\'"` to be executed.
By submitting `{"method": "setLanguage", "params": {"payload": "'; touch poc;'"}}`, `ubus call system_state_audio set_language '{"payload": "'; touch poc;'"}'` will be executed, which actually contains 3 commands: `ubus call system_state_audio set_language '{"payload": "'`, `touch poc`, and `'"}'`. The second one gives us full code execution.
Now, `uh_slp_proto_request` is used by another unnamed function managing all requests, which I named `main_server_function`. If a request is valid (does not exceed maximum length, uses http or https depending on the server config, etc.), `main_server_function` checks if URL contains `/cgi-bin/luci` or `/web-static`. If it doesn't, `uh_slp_proto_request` is called.

By guessing and sending a couple of requests to the camera, we can check that data used by `uh_slp_proto_request` is regular POST data. So, if we send a POST request to `/` with the previous payload, `uh_slp_proto_request` will process this data, call `set_language` and our payload will be injected in the command executed by `exec_and_get_result`.
As you can see, I didn't mention anything about authentication, since `setLanguage` method can be called without login. This allows any user to take full control of the camera with just one unanthenticated request.
文件快照
[4.0K] /data/pocs/bb5c93afa91b188d8eb9edd8c1e5f3f5aaaefe86
├── [4.0K] images
│ ├── [137K] exec_and_get_json.png
│ ├── [248K] main_func_1.png
│ ├── [163K] main_func_2.png
│ ├── [241K] poc.png
│ ├── [1.0M] pwnTapo_rtsp.png
│ ├── [122K] pwnTapo_shell.png
│ ├── [201K] set_language.png
│ ├── [220K] uh_slp_proto_request_entrypoint.png
│ └── [234K] wifi_connect.png
├── [2.1K] pwntapo.py
└── [3.6K] README.md
1 directory, 11 files
备注
1. 建议优先通过来源进行访问。
2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。