
Footprinting OSINT incentrato sull'organizzazione e basato su opinioni, ispirato da recon-ng e Maltego.
Nota
Questo progetto è solo parzialmente completo e devo ancora implementare molte delle funzionalità descritte nel seguente post del blog che ho scritto: https://penafieljlm.com/2017/07/14/inquisitor/.
Inquisitor è un semplice strumento per raccogliere informazioni su aziende e organizzazioni attraverso l'uso di fonti di intelligence open source (OSINT). È fortemente ispirato dal funzionamento di Maltego e recon-ng, e lo strumento reimplementa in gran parte alcune delle funzionalità di quei strumenti, ma aggiunge un ulteriore strato di semantica basata su opinioni sopra i tipi di asset per creare un flusso di lavoro facile da usare.
Le caratteristiche principali di Inquisitor includono:
L'intero concetto di Inquisitor ruota attorno all'idea di estrarre informazioni da fonti aperte basandosi su ciò che è già noto su un'organizzazione target. Nel contesto di Inquisitor, queste sono chiamate "trasformazioni". Informazioni correlate possono anche essere recuperate immediatamente da un asset noto basandosi su metadati anch'essi recuperabili da fonti aperte come whois e registri internet.
I concetti sono discussi in maggior dettaglio in questo articolo del blog: https://penafieljlm.com/2017/07/14/inquisitor/
Per installare Inquisitor, basta clonare il repository, entrarvi, ed eseguire lo script di installazione.``` pip install Cython click git clone [email protected]:penafieljlm/inquisitor.git cd inquisitor python setup.py install
## Usage
Inquisitor ha cinque comandi di base che includono `scan`, `status`, `classify`, `dump` e `visualize`.```
usage: inq [-h] {scan,status,classify,dump,visualize} ...
optional arguments:
-h, --help show this help message and exit
command:
{scan,status,classify,dump,visualize}
The action to perform.
scan Search OSINT sources for intelligence based on known
assets belonging to the target.
status Prints out the current status of the specified
intelligence database.
classify Classifies an existing asset as either belonging or
not belonging to the target. Adds a new asset with the
specified classification if none is present.
dump Dumps the contents of the database into a JSON file
visualize Create a D3.js visualization based on the contents of
the specified intelligence database.
In modalità scan, lo strumento esegue tutte le trasformazioni disponibili per tutti gli asset presenti nel tuo Intelligence Database. Assicurati di creare API Keys per le varie fonti OSINT indicate di seguito e di fornirle allo script, altrimenti le trasformazioni che utilizzano tali fonti verranno saltate. Inoltre, assicurati di popolare il tuo Intelligence Database con alcuni asset target posseduti noti utilizzando prima il comando classify, perché se il database non contiene alcun asset posseduto, non ci sarà nulla da trasformare.```
usage: inq scan [-h] [--google-dev-key GOOGLE_DEV_KEY]
[--google-cse-id GOOGLE_CSE_ID]
[--google-limit GOOGLE_LIMIT]
[--shodan-api-key SHODAN_API_KEY]
[--shodan-limit SHODAN_LIMIT]
DATABASE
positional arguments: DATABASE The path to the intelligence database to use. If specified file does not exist, a new one will be created.
optional arguments: -h, --help show this help message and exit --google-dev-key GOOGLE_DEV_KEY Specifies the developer key to use to query Google Custom Search. Visit the Google APIs Console (http://code.google.com/apis/console) to get an API key. If notspecified, the script will simply skip asset transforms that involve Google Search. --google-cse-id GOOGLE_CSE_ID Specifies the custom search engine to query. Visit the Google Custom Search Console (https://cse.google.com/cse/all) to create your own Google Custom Search Engine. If not specified, the script will simply skip asset transforms that involve Google Search. --google-limit GOOGLE_LIMIT The number of pages to limit Google Search to. This is to avoid exhausting your daily quota. --shodan-api-key SHODAN_API_KEY Specifies the API key to use to query Shodan. Log into your Shodan account (https://www.shodan.io/) and look at the top right corner of the page in order to view your API key. If not specified, the script will simply skip asset transforms that involve Shodan. --shodan-limit SHODAN_LIMIT The number of pages to limit Shodan Search to. This is to avoid exhausting your daily quota.
### Status
In modalità stato, lo strumento stampa semplicemente un rapido riepilogo dello stato del tuo database di scansione.```
usage: inq status [-h] [-s] DATABASE
positional arguments:
DATABASE The path to the intelligence database to use. If specified
file does not exist, a new one will be created.
optional arguments:
-h, --help show this help message and exit
-s, --strong Indicates if the status will be based on the strong ownership
classification.
In modalità classifica, potrai aggiungere manualmente asset e riclassificare asset già esistenti nel Database di Intelligence. Dovresti usare questo comando per popolare il tuo Database di Intelligence con asset target noti posseduti.``` usage: inq classify [-h] [-ar REGISTRANT [REGISTRANT ...]] [-ur REGISTRANT [REGISTRANT ...]] [-rr REGISTRANT [REGISTRANT ...]] [-ab BLOCK [BLOCK ...]] [-ub BLOCK [BLOCK ...]] [-rb BLOCK [BLOCK ...]] [-ah HOST [HOST ...]] [-uh HOST [HOST ...]] [-rh HOST [HOST ...]] [-ae EMAIL [EMAIL ...]] [-ue EMAIL [EMAIL ...]] [-re EMAIL [EMAIL ...]] [-al LINKEDIN [LINKEDIN ...]] [-ul LINKEDIN [LINKEDIN ...]] [-rl LINKEDIN [LINKEDIN ...]] DATABASE
positional arguments: DATABASE The path to the intelligence database to use. If specified file does not exist, a new one will be created.
optional arguments: -h, --help show this help message and exit -ar REGISTRANT [REGISTRANT ...], --accept-registrant REGISTRANT [REGISTRANT ...] Specifies a registrant to classify as accepted. -ur REGISTRANT [REGISTRANT ...], --unmark-registrant REGISTRANT [REGISTRANT ...] Specifies a registrant to classify as unmarked. -rr REGISTRANT [REGISTRANT ...], --reject-registrant REGISTRANT [REGISTRANT ...] Specifies a registrant to classify as rejected. -ab BLOCK [BLOCK ...], --accept-block BLOCK [BLOCK ...] Specifies a block to classify as accepted. -ub BLOCK [BLOCK ...], --unmark-block BLOCK [BLOCK ...] Specifies a block to classify as unmarked. -rb BLOCK [BLOCK ...], --reject-block BLOCK [BLOCK ...] Specifies a block to classify as rejected. -ah HOST [HOST ...], --accept-host HOST [HOST ...] Specifies a host to classify as accepted. -uh HOST [HOST ...], --unmark-host HOST [HOST ...] Specifies a host to classify as unmarked. -rh HOST [HOST ...], --reject-host HOST [HOST ...] Specifies a host to classify as rejected. -ae EMAIL [EMAIL ...], --accept-email EMAIL [EMAIL ...] Specifies a email to classify as accepted. -ue EMAIL [EMAIL ...], --unmark-email EMAIL [EMAIL ...] Specifies a email to classify as unmarked. -re EMAIL [EMAIL ...], --reject-email EMAIL [EMAIL ...] Specifies a email to classify as rejected. -al LINKEDIN [LINKEDIN ...], --accept-linkedin LINKEDIN [LINKEDIN ...] Specifies a LinkedIn Account to classify as accepted. -ul LINKEDIN [LINKEDIN ...], --unmark-linkedin LINKEDIN [LINKEDIN ...] Specifies a LinkedIn Account to classify as unmarked. -rl LINKEDIN [LINKEDIN ...], --reject-linkedin LINKEDIN [LINKEDIN ...] Specifies a LinkedIn Account to classify as rejected.
### Dump
In modalità dump, potrai scaricare il contenuto del database di intelligence in un file JSON leggibile dall'uomo.```
usage: inq dump [-h] [-j FILE] [-a] DATABASE
positional arguments:
DATABASE The path to the intelligence database to use. If
specified file does not exist, a new one will be
created.
optional arguments:
-h, --help show this help message and exit
-j FILE, --json FILE The path to dump the JSON file to. Overwrites existing
files.
-a, --all Include rejected assets in dump.
In modalità Visualizza, sarai in grado di ottenere una visualizzazione gerarchica dell'Intelligence Repository.``` usage: inq visualize [-h] [-l] DATABASE
positional arguments: DATABASE The path to the intelligence database to use. If specified file does not exist, a new one will be created.
optional arguments: -h, --help show this help message and exit -l, --last Simply open the last visualization generated instead of creating a new one.
## Workflow
Ora che conosci le funzionalità di base di Inquisitor, è il momento di imparare come *usarlo* realmente. Inquisitor è stato sviluppato pensando ai seguenti passaggi:
### Seminazione
In questo passaggio, il tuo Database di Intelligence non contiene ancora nulla. Dobbiamo iniziare da qualche parte, quindi semina il database con asset che sai appartenere alla tua organizzazione target. Puoi farlo usando il comando `classify`.
### Scansione
Ora il database contiene asset noti per appartenere alla tua organizzazione target. Puoi quindi procedere con la scansione. Puoi farlo usando il comando `scan`.
Quando invochi il comando `scan` sul tuo Database di Intelligence, Inquisitor esegue i metodi `transform` degli asset classificati come `accepted`. Una volta terminata la scansione, otterrai ulteriori asset che potrebbero potenzialmente appartenere alla tua organizzazione target.
Se non ottieni nuovi asset, puoi seminare il tuo Database di Intelligence con nuove informazioni, oppure semplicemente procedere a concludere il processo passando alla fase di Report.
### Classificazione
Sebbene Inquisitor esegua automaticamente la classificazione degli asset per te, potrebbe non riuscire a identificare alcuni asset che effettivamente appartengono alla tua organizzazione target.
Quando ciò accade, dovrai controllare il contenuto del database e classificare manualmente gli asset. Di solito, è consigliabile prestare attenzione agli asset **Registrant**, poiché non esiste un modo per determinare automaticamente la proprietà per quel tipo di asset. Inoltre, la maggior parte degli altri tipi di asset si basa sulla classificazione di proprietà degli asset Registrant per determinare se appartengono o meno al tuo target, quindi è sicuramente meglio prestare attenzione ai tuoi asset Registrant. Inoltre, non ottieni molti asset Registrant in primo luogo, quindi non sarà così difficile esaminarli.
### Report
Puoi generare una visualizzazione degli asset che appartengono alla tua organizzazione target usando il comando `visualize` o il comando `dump`.
## Demo
Ho delle dimostrazioni video dello strumento in esecuzione al seguente link: https://drive.google.com/open?id=0B_O70BVu38TRclo5dWRBWkdTTWc
Non sono riuscito a registrare completamente l'esecuzione del comando `scan` perché il mio registratore gratuito registra solo fino a 10 minuti.
## Sviluppo
Il progetto Inquisitor è strutturato nel seguente formato:```
.
|-- README.md
|-- inquisitor
| |-- __init__.py
| |-- assets
| | |-- __init__.py
| | |-- block.py
| | |-- email.py
| | |-- host.py
| | |-- linkedin.py
| | `-- registrant.py
| |-- extractors
| | |-- __init__.py
| | `-- emails.py
| `-- sources
| |-- __init__.py
| |-- google_search.py
| `-- shodan_search.py
|-- inq
|-- report
| `-- index.html
|-- setup.py
`-- tests
|-- __init__.py
`-- test_inq.py
Ha tre moduli principali chiamati assets, extractors e sources. Lo script principale si chiama inq.
Come sviluppatore, sarai principalmente interessato ad aggiungere nuovi tipi di asset nel sistema, quindi la guida per sviluppatori si concentrerà principalmente su questo.
Prima di passare all'implementazione effettiva delle classi di asset, dobbiamo prima capire come interagire con il Database di Intelligence, poiché interagiremo con esso quando deriveremo asset correlati dalle nostre classi di asset.
Il codice sorgente per il Database di Intelligence è memorizzato nel file inquisitor/__init__.py. Il nome effettivo del wrapper logico del Database di Intelligence è IntelligenceRepository.
Devi solo chiamare la funzione IntelligenceRepository.get_asset_string dalle classi di asset, poiché l'aggiunta di nuovi asset al Database di Intelligence è responsabilità del modulo scan nello script inq. Utilizzerai principalmente questa funzione per creare istanze di asset o recuperarle dal database se esistono. Questa funzione è importante quando si restituiscono asset dalle funzioni related e transform delle tue classi di asset, poiché creare nuovi oggetti asset è costoso dato che alcuni di essi utilizzano risorse di rete durante l'inizializzazione.```
Function
IntelligenceRepository.get_asset_string(asset_type, identifier, create=False, store=False)
Description
Retrieves the primary key and asset object for the asset with the provided
type and identifier.
Parameters
asset_type: class, required
The type of the asset to retrieve from the Intelligence Database. You
will actually have to pass the class object of the asset type you want
to retrieve.
identifier: any, required
The identifier of the asset to retrieve. Consider the identifier as the
unique attribute of an asset object. As for which attribute is to be
used to identify an asset, it depends on the contents of the OBJECT_ID
variable in the asset module.
create: bool, optional, default=False
When no matching asset object is found, a new one will be created and
returned if this parameter is set to True. The new asset will not
necessarily be stored in the Intelligence Database unless specified
using the "store" parameter. However, I suggest you do not do this as
adding assets to the Intelligence Database is the responsibility of
another module.
store: bool, optional, default=False
When a new asset is created when none is found, the new one will be
stored in the Intelligence Database. As said previously, I suggest that
you do not do this as adding assets to the Intelligence Database is the
responsibility of another module.
Returns
A two-element tuple where the first element is the database primary key of
the element returned, and the second element is the deserialized asset
object retrieved from the database.
None if the asset was not found.
If the asset was not found and the create flag was set to True, the primary
key member of the tuple will be set to None.
### Risorse
Per creare un nuovo tipo di risorsa, crea un nuovo file all'interno della directory `inquisitor/assets` e incolla il seguente codice scheletro al suo interno:```python
import inquisitor.assets
class ASSET_NAMEValidateException(Exception):
pass
def canonicalize(ASSET_IDENTIFIER):
return ASSET_IDENTIFIER
def main_classify_args(parser):
parser.add_argument(
'-aASSET_NAME_LETTER', '--accept-ASSET_NAME',
metavar='ASSET_NAME',
type=canonicalize,
nargs='+',
help='Specifies a ASSET_NAME to classify as accepted.',
dest='ASSET_NAMEs_accepted',
default=list(),
)
parser.add_argument(
'-uASSET_NAME_LETTER', '--unmark-ASSET_NAME',
metavar='ASSET_NAME',
type=canonicalize,
nargs='+',
help='Specifies a ASSET_NAME to classify as unmarked.',
dest='ASSET_NAMEs_unmarked',
default=list(),
)
parser.add_argument(
'-rASSET_NAME_LETTER', '--reject-ASSET_NAME',
metavar='ASSET_NAME',
type=canonicalize,
nargs='+',
help='Specifies a ASSET_NAME to classify as rejected.',
dest='ASSET_NAME_rejected',
default=list(),
)
def main_classify_canonicalize(args):
accepted = set(args.ASSET_NAMEs_accepted)
unmarked = set(args.ASSET_NAMEs_unmarked)
rejected = set(args.ASSET_NAME_rejected)
redundant = set.intersection(accepted, unmarked, rejected)
if redundant:
raise ValueError(
('Conflicting classifications for ASSET_NAMEs '
': {}').format(list(redundant))
)
accepted = set([canonicalize(a) for a in accepted])
unmarked = set([canonicalize(a) for a in unmarked])
rejected = set([canonicalize(a) for a in rejected])
return (accepted, unmarked, rejected)
class ASSET_NAME(inquisitor.assets.Asset):
def __init__(self, ASSET_IDENTIFIER, owned=None):
super(self.__class__, self).__init__(owned=owned)
self.ASSET_IDENTIFIER = canonicalize(ASSET_IDENTIFIER)
# TODO: Perform other initialization actions here
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
return self.ASSET_IDENTIFIER == other.ASSET_IDENTIFIER
def related(self, repo):
# Prepare the results
results = set()
# TODO: Create related assets here based on the attributes of this asset
# Return the results
return results
def transform(self, repo, sources):
# Prepare the results
assets = set()
# Google Transforms
if sources.get('google'):
subassets = self.cache_transform_get('google', repo)
if not subassets:
# Acquire API
google = sources['google']
# TODO: Perform Google queries here and the results to 'subassets'
# Cache The Transform
self.cache_transform_store('google', subassets)
assets.update(subassets)
# Shodan Transforms
if sources.get('shodan'):
subassets = self.cache_transform_get('shodan', repo)
if not subassets:
# Acquire API
shodan = sources['shodan']
# TODO: Perform Google queries here and the results to 'subassets'
# Cache The Transform
self.cache_transform_store('shodan', subassets)
assets.update(subassets)
# Return the results
return assets
def is_owned(self, repo):
if self.owned:
return True
# TODO: Automatically determine ownership based on repo contents
return False
def parent_asset(self, repo):
# TODO: Return parent asset based on repo contents
return None
REPOSITORY = 'ASSET_REPOSITORY'
ASSET_CLASS = ASSET_NAME
OBJECT_ID = 'ASSET_IDENTIFIER'
Ora sostituisci le seguenti stringhe con i valori appropriati
ASSET_NAME : Nome proprio del tuo asset (es. Registrant, Host, ecc.)ASSET_IDENTIFIER : Il nome dell'attributo identificatore del tuo assetASSET_NAME_LETTER : La prima lettera del tuo asset in minuscoloASSET_REPOSITORY : Minuscolo della forma plurale del nome del tuo assetInfine, in inquisitor/__init__.py, registra il tuo asset nella lista ASSET_MODULES. Assicurati di importare il tuo nuovo asset dal file in questione.
Congratulazioni! A questo punto, hai un nuovo tipo di asset funzionante!
Tuttavia, dovrai implementare i seguenti metodi per assicurarti che i tuoi asset vengano correlati con altri tipi di asset:``` Function
related
Description
Returns the set of assets directly related to the asset in question (i.e.
those that can be derived without querying a search engine).
When creating asset objects, make sure you use the
IntelligenceRepository.get_asset_string method instead of instatiating a
new one your self so the asset can be returned from the repository if it
exists.
Set the create flag to True when calling the method in question in order
to return a new object when one isn't found.
Set the store flag to False as appending assets is the job of another
module.
Parameters
repo: IntelligenceRepository
The Intelligence Repository that is being used in the current context.
Returns
Set of assets directly related to the asset in question.
## Opzioni di configurazione
| Opzione | Descrizione | Valore predefinito |
| --- | --- | --- |
| `--config` | Percorso del file di configurazione | `config.yml` |
| `--debug` | Abilita l'output di debug | `false` |
| `--log-file` | Percorso del file di log | `app.log` |
| `--no-color` | Disabilita l'output a colori | `false` |
Queste opzioni possono essere passate tramite la riga di comando oppure impostate nel file di configurazione YAML. Se viene specificata la stessa opzione in entrambi i posti, ha la precedenza il valore della riga di comando.```
Function
transform
Description
Returns the set of assets potentially related to the asset in question
(i.e. those that can be derived by querying a search engine).
You may access search engine objects through the provided sources
parameter.
Each search engine object has a transform method which automatically
creates asset objects for you. You just need to provide it the repository
and your query string, and then append the objects it returns to the set
of assets to be returned by your asset's transform method.
Parameters
repo: IntelligenceRepository
The Intelligence Repository that is being used in the current context.
sources: dict
The list of search engine objects that are available for use.
Returns
Set of assets potentially related to the asset in question.
Funziona sia con l'URL di base che con quello corrente
Analizza il contenuto di un blog alla ricerca di blocchi
Genera automaticamente un sommario a partire dalle intestazioni
Fornisce una stima del tempo di lettura
Filtra i post in bozza utilizzando il front-matter JS
Paginazione
Ricerca incorporata``` Function
is_owned
Description
Determines if there is high confidence that this asset does indeed belong
to the target. Usually checks for any "strong" classification tag first by
looking at the contents of the "owned" variable, before performing
automatic evaluation.
Automatic evaluation depends on what type of asset you're writing. For
example, for a Host asset, the secondary sources of determining ownership
would include looking if its registrant is owned by the target, if it's
parent domain is owned by the target. etc.
Parameters
repo: IntelligenceRepository
The Intelligence Repository that is being used in the current context.
Returns
True it is determined with high confidence that this asset does indeed
belong to the target.
### Per maggiori informazioni su RAG, vedi [questa pagina](https://github.com/natescudella/riskagent/tree/main/rag/CLOVA_README.md)
## Licenza
Questo progetto è concesso in licenza MIT - vedi il file [LICENSE](https://github.com/penafieljlm/inquisitor/blob/HEAD/LICENSE) per i dettagli.
## Contatti
Per domande, suggerimenti o collaborazione, contatta [email protected].
---
*Disclaimer: Lo strumento è destinato esclusivamente a test di sicurezza autorizzati. Gli utenti sono responsabili del rispetto di tutte le leggi applicabili. L'autore non si assume alcuna responsabilità per uso improprio o danni.*```
Function
parent_asset
Description
Returns the asset object that is considered the parent of this asset
object.
Parameters
repo: IntelligenceRepository
Returns
The asset object that this asset falls under (e.g. a Block is under a
Registrant, a Host is under a Block, a Host is under another Host, an Email
is under a Host, etc. This is primarily used for visualization.
Dopo aver implementato i metodi sopra descritti, assicurati di impostare le variabili REPOSITORY, ASSET_CLASS e OBJECT_ID nella parte inferiore del codice sorgente del tuo asset.
La modalità di scansione non è stata completamente testata a causa delle quote relative ai motori di ricerca coinvolti. Inoltre, questo progetto è stato realizzato di fretta come parte di una sfida hackathon della durata di una settimana, quindi potrebbero esserci molti problemi in giro. Per favore, apri un ticket di segnalazione o contattami all'indirizzo [email protected] se trovi un bug o hai domande.
Questo lavoro deriva dagli approcci implementati dagli strumenti di Open Source Intelligence Maltego e recon-ng. Ho integrato questi approcci con idee che sono già di conoscenza comune (ad esempio, whois ti dice chi è il proprietario di un dominio, i sottodomini sono di proprietà della stessa organizzazione che possiede il loro dominio padre - come implicito negli attacchi di brute forcing dei nomi di dominio, le organizzazioni sono autoritarie per i nomi di dominio che possiedono, ecc.), oppure sono originali e sono state concepite da me nel mio tempo personale come parte del mio hobby (ad esempio, valutazioni di accettabilità, varie trasformazioni, ereditarietà della classificazione, ecc.).
Nessuna componente di questo lavoro è stata derivata da alcun lavoro che ho svolto per qualsiasi datore di lavoro in passato. L'intero progetto, inclusa la prova di concetto, è stato scritto da zero ed è stato arricchito con idee della comunità della sicurezza informatica.