802 lines
39 KiB
HTML
Executable File
802 lines
39 KiB
HTML
Executable File
<?xml version="1.0" encoding="UTF-8" ?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
|
||
<head>
|
||
<title>Session Stored XSS PENTEST.html</title>
|
||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
||
|
||
</head>
|
||
|
||
<body>
|
||
|
||
<h1 id="links">Links:</h1>
|
||
<ul>
|
||
<li>[[Cross Site Scripting (XSS)]]</li>
|
||
</ul>
|
||
<h1 id="metadata">Metadata</h1>
|
||
<ul>
|
||
<li>Name<br />
|
||
Understanding Session XSS</li>
|
||
<li>Overview<br />
|
||
Pages 33–34 document an informational “Session stored XSS” finding on
|
||
the TMC Schedule Execution Board. The issue is real (unescaped user
|
||
input in a JavaScript context) but impact is limited because only the
|
||
submitting user’s session is affected—classic self-XSS, not cross-user
|
||
attack.</li>
|
||
</ul>
|
||
<h2 id="todos">Todos</h2>
|
||
<ul class="task-list">
|
||
<li><label><input type="checkbox" checked="" />review-finding<br />
|
||
Read pages 33–34 and map finding to SaveSearchCriteriaToSession +
|
||
ScheduleExecutionBoard.aspx flow</label></li>
|
||
<li><label><input type="checkbox" checked="" />locate-source<br />
|
||
Open TMC Web Portal repo and find session save + inline script render
|
||
for date/orderID/time</label></li>
|
||
<li><label><input type="checkbox" />remediate-encode<br />
|
||
Apply HttpUtility.JavaScriptStringEncode to all session values in
|
||
SetupControls() (~1849-1879)</label></li>
|
||
<li><label><input type="checkbox" />remediate-validate<br />
|
||
Add server-side validation in SaveSearchCriteriaToSession before writing
|
||
SEBSessionState</label></li>
|
||
<li><label><input type="checkbox" />remediate-retest<br />
|
||
Retest with direct POST payload + normal UI search flow on
|
||
ScheduleExecutionBoard</label></li>
|
||
</ul>
|
||
<h1
|
||
id="understanding-the-session-stored-xss-finding-pages-3334">Understanding
|
||
the Session Stored XSS Finding (Pages 33–34)</h1>
|
||
<h2 id="where-this-sits-in-the-report">Where this sits in the
|
||
report</h2>
|
||
<p>The <a
|
||
href="d:/_dev/_misc/Pentest-04-26/Microlise%20TMC%20PO%20WA%20April%202026%20v1.0.pdf">Microlise
|
||
TMC PO WA April 2026 v1.0.pdf</a> lists <strong>14 findings</strong>
|
||
total. Pages 33–34 (<a
|
||
href="d:/_dev/_misc/Pentest-04-26/33-34.pdf">33-34.pdf</a>) are the last
|
||
technical finding before “END OF DOCUMENT”:</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 10%" />
|
||
<col style="width: 89%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Field</th>
|
||
<th>Value</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Title</td>
|
||
<td><strong>Session stored XSS</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Severity</td>
|
||
<td><strong>Informational</strong> (lowest tier; 4 informational
|
||
findings in the report)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Status</td>
|
||
<td>Open</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CWE</td>
|
||
<td><a href="https://cwe.mitre.org/data/definitions/79.html">CWE-79</a>
|
||
— Improper Neutralization of Input</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Environment</td>
|
||
<td><code>cert.microlise.com</code> (cert/UAT), path prefix
|
||
<code>/PENTEST/TMCWebPortal/</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Higher-severity items in the same report (SQLi, IDOR, BFLA, etc.) are
|
||
separate; this finding is documented as <strong>technically valid but
|
||
low business risk</strong>.</p>
|
||
<hr />
|
||
<h2 id="what-xss-is-general">What XSS is (general)</h2>
|
||
<p><strong>Cross-Site Scripting (XSS)</strong> means untrusted data ends
|
||
up in a web page in a way the <strong>browser treats as executable
|
||
JavaScript</strong>, instead of inert text.</p>
|
||
<p>The name “cross-site” is historical: classic attacks trick a
|
||
<strong>victim</strong> into loading a page on <strong>your</strong> app
|
||
so script runs in <strong>your</strong> origin (stealing session
|
||
cookies, performing actions as the user, etc.).</p>
|
||
<p>Common types:</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 15%" />
|
||
<col style="width: 45%" />
|
||
<col style="width: 39%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Type</th>
|
||
<th>Persistence</th>
|
||
<th>Typical delivery</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><strong>Reflected</strong></td>
|
||
<td>Not stored; one-off response</td>
|
||
<td>Malicious link/query param</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Stored</strong></td>
|
||
<td>Saved server-side (DB, file, session)</td>
|
||
<td>Victim loads a normal page later</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>DOM-based</strong></td>
|
||
<td>Client-side only</td>
|
||
<td>Unsafe innerHTML, eval, etc.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Defense in depth:</strong> validate input on the server
|
||
(whitelist formats), and <strong>encode output</strong> for the exact
|
||
context (HTML, attribute, JavaScript string, URL).</p>
|
||
<hr />
|
||
<h2 id="what-happened-in-this-finding-tmc-context">What happened in
|
||
<em>this</em> finding (TMC context)</h2>
|
||
<h3 id="affected-surface-source-located">Affected surface (source
|
||
located)</h3>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 20%" />
|
||
<col style="width: 79%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Role</th>
|
||
<th>Path</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Page + inline JS</td>
|
||
<td><a
|
||
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx">ScheduleExecutionBoard.aspx</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td>WebMethod + page properties</td>
|
||
<td><a
|
||
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx.cs">ScheduleExecutionBoard.aspx.cs</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Session storage</td>
|
||
<td><a
|
||
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/SEBSessionState.cs">SEBSessionState.cs</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<ul>
|
||
<li><strong>Endpoint:</strong> ASP.NET <code>[WebMethod]</code>
|
||
<code>SaveSearchCriteriaToSession</code> on
|
||
<code>ScheduleExecutionBoard.aspx</code></li>
|
||
<li><strong>Parameters:</strong> JSON fields <code>date</code>,
|
||
<code>orderID</code>, <code>time</code> (also <code>searchID</code>,
|
||
<code>hours</code>, <code>quickSearch</code> in the same flow)</li>
|
||
<li><strong>Host (pentest):</strong> <code>cert.microlise.com</code>,
|
||
path <code>/PENTEST/TMCWebPortal/SEB/...</code></li>
|
||
</ul>
|
||
<h3 id="attack-flow-as-tested">Attack flow (as tested)</h3>
|
||
<pre class="mermaid"><code>flowchart LR
|
||
subgraph submit [Step1_Submit]
|
||
A[Tester sends POST directly]
|
||
B[SaveSearchCriteriaToSession]
|
||
C[Values stored in server session]
|
||
end
|
||
subgraph render [Step2_Render]
|
||
D[User loads ScheduleExecutionBoard.aspx]
|
||
E[Server embeds session values in script block]
|
||
F[Browser executes unescaped JS]
|
||
end
|
||
A --> B --> C
|
||
C --> D --> E --> F</code></pre>
|
||
<ol type="1">
|
||
<li><strong>Save:</strong> User (or tester) POSTs JSON to
|
||
<code>SaveSearchCriteriaToSession</code>. The app saves search criteria
|
||
into the <strong>server-side session</strong>.</li>
|
||
<li><strong>Render:</strong> On the next load of
|
||
<code>ScheduleExecutionBoard.aspx</code>, those values are written into
|
||
the HTML <strong>inside a <code><script></code> block</strong>, as
|
||
JavaScript string literals.</li>
|
||
<li><strong>Bug:</strong> Values are inserted <strong>without JavaScript
|
||
string encoding</strong>. A crafted <code>date</code> can <strong>break
|
||
out of the string</strong> and run arbitrary JS.</li>
|
||
<li><strong>Proof:</strong> Pentesters confirmed execution in the
|
||
browser; screenshots in the PDF show the POST and page source.</li>
|
||
</ol>
|
||
<h3 id="code-path-matches-report-exactly">Code path (matches report
|
||
exactly)</h3>
|
||
<p><strong>1. Save — no server-side validation</strong></p>
|
||
<div class="sourceCode" id="cb2"><pre
|
||
class="sourceCode csharp"><code class="sourceCode cs"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">// ScheduleExecutionBoard.aspx.cs lines 336-348</span></span>
|
||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="op">[</span>WebMethod<span class="op">]</span></span>
|
||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">static</span> <span class="dt">void</span> <span class="fu">SaveSearchCriteriaToSession</span><span class="op">(</span><span class="dt">string</span> searchID<span class="op">,</span> <span class="dt">string</span> orderID<span class="op">,</span> <span class="dt">string</span> date<span class="op">,</span> <span class="dt">string</span> time<span class="op">,</span> <span class="dt">int</span> hours<span class="op">,</span> <span class="dt">bool</span> displayPriorityJourneys<span class="op">,</span> <span class="dt">string</span> quickSearch<span class="op">)</span></span>
|
||
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
|
||
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> sebState <span class="op">=</span> <span class="kw">new</span> <span class="fu">SEBSessionState</span><span class="op">();</span></span>
|
||
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> sebState<span class="op">.</span><span class="fu">ComplexSearch</span> <span class="op">=</span> searchID<span class="op">;</span></span>
|
||
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> sebState<span class="op">.</span><span class="fu">OrderBy</span> <span class="op">=</span> orderID<span class="op">;</span></span>
|
||
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> sebState<span class="op">.</span><span class="fu">SearchDate</span> <span class="op">=</span> date<span class="op">;</span></span>
|
||
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> sebState<span class="op">.</span><span class="fu">SearchTime</span> <span class="op">=</span> time<span class="op">;</span></span>
|
||
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
|
||
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p><strong>2. Persist — per-user ASP.NET session</strong></p>
|
||
<p><a
|
||
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/SEBSessionState.cs">SEBSessionState.cs</a>
|
||
stores values under keys <code>dateID</code>, <code>timeID</code>,
|
||
<code>orderByID</code>.</p>
|
||
<p><strong>3. Load — on next full page GET</strong></p>
|
||
<div class="sourceCode" id="cb3"><pre
|
||
class="sourceCode csharp"><code class="sourceCode cs"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">// ScheduleExecutionBoard.aspx.cs lines 267-277</span></span>
|
||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span> <span class="dt">void</span> <span class="fu">SetupControls</span><span class="op">()</span></span>
|
||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
|
||
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> sebState <span class="op">=</span> <span class="kw">new</span> <span class="fu">SEBSessionState</span><span class="op">();</span></span>
|
||
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> SessionOrderID <span class="op">=</span> sebState<span class="op">.</span><span class="fu">OrderBy</span><span class="op">;</span></span>
|
||
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> SessionDate <span class="op">=</span> sebState<span class="op">.</span><span class="fu">SearchDate</span><span class="op">;</span></span>
|
||
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> SessionTime <span class="op">=</span> sebState<span class="op">.</span><span class="fu">SearchTime</span><span class="op">;</span></span>
|
||
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
|
||
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p><strong>4. Render — vulnerable inline JavaScript (root
|
||
cause)</strong></p>
|
||
<div class="sourceCode" id="cb4"><pre
|
||
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">// ScheduleExecutionBoard.aspx lines 1853-1875</span></span>
|
||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> (<span class="st">"<%=SessionDate%>"</span>) {</span>
|
||
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">$</span>(<span class="st">'#txtStart'</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">"<%= SessionDate %>"</span>)<span class="op">;</span></span>
|
||
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>}</span>
|
||
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> (<span class="st">"<%=SessionTime%>"</span>) {</span>
|
||
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">$</span>(<span class="st">'#inputtime'</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">"<%=SessionTime%>"</span>)<span class="op">;</span></span>
|
||
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>}</span>
|
||
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> (<span class="st">"<%=SessionOrderID%>"</span>) {</span>
|
||
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">$</span>(orderBySelector <span class="op">+</span> <span class="st">' option[value="<%=SessionOrderID%>"]'</span>)<span class="op">.</span><span class="fu">attr</span>(<span class="st">'selected'</span><span class="op">,</span> <span class="st">'selected'</span>)<span class="op">;</span></span>
|
||
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
||
<p>Example payload in session:
|
||
<code>"); alert(document.domain); //</code></p>
|
||
<div class="sourceCode" id="cb5"><pre
|
||
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">$</span>(<span class="st">'#txtStart'</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">""</span>)<span class="op">;</span> <span class="fu">alert</span>(<span class="bu">document</span><span class="op">.</span><span class="at">domain</span>)<span class="op">;</span> <span class="co">//");</span></span></code></pre></div>
|
||
<p><strong>Related:</strong> <code>QuickSearch</code> at line ~1879 —
|
||
fix in the same pass.</p>
|
||
<h3 id="why-stored-session-and-self-xss">Why “stored”, “session”, and
|
||
“self-XSS”</h3>
|
||
<ul>
|
||
<li><strong>Stored:</strong> Payload survives page navigation in
|
||
<strong>session state</strong>.</li>
|
||
<li><strong>Self-XSS:</strong> Only the submitter’s session is affected;
|
||
no normal cross-user path.</li>
|
||
<li>Severity <strong>Informational</strong> because threat model is weak
|
||
vs shared stored XSS.</li>
|
||
</ul>
|
||
<h3 id="client-vs-server-validation-gap">Client vs server validation
|
||
gap</h3>
|
||
<p>Pentesters bypassed browser validation via direct POST. No
|
||
server-side validation blocked arbitrary strings.</p>
|
||
<hr />
|
||
<h2 id="replicating-the-vulnerability-hands-on">Replicating the
|
||
vulnerability (hands-on)</h2>
|
||
<p>Use this section to <strong>see the bug work</strong> on an
|
||
authorized environment (e.g. cert/UAT), then <strong>repeat the same
|
||
steps after fixes</strong> and compare outcomes.</p>
|
||
<h3 id="prerequisites">Prerequisites</h3>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 20%" />
|
||
<col style="width: 80%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Requirement</th>
|
||
<th>Detail</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><strong>Authorization</strong></td>
|
||
<td>Pentest scope or internal security test policy only</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Permission</strong></td>
|
||
<td><code>Microlise:TMC:SEB:Read</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>URL</strong></td>
|
||
<td>e.g. <code>https://<host>/TMCWebPortal/SEB/ScheduleExecutionBoard.aspx</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Tools</strong></td>
|
||
<td>Browser + DevTools or Burp Suite</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Build</strong></td>
|
||
<td>Before-fix build first; redeploy with remediation for after-fix
|
||
runs</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Must be logged in (valid session cookie on POST).</p>
|
||
<h3 id="what-you-should-observe-before-fix">What you should observe
|
||
(before fix)</h3>
|
||
<pre class="mermaid"><code>sequenceDiagram
|
||
participant You as Tester_browser
|
||
participant API as SaveSearchCriteriaToSession
|
||
participant Sess as ASP.NET_session
|
||
participant Page as ScheduleExecutionBoard_GET
|
||
|
||
You->>API: POST JSON with malicious date
|
||
API->>Sess: Store raw date in session
|
||
You->>Page: Reload SEB page
|
||
Page->>You: HTML with unescaped date inside script
|
||
You->>You: alert or other JS runs</code></pre>
|
||
<ol type="1">
|
||
<li>WebMethod returns HTTP 200.</li>
|
||
<li>Payload never went through <code>DateValidation()</code>.</li>
|
||
<li>Full page reload → JS runs (e.g. <code>alert</code>).</li>
|
||
<li>View Source: payload inside double-quoted JS string, unescaped.</li>
|
||
</ol>
|
||
<p><strong>Self-XSS:</strong> only your session is poisoned.</p>
|
||
<h3 id="step-by-step-reproduction">Step-by-step reproduction</h3>
|
||
<p><strong>Step 1 — Baseline (optional)</strong></p>
|
||
<ol type="1">
|
||
<li>Open SEB, perform a search.</li>
|
||
<li>DevTools → Network → <code>SaveSearchCriteriaToSession</code>.</li>
|
||
<li>Note POST, <code>application/json</code>, body shape, Cookie
|
||
header.</li>
|
||
</ol>
|
||
<p><strong>Step 2 — Inject via direct POST (bypass UI)</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Parameter</th>
|
||
<th>Suggested test value</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>searchID</code></td>
|
||
<td><code>0.X</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>orderID</code></td>
|
||
<td><code>0.X</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>date</code></td>
|
||
<td><code>"); alert(document.domain);//</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>time</code></td>
|
||
<td><code>00:00</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>hours</code></td>
|
||
<td><code>24</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>displayPriorityJourneys</code></td>
|
||
<td><code>false</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>quickSearch</code></td>
|
||
<td><code>""</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Burp:</strong> Repeater → replace JSON body → send.</p>
|
||
<p><strong>Browser console</strong> (on SEB page, same origin):</p>
|
||
<div class="sourceCode" id="cb7"><pre
|
||
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fetch</span>(<span class="st">'ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession'</span><span class="op">,</span> {</span>
|
||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">method</span><span class="op">:</span> <span class="st">'POST'</span><span class="op">,</span></span>
|
||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">credentials</span><span class="op">:</span> <span class="st">'include'</span><span class="op">,</span></span>
|
||
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">headers</span><span class="op">:</span> { <span class="st">'Content-Type'</span><span class="op">:</span> <span class="st">'application/json; charset=utf-8'</span> }<span class="op">,</span></span>
|
||
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">body</span><span class="op">:</span> <span class="bu">JSON</span><span class="op">.</span><span class="fu">stringify</span>({</span>
|
||
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">searchID</span><span class="op">:</span> <span class="st">'0.X'</span><span class="op">,</span></span>
|
||
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">orderID</span><span class="op">:</span> <span class="st">'0.X'</span><span class="op">,</span></span>
|
||
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">date</span><span class="op">:</span> <span class="st">'"); alert(document.domain);//'</span><span class="op">,</span></span>
|
||
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">time</span><span class="op">:</span> <span class="st">'00:00'</span><span class="op">,</span></span>
|
||
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">hours</span><span class="op">:</span> <span class="dv">24</span><span class="op">,</span></span>
|
||
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">displayPriorityJourneys</span><span class="op">:</span> <span class="kw">false</span><span class="op">,</span></span>
|
||
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">quickSearch</span><span class="op">:</span> <span class="st">''</span></span>
|
||
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> })</span>
|
||
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>})<span class="op">.</span><span class="fu">then</span>(r <span class="kw">=></span> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">'status'</span><span class="op">,</span> r<span class="op">.</span><span class="at">status</span>))<span class="op">;</span></span></code></pre></div>
|
||
<p><strong>curl</strong> (replace host, path, cookies):</p>
|
||
<div class="sourceCode" id="cb8"><pre
|
||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">curl</span> <span class="at">-s</span> <span class="at">-o</span> /dev/null <span class="at">-w</span> <span class="st">"%{http_code}"</span> <span class="dt">\</span></span>
|
||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="at">-X</span> POST <span class="st">"https://<host>/<TMCWebPortal>/SEB/ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession"</span> <span class="dt">\</span></span>
|
||
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="at">-H</span> <span class="st">"Content-Type: application/json; charset=utf-8"</span> <span class="dt">\</span></span>
|
||
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="at">-H</span> <span class="st">"Cookie: <paste-session-cookies>"</span> <span class="dt">\</span></span>
|
||
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="at">-d</span> <span class="st">"{</span><span class="dt">\"</span><span class="st">searchID</span><span class="dt">\"</span><span class="st">:</span><span class="dt">\"</span><span class="st">0.X</span><span class="dt">\"</span><span class="st">,</span><span class="dt">\"</span><span class="st">orderID</span><span class="dt">\"</span><span class="st">:</span><span class="dt">\"</span><span class="st">0.X</span><span class="dt">\"</span><span class="st">,</span><span class="dt">\"</span><span class="st">date</span><span class="dt">\"</span><span class="st">:</span><span class="dt">\"\\\"</span><span class="st">); alert(document.domain);//</span><span class="dt">\"</span><span class="st">,</span><span class="dt">\"</span><span class="st">time</span><span class="dt">\"</span><span class="st">:</span><span class="dt">\"</span><span class="st">00:00</span><span class="dt">\"</span><span class="st">,</span><span class="dt">\"</span><span class="st">hours</span><span class="dt">\"</span><span class="st">:24,</span><span class="dt">\"</span><span class="st">displayPriorityJourneys</span><span class="dt">\"</span><span class="st">:false,</span><span class="dt">\"</span><span class="st">quickSearch</span><span class="dt">\"</span><span class="st">:</span><span class="dt">\"\"</span><span class="st">}"</span></span></code></pre></div>
|
||
<p><strong>Step 3 — Trigger render (stored XSS)</strong></p>
|
||
<ol type="1">
|
||
<li>Full navigation reload of <code>ScheduleExecutionBoard.aspx</code>
|
||
(F5).</li>
|
||
<li><code>SetupControls()</code> embeds session <code>date</code>
|
||
(~lines 1854–1855).</li>
|
||
</ol>
|
||
<p><strong>Step 4 — Confirm</strong></p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 19%" />
|
||
<col style="width: 80%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Check</th>
|
||
<th>Before fix (expected)</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Popup / console</td>
|
||
<td><code>alert(document.domain)</code> runs</td>
|
||
</tr>
|
||
<tr>
|
||
<td>View Source</td>
|
||
<td>Literal <code>"); alert(...)</code> inside
|
||
<code>$('#txtStart').val("...")</code> unescaped</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Network on reload</td>
|
||
<td>Normal GET only; XSS from inline script</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Other users</td>
|
||
<td>No effect (different session)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Step 5 — Optional:</strong> malicious <code>time</code> or
|
||
<code>orderID</code>.</p>
|
||
<p><strong>Step 6 — Clean up:</strong> log out/in or POST valid
|
||
date/time.</p>
|
||
<h3 id="comparison-matrix-before-vs-after-fixes">Comparison matrix
|
||
(before vs after fixes)</h3>
|
||
<p>Run the same Steps 2–4 after each change:</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 33%" />
|
||
<col style="width: 10%" />
|
||
<col style="width: 20%" />
|
||
<col style="width: 22%" />
|
||
<col style="width: 13%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Observation</th>
|
||
<th>Before fix</th>
|
||
<th>After encoding only</th>
|
||
<th>After validation only</th>
|
||
<th>After both</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>POST malicious <code>date</code> accepted?</td>
|
||
<td>Yes (200)</td>
|
||
<td>Yes (200)</td>
|
||
<td>No / not stored</td>
|
||
<td>No</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>alert</code> on reload?</td>
|
||
<td><strong>Yes</strong></td>
|
||
<td><strong>No</strong></td>
|
||
<td>Depends*</td>
|
||
<td><strong>No</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Executable JS in View Source?</td>
|
||
<td><strong>Yes</strong></td>
|
||
<td><strong>No</strong> (escaped)</td>
|
||
<td>Depends*</td>
|
||
<td><strong>No</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>#txtStart</code> shows attack text?</td>
|
||
<td>Maybe</td>
|
||
<td>Escaped/safe</td>
|
||
<td>Default/empty</td>
|
||
<td>Default/empty</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Normal UI search + reload works?</td>
|
||
<td>Yes</td>
|
||
<td>Yes</td>
|
||
<td>Yes</td>
|
||
<td>Yes</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>*If only validation: reload may show no XSS without encoding — still
|
||
apply both fixes.</p>
|
||
<h3 id="why-ui-only-testing-misses-the-bug">Why UI-only testing misses
|
||
the bug</h3>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 35%" />
|
||
<col style="width: 32%" />
|
||
<col style="width: 32%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Path</th>
|
||
<th><code>DateValidation()</code> runs?</th>
|
||
<th>Payload reaches session?</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Click Search in UI</td>
|
||
<td>Yes</td>
|
||
<td>No (normal typing)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Direct POST / Burp / fetch</td>
|
||
<td><strong>No</strong></td>
|
||
<td><strong>Yes</strong></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Reproduction <strong>must</strong> use direct POST to match the
|
||
pentest.</p>
|
||
<h3 id="evidence-to-capture-for-fix-sign-off">Evidence to capture (for
|
||
fix sign-off)</h3>
|
||
<ol type="1">
|
||
<li>Request (POST body with payload).</li>
|
||
<li>Screenshot of alert (before) or no alert (after).</li>
|
||
<li>View Source snippet around <code>$('#txtStart').val(</code>.</li>
|
||
<li>Regression: legitimate date, reload, criteria restored.</li>
|
||
</ol>
|
||
<h3 id="safety-and-scope">Safety and scope</h3>
|
||
<ul>
|
||
<li>No production without approval.</li>
|
||
<li>Prefer <code>alert(document.domain)</code> over exfiltration
|
||
demos.</li>
|
||
<li>Self-XSS: coding defect demo, not mass compromise.</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="how-to-fix-it">How to fix it</h2>
|
||
<p>Use <strong>two layers</strong>: output encoding + server-side
|
||
validation.</p>
|
||
<h3 id="fix-1-output-encoding-required">Fix 1 — Output encoding
|
||
(required)</h3>
|
||
<p>File: <a
|
||
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx">ScheduleExecutionBoard.aspx</a>,
|
||
<code>SetupControls()</code> (~1847–1884).</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Line (approx)</th>
|
||
<th>Field</th>
|
||
<th>Encode</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>1849–1850</td>
|
||
<td>SessionSearchID</td>
|
||
<td>Yes</td>
|
||
</tr>
|
||
<tr>
|
||
<td>1854–1855</td>
|
||
<td>SessionDate</td>
|
||
<td>Yes</td>
|
||
</tr>
|
||
<tr>
|
||
<td>1860–1861</td>
|
||
<td>SessionTime</td>
|
||
<td>Yes</td>
|
||
</tr>
|
||
<tr>
|
||
<td>1872–1874</td>
|
||
<td>SessionOrderID</td>
|
||
<td>Yes</td>
|
||
</tr>
|
||
<tr>
|
||
<td>1878–1879</td>
|
||
<td>QuickSearch</td>
|
||
<td>Yes</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Before:</strong></p>
|
||
<div class="sourceCode" id="cb9"><pre
|
||
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">$</span>(<span class="st">'#txtStart'</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">"<%= SessionDate %>"</span>)<span class="op">;</span></span></code></pre></div>
|
||
<p><strong>After:</strong></p>
|
||
<div class="sourceCode" id="cb10"><pre
|
||
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="fu">$</span>(<span class="st">'#txtStart'</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">"<%= HttpUtility.JavaScriptStringEncode(SessionDate ?? string.Empty) %>"</span>)<span class="op">;</span></span></code></pre></div>
|
||
<p>Encode <code>if</code> guards too, or use code-behind booleans
|
||
(<code>HasSessionDate</code>).</p>
|
||
<h3 id="fix-2-server-side-input-validation">Fix 2 — Server-side input
|
||
validation</h3>
|
||
<p>File: <a
|
||
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx.cs">ScheduleExecutionBoard.aspx.cs</a>,
|
||
<code>SaveSearchCriteriaToSession</code> (~337).</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Parameter</th>
|
||
<th>Validation rule</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>date</code></td>
|
||
<td>Same regex as client <code>DateValidation()</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>time</code></td>
|
||
<td><code>^[0-2][0-9]:[0-5][0-9]$</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>orderID</code></td>
|
||
<td><code>^[0-9]+(\.X)?$</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>searchID</code></td>
|
||
<td>Same as <code>orderID</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>hours</code></td>
|
||
<td>Clamp 1–999</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="sourceCode" id="cb11"><pre
|
||
class="sourceCode csharp"><code class="sourceCode cs"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="op">[</span>WebMethod<span class="op">]</span></span>
|
||
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">static</span> <span class="dt">void</span> <span class="fu">SaveSearchCriteriaToSession</span><span class="op">(...)</span></span>
|
||
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
|
||
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">if</span> <span class="op">(!</span><span class="fu">IsValidSebDate</span><span class="op">(</span>date<span class="op">)</span> <span class="op">||</span> <span class="op">!</span><span class="fu">IsValidSebTime</span><span class="op">(</span>time<span class="op">)</span></span>
|
||
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> <span class="op">||</span> <span class="op">!</span><span class="fu">IsValidQueryComponentId</span><span class="op">(</span>orderID<span class="op">)</span> <span class="op">||</span> <span class="op">!</span><span class="fu">IsValidQueryComponentId</span><span class="op">(</span>searchID<span class="op">))</span></span>
|
||
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span></span>
|
||
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span><span class="op">;</span></span>
|
||
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> sebState <span class="op">=</span> <span class="kw">new</span> <span class="fu">SEBSessionState</span><span class="op">();</span></span>
|
||
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
|
||
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p><strong>Date regex:</strong></p>
|
||
<pre><code>^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$</code></pre>
|
||
<h3 id="fix-3-what-not-to-do">Fix 3 — What not to do</h3>
|
||
<ul>
|
||
<li>Do not rely on client <code>DateValidation()</code> alone.</li>
|
||
<li>Do not use <code>HtmlEncode</code> in JS string literals.</li>
|
||
<li>Do not use <code>innerHTML</code>; keep <code>.val()</code>.</li>
|
||
</ul>
|
||
<h3 id="fix-4-verification-test-plan">Fix 4 — Verification / test
|
||
plan</h3>
|
||
<p>Master procedure: <strong>Replicating the vulnerability</strong>
|
||
section above.</p>
|
||
<p><strong>Negative test:</strong></p>
|
||
<div class="sourceCode" id="cb13"><pre
|
||
class="sourceCode json"><code class="sourceCode json"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
|
||
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">"searchID"</span><span class="fu">:</span> <span class="st">"0.X"</span><span class="fu">,</span></span>
|
||
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">"orderID"</span><span class="fu">:</span> <span class="st">"0.X"</span><span class="fu">,</span></span>
|
||
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">"date"</span><span class="fu">:</span> <span class="st">"</span><span class="ch">\"</span><span class="st">); alert(1);//"</span><span class="fu">,</span></span>
|
||
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">"time"</span><span class="fu">:</span> <span class="st">"00:00"</span><span class="fu">,</span></span>
|
||
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">"hours"</span><span class="fu">:</span> <span class="dv">24</span><span class="fu">,</span></span>
|
||
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">"displayPriorityJourneys"</span><span class="fu">:</span> <span class="kw">false</span><span class="fu">,</span></span>
|
||
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">"quickSearch"</span><span class="fu">:</span> <span class="st">""</span></span>
|
||
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
|
||
<p><strong>Pass:</strong> No alert; escaped in source; invalid date not
|
||
stored (with Fix 2).</p>
|
||
<p><strong>Positive test:</strong> UI search + reload restores
|
||
criteria.</p>
|
||
<h3 id="files-to-change-summary">Files to change (summary)</h3>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 70%" />
|
||
<col style="width: 29%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>File</th>
|
||
<th>Change</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><a
|
||
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx">ScheduleExecutionBoard.aspx</a></td>
|
||
<td><code>JavaScriptStringEncode</code> in
|
||
<code>SetupControls()</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><a
|
||
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx.cs">ScheduleExecutionBoard.aspx.cs</a></td>
|
||
<td>Validation in <code>SaveSearchCriteriaToSession</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>References:</strong> <a
|
||
href="https://owasp.org/www-community/attacks/xss/">OWASP XSS</a>, <a
|
||
href="https://portswigger.net/web-security/cross-site-scripting/stored">PortSwigger
|
||
Stored XSS</a>, <a
|
||
href="https://learn.microsoft.com/en-us/dotnet/api/system.web.httputility.javascriptstringencode">JavaScriptStringEncode</a></p>
|
||
<hr />
|
||
<h2 id="mental-model-severity-vs-correctness">Mental model: severity vs
|
||
correctness</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Question</th>
|
||
<th>Answer</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Real coding flaw?</td>
|
||
<td><strong>Yes</strong> (CWE-79)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Cross-user session hijack?</td>
|
||
<td><strong>Not under normal use</strong> (self-XSS)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Should it still be fixed?</td>
|
||
<td><strong>Yes</strong>, as hygiene</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Priority vs SQLi / IDOR?</td>
|
||
<td><strong>Much lower</strong> (informational)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2 id="code-snippets">Code snippets</h2>
|
||
<h3 id="reset">Reset:</h3>
|
||
<pre><code>fetch('ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession', {
|
||
method: 'POST',
|
||
credentials: 'include',
|
||
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
||
body: JSON.stringify({
|
||
searchID: '0.X', orderID: '0.X',
|
||
date: '2026-05-27', time: '00:00', hours: 24,
|
||
displayPriorityJourneys: false, quickSearch: ''
|
||
})
|
||
}).then(() => location.reload());</code></pre>
|
||
<h3 id="alert">Alert</h3>
|
||
<pre><code>fetch('ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession', {
|
||
method: 'POST',
|
||
credentials: 'include',
|
||
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
||
body: JSON.stringify({
|
||
searchID: '0.X',
|
||
orderID: '0.X',
|
||
date: '"+alert(1)+"',
|
||
time: '00:00',
|
||
hours: 24,
|
||
displayPriorityJourneys: false,
|
||
quickSearch: ''
|
||
})
|
||
}).then(r => console.log(r.status, r.statusText));</code></pre>
|
||
<h3 id="poison-session">Poison Session</h3>
|
||
<pre><code>function poisonSession(field, payload) {
|
||
const body = {
|
||
searchID: '0.X',
|
||
orderID: '0.X',
|
||
date: '2026-05-27',
|
||
time: '00:00',
|
||
hours: 24,
|
||
displayPriorityJourneys: false,
|
||
quickSearch: ''
|
||
};
|
||
body[field] = payload;
|
||
return fetch('ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession', {
|
||
method: 'POST',
|
||
credentials: 'include',
|
||
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
||
body: JSON.stringify(body)
|
||
}).then(r => console.log(field, r.status, r.statusText));
|
||
}</code></pre>
|
||
<h3 id="confirm-prompt-alternative-dialog-evidence">Confirm / prompt
|
||
(alternative dialog evidence)</h3>
|
||
<pre><code>poisonSession('date', '"+confirm("XSS: SEB session poisoned")+"');</code></pre>
|
||
<h3 id="visible-banner">Visible banner</h3>
|
||
<pre><code>poisonSession('date', '"+document.body.insertAdjacentHTML("afterbegin","<div style=\\"position:fixed;top:0;left:0;right:0;background:red;color:white;z-index:99999;padding:12px;text-align:center\\">XSS PoC — arbitrary script executed in SEB context</div>")+"');</code></pre>
|
||
|
||
</body>
|
||
</html>
|