<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Hirara</title><description>Bug Bounty &amp; Security Research</description><link>https://blog.hirara.dev/</link><language>en</language><item><title>From WebSocket PING to Jetty Backend: Reconnaissance of a Live Casino Platform</title><link>https://blog.hirara.dev/posts/websocket-ping-to-jetty/</link><guid isPermaLink="true">https://blog.hirara.dev/posts/websocket-ping-to-jetty/</guid><description>How a single intercepted WebSocket request led to information disclosure, directory listing, and backend fingerprinting of a live casino platform.</description><pubDate>Sun, 21 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0x00 — Prologue: A Single Intercept&lt;/h2&gt;
&lt;p&gt;It all started with one simple request while I was browsing a live casino client portal. Burp Suite caught this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GET /ws HTTP/1.1
Host: dga.dkitrxmdwoqruvsi.net
Connection: Upgrade
Upgrade: websocket
Origin: https://client.dkitrxmdwoqruvsi.net
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: oRRH9vs2xQP9GEC6oioO4w==
Cookie: AWSALB=...; AWSALBCORS=...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A WebSocket handshake. But the interesting part wasn&apos;t the &lt;code&gt;Sec-WebSocket-Key&lt;/code&gt; — that&apos;s just an RFC 6455 nonce. What caught my eye was the exposed endpoint with a full session cookie, and the fact that there were other subdomains pointing to a deeper infrastructure.&lt;/p&gt;
&lt;h2&gt;0x01 — Phase 1: WebSocket Reconnaissance&lt;/h2&gt;
&lt;p&gt;First attempts with &lt;code&gt;websocat&lt;/code&gt; and &lt;code&gt;openssl&lt;/code&gt; failed — the server required a valid &lt;code&gt;Origin&lt;/code&gt; header and session cookie. After some trial and error, a Python script finally completed the handshake:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import websocket, ssl

ws = websocket.WebSocket(sslopt={&quot;cert_reqs&quot;: ssl.CERT_NONE})
ws.connect(
    &quot;wss://dga.dkitrxmdwoqruvsi.net/ws&quot;,
    header=[&quot;Origin: https://client.dkitrxmdwoqruvsi.net&quot;],
    cookie=&quot;JSESSIONID=...&quot;
)
ws.send(&apos;{&quot;type&quot;:&quot;ping&quot;}&apos;)
print(ws.recv())
# {&quot;pongTime&quot;:1781999879654,&quot;pingTime&quot;:0}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Finding #1: WebSocket Information Disclosure&lt;/h3&gt;
&lt;p&gt;The server responded with an internal &lt;code&gt;pongTime&lt;/code&gt; timestamp and &lt;code&gt;userId: &quot;null&quot;&lt;/code&gt;, &lt;code&gt;role: &quot;null&quot;&lt;/code&gt;. This indicated anonymous access to the heartbeat endpoint — valuable reconnaissance data.&lt;/p&gt;
&lt;p&gt;I moved on to the &lt;code&gt;/chat&lt;/code&gt; WebSocket endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ws.connect(&quot;wss://chat.dkitrxmdwoqruvsi.net/chat&quot;, ...)
ws.send(&apos;{&quot;action&quot;:&quot;ping&quot;}&apos;)
# {&quot;action&quot;:&quot;PONG&quot;,&quot;status&quot;:&quot;SUCCESS&quot;,&quot;userId&quot;:&quot;null&quot;,&quot;role&quot;:&quot;null&quot;,&quot;pongtime&quot;:...}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Finding #2: Protocol Structure Leak&lt;/h3&gt;
&lt;p&gt;Invalid payloads returned structured error messages, revealing the server expects an &lt;code&gt;action&lt;/code&gt; field (not &lt;code&gt;type&lt;/code&gt;). More importantly: no rate limiting and the server didn&apos;t aggressively drop connections, leaving room for enumeration.&lt;/p&gt;
&lt;h2&gt;0x02 — Phase 2: The URL Goldmine&lt;/h2&gt;
&lt;p&gt;Looking closer at the browser URL bar, I found something alarming. The client portal query parameters contained sensitive data that should never be in a URL:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://games.dkitrxmdwoqruvsi.net/...&amp;amp;config_url=/cgibin/appconfig/xml/configs/urls.xml
&amp;amp;JSESSIONID=vWhhhigmpIj5tOA0Y3K8bjdbkr6eu3B3OikeOlkl0pkXe1B-5ByJ!...
&amp;amp;userId=ppc1735045641964
&amp;amp;socket_server=wss://games.dkitrxmdwoqruvsi.net/game
&amp;amp;token=...
&amp;amp;stats_collector_uuid=328e5abc-17f0-49f3-8eb0-0ed92fd9e1d1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Finding #3: Sensitive Information in URL Parameters (P3)&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;JSESSIONID&lt;/code&gt;, session token, &lt;code&gt;userId&lt;/code&gt;, internal paths (&lt;code&gt;cgibin/appconfig/xml/configs/urls.xml&lt;/code&gt;), and internal WebSocket endpoints were all exposed in the URL. Impact: browser history, proxy logs, and referrer headers will carry these credentials.&lt;/p&gt;
&lt;h2&gt;0x03 — Phase 3: Unauthenticated Manifest &amp;amp; CORS&lt;/h2&gt;
&lt;p&gt;Following the &lt;code&gt;config_url&lt;/code&gt; parameter, I tried direct access:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -s &quot;https://client.dkitrxmdwoqruvsi.net/apps/feature-flags/1.0.0/lobby.manifest.json&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Response:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;game&quot;: [{&quot;version&quot;: &quot;3.83.0&quot;}],
  &quot;defaultFeaturedGames&quot;: [{&quot;value&quot;: [&quot;270&quot;, &quot;292&quot;, &quot;204&quot;]}],
  &quot;heroBannerVideo&quot;: [{&quot;enabled&quot;: true}],
  &quot;gameAssetsBaseUrl&quot;: [{&quot;value&quot;: &quot;&quot;}],
  &quot;newComms&quot;: [{&quot;enabled&quot;: true}],
  &quot;slotsCurrencyNewFormat&quot;: [{&quot;enabled&quot;: true}]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Finding #4: Feature Flags Manifest Exposure (P3)&lt;/h3&gt;
&lt;p&gt;Internal configuration files were accessible without authentication. This revealed version disclosure (&lt;code&gt;3.83.0&lt;/code&gt;), internal game IDs (&lt;code&gt;270&lt;/code&gt;, &lt;code&gt;292&lt;/code&gt;, &lt;code&gt;204&lt;/code&gt;), and active feature flags exposing business logic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bonus:&lt;/strong&gt; CORS headers showed &lt;code&gt;access-control-allow-origin: *&lt;/code&gt; on static files — limited impact since the files are public-by-design, but still worth noting.&lt;/p&gt;
&lt;h2&gt;0x04 — Phase 4: Directory Listing &amp;amp; Source Code Exposure&lt;/h2&gt;
&lt;p&gt;Reconnaissance continued to the &lt;code&gt;games.&lt;/code&gt; subdomain — and that&apos;s where the door opened wider.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -s &quot;https://games.dkitrxmdwoqruvsi.net/authentication/&quot; | grep &apos;href=&quot;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/authentication/../
/authentication/authenticate.jsp
/authentication/logout.jsp
/authentication/request.js
/authentication/xlg_BO_footer.png
/authentication/xlg_BO_footer_over.png
jetty-dir.css
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Finding #5: Directory Listing Enabled (P3)&lt;/h3&gt;
&lt;p&gt;The server exposed directory listing under &lt;code&gt;/authentication/&lt;/code&gt;, revealing JSP files and internal JavaScript logic.&lt;/p&gt;
&lt;p&gt;I grabbed &lt;code&gt;authenticate.jsp&lt;/code&gt; and &lt;code&gt;request.js&lt;/code&gt;. The contents were surprising:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;authenticate.jsp&lt;/code&gt; revealed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Login API endpoint: &lt;code&gt;POST /api/security/portal/login&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Internal casino IDs: &lt;code&gt;il9srgw4dna23p47&lt;/code&gt;, &lt;code&gt;il9srgw4dna11111&lt;/code&gt;, &lt;code&gt;il9srgw4dna22222&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Session token passed via URL: &lt;code&gt;/portal?JSESSIONID=...&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withCredentials: true&lt;/code&gt; on CORS requests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;request.js&lt;/code&gt; revealed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CORS request handler with &lt;code&gt;xhr.withCredentials = true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Content-type: &lt;code&gt;application/json&lt;/code&gt; on POST requests&lt;/li&gt;
&lt;li&gt;&lt;code&gt;extractDomain()&lt;/code&gt; helper for URL parsing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;0x05 — Phase 5: Backend Fingerprinting — The Jetty Revelation&lt;/h2&gt;
&lt;p&gt;I tried sending an invalid JSON payload to the login API:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -s -X POST &quot;https://games.dkitrxmdwoqruvsi.net/api/security/portal/login&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -d &apos;{&quot;username&quot;:{&quot;$ne&quot;:null},&quot;pass&quot;:{&quot;$ne&quot;:null},&quot;time&quot;:1234567890}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The response was a goldmine:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: HttpInput@627799400 cs=HttpChannelState@4543fddc...
 cp=org.eclipse.jetty.ee8.nested.BlockingContentProducer@49b2d60f...
 (through reference chain: com.extremelivegaming.api.security.vo.LoginVO[&quot;username&quot;])
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Finding #6: Java Backend &amp;amp; Package Name Disclosure (P3/P4)&lt;/h3&gt;
&lt;p&gt;From the stack trace error, I extracted:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server:&lt;/strong&gt; Jetty EE8 (&lt;code&gt;org.eclipse.jetty.ee8.nested.BlockingContentProducer&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vendor Package:&lt;/strong&gt; &lt;code&gt;com.extremelivegaming.api.security.vo.LoginVO&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deserialization:&lt;/strong&gt; Jackson strict type checking&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is critical information disclosure — internal package structure that can be used to build gadget chains or further reconnaissance.&lt;/p&gt;
&lt;h2&gt;0x06 — Phase 6: The Bigger Picture&lt;/h2&gt;
&lt;p&gt;From all findings, the target architecture became clear:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;S3 + CloudFront (Static)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reverse Proxy&lt;/td&gt;
&lt;td&gt;nginx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application Server&lt;/td&gt;
&lt;td&gt;Jetty EE8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Java (Extreme Live Gaming)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket&lt;/td&gt;
&lt;td&gt;Custom protocol (action-based JSON)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session&lt;/td&gt;
&lt;td&gt;JSESSIONID (Java/Jetty style)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;0x07 — Impact Summary&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Finding&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensitive tokens in URL&lt;/td&gt;
&lt;td&gt;P3&lt;/td&gt;
&lt;td&gt;JSESSIONID, userId, token leak via URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Feature flags manifest&lt;/td&gt;
&lt;td&gt;P3&lt;/td&gt;
&lt;td&gt;Unauthenticated internal config access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Directory listing&lt;/td&gt;
&lt;td&gt;P3&lt;/td&gt;
&lt;td&gt;Source code &amp;amp; JSP exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internal package leak&lt;/td&gt;
&lt;td&gt;P4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;com.extremelivegaming&lt;/code&gt; package disclosure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket info leak&lt;/td&gt;
&lt;td&gt;P4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pongTime&lt;/code&gt;, &lt;code&gt;userId: null&lt;/code&gt; exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS wildcard&lt;/td&gt;
&lt;td&gt;P4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;access-control-allow-origin: *&lt;/code&gt; on static&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;0x08 — Takeaways &amp;amp; Lessons Learned&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;WebSocket is not just &quot;real-time chat&quot;&lt;/strong&gt; — it&apos;s often a gateway to deeper backend logic. Never skip WS recon.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;URL parameters are the enemy&lt;/strong&gt; — always inspect query strings in intercepts; credentials often &quot;stick&quot; there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Directory listing is still alive in 2026&lt;/strong&gt; — &lt;code&gt;/authentication/&lt;/code&gt; with &lt;code&gt;jetty-dir.css&lt;/code&gt; is proof that classic misconfigs never die.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error messages are gold&lt;/strong&gt; — one invalid JSON payload opened the entire backend stack (&lt;code&gt;org.eclipse.jetty.ee8&lt;/code&gt;, &lt;code&gt;com.extremelivegaming&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don&apos;t chase CVEs blindly&lt;/strong&gt; — this target wasn&apos;t Next.js, wasn&apos;t Spring Boot (despite similar-looking errors), but Jetty EE8 + custom Java stack. Match the CVE to the stack.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;0x09 — Responsible Disclosure&lt;/h2&gt;
&lt;p&gt;All findings were documented with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Screenshots of requests and responses&lt;/li&gt;
&lt;li&gt;cURL commands for reproducibility&lt;/li&gt;
&lt;li&gt;Testing timeline (June 2026)&lt;/li&gt;
&lt;li&gt;Per-finding impact assessment&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; No exploitation beyond proof-of-concept was performed. No game state manipulation, betting interference, or unauthorized data access was attempted. All testing stayed within the scope of security research.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks for reading. If you have feedback or corrections, feel free to reach out. Happy hacking! 🎯&lt;/p&gt;
</content:encoded></item></channel></rss>