cscg24-njs

CSCG 2024 Challenge 'Nimble Join Service'
git clone https://git.sinitax.com/sinitax/cscg24-njs
Log | Files | Refs | sfeed.txt

join.js (1777B)


      1var flag = "CSCG{This_is_a_fake_flag!}";
      2
      3// Combines several responses asynchronously into a singel reply
      4async function join(r) {
      5    if (r.method !== "POST") {
      6        r.return(401, "Unsupported method\n");
      7        return;
      8    }
      9
     10    let body  = JSON.parse((r.requestText));
     11
     12    if (!body['endpoints']) {
     13        r.return(400, "Missing Parameters!");
     14        return;
     15    }
     16
     17    // Make sure to prevent LFI since directory root does not apply to subrequests...
     18    let subs = body.endpoints.filter(sub => (typeof sub === "string" && !sub.includes(".")));
     19    if (subs.length === 0) {
     20        r.return(400, "No valid endpoint supplied!");
     21        return;
     22    }
     23
     24    let response = await join_subrequests(r, subs);
     25
     26    var ascii_error = "Error: No ASCII data!";
     27    
     28    // Using alloc() instead of allocUnsafe() to ensure no sensitive data is leaked!
     29    let reply_buffer = Buffer.alloc(response.length);
     30
     31    if ( r.headersIn["Accept"] === "text/html; charset=utf-8" ) {
     32        // Remove non ASCII character
     33        let ascii_string = response.replace(/[^\x00-\x7F]/g, "");
     34
     35        if ( ascii_string.length == 0 ) {
     36            // Joined response does not contain any ASCII data...
     37            reply_buffer.write(ascii_error);
     38        } else {
     39            reply_buffer.write(ascii_string);
     40        }
     41
     42        // Return response as string
     43        r.return(200, reply_buffer.toString());
     44    } else {
     45        reply_buffer.write(response);
     46
     47        // Return response as buffer
     48        r.return(200, reply_buffer);
     49    }
     50}
     51
     52async function join_subrequests(r, subs) {
     53
     54    let results = await Promise.all(subs.map(uri => r.subrequest("/data/" + uri)));
     55    let response = results.map(reply => (reply.responseText)).join("");
     56
     57    return response;
     58}
     59
     60export default { join };