├── CNAME
├── fsociety
├── core
│ ├── __init__.py
│ ├── usernames.py
│ ├── hosts.py
│ ├── config.py
│ ├── utilities.py
│ ├── menu.py
│ └── repo.py
├── __init__.py
├── __version__.py
├── networking
│ ├── __init__.py
│ ├── cli.py
│ ├── bettercap.py
│ └── nmap.py
├── passwords
│ ├── __init__.py
│ ├── cli.py
│ ├── cupp.py
│ ├── hash_buster.py
│ ├── cr3dov3r.py
│ └── changeme.py
├── web_apps
│ ├── __init__.py
│ ├── cli.py
│ ├── photon.py
│ └── xsstrike.py
├── obfuscation
│ ├── __init__.py
│ ├── cli.py
│ └── cuteit.py
├── information_gathering
│ ├── __init__.py
│ ├── cli.py
│ ├── striker.py
│ ├── sublist3r.py
│ ├── hydrarecon.py
│ ├── sqlmap.py
│ ├── s3scanner.py
│ ├── sherlock.py
│ └── gitgraber.py
├── console.py
└── cli.py
├── requirements.txt
├── images
├── cli.png
├── logo.png
└── fsociety.png
├── .github
├── FUNDING.yml
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── ---tool-request.md
│ └── ---bug-report.md
├── dependabot.yml
├── workflows
│ ├── pylint.yml
│ └── python-publish.yml
└── CODE_OF_CONDUCT.md
├── Dockerfile
├── _config.yml
├── LICENSE
├── PACKAGES.md
├── README.md
├── .gitignore
├── setup.py
├── CHANGELOG.md
└── .pylintrc
/CNAME:
--------------------------------------------------------------------------------
1 | fsociety.dev
--------------------------------------------------------------------------------
/fsociety/core/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | rich>=2.0.0
2 | requests>=2.23.0
3 | GitPython>=3.1.3
--------------------------------------------------------------------------------
/fsociety/__init__.py:
--------------------------------------------------------------------------------
1 | from .cli import main as cli
2 |
3 | __all__ = ["cli"]
4 |
--------------------------------------------------------------------------------
/images/cli.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Agent00049/fsociety/master/images/cli.png
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Agent00049/fsociety/master/images/logo.png
--------------------------------------------------------------------------------
/fsociety/__version__.py:
--------------------------------------------------------------------------------
1 | VERSION = (3, 2, 3)
2 |
3 | __version__ = '.'.join(map(str, VERSION))
4 |
--------------------------------------------------------------------------------
/images/fsociety.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Agent00049/fsociety/master/images/fsociety.png
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: thehappydinoa
4 |
--------------------------------------------------------------------------------
/fsociety/networking/__init__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli, __tools__
2 |
3 | __all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
4 |
--------------------------------------------------------------------------------
/fsociety/passwords/__init__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli, __tools__
2 |
3 | __all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
4 |
--------------------------------------------------------------------------------
/fsociety/web_apps/__init__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli, __tools__
2 |
3 | __all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
4 |
--------------------------------------------------------------------------------
/fsociety/obfuscation/__init__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli, __tools__
2 |
3 | __all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
4 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.7-alpine
2 | COPY . /fsociety
3 | WORKDIR /fsociety
4 | RUN apk --update add git nmap
5 | RUN pip install -e .
6 | CMD fsociety --info
--------------------------------------------------------------------------------
/fsociety/information_gathering/__init__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli, __tools__
2 |
3 | __all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
4 |
--------------------------------------------------------------------------------
/fsociety/obfuscation/cli.py:
--------------------------------------------------------------------------------
1 | # Core
2 | from fsociety.core.menu import tools_cli
3 |
4 | from .cuteit import cuteit
5 |
6 | __tools__ = [cuteit]
7 |
8 |
9 | def cli():
10 | tools_cli(__name__, __tools__)
11 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | **Working on your first Pull Request?** You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)
2 |
--------------------------------------------------------------------------------
/fsociety/networking/cli.py:
--------------------------------------------------------------------------------
1 | # Core
2 | from fsociety.core.menu import tools_cli
3 |
4 | from .nmap import nmap
5 | from .bettercap import bettercap
6 |
7 | __tools__ = [nmap, bettercap]
8 |
9 |
10 | def cli():
11 | tools_cli(__name__, __tools__)
12 |
--------------------------------------------------------------------------------
/fsociety/web_apps/cli.py:
--------------------------------------------------------------------------------
1 | # Core
2 | from fsociety.core.menu import tools_cli
3 |
4 | from .xsstrike import xsstrike
5 | from .photon import photon
6 |
7 | __tools__ = [xsstrike, photon]
8 |
9 |
10 | def cli():
11 | tools_cli(__name__, __tools__)
12 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/---tool-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "⛏️ Tool request"
3 | about: Suggest an tool for fsociety
4 | title: ''
5 | labels: tool
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Link to Tool**
11 | https://github.com/really_cool_project
12 |
13 | **Why?**
14 | _Why should we add this tool?_
15 |
--------------------------------------------------------------------------------
/fsociety/console.py:
--------------------------------------------------------------------------------
1 | from rich.console import Console
2 | from rich.theme import Theme
3 | from rich.traceback import install
4 |
5 | # Install Traceback
6 | install()
7 |
8 | # Console Setup
9 | fsociety_theme = Theme({
10 | "command": "black on white",
11 | "warning": "bold yellow",
12 | })
13 | console = Console(theme=fsociety_theme)
14 |
--------------------------------------------------------------------------------
/fsociety/passwords/cli.py:
--------------------------------------------------------------------------------
1 | # Core
2 | from fsociety.core.menu import tools_cli
3 |
4 | from .cupp import cupp
5 | from .cr3dov3r import cr3dov3r
6 | from .hash_buster import hash_buster
7 | from .changeme import changeme
8 |
9 | __tools__ = [cupp, cr3dov3r, hash_buster, changeme]
10 |
11 |
12 | def cli():
13 | tools_cli(__name__, __tools__)
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/---bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: "\U0001F41B Bug report"
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Which Tool?**
11 | A clear and concise description of what the bug is.
12 |
13 | **What is the error?**
14 | Stacktrace:
15 |
16 | ```bash
17 | ```
18 |
19 | **fsociety info**
20 | Run `fsociety --info` in your terminal and copy the results here.
21 |
22 | ```bash
23 | ```
24 |
--------------------------------------------------------------------------------
/fsociety/passwords/cupp.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 |
5 |
6 | class CuppRepo(GitHubRepo):
7 | def __init__(self):
8 | super().__init__(path="Mebus/cupp",
9 | install=None,
10 | description="Common User Passwords Profiler")
11 |
12 | def run(self):
13 | os.chdir(self.full_path)
14 | return os.system("python3 cupp.py -i")
15 |
16 |
17 | cupp = CuppRepo()
18 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "pip"
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "daily"
12 |
--------------------------------------------------------------------------------
/fsociety/information_gathering/cli.py:
--------------------------------------------------------------------------------
1 | # Core
2 | from fsociety.core.menu import tools_cli
3 |
4 | from .sqlmap import sqlmap
5 | from .striker import striker
6 | from .sublist3r import sublist3r
7 | from .sherlock import sherlock
8 | from .s3scanner import s3scanner
9 | from .gitgraber import gitgraber
10 | from .hydrarecon import hydrarecon
11 |
12 | __tools__ = [sqlmap, striker, sublist3r,
13 | sherlock, s3scanner, gitgraber, hydrarecon]
14 |
15 |
16 | def cli():
17 | tools_cli(__name__, __tools__)
18 |
--------------------------------------------------------------------------------
/fsociety/obfuscation/cuteit.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 |
5 |
6 | class CuteitRepo(GitHubRepo):
7 | def __init__(self):
8 | super().__init__(
9 | path="D4Vinci/Cuteit",
10 | install=None,
11 | description="IP obfuscator made to make a malicious ip a bit cuter"
12 | )
13 |
14 | def run(self):
15 | os.chdir(self.full_path)
16 | user_ip = input("\nEnter a ip: ").strip()
17 | return os.system(f"python3 Cuteit.py {user_ip}")
18 |
19 |
20 | cuteit = CuteitRepo()
21 |
--------------------------------------------------------------------------------
/fsociety/passwords/hash_buster.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 |
5 |
6 | class HashBusterRepo(GitHubRepo):
7 | def __init__(self):
8 | super().__init__(
9 | path="s0md3v/Hash-Buster",
10 | install=None,
11 | description="Why crack hashes when you can bust them?")
12 |
13 | def run(self):
14 | os.chdir(self.full_path)
15 | user_hash = input("\nEnter a hash: ").strip()
16 | return os.system(f"python3 hash.py -s {user_hash}")
17 |
18 |
19 | hash_buster = HashBusterRepo()
20 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | title: fsociety
2 | tagline: A Penetration Testing Framework
3 | author: fsociety-team
4 | url: https://fsociety.dev
5 | permalink: pretty
6 |
7 | remote_theme: pmarsceill/just-the-docs
8 | color_scheme: nil
9 | logo: "/images/logo.png"
10 | aux_links:
11 | "fsociety on GitHub":
12 | - "https://github.com/fsociety-team/fsociety"
13 | footer_content: "Copyright © 2020 fsociety-team. Distributed by an MIT license."
14 |
15 | ga_tracking: UA-111350566-3
16 |
17 | plugins:
18 | - jekyll-seo-tag
19 |
--------------------------------------------------------------------------------
/fsociety/core/usernames.py:
--------------------------------------------------------------------------------
1 | import os.path
2 |
3 | from fsociety.core.config import INSTALL_DIR, get_config
4 |
5 | config = get_config()
6 |
7 | full_path = os.path.join(INSTALL_DIR, config.get("fsociety", "usernames_file"))
8 |
9 |
10 | def get_usernames():
11 | try:
12 | with open(full_path, "r") as usernamefile:
13 | return [username.strip() for username in usernamefile]
14 | except FileNotFoundError:
15 | return list()
16 |
17 |
18 | def add_username(username):
19 | with open(full_path, "a") as usernamefile:
20 | usernamefile.write(f"\n{username}")
21 |
--------------------------------------------------------------------------------
/fsociety/core/hosts.py:
--------------------------------------------------------------------------------
1 | import os.path
2 |
3 | from fsociety.core.config import INSTALL_DIR, get_config
4 |
5 | config = get_config()
6 |
7 | full_path = os.path.join(INSTALL_DIR, config.get("fsociety", "host_file"))
8 |
9 |
10 | class InvalidHost(Exception):
11 | pass
12 |
13 |
14 | def get_hosts():
15 | try:
16 | with open(full_path, "r") as hostfile:
17 | return [host.strip() for host in hostfile]
18 | except FileNotFoundError:
19 | return list()
20 |
21 |
22 | def add_host(host):
23 | if not host:
24 | raise ValueError
25 | with open(full_path, "a") as hostfile:
26 | hostfile.write(f"\n{host}")
27 |
--------------------------------------------------------------------------------
/fsociety/passwords/cr3dov3r.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import set_readline
5 |
6 |
7 | class Cr3dov3rRepo(GitHubRepo):
8 | def __init__(self):
9 | super().__init__(
10 | path="D4Vinci/Cr3dOv3r",
11 | install={"pip": "requirements.txt"},
12 | description="Your best friend in credential reuse attacks")
13 |
14 | def run(self):
15 | os.chdir(self.full_path)
16 | set_readline([])
17 | user_email = input("\nEnter a email: ").strip()
18 | return os.system(f"python3 Cr3d0v3r.py {user_email}")
19 |
20 |
21 | cr3dov3r = Cr3dov3rRepo()
22 |
--------------------------------------------------------------------------------
/fsociety/information_gathering/striker.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import set_readline
5 |
6 |
7 | class StrikerRepo(GitHubRepo):
8 | def __init__(self):
9 | super().__init__(path="s0md3v/Striker",
10 | install={"pip": "requirements.txt"},
11 | description="Recon & Vulnerability Scanning Suite")
12 |
13 | def run(self):
14 | os.chdir(self.full_path)
15 | set_readline([])
16 | user_domain = input("\nEnter a domain to scan: ").strip()
17 | return os.system(f"python3 striker.py {user_domain}")
18 |
19 |
20 | striker = StrikerRepo()
21 |
--------------------------------------------------------------------------------
/fsociety/information_gathering/sublist3r.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import set_readline
5 |
6 |
7 | class Sublist3rRepo(GitHubRepo):
8 | def __init__(self):
9 | super().__init__(
10 | path="aboul3la/Sublist3r",
11 | install={"pip": "requirements.txt"},
12 | description="Fast subdomains enumeration tool for penetration testers")
13 |
14 | def run(self):
15 | os.chdir(self.full_path)
16 | set_readline([])
17 | user_domain = input("\nEnter a domain to enumerate: ").strip()
18 | return os.system(f"python3 sublist3r.py -v -d {user_domain}")
19 |
20 |
21 | sublist3r = Sublist3rRepo()
22 |
--------------------------------------------------------------------------------
/fsociety/information_gathering/hydrarecon.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import set_readline, confirm
5 |
6 |
7 | class HydrareconRepo(GitHubRepo):
8 | def __init__(self):
9 | super().__init__(path="aufzayed/HydraRecon",
10 | install={"pip": "requirements.txt"},
11 | description="Simple recon tool")
12 |
13 | def run(self):
14 | os.chdir(self.full_path)
15 | set_readline([])
16 | user_domain = input("\nEnter a domain to scan: ").strip()
17 | arg = "--basic"
18 | if confirm("\nDo you want to crawl? [default=No]"):
19 | arg = "--crawl"
20 | return os.system(f"python3 hydrarecon.py {arg} -d {user_domain}")
21 |
22 |
23 | hydrarecon = HydrareconRepo()
24 |
--------------------------------------------------------------------------------
/fsociety/information_gathering/sqlmap.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import confirm
5 |
6 |
7 | class SqlmapRepo(GitHubRepo):
8 | def __init__(self):
9 | super().__init__(
10 | path="sqlmapproject/sqlmap",
11 | install=None,
12 | description="Automatic SQL injection and database takeover tool")
13 |
14 | def run(self):
15 | os.chdir(self.full_path)
16 | user_url = input("\nEnter a url to scan: ").strip()
17 | user_args = str()
18 | if confirm("\nDo you want to add any extra args?"):
19 | os.system("python3 sqlmap.py --help")
20 | user_args = input("\nEnter any extra args: ").strip()
21 | return os.system(f"python3 sqlmap.py -u {user_url} {user_args}")
22 |
23 |
24 | sqlmap = SqlmapRepo()
25 |
--------------------------------------------------------------------------------
/fsociety/web_apps/photon.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import confirm
5 |
6 |
7 | class PhotonRepo(GitHubRepo):
8 | def __init__(self):
9 | super().__init__(
10 | path="s0md3v/Photon",
11 | install={"pip": "requirements.txt"},
12 | description="Incredibly fast crawler designed for OSINT")
13 |
14 | def run(self):
15 | os.chdir(self.full_path)
16 | user_url = input("\nEnter a url to scan: ").strip()
17 | args = list()
18 | if confirm("Do you want to clone the site?"):
19 | args.append("--clone")
20 | if confirm("Do you want to use wayback?"):
21 | args.append("--wayback")
22 | args_str = " ".join(args)
23 | return os.system(f"python3 photon.py --url {user_url} {args_str}")
24 |
25 |
26 | photon = PhotonRepo()
27 |
--------------------------------------------------------------------------------
/fsociety/passwords/changeme.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import set_readline
5 | from fsociety.core.hosts import get_hosts, add_host, InvalidHost
6 |
7 |
8 | class ChangemeRepo(GitHubRepo):
9 | def __init__(self):
10 | super().__init__(path="ztgrace/changeme",
11 | install={"pip": "requirements.txt"},
12 | description="A default credential scanner")
13 |
14 | def run(self):
15 | os.chdir(self.full_path)
16 | hosts = get_hosts()
17 | set_readline(hosts)
18 | user_host = input("\nEnter a host: ").strip()
19 | if not user_host:
20 | raise InvalidHost
21 | if user_host not in hosts:
22 | add_host(user_host)
23 | return os.system(f"python3 changeme.py {user_host}")
24 |
25 |
26 | changeme = ChangemeRepo()
27 |
--------------------------------------------------------------------------------
/fsociety/web_apps/xsstrike.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import confirm
5 |
6 |
7 | class XsstrikeRepo(GitHubRepo):
8 | def __init__(self):
9 | super().__init__(path="s0md3v/XSStrike",
10 | install={"pip": "requirements.txt"},
11 | description="Advanced XSS Detection Suite")
12 |
13 | def run(self):
14 | os.chdir(self.full_path)
15 | user_url = input("\nEnter a url to scan: ").strip()
16 | args = list()
17 | if confirm("Do you want to crawl?"):
18 | args.append("--crawl")
19 | if confirm("Do you want to find hidden parameters?"):
20 | args.append("--params")
21 | args_str = " ".join(args)
22 | return os.system(f"python3 xsstrike.py --url {user_url} {args_str}")
23 |
24 |
25 | xsstrike = XsstrikeRepo()
26 |
--------------------------------------------------------------------------------
/fsociety/information_gathering/s3scanner.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import set_readline
5 | from fsociety.core.config import INSTALL_DIR
6 |
7 |
8 | class S3scannerRepo(GitHubRepo):
9 | def __init__(self):
10 | super().__init__(
11 | path="sa7mon/S3Scanner",
12 | install={"pip": "requirements.txt"},
13 | description="A tool to find open S3 buckets and dump their contents")
14 |
15 | def run(self):
16 | os.chdir(self.full_path)
17 | set_readline([])
18 | user_domains = input("\nEnter one or more domains: ").strip()
19 | txt_path = os.path.join(INSTALL_DIR, "s3_domains.txt")
20 | with open(txt_path, "w") as domains_file:
21 | for domain in user_domains.split():
22 | domains_file.write(domain)
23 | return os.system(f"python3 s3scanner.py {txt_path}")
24 |
25 |
26 | s3scanner = S3scannerRepo()
27 |
--------------------------------------------------------------------------------
/fsociety/information_gathering/sherlock.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import set_readline
5 | from fsociety.core.usernames import get_usernames, add_username
6 |
7 |
8 | class SherlockRepo(GitHubRepo):
9 | def __init__(self):
10 | super().__init__(
11 | path="sherlock-project/sherlock",
12 | install={"pip": "requirements.txt"},
13 | description="Hunt down social media accounts by username across social networks"
14 | )
15 |
16 | def run(self):
17 | os.chdir(self.full_path)
18 | usernames = get_usernames()
19 | set_readline(usernames)
20 | user_usernames = input("\nEnter one or more usernames: ").strip()
21 | for username in user_usernames.split():
22 | if not username in usernames:
23 | add_username(username)
24 | return os.system(f"python3 sherlock {user_usernames} -r")
25 |
26 |
27 | sherlock = SherlockRepo()
28 |
--------------------------------------------------------------------------------
/fsociety/networking/bettercap.py:
--------------------------------------------------------------------------------
1 | # pylint: disable=line-too-long
2 | import os
3 | from shutil import which
4 |
5 | from fsociety.core.repo import GitHubRepo
6 |
7 |
8 | class BettercapRepo(GitHubRepo):
9 | def __init__(self):
10 | super().__init__(
11 | path="bettercap/bettercap",
12 | install={
13 | "linux":
14 | "sudo apt install golang git build-essential libpcap-dev libusb-1.0-0-dev libnetfilter-queue-dev; go get -u github.com/bettercap/bettercap",
15 | "brew": "install bettercap"
16 | },
17 | description="Swiss army knife for network attacks and monitoring")
18 |
19 | def installed(self):
20 | return which("bettercap")
21 |
22 | def install(self):
23 | super().install(clone=False)
24 |
25 | def run(self):
26 | print("Please note that bettercap must be run with sudo")
27 | return os.system("sudo bettercap")
28 |
29 |
30 | bettercap = BettercapRepo()
31 |
--------------------------------------------------------------------------------
/.github/workflows/pylint.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Pylint
4 |
5 | # Controls when the action will run. Triggers the workflow on push or pull request
6 | # events but only for the master branch
7 | on:
8 | push:
9 | paths:
10 | - "*/**.py"
11 | pull_request:
12 | paths:
13 | - "*/**.py"
14 |
15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
16 | jobs:
17 | # This workflow contains a single job called "build"
18 | build:
19 | # The type of runner that the job will run on
20 | runs-on: ubuntu-latest
21 |
22 | # Steps represent a sequence of tasks that will be executed as part of the job
23 | steps:
24 | - name: Install apt
25 | run: sudo apt-get install libffi-dev
26 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
27 | - uses: actions/checkout@v2
28 |
29 | - name: GitHub Action for pylint
30 | uses: cclauss/GitHub-Action-for-pylint@0.7.0
31 | with:
32 | args: "pip install .;pip install .[dev]; pylint **/*.py"
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 fsociety
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/python-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflows will upload a Python Package using Twine when a release is created
2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3 |
4 | name: Upload Python Package
5 |
6 | on:
7 | push:
8 | tags:
9 | - v*
10 |
11 | jobs:
12 | deploy:
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 | - name: Set up Python 3.7
18 | uses: actions/setup-python@v2
19 | with:
20 | python-version: 3.7
21 | - name: Test install
22 | run: |
23 | pip install -e .
24 | fsociety --info
25 | - name: Install dependencies
26 | run: |
27 | python -m pip install --upgrade pip
28 | pip install setuptools wheel twine
29 | - name: Build and publish
30 | env:
31 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
32 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
33 | run: |
34 | python setup.py sdist bdist_wheel --universal
35 | twine upload dist/*
36 |
--------------------------------------------------------------------------------
/fsociety/information_gathering/gitgraber.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from fsociety.core.repo import GitHubRepo
4 | from fsociety.core.menu import set_readline, confirm
5 |
6 |
7 | class GitgraberRepo(GitHubRepo):
8 | def __init__(self):
9 | super().__init__(
10 | path="hisxo/gitGraber",
11 | install={"pip": "requirements.txt"},
12 | description="Search and find sensitive data in real time for GitHub"
13 | )
14 |
15 | def run(self):
16 | os.chdir(self.full_path)
17 | wordlists_path = os.path.join(self.full_path, "wordlists")
18 | set_readline([])
19 | user_query = input("\nEnter a search query: ").strip()
20 | set_readline([
21 | f for f in os.listdir(os.path.join(self.full_path, "wordlists"))
22 | if os.path.isfile(
23 | os.path.join(os.path.join(self.full_path, "wordlists"), f))
24 | ])
25 | user_keywords = input(
26 | "\nEnter a keywords path [default=keywords.txt]: ").strip()
27 | if not user_keywords:
28 | user_keywords = "keywords.txt"
29 | keywords_path = os.path.join(wordlists_path, user_keywords)
30 | if confirm("\nDo you want to add a GitHub token?"):
31 | github_token = input("\nEnter a GitHub token: ").strip()
32 | os.environ["GITHUB_TOKENS"] = f"['{github_token}']"
33 | return os.system(
34 | f"python3 gitGraber.py -k {keywords_path} -q {user_query}")
35 |
36 |
37 | gitgraber = GitgraberRepo()
38 |
--------------------------------------------------------------------------------
/PACKAGES.md:
--------------------------------------------------------------------------------
1 | # Packages
2 |
3 | ## Information Gathering
4 |
5 | - [sqlmap](https://github.com/sqlmapproject/sqlmap)
6 | Automatic SQL injection and database takeover tool
7 | - [Striker](https://github.com/s0md3v/Striker)
8 | Recon & Vulnerability Scanning Suite
9 | - [Sublist3r](https://github.com/aboul3la/Sublist3r)
10 | Fast subdomains enumeration tool for penetration testers
11 | - [sherlock](https://github.com/sherlock-project/sherlock)
12 | Hunt down social media accounts by username across social networks
13 | - [S3Scanner](https://github.com/sa7mon/S3Scanner)
14 | A tool to find open S3 buckets and dump their contents
15 | - [gitGraber](https://github.com/hisxo/gitGraber)
16 | Search and find sensitive data in real time for GitHub
17 | - [HydraRecon](https://github.com/aufzayed/HydraRecon)
18 | Simple recon tool
19 |
20 | ## Networking
21 |
22 | - [nmap](https://github.com/nmap/nmap)
23 | the Network Mapper
24 | - [bettercap](https://github.com/bettercap/bettercap)
25 | Swiss army knife for network attacks and monitoring
26 |
27 | ## Web Apps
28 |
29 | - [XSStrike](https://github.com/s0md3v/XSStrike)
30 | Advanced XSS Detection Suite
31 | - [Photon](https://github.com/s0md3v/Photon)
32 | Incredibly fast crawler designed for OSINT
33 |
34 | ## Passwords
35 |
36 | - [cupp](https://github.com/Mebus/cupp)
37 | Common User Passwords Profiler
38 | - [Cr3d0v3r](https://github.com/D4Vinci/Cr3d0v3r)
39 | Your best friend in credential reuse attacks
40 | - [Hash-Buster](https://github.com/s0md3v/Hash-Buster)
41 | Why crack hashes when you can bust them?
42 | - [changeme](https://github.com/ztgrace/changeme)
43 | A default credential scanner
44 |
45 | ## Obfuscation
46 |
47 | - [Cuteit](https://github.com/D4Vinci/Cuteit)
48 | IP obfuscator made to make a malicious ip a bit cuter
49 |
--------------------------------------------------------------------------------
/fsociety/core/config.py:
--------------------------------------------------------------------------------
1 | import os.path
2 | from sys import platform
3 | from pathlib import Path
4 | from configparser import RawConfigParser, NoOptionError
5 |
6 | from fsociety.__version__ import __version__
7 |
8 | CURRENT_PLATFORM = platform
9 | if platform in ["win32", "cygwin"]:
10 | CURRENT_PLATFORM = "windows"
11 | elif platform.startswith("darwin"):
12 | CURRENT_PLATFORM = "macos"
13 | elif platform.startswith("linux") or platform.startswith("freebsd"):
14 | CURRENT_PLATFORM = "linux"
15 |
16 | INSTALL_DIR = os.path.join(str(Path.home()), ".fsociety")
17 | CONFIG_FILE = os.path.join(INSTALL_DIR, "fsociety.cfg")
18 | GITHUB_PATH = "fsociety-team/fsociety"
19 |
20 | DEFAULT_CONFIG = {
21 | "version": __version__,
22 | "agreement": "false",
23 | "ssh_clone": "false",
24 | "os": CURRENT_PLATFORM,
25 | "host_file": "hosts.txt",
26 | "usernames_file": "usernames.txt"
27 | }
28 |
29 |
30 | def get_config():
31 | config = RawConfigParser()
32 | if not os.path.exists(INSTALL_DIR):
33 | os.mkdir(INSTALL_DIR)
34 | if not os.path.exists(CONFIG_FILE):
35 | config["fsociety"] = DEFAULT_CONFIG
36 | with open(CONFIG_FILE, "w") as configfile:
37 | config.write(configfile)
38 | config.read(CONFIG_FILE)
39 | check_config(config)
40 | if config.get("fsociety", "version") != __version__:
41 | config.set("fsociety", "version", __version__)
42 | write_config(config)
43 | return config
44 |
45 |
46 | def write_config(config):
47 | with open(CONFIG_FILE, "w") as configfile:
48 | config.write(configfile)
49 |
50 |
51 | def check_config(config):
52 | for key in DEFAULT_CONFIG:
53 | try:
54 | config.get("fsociety", key)
55 | except NoOptionError:
56 | config.set("fsociety", key, DEFAULT_CONFIG.get(key))
57 | write_config(config)
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # fsociety [](https://www.python.org/downloads/) [](https://pypi.org/project/fsociety/)   [](https://hub.docker.com/r/fsocietyteam/fsociety)
2 |
3 | A Modular Penetration Testing Framework
4 |
5 | [](https://github.com/fsociety-team/fsociety/blob/master/PACKAGES.md) [](https://github.com/fsociety-team/fsociety/blob/master/CHANGELOG.md)
6 |
7 | [](https://github.com/fsociety-team/fsociety)
8 |
9 | 
10 |
11 | ## Install
12 |
13 | ```bash
14 | pip install fsociety
15 | ```
16 |
17 | ## Update
18 |
19 | ```bash
20 | pip install --upgrade fsociety
21 | ```
22 |
23 | ## Usage
24 |
25 | ```bash
26 | usage: fsociety [-h] [-i] [-s]
27 |
28 | A Penetration Testing Framework
29 |
30 | optional arguments:
31 | -h, --help show this help message and exit
32 | -i, --info gets fsociety info
33 | -s, --suggest suggest a tool
34 | ```
35 |
36 | ## Develop
37 |
38 | ```bash
39 | git clone https://github.com/fsociety-team/fsociety.git
40 | pip install -e ".[dev]"
41 | ```
42 |
43 | ## Docker
44 |
45 | ```bash
46 | docker pull fsocietyteam/fsociety
47 | docker run -it fsocietyteam/fsociety fsociety
48 | ```
49 |
50 | ## License
51 |
52 | [](https://github.com/fsociety-team/fsociety/blob/master/LICENSE)
53 |
54 | [](https://twitter.com/fsociety_team) [](https://twitter.com/fsociety_team)
55 |
--------------------------------------------------------------------------------
/fsociety/networking/nmap.py:
--------------------------------------------------------------------------------
1 | # pylint: disable=line-too-long
2 | import os
3 | from shutil import which
4 |
5 | from fsociety.core.repo import GitHubRepo
6 | from fsociety.core.menu import set_readline
7 | from fsociety.core.hosts import get_hosts, add_host, InvalidHost
8 |
9 | premade_args = {
10 | "simple":
11 | "{host}",
12 | "common_ports":
13 | "-F {host}",
14 | "all_ports":
15 | "-p- {host}",
16 | "detect_os":
17 | "-A {host}",
18 | "tcp_syn_scan":
19 | "-sS {host}",
20 | "tcp_connect":
21 | "-sT {host}",
22 | "nse_standard":
23 | "-sV -sC {host}",
24 | "vuln_scan":
25 | "-Pn --script vuln {host}",
26 | "google_malware":
27 | "-p80 --script http-google-malware {host}",
28 | "argressive_scan":
29 | "-A -T4 {host}",
30 | "detect_web_app":
31 | "--script=http-enum {host}",
32 | "subdomain_enumaration":
33 | "-sn --script hostmap-crtsh {host}",
34 | "heartbleed_test":
35 | "-sV -p 443 --script=ssl-heartbleed {host}",
36 | "slowloris":
37 | "-max-parallelism 800 -Pn --script http-slowloris --script-args http-slowloris.runforever=true {host}"
38 | }
39 |
40 |
41 | class NmapRepo(GitHubRepo):
42 | def __init__(self):
43 | super().__init__(path="nmap/nmap",
44 | install={
45 | "linux": "sudo apt-get install nmap",
46 | "brew": "install nmap"
47 | },
48 | description="the Network Mapper")
49 |
50 | def installed(self):
51 | return which("nmap")
52 |
53 | def install(self):
54 | super().install(clone=False)
55 |
56 | def run(self):
57 | hosts = get_hosts()
58 | set_readline(hosts)
59 | host = input("\nEnter a host: ").strip()
60 | if not host:
61 | raise InvalidHost
62 | if host not in hosts:
63 | add_host(host)
64 | longest_key = max([len(key) for key in premade_args]) + 2
65 | print("\nName".ljust(longest_key) + " | Args")
66 | for name, args in premade_args.items():
67 | print(f"{name.ljust(longest_key)}: {args.format(host=host)}")
68 | set_readline(premade_args.keys())
69 | selected = input("\nMake a selection: ")
70 | if selected and selected in premade_args.keys():
71 | args = premade_args.get(selected).format(host=host)
72 | return os.system(f"nmap {args}")
73 | return self.run()
74 |
75 |
76 | nmap = NmapRepo()
77 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
131 | # VSCord
132 | .vscode/
133 |
134 | # macOS
135 | .DS_Store
136 |
--------------------------------------------------------------------------------
/fsociety/core/utilities.py:
--------------------------------------------------------------------------------
1 | # pylint: disable=invalid-name,line-too-long
2 | import os
3 | from base64 import b64decode
4 | from socket import gethostbyname
5 | from webbrowser import open_new_tab
6 | from abc import ABCMeta, abstractmethod
7 |
8 | from requests import get
9 |
10 | from fsociety.console import console
11 |
12 | from .menu import set_readline, tools_cli
13 | from .config import INSTALL_DIR, GITHUB_PATH
14 | from .hosts import get_hosts, add_host
15 |
16 |
17 | class Utility(metaclass=ABCMeta):
18 | def __init__(self, description=None):
19 | self.description = description
20 |
21 | def __str__(self):
22 | return self.__class__.__name__
23 |
24 | @abstractmethod
25 | def run(self):
26 | pass
27 |
28 |
29 | class host2ip(Utility):
30 | def __init__(self):
31 | super().__init__(description="Gets IP from host")
32 |
33 | def run(self):
34 | hosts = get_hosts()
35 | set_readline(hosts)
36 | user_host = input("\nEnter a host: ").strip()
37 | if not user_host in hosts:
38 | add_host(user_host)
39 | ip = gethostbyname(user_host)
40 | console.print(f"\n{user_host} has the IP of {ip}")
41 |
42 |
43 | class base64_decode(Utility):
44 | def __init__(self):
45 | super().__init__(description="Decodes base64")
46 |
47 | def run(self):
48 | user_base64 = input("\nEnter base64: ").strip()
49 | text = b64decode(user_base64)
50 | console.print(f"\nDecoded that is: {text}")
51 |
52 |
53 | class spawn_shell(Utility):
54 | def __init__(self):
55 | super().__init__(description="Spawns a local shell")
56 |
57 | def run(self):
58 | console.print("Enter `exit` to return to fsociety")
59 | shell = os.getenv("SHELL", "/bin/bash")
60 | os.chdir(INSTALL_DIR)
61 | os.system(shell)
62 |
63 |
64 | class suggest_tool(Utility):
65 | def __init__(self):
66 | super().__init__(description="Suggest a tool or utility")
67 |
68 | def run(self):
69 | open_new_tab(
70 | f"https://github.com/{GITHUB_PATH}/issues/new?assignees=&labels=tool&template=---tool-request.md&title="
71 | )
72 |
73 |
74 | class print_contributors(Utility):
75 | def __init__(self):
76 | super().__init__(description="Prints the usernames of our devs")
77 |
78 | def run(self):
79 | console.print("""
80 | 8888b. 888888 Yb dP .dP"Y8
81 | 8I Yb 88__ Yb dP `Ybo."
82 | 8I dY 88"" YbdP o.`Y8b
83 | 8888Y" 888888 YP 8bodP'
84 | """, style="bold yellow", highlight=False)
85 | response = get(
86 | f"https://api.github.com/repos/{GITHUB_PATH}/contributors")
87 | contributors = response.json()
88 | for contributor in sorted(contributors,
89 | key=lambda c: c['contributions'],
90 | reverse=True):
91 | username = contributor.get("login")
92 | console.print(f" {username} ".center(30, "-"))
93 |
94 |
95 | __tools__ = [
96 | tool() for tool in
97 | [host2ip, base64_decode, spawn_shell, suggest_tool, print_contributors]
98 | ]
99 |
100 |
101 | def cli():
102 | tools_cli(__name__, __tools__, links=False)
103 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | - Using welcoming and inclusive language
18 | - Being respectful of differing viewpoints and experiences
19 | - Gracefully accepting constructive criticism
20 | - Focusing on what is best for the community
21 | - Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | - The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | - Trolling, insulting/derogatory comments, and personal or political attacks
28 | - Public or private harassment
29 | - Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | - Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at contact@fsociety.dev. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 |
77 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | import io
5 | import os
6 | import sys
7 |
8 | from setuptools import find_packages, setup, Command
9 |
10 | # Package meta-data.
11 | NAME = 'fsociety'
12 | DESCRIPTION = 'A Modular Penetration Testing Framework'
13 | URL = 'https://fsociety.dev/'
14 | PROJECT_URLS = {
15 | 'Packages': 'https://github.com/fsociety-team/fsociety/blob/master/PACKAGES.md',
16 | 'Changelog': 'https://github.com/fsociety-team/fsociety/blob/master/CHANGELOG.md',
17 | 'Funding': 'https://github.com/sponsors/thehappydinoa',
18 | 'Tracker': 'https://github.com/fsociety-team/fsociety/issues',
19 | 'Source': 'https://github.com/fsociety-team/fsociety',
20 | }
21 | EMAIL = 'contact@fsociety.dev'
22 | AUTHOR = 'fsociety-team'
23 | REQUIRES_PYTHON = '>=3.7.0'
24 | VERSION = None
25 |
26 | # Required Packages
27 | REQUIRED = ['gitpython', 'rich', 'requests']
28 |
29 | # Optional Packages
30 | EXTRAS = {
31 | 'dev': [
32 | 'wheel',
33 | 'pylint',
34 | 'autopep8',
35 | 'twine',
36 | ]
37 | }
38 |
39 | here = os.path.abspath(os.path.dirname(__file__))
40 |
41 | try:
42 | with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
43 | long_description = '\n' + f.read()
44 | except FileNotFoundError:
45 | long_description = DESCRIPTION
46 |
47 | about = {}
48 | if not VERSION:
49 | project_slug = NAME.lower().replace("-", "_").replace(" ", "_")
50 | with open(os.path.join(here, project_slug, '__version__.py')) as f:
51 | exec(f.read(), about)
52 | else:
53 | about['__version__'] = VERSION
54 |
55 |
56 | class TagCommand(Command):
57 | """Support setup.py push_tag."""
58 |
59 | description = 'Push latest version as tag.'
60 | user_options = []
61 |
62 | @staticmethod
63 | def status(s):
64 | print('\033[1m{0}\033[0m'.format(s))
65 |
66 | def initialize_options(self):
67 | pass
68 |
69 | def finalize_options(self):
70 | pass
71 |
72 | def run(self):
73 | self.status('Pushing git tags…')
74 | os.system('git tag v{0}'.format(about['__version__']))
75 | os.system('git push --tags')
76 |
77 | sys.exit()
78 |
79 |
80 | setup(
81 | name=NAME,
82 | version=about['__version__'],
83 | description=DESCRIPTION,
84 | long_description=long_description,
85 | long_description_content_type='text/markdown',
86 | author=AUTHOR,
87 | author_email=EMAIL,
88 | python_requires=REQUIRES_PYTHON,
89 | url=URL,
90 | project_urls=PROJECT_URLS,
91 | packages=find_packages(
92 | exclude=["tests", "*.tests", "*.tests.*", "tests.*"]),
93 | entry_points={
94 | 'console_scripts': ['fsociety=fsociety:cli'],
95 | },
96 | install_requires=REQUIRED,
97 | extras_require=EXTRAS,
98 | include_package_data=True,
99 | license='MIT',
100 | classifiers=[
101 | # Trove classifiers
102 | # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
103 | 'Topic :: Security',
104 | 'License :: OSI Approved :: MIT License',
105 | 'Programming Language :: Python',
106 | 'Programming Language :: Python :: 3 :: Only',
107 | 'Programming Language :: Python :: 3',
108 | 'Programming Language :: Python :: 3.7',
109 | 'Programming Language :: Python :: 3.8',
110 | 'Programming Language :: Python :: Implementation :: PyPy'
111 | ],
112 | # python setup.py upload
113 | cmdclass={
114 | 'push_tag': TagCommand,
115 | },
116 | )
117 |
--------------------------------------------------------------------------------
/fsociety/core/menu.py:
--------------------------------------------------------------------------------
1 | # pylint: disable=unused-import,broad-except,inconsistent-return-statements
2 | import os
3 | import shutil
4 |
5 | from rich.text import Text
6 | from rich.table import Table
7 | from rich.style import Style
8 | from rich import box
9 |
10 | from fsociety.console import console
11 | from fsociety.core.config import INSTALL_DIR
12 |
13 | BACK_COMMANDS = ["back", "return"]
14 |
15 |
16 | class CommandCompleter():
17 | def __init__(self, options):
18 | self.options = sorted(options)
19 | self.matches = list()
20 |
21 | def complete(self, text, state):
22 | response = None
23 | if state == 0:
24 | if text:
25 | self.matches = [
26 | s for s in self.options if s and s.startswith(text)
27 | ]
28 | else:
29 | self.matches = self.options[:]
30 | try:
31 | response = self.matches[state]
32 | except IndexError:
33 | response = None
34 | return response
35 |
36 |
37 | def set_readline(items):
38 | try:
39 | import readline
40 | except ImportError:
41 | pass
42 | else:
43 | import rlcompleter
44 | if isinstance(items, list):
45 | readline.set_completer(CommandCompleter(items).complete)
46 | elif isinstance(items, dict):
47 | readline.set_completer(CommandCompleter(items.keys()).complete)
48 | else:
49 | readline.set_completer(CommandCompleter(list(items)).complete)
50 | readline.parse_and_bind("tab: complete")
51 |
52 |
53 | def clear_screen():
54 | os.system('cls' if os.name == 'nt' else 'clear')
55 |
56 |
57 | def format_tools(tools):
58 | cutoff = 5
59 | etc = False
60 | if len(tools) > cutoff:
61 | tools = tools[:cutoff]
62 | etc = True
63 | res = "".join([f"\n{str(tool)}" for tool in tools])
64 | if etc:
65 | res += "\n..."
66 | return res
67 |
68 |
69 | def module_name(module):
70 | return module.__name__.split(".")[-1]
71 |
72 |
73 | def prompt(path="", base_path="~"):
74 | encoded_path = os.path.join(base_path, path, "")
75 | return f"\nfsociety {encoded_path}# "
76 |
77 |
78 | def input_wait():
79 | input("\nPress [ENTER] to continue... ")
80 |
81 |
82 | def tools_cli(name, tools, links=True):
83 | table = Table(box=box.HEAVY_HEAD)
84 | table.add_column("Name", style="red", no_wrap=True)
85 | table.add_column("Description", style="magenta")
86 | if links:
87 | table.add_column("Link", no_wrap=True)
88 |
89 | tools_dict = dict()
90 | for tool in tools:
91 | tools_dict[str(tool)] = tool
92 | args = [str(tool), tool.description]
93 | if links:
94 | text_link = Text(f"{tool.path}")
95 | text_link.stylize_all(
96 | Style(link=f"https://github.com/{tool.path}"))
97 | args.append(text_link)
98 | table.add_row(*args)
99 |
100 | console.print(table)
101 | console.print("back", style="command")
102 | set_readline(list(tools_dict.keys()) + BACK_COMMANDS)
103 | selected_tool = input(prompt(name.split(".")[-2])).strip()
104 | if not selected_tool in tools_dict.keys():
105 | if selected_tool in BACK_COMMANDS:
106 | return
107 | console.print("Invalid Command", style="bold yellow")
108 | return tools_cli(name, tools, links)
109 | tool = tools_dict.get(selected_tool)
110 | if hasattr(tool, "install") and not tool.installed():
111 | tool.install()
112 | try:
113 | response = tool.run()
114 | if response and response > 0 and response != 256:
115 | console.print(
116 | f"{selected_tool} returned a non-zero exit code", style="bold red")
117 | if hasattr(tool, "install") and confirm("Do you want to reinstall?"):
118 | os.chdir(INSTALL_DIR)
119 | shutil.rmtree(tool.full_path)
120 | tool.install()
121 | except KeyboardInterrupt:
122 | return
123 |
124 | return input_wait()
125 |
126 |
127 | def confirm(message="Do you want to?"):
128 | response = input(f"{message} (y/n): ").lower()
129 | if response:
130 | return response[0] == "y"
131 | return False
132 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [Unreleased]
9 |
10 | - Any unreleased changes
11 |
12 | ## [3.2.3] - 06-09-2020
13 |
14 | - Update Docs
15 | - Misc fixes
16 |
17 | ## [3.2.2] - 06-08-2020
18 |
19 | - Update Docs
20 | - Misc fixes
21 | - Replaced `colorama` with `rich`
22 | - Added `GitPython` package
23 | - Python Dependency graph
24 |
25 | ## [3.2.1] - 06-02-2020
26 |
27 | - Update Docs
28 | - Misc fixes
29 |
30 | ## [3.1.9] - 05-30-2020
31 |
32 | - Implement Pylint
33 | - Refactor
34 | - Update Docs
35 | - Random Banner
36 |
37 | ## [3.1.8] - 05-28-2020
38 |
39 | - Fixed config
40 | - Cleaned up workflow
41 | - Added [Striker](https://github.com/s0md3v/Striker)
42 | - Added [HydraRecon](https://github.com/aufzayed/HydraRecon)
43 |
44 | ## [3.1.5] - 05-28-2020
45 |
46 | - Added Networking category
47 | - Added [bettercap](https://github.com/bettercap/bettercap)
48 | - Moved [nmap](https://github.com/nmap/nmap) to Networking
49 | - Added [Photon](https://github.com/s0md3v/Photon)
50 | - Added [gitGraber](https://github.com/hisxo/gitGraber)
51 |
52 | ## [3.1.4] - 05-28-2020
53 |
54 | - Added `--suggest` argument
55 |
56 | ## [3.1.3] - 05-23-2020
57 |
58 | - Added GitHub Templates
59 | - Added Docker Support
60 | - New Icon
61 | - Changed ASCII art
62 | - Added `--info` argument
63 | - Added `base64_decode` to utilities
64 |
65 | ## [3.1.2] - 05-20-2020
66 |
67 | - Added [changeme](https://github.com/ztgrace/changeme)
68 | - Added nmap scripts
69 |
70 | ## [3.1.1] - 05-19-2020
71 |
72 | - Added [sqlmap](https://github.com/sqlmapproject/sqlmap)
73 | - Added `utility`
74 |
75 | ## [3.1.0] - 05-19-2020
76 |
77 | - Fixed `packages` in `setup.py`
78 |
79 | ## [3.0.9] - 05-19-2020
80 |
81 | - Fixed `setup.py`
82 |
83 | ## [3.0.8] - 05-18-2020
84 |
85 | - Added [Hash-Buster](https://github.com/s0md3v/Hash-Buster)
86 | - Added [Sublist3r](https://github.com/aboul3la/Sublist3r)
87 | - Added [S3Scanner](https://github.com/sa7mon/S3Scanner)
88 | - Added [Cr3d0v3r](https://github.com/D4Vinci/Cr3d0v3r)
89 | - Added [Cuteit](https://github.com/D4Vinci/Cuteit)
90 |
91 | ## [3.0.7] - 05-18-2020
92 |
93 | - Created [Docs](https://fsociety.dev/) with `pmarsceill/just-the-docs`
94 |
95 | ## [3.0.6] - 05-17-2020
96 |
97 | - Added [XSStrike](https://github.com/s0md3v/XSStrike)
98 |
99 | ## [3.0.5] - 05-17-2020
100 |
101 | - Changed minimum Python version to 3.7
102 | - Added PyPi Badge to `README.md`
103 |
104 | ## [3.0.4] - 05-17-2020
105 |
106 | - Added hosts file at `~/.fsociety/hosts.txt`
107 | - Added usernames file at `~/.fsociety/usernames.txt`
108 | - Added [nmap](https://github.com/nmap/nmap)
109 | - Added [sherlock](https://github.com/sherlock-project/sherlock)
110 |
111 | ## [3.0.3] - 05-17-2020
112 |
113 | - Added `argparse`
114 |
115 | ## [3.0.2] - 05-17-2020
116 |
117 | - Published to `pypi`
118 | - Added upload script to `setup.py`
119 | - Added config file at `~/.fsociety/fsociety.cfg`
120 | - Added `colorama` package
121 | - Added `GitHubRepo` class
122 | - Added [cupp](https://github.com/Mebus/cupp)
123 |
124 | ## [3.0.0] - 05-16-2020
125 |
126 | - Initial Release
127 |
128 | [unreleased]: https://github.com/fsociety-team/fsociety/compare/v3.2.3...HEAD
129 | [3.2.3]: https://github.com/fsociety-team/fsociety/compare/v3.2.2...v3.2.3
130 | [3.2.2]: https://github.com/fsociety-team/fsociety/compare/v3.2.1...v3.2.2
131 | [3.2.1]: https://github.com/fsociety-team/fsociety/compare/v3.1.9...v3.2.1
132 | [3.1.9]: https://github.com/fsociety-team/fsociety/compare/v3.1.8...v3.1.9
133 | [3.1.8]: https://github.com/fsociety-team/fsociety/compare/v3.1.5...v3.1.8
134 | [3.1.5]: https://github.com/fsociety-team/fsociety/compare/v3.1.4...v3.1.5
135 | [3.1.4]: https://github.com/fsociety-team/fsociety/compare/v3.1.3...v3.1.4
136 | [3.1.3]: https://github.com/fsociety-team/fsociety/compare/v3.1.2...v3.1.3
137 | [3.1.2]: https://github.com/fsociety-team/fsociety/compare/v3.1.1...v3.1.2
138 | [3.1.1]: https://github.com/fsociety-team/fsociety/compare/v3.1.0...v3.1.1
139 | [3.1.0]: https://github.com/fsociety-team/fsociety/compare/v3.0.9...v3.1.0
140 | [3.0.9]: https://github.com/fsociety-team/fsociety/compare/v3.0.8...v3.0.9
141 | [3.0.8]: https://github.com/fsociety-team/fsociety/compare/v3.0.7...v3.0.8
142 | [3.0.7]: https://github.com/fsociety-team/fsociety/compare/v3.0.6...v3.0.7
143 | [3.0.6]: https://github.com/fsociety-team/fsociety/compare/v3.0.5...v3.0.6
144 | [3.0.5]: https://github.com/fsociety-team/fsociety/compare/v3.0.4...v3.0.5
145 | [3.0.4]: https://github.com/fsociety-team/fsociety/compare/v3.0.3...v3.0.4
146 | [3.0.3]: https://github.com/fsociety-team/fsociety/compare/v3.0.2...v3.0.3
147 | [3.0.2]: https://github.com/fsociety-team/fsociety/compare/v3.0.0...v3.0.2
148 | [3.0.0]: https://github.com/fsociety-team/fsociety/releases/tag/v3.0.0
149 |
--------------------------------------------------------------------------------
/fsociety/core/repo.py:
--------------------------------------------------------------------------------
1 | # pylint: disable=too-many-branches,line-too-long
2 | import os
3 | from shutil import rmtree, which
4 | from abc import ABCMeta, abstractmethod
5 | from collections.abc import Iterable
6 |
7 | from git import Repo, RemoteProgress
8 | from rich.progress import BarColumn, Progress
9 | from rich.table import Table
10 |
11 | from fsociety.core.config import INSTALL_DIR, get_config
12 | from fsociety.core.menu import confirm
13 | from fsociety.console import console
14 |
15 | config = get_config()
16 |
17 |
18 | def print_pip_deps(packages):
19 | requirements = list()
20 | if isinstance(packages, str) and os.path.exists(packages):
21 | with open(packages, "r") as requirements_file:
22 | for line in requirements_file:
23 | if line.strip():
24 | requirements.append(line)
25 | elif isinstance(packages, Iterable):
26 | requirements = packages
27 | else:
28 | raise ValueError
29 | table = Table("Packages", title="Pip Dependencies")
30 | for req in requirements:
31 | table.add_row(req)
32 | console.print()
33 | console.print(table)
34 |
35 |
36 | class InstallError(Exception):
37 | pass
38 |
39 |
40 | class CloneError(Exception):
41 | pass
42 |
43 |
44 | class GitProgress(RemoteProgress):
45 | def __init__(self):
46 | super().__init__()
47 | self.progress = Progress(
48 | "[progress.description]{task.description}",
49 | BarColumn(None),
50 | "[progress.percentage]{task.percentage:>3.0f}%",
51 | "[progress.filesize]{task.fields[msg]}",
52 | )
53 | self.current_opcode = None
54 | self.task = None
55 |
56 | def update(self, opcode, count, max_value, msg=None):
57 | opcode_strs = {
58 | self.COUNTING: 'Counting',
59 | self.COMPRESSING: 'Compressing',
60 | self.WRITING: 'Writing',
61 | self.RECEIVING: 'Receiving',
62 | self.RESOLVING: 'Resolving',
63 | self.FINDING_SOURCES: 'Finding sources',
64 | self.CHECKING_OUT: 'Checking out',
65 | }
66 | stage, real_opcode = opcode & self.STAGE_MASK, opcode & self.OP_MASK
67 |
68 | try:
69 | count = int(count)
70 | max_value = int(max_value)
71 | except ValueError:
72 | return
73 |
74 | if self.current_opcode != real_opcode:
75 | if self.task:
76 | self.progress.update(self.task, total=1, completed=1, msg='')
77 | self.current_opcode = real_opcode
78 | self.task = self.progress.add_task(
79 | opcode_strs[real_opcode].ljust(15), msg='')
80 |
81 | if stage & self.BEGIN:
82 | self.progress.start()
83 | if stage & self.END:
84 | self.progress.stop()
85 | self.progress.update(self.task, msg=msg or '',
86 | total=max_value, completed=count)
87 |
88 |
89 | class GitHubRepo(metaclass=ABCMeta):
90 | def __init__(self,
91 | path="fsociety-team/fsociety",
92 | install="pip install -e .",
93 | description=None):
94 | self.path = path
95 | self.name = self.path.split("/")[-1]
96 | self.install_options = install
97 | self.full_path = os.path.join(INSTALL_DIR, self.name)
98 | self.description = description
99 |
100 | def __str__(self):
101 | return self.name.lower().replace("-", "_")
102 |
103 | def clone(self, overwrite=False):
104 | if os.path.exists(self.full_path):
105 | if not overwrite:
106 | repo = Repo(self.full_path)
107 | repo.remotes.origin.pull()
108 | return self.full_path
109 | rmtree(self.full_path)
110 | url = f"https://github.com/{self.path}"
111 | if config.getboolean("fsociety", "ssh_clone"):
112 | url = f"git@github.com:{self.path}.git"
113 | Repo.clone_from(url, self.full_path, progress=GitProgress())
114 | if not os.path.exists(self.full_path):
115 | raise CloneError(f"{self.full_path} not found")
116 | return self.full_path
117 |
118 | def install(self, no_confirm=False, clone=True):
119 | if no_confirm or not confirm(
120 | f"\nDo you want to install https://github.com/{self.path}?"):
121 | print("Cancelled")
122 | return
123 | if clone:
124 | self.clone()
125 | if self.install_options:
126 | if clone:
127 | os.chdir(self.full_path)
128 | else:
129 | os.chdir(INSTALL_DIR)
130 | install = self.install_options
131 |
132 | if isinstance(install, dict):
133 | if "pip" in install.keys():
134 | packages = install.get("pip")
135 | if isinstance(packages, list):
136 | message = "Do you want to install these packages?"
137 | packages_str = " ".join(packages)
138 | command = f"pip install {packages_str}"
139 | elif isinstance(packages, str):
140 | requirements_txt = os.path.join(
141 | self.full_path, "requirements.txt")
142 | message = f"Do you want to install these packages from {requirements_txt}?"
143 | command = f"pip install -r {requirements_txt}"
144 |
145 | print_pip_deps(packages)
146 | if not confirm(message):
147 | raise InstallError("User Cancelled")
148 | elif config.get("fsociety", "os") == "macos" and "brew" in install.keys() and which("brew"):
149 | brew_opts = install.get("brew")
150 | command = f"brew {brew_opts}"
151 | elif "linux" in install.keys() or "windows" in install.keys() or "macs" in install.keys():
152 | command = install.get(config.get(
153 | "fsociety", "os"), install.get("linux"))
154 | else:
155 | command = install
156 |
157 | os.system(command)
158 |
159 | def installed(self):
160 | return os.path.exists(self.full_path)
161 |
162 | @abstractmethod
163 | def run(self):
164 | pass
165 |
--------------------------------------------------------------------------------
/fsociety/cli.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | # pylint: disable=exec-used,broad-except,inconsistent-return-statements,invalid-name,trailing-whitespace
4 |
5 | import argparse
6 | import platform
7 | from random import choice
8 |
9 | from rich.text import Text
10 | from rich.columns import Columns
11 |
12 | # Core
13 | from fsociety.console import console
14 | from fsociety.core.menu import (set_readline, format_tools,
15 | module_name, prompt, clear_screen)
16 | from fsociety.core.config import get_config, write_config, CONFIG_FILE
17 | import fsociety.core.utilities
18 | import fsociety.information_gathering
19 | import fsociety.passwords
20 | import fsociety.web_apps
21 | import fsociety.obfuscation
22 | import fsociety.networking
23 |
24 | # Config
25 | config = get_config()
26 |
27 | # Menu
28 | TERMS = """
29 | I shall not use fsociety to:
30 | (i) upload or otherwise transmit, display or distribute any
31 | content that infringes any trademark, trade secret, copyright
32 | or other proprietary or intellectual property rights of any
33 | person; (ii) upload or otherwise transmit any material that contains
34 | software viruses or any other computer code, files or programs
35 | designed to interrupt, destroy or limit the functionality of any
36 | computer software or hardware or telecommunications equipment;
37 | """
38 | BANNER1 = (
39 | """
40 | ____ _ __
41 | / __/________ _____(_)__ / /___ __
42 | / /_/ ___/ __ \/ ___/ / _ \/ __/ / / /
43 | / __(__ ) /_/ / /__/ / __/ /_/ /_/ /
44 | /_/ /____/\____/\___/_/\___/\__/\__, /
45 | /____/
46 | """)
47 | BANNER2 = (
48 | """
49 | __ _ _
50 | / _|___ ___ ___(_) ___| |_ _ _
51 | | |_/ __|/ _ \ / __| |/ _ \ __| | | |
52 | | _\__ \ (_) | (__| | __/ |_| |_| |
53 | |_| |___/\___/ \___|_|\___|\__|\__, |
54 | |___/
55 | """)
56 | BANNER3 = (
57 | """
58 | .-. .
59 | | o _|_
60 | -|-.--. .-. .-. . .-. | . .
61 | | `--.( )( | (.-' | | |
62 | ' `--' `-' `-'-' `-`--'`-'`--|
63 | ;
64 | `-'
65 | """)
66 | BANNER4 = (
67 | """
68 | ,__ .
69 | / ` ____ __. ___ ` ___ _/_ , .
70 | |__ ( .' \ .' ` | .' ` | | `
71 | | `--. | | | | |----' | | |
72 | | \___.' `._.' `._.' / `.___, \__/ `---|.
73 | / \___/
74 | """)
75 | BANNERS = [BANNER1, BANNER2, BANNER3, BANNER4]
76 | MENU_ITEMS = [
77 | fsociety.information_gathering, fsociety.networking, fsociety.web_apps,
78 | fsociety.passwords, fsociety.obfuscation, fsociety.core.utilities
79 | ]
80 | BUILTIN_FUNCTIONS = {
81 | "exit": lambda: exec('raise KeyboardInterrupt'),
82 | }
83 | items = dict()
84 |
85 |
86 | def print_menu_items():
87 | cols = list()
88 | for value in MENU_ITEMS:
89 | name = module_name(value)
90 | tools = format_tools(value.__tools__)
91 | tools_str = Text()
92 | tools_str.append("\n")
93 | tools_str.append(name, style="command")
94 | tools_str.append(tools)
95 | cols.append(tools_str)
96 |
97 | console.print(Columns(cols, equal=True, expand=True))
98 |
99 | for key in BUILTIN_FUNCTIONS:
100 | print()
101 | console.print(key, style="command")
102 |
103 |
104 | def agreement():
105 | while not config.getboolean("fsociety", "agreement"):
106 | clear_screen()
107 | console.print(TERMS, style="bold yellow")
108 | agree = input(
109 | "You must agree to our terms and conditions first (Y/n) ")
110 | if agree.lower()[0] == "y":
111 | config.set('fsociety', 'agreement', 'true')
112 |
113 |
114 | for item in MENU_ITEMS:
115 | items[module_name(item)] = item
116 |
117 | commands = list(items.keys()) + list(BUILTIN_FUNCTIONS.keys())
118 |
119 |
120 | def mainloop():
121 | agreement()
122 | console.print(choice(BANNERS), style="red", highlight=False)
123 | print_menu_items()
124 | selected_command = input(prompt()).strip()
125 | if not selected_command or (not selected_command in commands):
126 | console.print("Invalid Command", style="bold yellow")
127 | return
128 | if selected_command in BUILTIN_FUNCTIONS.keys():
129 | func = BUILTIN_FUNCTIONS.get(selected_command)
130 | return func()
131 | try:
132 | func = items[selected_command].cli
133 | return func()
134 | except Exception as error:
135 | console.print(str(error))
136 | console.print_exception()
137 | return
138 |
139 |
140 | def info():
141 | data = dict()
142 | # Config File
143 | with open(CONFIG_FILE) as file:
144 | data["Config File"] = file.read().strip()
145 | data["Python Version"] = platform.python_version()
146 | data["Platform"] = platform.platform()
147 | os = config.get("fsociety", "os")
148 | if os == "macos":
149 | data["macOS"] = platform.mac_ver()[0]
150 | elif os == "windows":
151 | data["Windows"] = platform.win32_ver()[0]
152 |
153 | for key, value in data.items():
154 | console.print(f"# {key}")
155 | console.print(value, end="\n\n")
156 |
157 |
158 | def interactive():
159 |
160 | try:
161 | while True:
162 | set_readline(commands)
163 | mainloop()
164 | except KeyboardInterrupt:
165 | console.print("\nExitting...")
166 | write_config(config)
167 | exit(0)
168 |
169 |
170 | def main():
171 | parser = argparse.ArgumentParser(
172 | description='A Penetration Testing Framework')
173 | parser.add_argument('-i',
174 | '--info',
175 | action='store_true',
176 | help='gets fsociety info')
177 | parser.add_argument('-s',
178 | '--suggest',
179 | action='store_true',
180 | help='suggest a tool')
181 |
182 | args = parser.parse_args()
183 |
184 | if args.info:
185 | info()
186 | elif args.suggest:
187 | fsociety.core.utilities.suggest_tool()
188 | else:
189 | interactive()
190 |
191 |
192 | if __name__ == "__main__":
193 | main()
194 |
--------------------------------------------------------------------------------
/.pylintrc:
--------------------------------------------------------------------------------
1 | [MASTER]
2 |
3 | # A comma-separated list of package or module names from where C extensions may
4 | # be loaded. Extensions are loading into the active Python interpreter and may
5 | # run arbitrary code.
6 | extension-pkg-whitelist=
7 |
8 | # Specify a score threshold to be exceeded before program exits with error.
9 | fail-under=10
10 |
11 | # Add files or directories to the blacklist. They should be base names, not
12 | # paths.
13 | ignore=CVS
14 |
15 | # Add files or directories matching the regex patterns to the blacklist. The
16 | # regex matches against base names, not paths.
17 | ignore-patterns=
18 |
19 | # Python code to execute, usually for sys.path manipulation such as
20 | # pygtk.require().
21 | #init-hook=
22 |
23 | # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
24 | # number of processors available to use.
25 | jobs=1
26 |
27 | # Control the amount of potential inferred values when inferring a single
28 | # object. This can help the performance when dealing with large functions or
29 | # complex, nested conditions.
30 | limit-inference-results=100
31 |
32 | # List of plugins (as comma separated values of python module names) to load,
33 | # usually to register additional checkers.
34 | load-plugins=
35 |
36 | # Pickle collected data for later comparisons.
37 | persistent=yes
38 |
39 | # When enabled, pylint would attempt to guess common misconfiguration and emit
40 | # user-friendly hints instead of false-positive error messages.
41 | suggestion-mode=yes
42 |
43 | # Allow loading of arbitrary C extensions. Extensions are imported into the
44 | # active Python interpreter and may run arbitrary code.
45 | unsafe-load-any-extension=no
46 |
47 |
48 | [MESSAGES CONTROL]
49 |
50 | # Only show warnings with the listed confidence levels. Leave empty to show
51 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
52 | confidence=
53 |
54 | # Disable the message, report, category or checker with the given id(s). You
55 | # can either give multiple identifiers separated by comma (,) or put this
56 | # option multiple times (only on the command line, not in the configuration
57 | # file where it should appear only once). You can also use "--disable=all" to
58 | # disable everything first and then reenable specific checks. For example, if
59 | # you want to run only the similarities checker, you can use "--disable=all
60 | # --enable=similarities". If you want to run only the classes checker, but have
61 | # no Warning level messages displayed, use "--disable=all --enable=classes
62 | # --disable=W".
63 | disable=print-statement,
64 | parameter-unpacking,
65 | unpacking-in-except,
66 | old-raise-syntax,
67 | backtick,
68 | long-suffix,
69 | old-ne-operator,
70 | old-octal-literal,
71 | import-star-module-level,
72 | non-ascii-bytes-literal,
73 | raw-checker-failed,
74 | bad-inline-option,
75 | locally-disabled,
76 | file-ignored,
77 | suppressed-message,
78 | useless-suppression,
79 | deprecated-pragma,
80 | use-symbolic-message-instead,
81 | apply-builtin,
82 | basestring-builtin,
83 | buffer-builtin,
84 | cmp-builtin,
85 | coerce-builtin,
86 | execfile-builtin,
87 | file-builtin,
88 | long-builtin,
89 | raw_input-builtin,
90 | reduce-builtin,
91 | standarderror-builtin,
92 | unicode-builtin,
93 | xrange-builtin,
94 | coerce-method,
95 | delslice-method,
96 | getslice-method,
97 | setslice-method,
98 | no-absolute-import,
99 | old-division,
100 | dict-iter-method,
101 | dict-view-method,
102 | next-method-called,
103 | metaclass-assignment,
104 | indexing-exception,
105 | raising-string,
106 | reload-builtin,
107 | oct-method,
108 | hex-method,
109 | nonzero-method,
110 | cmp-method,
111 | input-builtin,
112 | round-builtin,
113 | intern-builtin,
114 | unichr-builtin,
115 | map-builtin-not-iterating,
116 | zip-builtin-not-iterating,
117 | range-builtin-not-iterating,
118 | filter-builtin-not-iterating,
119 | using-cmp-argument,
120 | eq-without-hash,
121 | div-method,
122 | idiv-method,
123 | rdiv-method,
124 | exception-message-attribute,
125 | invalid-str-codec,
126 | sys-max-int,
127 | bad-python3-import,
128 | deprecated-string-function,
129 | deprecated-str-translate-call,
130 | deprecated-itertools-function,
131 | deprecated-types-field,
132 | next-method-defined,
133 | dict-items-not-iterating,
134 | dict-keys-not-iterating,
135 | dict-values-not-iterating,
136 | deprecated-operator-function,
137 | deprecated-urllib-function,
138 | xreadlines-attribute,
139 | deprecated-sys-function,
140 | exception-escape,
141 | comprehension-escape,
142 | missing-module-docstring,
143 | missing-class-docstring,
144 | missing-function-docstring,
145 | anomalous-backslash-in-string,
146 | consider-using-sys-exit,
147 | too-few-public-methods,
148 | arguments-differ,
149 | import-outside-toplevel
150 |
151 | # Enable the message, report, category or checker with the given id(s). You can
152 | # either give multiple identifier separated by comma (,) or put this option
153 | # multiple time (only on the command line, not in the configuration file where
154 | # it should appear only once). See also the "--disable" option for examples.
155 | enable=c-extension-no-member
156 |
157 |
158 | [REPORTS]
159 |
160 | # Python expression which should return a score less than or equal to 10. You
161 | # have access to the variables 'error', 'warning', 'refactor', and 'convention'
162 | # which contain the number of messages in each category, as well as 'statement'
163 | # which is the total number of statements analyzed. This score is used by the
164 | # global evaluation report (RP0004).
165 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
166 |
167 | # Template used to display messages. This is a python new-style format string
168 | # used to format the message information. See doc for all details.
169 | #msg-template=
170 |
171 | # Set the output format. Available formats are text, parseable, colorized, json
172 | # and msvs (visual studio). You can also give a reporter class, e.g.
173 | # mypackage.mymodule.MyReporterClass.
174 | output-format=text
175 |
176 | # Tells whether to display a full report or only the messages.
177 | reports=no
178 |
179 | # Activate the evaluation score.
180 | score=yes
181 |
182 |
183 | [REFACTORING]
184 |
185 | # Maximum number of nested blocks for function / method body
186 | max-nested-blocks=5
187 |
188 | # Complete name of functions that never returns. When checking for
189 | # inconsistent-return-statements if a never returning function is called then
190 | # it will be considered as an explicit return statement and no message will be
191 | # printed.
192 | never-returning-functions=sys.exit
193 |
194 |
195 | [LOGGING]
196 |
197 | # The type of string formatting that logging methods do. `old` means using %
198 | # formatting, `new` is for `{}` formatting.
199 | logging-format-style=old
200 |
201 | # Logging modules to check that the string format arguments are in logging
202 | # function parameter format.
203 | logging-modules=logging
204 |
205 |
206 | [SPELLING]
207 |
208 | # Limits count of emitted suggestions for spelling mistakes.
209 | max-spelling-suggestions=4
210 |
211 | # Spelling dictionary name. Available dictionaries: none. To make it work,
212 | # install the python-enchant package.
213 | spelling-dict=
214 |
215 | # List of comma separated words that should not be checked.
216 | spelling-ignore-words=
217 |
218 | # A path to a file that contains the private dictionary; one word per line.
219 | spelling-private-dict-file=
220 |
221 | # Tells whether to store unknown words to the private dictionary (see the
222 | # --spelling-private-dict-file option) instead of raising a message.
223 | spelling-store-unknown-words=no
224 |
225 |
226 | [MISCELLANEOUS]
227 |
228 | # List of note tags to take in consideration, separated by a comma.
229 | notes=FIXME,
230 | XXX,
231 | TODO
232 |
233 | # Regular expression of note tags to take in consideration.
234 | #notes-rgx=
235 |
236 |
237 | [TYPECHECK]
238 |
239 | # List of decorators that produce context managers, such as
240 | # contextlib.contextmanager. Add to this list to register other decorators that
241 | # produce valid context managers.
242 | contextmanager-decorators=contextlib.contextmanager
243 |
244 | # List of members which are set dynamically and missed by pylint inference
245 | # system, and so shouldn't trigger E1101 when accessed. Python regular
246 | # expressions are accepted.
247 | generated-members=
248 |
249 | # Tells whether missing members accessed in mixin class should be ignored. A
250 | # mixin class is detected if its name ends with "mixin" (case insensitive).
251 | ignore-mixin-members=yes
252 |
253 | # Tells whether to warn about missing members when the owner of the attribute
254 | # is inferred to be None.
255 | ignore-none=yes
256 |
257 | # This flag controls whether pylint should warn about no-member and similar
258 | # checks whenever an opaque object is returned when inferring. The inference
259 | # can return multiple potential results while evaluating a Python object, but
260 | # some branches might not be evaluated, which results in partial inference. In
261 | # that case, it might be useful to still emit no-member and other checks for
262 | # the rest of the inferred objects.
263 | ignore-on-opaque-inference=yes
264 |
265 | # List of class names for which member attributes should not be checked (useful
266 | # for classes with dynamically set attributes). This supports the use of
267 | # qualified names.
268 | ignored-classes=optparse.Values,thread._local,_thread._local
269 |
270 | # List of module names for which member attributes should not be checked
271 | # (useful for modules/projects where namespaces are manipulated during runtime
272 | # and thus existing member attributes cannot be deduced by static analysis). It
273 | # supports qualified module names, as well as Unix pattern matching.
274 | ignored-modules=
275 |
276 | # Show a hint with possible names when a member name was not found. The aspect
277 | # of finding the hint is based on edit distance.
278 | missing-member-hint=yes
279 |
280 | # The minimum edit distance a name should have in order to be considered a
281 | # similar match for a missing member name.
282 | missing-member-hint-distance=1
283 |
284 | # The total number of similar names that should be taken in consideration when
285 | # showing a hint for a missing member.
286 | missing-member-max-choices=1
287 |
288 | # List of decorators that change the signature of a decorated function.
289 | signature-mutators=
290 |
291 |
292 | [VARIABLES]
293 |
294 | # List of additional names supposed to be defined in builtins. Remember that
295 | # you should avoid defining new builtins when possible.
296 | additional-builtins=
297 |
298 | # Tells whether unused global variables should be treated as a violation.
299 | allow-global-unused-variables=yes
300 |
301 | # List of strings which can identify a callback function by name. A callback
302 | # name must start or end with one of those strings.
303 | callbacks=cb_,
304 | _cb
305 |
306 | # A regular expression matching the name of dummy variables (i.e. expected to
307 | # not be used).
308 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
309 |
310 | # Argument names that match this expression will be ignored. Default to name
311 | # with leading underscore.
312 | ignored-argument-names=_.*|^ignored_|^unused_
313 |
314 | # Tells whether we should check for unused import in __init__ files.
315 | init-import=no
316 |
317 | # List of qualified module names which can have objects that can redefine
318 | # builtins.
319 | redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
320 |
321 |
322 | [FORMAT]
323 |
324 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
325 | expected-line-ending-format=
326 |
327 | # Regexp for a line that is allowed to be longer than the limit.
328 | ignore-long-lines=^\s*(# )??$
329 |
330 | # Number of spaces of indent required inside a hanging or continued line.
331 | indent-after-paren=4
332 |
333 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
334 | # tab).
335 | indent-string=' '
336 |
337 | # Maximum number of characters on a single line.
338 | max-line-length=100
339 |
340 | # Maximum number of lines in a module.
341 | max-module-lines=1000
342 |
343 | # List of optional constructs for which whitespace checking is disabled. `dict-
344 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
345 | # `trailing-comma` allows a space between comma and closing bracket: (a, ).
346 | # `empty-line` allows space-only lines.
347 | no-space-check=trailing-comma,
348 | dict-separator
349 |
350 | # Allow the body of a class to be on the same line as the declaration if body
351 | # contains single statement.
352 | single-line-class-stmt=no
353 |
354 | # Allow the body of an if to be on the same line as the test if there is no
355 | # else.
356 | single-line-if-stmt=no
357 |
358 |
359 | [SIMILARITIES]
360 |
361 | # Ignore comments when computing similarities.
362 | ignore-comments=yes
363 |
364 | # Ignore docstrings when computing similarities.
365 | ignore-docstrings=yes
366 |
367 | # Ignore imports when computing similarities.
368 | ignore-imports=no
369 |
370 | # Minimum lines number of a similarity.
371 | min-similarity-lines=4
372 |
373 |
374 | [BASIC]
375 |
376 | # Naming style matching correct argument names.
377 | argument-naming-style=snake_case
378 |
379 | # Regular expression matching correct argument names. Overrides argument-
380 | # naming-style.
381 | #argument-rgx=
382 |
383 | # Naming style matching correct attribute names.
384 | attr-naming-style=snake_case
385 |
386 | # Regular expression matching correct attribute names. Overrides attr-naming-
387 | # style.
388 | #attr-rgx=
389 |
390 | # Bad variable names which should always be refused, separated by a comma.
391 | bad-names=foo,
392 | bar,
393 | baz,
394 | toto,
395 | tutu,
396 | tata
397 |
398 | # Bad variable names regexes, separated by a comma. If names match any regex,
399 | # they will always be refused
400 | bad-names-rgxs=
401 |
402 | # Naming style matching correct class attribute names.
403 | class-attribute-naming-style=any
404 |
405 | # Regular expression matching correct class attribute names. Overrides class-
406 | # attribute-naming-style.
407 | #class-attribute-rgx=
408 |
409 | # Naming style matching correct class names.
410 | class-naming-style=PascalCase
411 |
412 | # Regular expression matching correct class names. Overrides class-naming-
413 | # style.
414 | #class-rgx=
415 |
416 | # Naming style matching correct constant names.
417 | const-naming-style=UPPER_CASE
418 |
419 | # Regular expression matching correct constant names. Overrides const-naming-
420 | # style.
421 | #const-rgx=
422 |
423 | # Minimum line length for functions/classes that require docstrings, shorter
424 | # ones are exempt.
425 | docstring-min-length=-1
426 |
427 | # Naming style matching correct function names.
428 | function-naming-style=snake_case
429 |
430 | # Regular expression matching correct function names. Overrides function-
431 | # naming-style.
432 | #function-rgx=
433 |
434 | # Good variable names which should always be accepted, separated by a comma.
435 | good-names=i,
436 | j,
437 | k,
438 | ex,
439 | Run,
440 | _
441 |
442 | # Good variable names regexes, separated by a comma. If names match any regex,
443 | # they will always be accepted
444 | good-names-rgxs=
445 |
446 | # Include a hint for the correct naming format with invalid-name.
447 | include-naming-hint=no
448 |
449 | # Naming style matching correct inline iteration names.
450 | inlinevar-naming-style=any
451 |
452 | # Regular expression matching correct inline iteration names. Overrides
453 | # inlinevar-naming-style.
454 | #inlinevar-rgx=
455 |
456 | # Naming style matching correct method names.
457 | method-naming-style=snake_case
458 |
459 | # Regular expression matching correct method names. Overrides method-naming-
460 | # style.
461 | #method-rgx=
462 |
463 | # Naming style matching correct module names.
464 | module-naming-style=snake_case
465 |
466 | # Regular expression matching correct module names. Overrides module-naming-
467 | # style.
468 | #module-rgx=
469 |
470 | # Colon-delimited sets of names that determine each other's naming style when
471 | # the name regexes allow several styles.
472 | name-group=
473 |
474 | # Regular expression which should only match function or class names that do
475 | # not require a docstring.
476 | no-docstring-rgx=^_
477 |
478 | # List of decorators that produce properties, such as abc.abstractproperty. Add
479 | # to this list to register other decorators that produce valid properties.
480 | # These decorators are taken in consideration only for invalid-name.
481 | property-classes=abc.abstractproperty
482 |
483 | # Naming style matching correct variable names.
484 | variable-naming-style=snake_case
485 |
486 | # Regular expression matching correct variable names. Overrides variable-
487 | # naming-style.
488 | #variable-rgx=
489 |
490 |
491 | [STRING]
492 |
493 | # This flag controls whether inconsistent-quotes generates a warning when the
494 | # character used as a quote delimiter is used inconsistently within a module.
495 | check-quote-consistency=no
496 |
497 | # This flag controls whether the implicit-str-concat should generate a warning
498 | # on implicit string concatenation in sequences defined over several lines.
499 | check-str-concat-over-line-jumps=no
500 |
501 |
502 | [IMPORTS]
503 |
504 | # List of modules that can be imported at any level, not just the top level
505 | # one.
506 | allow-any-import-level=
507 |
508 | # Allow wildcard imports from modules that define __all__.
509 | allow-wildcard-with-all=no
510 |
511 | # Analyse import fallback blocks. This can be used to support both Python 2 and
512 | # 3 compatible code, which means that the block might have code that exists
513 | # only in one or another interpreter, leading to false positives when analysed.
514 | analyse-fallback-blocks=no
515 |
516 | # Deprecated modules which should not be used, separated by a comma.
517 | deprecated-modules=optparse,tkinter.tix
518 |
519 | # Create a graph of external dependencies in the given file (report RP0402 must
520 | # not be disabled).
521 | ext-import-graph=
522 |
523 | # Create a graph of every (i.e. internal and external) dependencies in the
524 | # given file (report RP0402 must not be disabled).
525 | import-graph=
526 |
527 | # Create a graph of internal dependencies in the given file (report RP0402 must
528 | # not be disabled).
529 | int-import-graph=
530 |
531 | # Force import order to recognize a module as part of the standard
532 | # compatibility libraries.
533 | known-standard-library=
534 |
535 | # Force import order to recognize a module as part of a third party library.
536 | known-third-party=enchant
537 |
538 | # Couples of modules and preferred modules, separated by a comma.
539 | preferred-modules=
540 |
541 |
542 | [CLASSES]
543 |
544 | # List of method names used to declare (i.e. assign) instance attributes.
545 | defining-attr-methods=__init__,
546 | __new__,
547 | setUp,
548 | __post_init__
549 |
550 | # List of member names, which should be excluded from the protected access
551 | # warning.
552 | exclude-protected=_asdict,
553 | _fields,
554 | _replace,
555 | _source,
556 | _make
557 |
558 | # List of valid names for the first argument in a class method.
559 | valid-classmethod-first-arg=cls
560 |
561 | # List of valid names for the first argument in a metaclass class method.
562 | valid-metaclass-classmethod-first-arg=cls
563 |
564 |
565 | [DESIGN]
566 |
567 | # Maximum number of arguments for function / method.
568 | max-args=5
569 |
570 | # Maximum number of attributes for a class (see R0902).
571 | max-attributes=7
572 |
573 | # Maximum number of boolean expressions in an if statement (see R0916).
574 | max-bool-expr=5
575 |
576 | # Maximum number of branch for function / method body.
577 | max-branches=12
578 |
579 | # Maximum number of locals for function / method body.
580 | max-locals=15
581 |
582 | # Maximum number of parents for a class (see R0901).
583 | max-parents=7
584 |
585 | # Maximum number of public methods for a class (see R0904).
586 | max-public-methods=20
587 |
588 | # Maximum number of return / yield for function / method body.
589 | max-returns=6
590 |
591 | # Maximum number of statements in function / method body.
592 | max-statements=50
593 |
594 | # Minimum number of public methods for a class (see R0903).
595 | min-public-methods=2
596 |
597 |
598 | [EXCEPTIONS]
599 |
600 | # Exceptions that will emit a warning when being caught. Defaults to
601 | # "BaseException, Exception".
602 | overgeneral-exceptions=BaseException,
603 | Exception
604 |
--------------------------------------------------------------------------------