Home Are you the admin? TFCCTF 2022
Post
Cancel

Are you the admin? TFCCTF 2022

ARE YOU THE ADMIN? - TFCCTF2022

Untitled

Source code đi kèm

schema.prisma

1
2
3
4
5
6
7
8
9
10
11
12
13
14
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = "file:./app.db"
}

model User {
  id       String  @id @default(uuid())
  username String
  isAdmin  Boolean @default(false)
}

auth.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
import { NextApiRequest, NextApiResponse } from "next";
import { prisma } from "../../globals/prisma";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const body = req.body;
  await prisma.user.create({
    data: body,
  });
  return res.status(200).end();
}

index.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import type { GetServerSideProps, NextPage } from "next";
import type { User } from "@prisma/client";
import { prisma } from "../globals/prisma";
import { useState } from "react";
import { useRouter } from "next/router";

type Props = {
  users: (User &
    (
      | {
          flag: string;
          isAdmin: true;
        }
      | {
          flag?: never;
          isAdmin: false;
        }
    ))[];
};

const Home: NextPage<Props> = ({ users }) => {
  const [username, setUsername] = useState("");

  const router = useRouter();

  const create = async () => {
    await fetch("/api/auth", {
      headers: {
        "Content-Type": "application/json",
      },
      method: "POST",
      body: JSON.stringify({
        username,
      }),
    });
    await router.replace(router.asPath);
  };

  return (
    <div>
      <div>Create user:</div>
      <input
        value={username}
        onChange={(event) => setUsername(event.target.value)}
      />
      <button onClick={create}>Create</button>
      <div>Users:</div>
      {users.map((user) => (
        <div key={user.id}>
          <div>Username: {user.username}</div>
          <div>Is admin? {user.isAdmin ? "yes" : "no"}</div>
          {user.isAdmin && <div>{user.flag}</div>}
        </div>
      ))}
    </div>
  );
};

export default Home;

export const getServerSideProps: GetServerSideProps<Props> = async (
  context
) => {
  const users = (await prisma.user.findMany()) as Props["users"];

  for (const user of users) {
    if (user.isAdmin) {
      user.flag = process.env.FLAG!;
    }
  }

  return {
    props: {
      users,
    },
  };
};

Trang web rất đơn giản, gồm 1 cái form để điền username và nút Create

Untitled

Untitled

Khi click vào button Create, web sẽ POST đến endpoint /api/auth với body là username

Untitled

Đọc code để xem endpoint /api/auth sẽ làm gì

Theo mình hiểu thì nó sẽ lấy dữ liệu được POST lên và tạo 1 user mới

Untitled

Nếu user là admin, web sẽ lấy flag và in ra

Untitled

Ok quay trở lại với request create user

Untitled

Vì /api/auth không hề check lại body hay lọc dữ liệu mà chỉ lấy toàn bộ body nên mình chỉ cần thêm trường “isAdmin”:true

Untitled

Ok ngon lành

Untitled

Untitled

1
Flag: TFCCTF{S4n1t1z3_Y0ur_1nput5!}
This post is licensed under CC BY 4.0 by the author.

WhiteHat Play 11 Writeup

Đừng chơi Bug bounty, chạy, chạy ngay đi!!