Reading file: server.js

const express = require('express');
const bodyParser = require('body-parser');
const sqlite3 = require('sqlite3').verbose();
const fs = require('fs');
const path = require('path');

const app = express();
const PORT = 3000;
const DB_FILE = path.join(__dirname, 'lab.db');
const DUMMY_SQL_FILE = path.join(__dirname, 'dummy_data.sql');

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// Very simple HTML templates (no view engine)
function layout(title, body) {
  return `
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>${title}</title>
</head>
<body>
  <h1>${title}</h1>
  ${body}
</body>
</html>`;
}

// Initialize database if not present
function initDatabase() {
  const exists = fs.existsSync(DB_FILE);
  const db = new sqlite3.Database(DB_FILE);

  if (!exists) {
    console.log('Database not found, initializing from dummy_data.sql...');
    const sql = fs.readFileSync(DUMMY_SQL_FILE, 'utf8');
    db.exec(sql, (err) => {
      if (err) {
        console.error('Error initializing database:', err);
      } else {
        console.log('Database initialized with dummy data.');
      }
    });
  }

  return db;
}

const db = initDatabase();

// Home page with links to features
app.get('/', (req, res) => {
  const body = `
    <ul>
      <li><a href="/search?q=test">Search (Reflected XSS target)</a></li>
      <li><a href="/feedback">Feedback (Stored XSS target)</a></li>
      <li><a href="/read-file?file=server.js">Read File (Path Traversal / LFI target)</a></li>
      <li><a href="/debug-users">Debug Users (view users table)</a></li>
    </ul>
    <p>API endpoints:</p>
    <ul>
      <li><code>GET /api/products?id=1</code> (SQL Injection target)</li>
      <li><code>POST /api/login</code> (SQL Injection target)</li>
    </ul>
  `;
  res.send(layout('lab.dctm.ir Vulnerable App', body));
});

// Vulnerable SQLi endpoint for sqlmap: GET /api/products?id=1
app.get('/api/products', (req, res) => {
  const id = req.query.id || '1';
  // INTENTIONALLY VULNERABLE: raw string concatenation
  const query = "SELECT id, name, description, price, secret_note FROM products WHERE id = " + id + ";";
  console.log('Executing vulnerable query:', query);

  db.all(query, (err, rows) => {
    if (err) {
      return res.status(500).json({ error: err.toString(), query });
    }
    res.json({ query, rows });
  });
});

// Vulnerable SQLi login: POST /api/login
app.post('/api/login', (req, res) => {
  const username = req.body.username || '';
  const password = req.body.password || '';

  // INTENTIONALLY VULNERABLE: raw string concatenation
  const query =
    "SELECT id, username, is_admin, secret_token FROM users WHERE username = '" +
    username +
    "' AND password = '" +
    password +
    "';";

  console.log('Executing vulnerable login query:', query);

  db.get(query, (err, row) => {
    if (err) {
      return res.status(500).send(layout('Login Error', `<p>${err.toString()}</p><pre>${query}</pre>`));
    }
    if (!row) {
      return res.send(
        layout(
          'Login Failed',
          `<p>Invalid credentials for user: <b>${username}</b></p><pre>${query}</pre>`
        )
      );
    }
    res.send(
      layout(
        'Login Successful',
        `<p>Welcome, <b>${row.username}</b>!</p>
         <p>is_admin: ${row.is_admin}</p>
         <p>secret_token: ${row.secret_token}</p>
         <pre>${query}</pre>`
      )
    );
  });
});

// Reflected XSS target: /search?q=test
app.get('/search', (req, res) => {
  const q = req.query.q || '';
  // INTENTIONALLY VULNERABLE: reflected straight into HTML
  const body = `
    <form method="GET" action="/search">
      <label>Search query: <input type="text" name="q" value="${q}"></label>
      <button type="submit">Search</button>
    </form>
    <p>Results for: <b>${q}</b></p>
    <p>(No actual search is performed. This is a reflected XSS target for tools like Dalfox and XSStrike.)</p>
  `;
  res.send(layout('Search', body));
});

// Stored XSS target: Feedback form
app.get('/feedback', (req, res) => {
  const body = `
    <form method="POST" action="/feedback">
      <p><label>Name: <input type="text" name="name"></label></p>
      <p><label>Message: <textarea name="message" rows="4" cols="40"></textarea></label></p>
      <button type="submit">Submit</button>
    </form>
    <h2>Previous Feedback</h2>
  `;

  // INTENTIONALLY VULNERABLE: feedback messages are rendered without encoding
  db.all('SELECT name, message, created_at FROM feedback ORDER BY id DESC LIMIT 20;', (err, rows) => {
    if (err) {
      return res.send(layout('Feedback Error', `<p>${err.toString()}</p>`));
    }

    let list = '<ul>';
    rows.forEach((row) => {
      list += `<li><b>${row.name}</b> (${row.created_at}): ${row.message}</li>`;
    });
    list += '</ul>';

    res.send(layout('Feedback', body + list));
  });
});

app.post('/feedback', (req, res) => {
  const name = req.body.name || 'Anonymous';
  const message = req.body.message || '';

  // Simple insert (no sanitization of content; intentional for stored XSS)
  const stmt = db.prepare('INSERT INTO feedback (name, message, created_at) VALUES (?, ?, datetime("now"))');
  stmt.run(name, message, (err) => {
    if (err) {
      return res.send(layout('Feedback Error', `<p>${err.toString()}</p>`));
    }
    res.redirect('/feedback');
  });
  stmt.finalize();
});

// File inclusion / path traversal target: /read-file?file=server.js
app.get('/read-file', (req, res) => {
  const file = req.query.file || 'server.js';

  // INTENTIONALLY VULNERABLE: no sanitization, resolves relative to project root
  const targetPath = path.join(__dirname, file);
  fs.readFile(targetPath, 'utf8', (err, data) => {
    if (err) {
      return res
        .status(404)
        .send(layout('Read File Error', `<p>Could not read file: ${file}</p><p>${err.toString()}</p>`));
    }
    res.send(
      layout(
        `Reading file: ${file}`,
        `<pre>${data.replace(/</g, '<').replace(/>/g, '>')}</pre>
         <p>Try path traversal like <code>?file=../server.js</code> or other files on disk.</p>`
      )
    );
  });
});

// Simple debug endpoint to see users table (not protected)
app.get('/debug-users', (req, res) => {
  db.all('SELECT id, username, password, is_admin, secret_token FROM users;', (err, rows) => {
    if (err) {
      return res.send(layout('Debug Users Error', `<p>${err.toString()}</p>`));
    }
    let table = '<table border="1"><tr><th>id</th><th>username</th><th>password</th><th>is_admin</th><th>secret_token</th></tr>';
    rows.forEach((row) => {
      table += `<tr><td>${row.id}</td><td>${row.username}</td><td>${row.password}</td><td>${row.is_admin}</td><td>${row.secret_token}</td></tr>`;
    });
    table += '</table>';
    res.send(layout('Debug Users', table));
  });
});

app.listen(PORT, () => {
  console.log(`Vulnerable lab app listening on http://127.0.0.1:${PORT}`);
});


Try path traversal like ?file=../server.js or other files on disk.