sysctl managmento for port hijacking
0
.dockerignore
Executable file → Normal file
0
.gitignore
vendored
Executable file → Normal file
0
Dockerfile
Executable file → Normal file
@@ -7,12 +7,18 @@ from jose import jwt
|
|||||||
from passlib.context import CryptContext
|
from passlib.context import CryptContext
|
||||||
from fastapi_socketio import SocketManager
|
from fastapi_socketio import SocketManager
|
||||||
from utils.sqlite import SQLite
|
from utils.sqlite import SQLite
|
||||||
from utils import API_VERSION, FIREGEX_PORT, JWT_ALGORITHM, get_interfaces, refresh_frontend, DEBUG
|
from utils import API_VERSION, FIREGEX_PORT, JWT_ALGORITHM, get_interfaces, refresh_frontend, DEBUG, SysctlManager
|
||||||
from utils.loader import frontend_deploy, load_routers
|
from utils.loader import frontend_deploy, load_routers
|
||||||
from utils.models import ChangePasswordModel, IpInterface, PasswordChangeForm, PasswordForm, ResetRequest, StatusModel, StatusMessageModel
|
from utils.models import ChangePasswordModel, IpInterface, PasswordChangeForm, PasswordForm, ResetRequest, StatusModel, StatusMessageModel
|
||||||
|
|
||||||
# DB init
|
# DB init
|
||||||
db = SQLite('db/firegex.db')
|
db = SQLite('db/firegex.db')
|
||||||
|
sysctl = SysctlManager({
|
||||||
|
"net.ipv4.conf.all.forwarding": True,
|
||||||
|
"net.ipv6.conf.all.forwarding": True,
|
||||||
|
"net.ipv4.conf.all.route_localnet": True,
|
||||||
|
"net.ipv4.ip_forward": True
|
||||||
|
})
|
||||||
|
|
||||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/login", auto_error=False)
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/login", auto_error=False)
|
||||||
crypto = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
crypto = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||||
@@ -114,6 +120,7 @@ async def startup_event():
|
|||||||
db.init()
|
db.init()
|
||||||
if os.getenv("HEX_SET_PSW"):
|
if os.getenv("HEX_SET_PSW"):
|
||||||
set_psw(bytes.fromhex(os.getenv("HEX_SET_PSW")).decode())
|
set_psw(bytes.fromhex(os.getenv("HEX_SET_PSW")).decode())
|
||||||
|
sysctl.set()
|
||||||
await startup()
|
await startup()
|
||||||
if not JWT_SECRET(): db.put("secret", secrets.token_hex(32))
|
if not JWT_SECRET(): db.put("secret", secrets.token_hex(32))
|
||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
@@ -121,6 +128,7 @@ async def startup_event():
|
|||||||
@app.on_event("shutdown")
|
@app.on_event("shutdown")
|
||||||
async def shutdown_event():
|
async def shutdown_event():
|
||||||
await shutdown()
|
await shutdown()
|
||||||
|
sysctl.reset()
|
||||||
db.disconnect()
|
db.disconnect()
|
||||||
|
|
||||||
@api.post('/reset', response_model=StatusMessageModel)
|
@api.post('/reset', response_model=StatusMessageModel)
|
||||||
@@ -130,6 +138,7 @@ async def reset_firegex(form: ResetRequest):
|
|||||||
db.delete()
|
db.delete()
|
||||||
db.init()
|
db.init()
|
||||||
db.put("secret", secrets.token_hex(32))
|
db.put("secret", secrets.token_hex(32))
|
||||||
|
sysctl.set()
|
||||||
await reset(form)
|
await reset(form)
|
||||||
await refresh_frontend()
|
await refresh_frontend()
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|||||||
0
backend/modules/regexproxy/proxy.py
Executable file → Normal file
0
backend/requirements.txt
Executable file → Normal file
30
backend/utils/__init__.py
Executable file → Normal file
@@ -29,6 +29,34 @@ def refactor_name(name:str):
|
|||||||
while " " in name: name = name.replace(" "," ")
|
while " " in name: name = name.replace(" "," ")
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
class SysctlManager:
|
||||||
|
def __init__(self, ctl_table):
|
||||||
|
self.old_table = {}
|
||||||
|
self.new_table = {}
|
||||||
|
if os.path.isdir("/sys_host/"):
|
||||||
|
self.old_table = dict()
|
||||||
|
self.new_table = dict(ctl_table)
|
||||||
|
for name in ctl_table.keys():
|
||||||
|
self.old_table[name] = read_sysctl(name)
|
||||||
|
|
||||||
|
def write_table(self, table):
|
||||||
|
for name, value in table.items():
|
||||||
|
write_sysctl(name, value)
|
||||||
|
|
||||||
|
def set(self):
|
||||||
|
self.write_table(self.new_table)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.write_table(self.old_table)
|
||||||
|
|
||||||
|
def read_sysctl(name:str):
|
||||||
|
with open(f"/sys_host/{name}", "rt") as f:
|
||||||
|
return "1" in f.read()
|
||||||
|
|
||||||
|
def write_sysctl(name:str, value:bool):
|
||||||
|
with open(f"/sys_host/{name}", "wt") as f:
|
||||||
|
f.write("1" if value else "0")
|
||||||
|
|
||||||
def list_files(mypath):
|
def list_files(mypath):
|
||||||
from os import listdir
|
from os import listdir
|
||||||
from os.path import isfile, join
|
from os.path import isfile, join
|
||||||
@@ -105,4 +133,4 @@ class NFTableManager(Singleton):
|
|||||||
def raw_list(self):
|
def raw_list(self):
|
||||||
return self.cmd({"list": {"ruleset": None}})["nftables"]
|
return self.cmd({"list": {"ruleset": None}})["nftables"]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
0
docs/FiregexLogo.png
Executable file → Normal file
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
0
frontend/README.md
Executable file → Normal file
0
frontend/globals.d.ts
vendored
Executable file → Normal file
0
frontend/package-lock.json
generated
Executable file → Normal file
0
frontend/package.json
Executable file → Normal file
0
frontend/public/android-chrome-192x192.png
Executable file → Normal file
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
0
frontend/public/android-chrome-512x512.png
Executable file → Normal file
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
0
frontend/public/apple-touch-icon.png
Executable file → Normal file
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
0
frontend/public/favicon-16x16.png
Executable file → Normal file
|
Before Width: | Height: | Size: 710 B After Width: | Height: | Size: 710 B |
0
frontend/public/favicon-32x32.png
Executable file → Normal file
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
0
frontend/public/favicon.ico
Executable file → Normal file
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
0
frontend/public/header-logo.png
Executable file → Normal file
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
0
frontend/public/index.html
Executable file → Normal file
0
frontend/public/robots.txt
Executable file → Normal file
0
frontend/public/site.webmanifest
Executable file → Normal file
0
frontend/src/App.tsx
Executable file → Normal file
0
frontend/src/_vars.scss
Executable file → Normal file
0
frontend/src/components/AddNewRegex.tsx
Executable file → Normal file
0
frontend/src/components/FilterTypeSelector.tsx
Executable file → Normal file
0
frontend/src/components/Footer/index.module.scss
Executable file → Normal file
0
frontend/src/components/Footer/index.tsx
Executable file → Normal file
0
frontend/src/components/Header/index.module.scss
Executable file → Normal file
0
frontend/src/components/Header/index.tsx
Executable file → Normal file
0
frontend/src/components/MainLayout.tsx
Executable file → Normal file
0
frontend/src/components/NFRegex/AddNewService.tsx
Executable file → Normal file
0
frontend/src/components/NFRegex/ServiceRow/index.module.scss
Executable file → Normal file
0
frontend/src/components/NFRegex/ServiceRow/index.tsx
Executable file → Normal file
0
frontend/src/components/NFRegex/utils.ts
Executable file → Normal file
0
frontend/src/components/PortHijack/AddNewService.tsx
Executable file → Normal file
0
frontend/src/components/PortHijack/ServiceRow/index.module.scss
Executable file → Normal file
0
frontend/src/components/PortHijack/ServiceRow/index.tsx
Executable file → Normal file
0
frontend/src/components/PortHijack/utils.ts
Executable file → Normal file
0
frontend/src/components/RegexProxy/AddNewService.tsx
Executable file → Normal file
0
frontend/src/components/RegexProxy/ServiceRow/ChangePortModal.tsx
Executable file → Normal file
0
frontend/src/components/RegexProxy/ServiceRow/ServiceRow.module.scss
Executable file → Normal file
0
frontend/src/components/RegexProxy/ServiceRow/index.tsx
Executable file → Normal file
0
frontend/src/components/RegexView/index.module.scss
Executable file → Normal file
0
frontend/src/components/RegexView/index.tsx
Executable file → Normal file
0
frontend/src/components/YesNoModal.tsx
Executable file → Normal file
0
frontend/src/index.scss
Executable file → Normal file
0
frontend/src/index.tsx
Executable file → Normal file
0
frontend/src/js/utils.tsx
Executable file → Normal file
0
frontend/src/pages/NFRegex/ServiceDetails.tsx
Executable file → Normal file
0
frontend/src/pages/NFRegex/index.tsx
Executable file → Normal file
0
frontend/src/pages/PortHijack/index.tsx
Executable file → Normal file
0
frontend/src/pages/RegexProxy/ServiceDetails.tsx
Executable file → Normal file
0
frontend/src/pages/RegexProxy/index.tsx
Executable file → Normal file
0
frontend/src/react-app-env.d.ts
vendored
Executable file → Normal file
0
frontend/tsconfig.json
Executable file → Normal file
114
start.py
Executable file → Normal file
@@ -4,6 +4,7 @@ import argparse, sys, platform, os, multiprocessing, subprocess, getpass
|
|||||||
|
|
||||||
pref = "\033["
|
pref = "\033["
|
||||||
reset = f"{pref}0m"
|
reset = f"{pref}0m"
|
||||||
|
composefile = "firegex-compose.yml"
|
||||||
|
|
||||||
class colors:
|
class colors:
|
||||||
black = "30m"
|
black = "30m"
|
||||||
@@ -72,6 +73,65 @@ args = parser.parse_args()
|
|||||||
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||||
run_checks()
|
run_checks()
|
||||||
|
|
||||||
|
def write_compose(psw_set=None):
|
||||||
|
with open(composefile,"wt") as compose:
|
||||||
|
|
||||||
|
if "linux" in sys.platform and not 'microsoft-standard' in platform.uname().release: #Check if not is a wsl also
|
||||||
|
compose.write(f"""
|
||||||
|
version: '3.9'
|
||||||
|
|
||||||
|
services:
|
||||||
|
firewall:
|
||||||
|
restart: unless-stopped
|
||||||
|
container_name: firegex
|
||||||
|
{"build: ." if args.build else "image: ghcr.io/pwnzer0tt1/firegex"}
|
||||||
|
network_mode: "host"
|
||||||
|
environment:
|
||||||
|
- PORT={args.port}
|
||||||
|
- NTHREADS={args.threads}
|
||||||
|
{"- HEX_SET_PSW="+psw_set.encode().hex() if psw_set else ""}
|
||||||
|
volumes:
|
||||||
|
- /execute/db
|
||||||
|
- type: bind
|
||||||
|
source: /proc/sys/net/ipv4/conf/all/route_localnet
|
||||||
|
target: /sys_host/net.ipv4.conf.all.route_localnet
|
||||||
|
- type: bind
|
||||||
|
source: /proc/sys/net/ipv4/ip_forward
|
||||||
|
target: /sys_host/net.ipv4.ip_forward
|
||||||
|
- type: bind
|
||||||
|
source: /proc/sys/net/ipv4/conf/all/forwarding
|
||||||
|
target: /sys_host/net.ipv4.conf.all.forwarding
|
||||||
|
- type: bind
|
||||||
|
source: /proc/sys/net/ipv6/conf/all/forwarding
|
||||||
|
target: /sys_host/net.ipv6.conf.all.forwarding
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
""")
|
||||||
|
|
||||||
|
else:
|
||||||
|
sep()
|
||||||
|
puts("--- WARNING ---", color=colors.yellow)
|
||||||
|
puts("You are not in a linux machine, due to docker limitation on other platform, the firewall will not work in this machine. You will only see the interface of firegex.", color=colors.red)
|
||||||
|
compose.write(f"""
|
||||||
|
version: '3.9'
|
||||||
|
|
||||||
|
services:
|
||||||
|
firewall:
|
||||||
|
restart: unless-stopped
|
||||||
|
container_name: firegex
|
||||||
|
{"build: ." if args.build else "image: ghcr.io/pwnzer0tt1/firegex"}
|
||||||
|
ports:
|
||||||
|
- {args.port}:{args.port}
|
||||||
|
environment:
|
||||||
|
- PORT={args.port}
|
||||||
|
- NTHREADS={args.threads}
|
||||||
|
{"- HEX_SET_PSW="+psw_set.encode().hex() if psw_set else ""}
|
||||||
|
volumes:
|
||||||
|
- /execute/db
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
""")
|
||||||
|
|
||||||
start_operation = not (args.stop or args.restart)
|
start_operation = not (args.stop or args.restart)
|
||||||
|
|
||||||
if args.build and not os.path.isfile("./Dockerfile"):
|
if args.build and not os.path.isfile("./Dockerfile"):
|
||||||
@@ -81,9 +141,12 @@ if args.build and not os.path.isfile("./Dockerfile"):
|
|||||||
if args.threads < 1:
|
if args.threads < 1:
|
||||||
args.threads = multiprocessing.cpu_count()
|
args.threads = multiprocessing.cpu_count()
|
||||||
|
|
||||||
if start_operation:
|
if start_operation and (not args.build or args.keep):
|
||||||
if check_if_exists("docker ps --filter 'name=^firegex$' --no-trunc | grep firegex"):
|
if check_if_exists("docker ps --filter 'name=^firegex$' --no-trunc | grep firegex"):
|
||||||
puts("Firegex is already running! use --help to see options useful to manage firegex execution", color=colors.yellow)
|
if args.keep:
|
||||||
|
write_compose()
|
||||||
|
else:
|
||||||
|
puts("Firegex is already running! use --help to see options useful to manage firegex execution", color=colors.yellow)
|
||||||
exit()
|
exit()
|
||||||
sep()
|
sep()
|
||||||
puts(f"Firegex", color=colors.yellow, end="")
|
puts(f"Firegex", color=colors.yellow, end="")
|
||||||
@@ -105,53 +168,8 @@ if start_operation:
|
|||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
composefile = "firegex-compose.yml"
|
write_compose(psw_set)
|
||||||
|
|
||||||
with open(composefile,"wt") as compose:
|
|
||||||
|
|
||||||
if "linux" in sys.platform and not 'microsoft-standard' in platform.uname().release: #Check if not is a wsl also
|
|
||||||
compose.write(f"""
|
|
||||||
version: '3.9'
|
|
||||||
|
|
||||||
services:
|
|
||||||
firewall:
|
|
||||||
restart: unless-stopped
|
|
||||||
container_name: firegex
|
|
||||||
{"build: ." if args.build else "image: ghcr.io/pwnzer0tt1/firegex"}
|
|
||||||
network_mode: "host"
|
|
||||||
environment:
|
|
||||||
- PORT={args.port}
|
|
||||||
- NTHREADS={args.threads}
|
|
||||||
{"- HEX_SET_PSW="+psw_set.encode().hex() if psw_set else ""}
|
|
||||||
volumes:
|
|
||||||
- /execute/db
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
""")
|
|
||||||
|
|
||||||
else:
|
|
||||||
sep()
|
|
||||||
puts("--- WARNING ---", color=colors.yellow)
|
|
||||||
puts("You are not in a linux machine, due to docker limitation on other platform, the firewall will not work in this machine. You will only see the interface of firegex.", color=colors.red)
|
|
||||||
compose.write(f"""
|
|
||||||
version: '3.9'
|
|
||||||
|
|
||||||
services:
|
|
||||||
firewall:
|
|
||||||
restart: unless-stopped
|
|
||||||
container_name: firegex
|
|
||||||
{"build: ." if args.build else "image: ghcr.io/pwnzer0tt1/firegex"}
|
|
||||||
ports:
|
|
||||||
- {args.port}:{args.port}
|
|
||||||
environment:
|
|
||||||
- PORT={args.port}
|
|
||||||
- NTHREADS={args.threads}
|
|
||||||
{"- HEX_SET_PSW="+psw_set.encode().hex() if psw_set else ""}
|
|
||||||
volumes:
|
|
||||||
- /execute/db
|
|
||||||
cap_add:
|
|
||||||
- NET_ADMIN
|
|
||||||
""")
|
|
||||||
sep()
|
sep()
|
||||||
if not args.no_autostart:
|
if not args.no_autostart:
|
||||||
try:
|
try:
|
||||||
|
|||||||