Skip to content

[SECURITY] Improve SSRF checks, strict path check for well_known_path #2510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 29, 2025

Conversation

ajinabraham
Copy link
Member

@ajinabraham ajinabraham commented Mar 28, 2025

Describe the Pull Request

* Improved SSRF checks (credential checks, length check, port check, path, query, and params check, ipv6, ipv4 coverage, handle possible decimal or hex IP bypasses)
* Add additional strict path check for Applink well known path
* Moved `valid_host` to `security.py`

Checklist for PR

  • Run MobSF unit tests and lint tox -e lint,test
  • Tested Working on Linux, Mac, Windows, and Docker
  • Add unit test for any new Web API (Refer: StaticAnalyzer/tests.py)
  • Make sure tests are passing on your PR MobSF tests

Additional Comments (if any)

DESCRIBE HERE

Copy link

👋 @ajinabraham
Thank you for sending this pull request ❤️.
Please make sure you have followed our contribution guidelines. We will review it as soon as possible

return False

prefixs = ('http://', 'https://')
if not host.startswith(prefixs):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not. Use host.scheme here?

Copy link
Member Author

@ajinabraham ajinabraham Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

host is not parsed yet, we can have hosts with user controlled scheme or no scheme at all, So forcing HTTP scheme on it.


# Resolve dns to get ipv4 or ipv6 address
socket.setdefaulttimeout(5) # 5 second timeout
ip_addresses = socket.getaddrinfo(hostname, None)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each time this is called a DNS rebinding is possible

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internal port scanning is still possible with the next urls, the ip_addresses = socket.getaddrinfo(hostname, None) does issue a DNS query thus permitting the host to switch from 1.1.1.1:80 to 127.0.0.1:80

  • "prefix1-make-1.1.1.1-rebindfor30safter1times-127.0.0.1-rr.1u.ms:80"
  • "prefix1-make-1.1.1.1-rebindfor30safter1times-127.0.0.1-rr.1u.ms:81"
  • ....
  • "prefix1-make-1.1.1.1-rebindfor30safter1times-127.0.0.1-rr.1u.ms:443"

measuring the response time would yield if the port is open or not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR doesn't do anything against DNS rebind. We cannot removesocket.getaddrinfo as it's required to translate IPs from hostnames dynamically to validate against a known private/internal list.

I did some overall refactoring to SSRF checks and enforced strict hardcoded path check for the 2 places we invoke user controlled requests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since firebase and assetlink looks at https://, or http://, I can also do a port check.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about using the initially retrieved value of socket.getaddreinfo to avoid the DNS rebind ?

Copy link
Member Author

@ajinabraham ajinabraham Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot rely on the IP alone to resolve a resource. It depends on the virtual hosting or domain based routing configurations of the server.

a single IP address can host different resources at the same path across multiple domain names.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, but after the resolving of socket.getaddrinfo() the next call to .get() would point to the second DNS rebinded host, thus still vulnerable to a certain extent with a limited impact.

Regards

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I acknowledge that this PR does not address the DNS rebind issue. A potential fix could involve monkey patching requests/urllib3 or implementing a custom HTTP request library with fixed domain name and IP. However, I am hesitant to add this unless there is a medium/high impact real-world exploit case. The current checks in place offer a balanced approach to mitigating the SSRF issue and its primary exploit use cases.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see now, anyway, keep me posted about when you would release the advisory. Thank you

@ajinabraham ajinabraham merged commit 4b8bab5 into master Mar 29, 2025
10 checks passed
@ajinabraham ajinabraham deleted the GHSA-fcfq-m8p6-gw56 branch March 29, 2025 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants