Monday, November 10, 2025

TERRAFORM for managing FortiOS blocklist

 With Iac growing, we have a means to write code for infrastructure. The Terraform FortiOS provider provides the means to do a host of items from deploying;

  •     policy 
  •     address
  •     static routes
  •     address groups 

This sample will focus on addr+addrgroup. The group here is the BLOCK_LIST, these would be the deny rules src+dst in/out. The SOC cyber-investigation team would write the straightforward line to update the main after extracting malicious addresses from a variety of logs or tools.tf code 


1st, we have to set up the FortiOS device with a API user. It is crucial that this account has read/write, and you should trust-host it. My TerarForm server is a DigitalOcean droplet. When setting up the API user, make sure to copy-api-key




Next we will set up a directory and our main.tf and define the hostname and api-key



terraform init

terraform validate



Next, make sure the rule exists in the blocklist, since TF will add these addresses existing rule that has the group. 



Since an addrgroup in FortiOS cannot be empty, you want to create a dummy host and have it always in the group. The APIPA address is ideal for this function



# dummy address for holding DO NOT REMOVE 

resource "fortios_firewall_address" "dumbaddress" {

  name   = "dumbaddress"

  subnet = "169.254.66.66/32"

}


The code will create the new address and add it to the BLOCK_LIST groups


e.g


# dummy address for holding DO NOT REMOVE 

resource "fortios_firewall_address" "dumbaddress" {

  name   = "dumbaddress"

  subnet = "169.254.66.66/32"

}



resource "fortios_firewall_address" "address11" {

  name   = "address11"

  subnet = "192.168.1.1/32"

}



resource "fortios_firewall_address" "INC56666_1" {

  name   = "INC56666_1"

  subnet = "26.26.26.26/32"

}






resource "fortios_firewall_object_addressgroup" "BLOCK_LIST2" {

  name    = "BLOCK_LIST2"

  member  = ["dumbaddress","address11","INC56666_1"]


}



resource "fortios_firewall_object_addressgroup" "BLOCK_LIST" {

  name    = "BLOCK_LIST"

  member  = ["dumbaddress","TXDOT","HOST111","address11","address12","INC56666_1" ]


}



Once you have the code check in, you can run the plan or auto-approve based on your comfort level



e.g




terraform apply -auto-approve


terraform state list







Using Terraform will help you maintain the cfg as code and have a simple means for revision and checks if you output a plan, and also check the main.tf into a repository like GitHub.







NSE ( network security expert) and Route/Switching Engineer
kfelix  -----a----t---- socpuppets ---dot---com
     ^      ^
=(  @  @ )=
         o

        /  \


  

Tuesday, October 21, 2025

Bulk creation of host objects for import into cisco ASA

 Work in a cisco FMC environment, the FMC has a simple means for importing list of entries.

For host entries, the file must have the following header at the top of the file:

NAME,DESCRIPTION,TYPE,VALUE,LOOKUP


The script takes a list of space-separated entries and applies the header 


#!/bin/bash

# source of files separated by "space"

# hosts.txt

#

filename="fixedup.txt"

#

#convert source.file to UPPERCASE

HDR="NAME,DESCRIPTION,TYPE,VALUE,LOOKUP"

 

# Prompt for a Upper or Lower Case

read -p "Please enter your 'lcase' for lower-case OR 'ucase' for upper-case: " case

# Prompt for a name of source file

read -p "Please enter your source filename: " fileloc

 

< $fileloc  dd conv=$case  >fixedup.txt

#

#

IFS=' '

#

#

while read -r hostname ipv4; do

echo "$hostname,,,$ipv4,"  >> importme.txt

done < "$filename"

 

sed -i '1i\'"$HDR" "importme.txt"


Creating an import file can help with the  mass creation of entries.  




NSE ( network security expert) and Route/Switching Engineer
kfelix  -----a----t---- socpuppets ---dot---com
     ^      ^
=(  @  @ )=
         o

        /  \

Thursday, July 31, 2025

Do you need a quick HTTPS web DataBAse

Here's a free online DB creator if you even need to construct a db for a simple POC

https://restdb.io

You can create a free DB with limited queries or the advanced dev will acquire a paid membership


You can import structured data from a csv , json , or excel file





For all database access, you can set api-keys and even restrict the access to GET/POST/PUT

https://restdb.io/docs/rest-api-code-examples#restdb






Sample POSTMAN







NSE ( network security expert) and Route/Switching Engineer
kfelix  -----a----t---- socpuppets ---dot---com
     ^      ^
=(  @  @ )=
         o

        /  \

Wednesday, February 12, 2025

Chrome and proxy settings with FortiOS Digest-Auth

 Okay 


Here's the issue a friend of mine has proxies in their network that are being mitigated. These proxies are open to the internal network.

So a user was hammering the proxy so hard the fotigate folded and collapsed. The solution was to set up auth and groups and only allow the groups that needed proxy access.

So an explicit web proxy was created but the main issue was Chrome was not honoring proxy settings.

Firefox btw did work from the get but Chrome was ignoring the proxy settings. If you start Chrome from a shell it works


e.g

open -a /Applications/Google\ Chrome.app --args --proxy-server=http://webproxy.socpuppets.net:3128 

In the fortigate we tried basic-auth to make things simple but ended up deploying digest-auth


# important cfg items


config authentication scheme

    edit "exproxy"

        set method negotiate

    next

    edit "Auth-scheme-Negotiate"

        set method digest

        set user-database "local-user-db"

    next

end


config authentication setting

    set active-auth-scheme "Auth-scheme-Negotiate"

end


config authentication rule

    edit "proxy-auth"

        set srcaddr "all"

        set ip-based disable

        set active-auth-method "Auth-scheme-Negotiate"

    next

end


By using diag wad debug and user commands we could verify the auth


 diag wad user  list


ID: 13, IP: 192.168.1.111, VDOM: root

  user name   : Control

  duration    : 462

  auth_type   : Session

  auth_method : Digest

  pol_id      : 1

  g_id        : 7

  user_based  : 0

  expire      : no

  LAN:

    bytes_in=1545373 bytes_out=7355346

  WAN:

    bytes_in=7325278 bytes_out=1473615



(sample debug output )


[499] __wad_hauth_user_node_put(2017): wad_http_session_free (8168): putting node(ref=107) 0x548f3b5c

[499] __wad_hauth_user_node_put(2017): wad_session_context_put (127): putting node(ref=106) 0x548f3b5c

[499] wad_auth_rule_match(1075): match auth rule succ: proxy-auth

[499] wad_http_request_get_user(25424): process=499 auth-rule=proxy-auth user=/0/0 ip-based/auth-cookie/transact=0/0/0 tp_proxy_auth=0 auth_req=(nil) auth_line=0x553f0898

[499] wad_http_parse_combo_line(280): parse auth line long=0

[499] wad_http_parse_combo_line(303): parse auth line ret=1

[499] wad_hauth_is_sso_guest(1287): check guest for Control/7

[499] wad_digest_authenticate(513): user=Control

[499] wad_http_digest_nonce_is_stale(188): stale=0 nc=4

[499] wad_http_auth_update_user_ext2(2773): updating user. ip: 192.168.1.111, type:SESSION

[499] wad_http_auth_update_user_ext2(2786): user found: Control(0x543294bc)

[499] __wad_hauth_user_node_hold(2007): wad_http_auth_update_user_ext2 (2810): holding node 0x548f3b5c

[499] wad_auth_membership_match(1187): grp(Guest-group): id=1 type=firewall member_sz=5; user(Control): type=firewall ms=(nil) ms-type=-1 member_sz=-1

[499] wad_auth_membership_match(1187): grp(IKEv2): id=2 type=firewall member_sz=2; user(Control): type=firewall ms=(nil) ms-type=-1 member_sz=-1

[499] wad_auth_membership_match(1187): grp(authg): id=6 type=firewall member_sz=1; user(Control): type=firewall ms=(nil) ms-type=-1 member_sz=-1

[499] wad_auth_membership_match(1187): grp(onelogin): id=4 type=firewall member_sz=1; user(Control): type=firewall ms=(nil) ms-type=-1 member_sz=-1

[499] wad_auth_membership_match(1187): grp(proxy_user): id=7 type=firewall member_sz=3; user(Control): type=firewall ms=(nil) ms-type=-1 member_sz=-1

[499] wad_auth_membership_match(1187): grp(radius): id=3 type=firewall member_sz=1; user(Control): type=firewall ms=(nil) ms-type=-1 member_sz=-1

[499] wad_auth_membership_match(1187): grp(remote-fgts): id=5 type=firewall member_sz=1; user(Control): type=firewall ms=(nil) ms-type=-1 member_sz=-1

[499] wad_auth_membership_match(1187): grp(SSO_Guest_Users): id=16777215 type=guest member_sz=0; user(Control): type=firewall ms=(nil) ms-type=-1 member_sz=-1

[499] wad_http_auth_status_proc(24919): authenticate result=success

[499] __wad_hauth_user_node_hold(2007): wad_user_node_stats_hold (473): holding node 0x548f3b5c

[499] __wad_hauth_user_node_hold(2007): wad_http_session_update_user_node (20525): holding node 0x548f3b5c

[499] __wad_hauth_user_node_hold(2007): wad_auth_update_usr_info (795): holding node 0x548f3b5c

[499] __wad_hauth_user_node_hold(2007): wad_http_auth_status_proc (24930): holding node 0x548f3b5c

[499] __wad_hauth_user_node_put(2017): wad_fw_pol_async_ctx_close (3127): putting node(ref=110) 0x548f3b5c

[499] __wad_hauth_user_node_hold(2007): wad_user_node_stats_hold (473): holding node 0x548f3b5c

[499] __wad_hauth_user_node_put(2017): wad_user_node_stats_put (479): putting node(ref=110) 0x548f3b5c


We tested numerous times by clearing the authenticated session with both Chrome ( Version 133.0.6943.99 (Official Build) (arm64))  and Firefox browser ( 35.0 (aarch64) )

diag wad user clear


By the summer will will redo this setup and use a squid setup that supports digest-auth.




NSE ( network security expert) and Route/Switching Engineer
kfelix  -----a----t---- socpuppets ---dot---com
     ^      ^
=(  @  @ )=
         o

        /  \



Wednesday, November 13, 2024

Proxies and python

 Okay I've been working in a role that has me neck up and engaged with end users mainly developers that are using proxies. So traffic to the internet is controlled by calling up an explicit proxy. 

What I've been finding out, their code needs to set and call the proxy when making the callout.

# sample python code with certification error disable


import requests

import ssl

proxies = {
           'http': 'http://172.16.23.1:80',
           'https': 'http://172.16.23.1:80'
              }


ssl._create_default_https_context = ssl._create_unverified_context

url = 'https://login.microsoft.com'
response = requests.get(url, proxies=proxies )
print(response)







NSE ( network security expert) and Route/Switching Engineer
kfelix  -----a----t---- socpuppets ---dot---com
     ^      ^
=(  @  @ )=
         o

        /  \



Tuesday, July 16, 2024

Fortigate Explicit proxy for SSH

lately, in my day job I'm doing a lot of proxy diagnostics and work mainly with Bluecoat. I want to show you how we can set a ssh proxy within a FortiGate

1st

The generic cfg is required;

# it's important that you have an interface set for explicit proxy and ssh-client needs to be able to reach it and the proxy-server port

config system interface

    edit "wan2"

        set vdom "root"

        set ip 209.xxxxx.2 255.255.255.0

        set allowaccess ping https ssh snmp

        set type physical

        set explicit-web-proxy enable

        set alias "internet uplink #2 XO "

        set role wan

        set snmp-index 4

    next

end


Here's a basic proxy-cfg


config web-proxy explicit

    set status enable

    set ftp-over-http enable

    set http-incoming-port 3128

    set https-incoming-port 3128

    set pac-file-server-status enable

    set pac-file-server-port 7888

    set pac-file-name "myorgproxy.pac"

end



Here's a simple proxy-cfg rule


# the proxy rule must say "ssh" in order to proxy ssh


config firewall proxy-policy

    edit 1

        set uuid 17517cfa-e15d-51ee-e807-fe331ad5ba2d

        set name "ssh out demo socpuppets"

        set proxy ssh

        set dstintf "upg-zone-wan2"

        set srcaddr "all"

        set dstaddr "all"

        set action accept

        set schedule "always"

        set logtraffic all

        set utm-status enable

    next

end



Now in unix/linux/macSOX you need to set your ssh client up to use the proxy and send a CONNECT. The simplest way is to define a .ssh/config file



e.g

 

.ssh/config


Host lg.homenoc.ad.jp

    ProxyCommand          nc -X connect -x 209.xxx.xxx.2:3128 %h %p

    ServerAliveInterval   15


Host route-server.ip.att.net

    ProxyCommand          nc -X connect -x 209.xxx.xxx.2:3128 %h %p

    ServerAliveInterval   15


 

Now let's look at some diagnostic output 







NSE ( network security expert) and Route/Switching Engineer
kfelix  -----a----t---- socpuppets ---dot---com
     ^      ^
=(  @  @ )=
         o

        /  \