Skip to content

Commit 36e79f2

Browse files
authored
Merge pull request #201 from CIRCL/python3
Python 3 migration + many new features + fixes
2 parents 21f3a7c + fbe3c99 commit 36e79f2

File tree

90 files changed

+1730
-1410
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+1730
-1410
lines changed

Diff for: .travis.yml

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: python
22

33
python:
4-
- "2.7"
4+
- "3.5"
55

66
sudo: required
77

@@ -16,20 +16,19 @@ env:
1616

1717
install:
1818
- ./installing_deps.sh
19+
- pip install coveralls codecov nose
1920

2021
script:
2122
- pushd bin
2223
- ./launch_redis.sh
2324
- ./launch_lvldb.sh
2425
- ./launch_logs.sh
2526
- ./launch_queues.sh
26-
- ./launch_scripts.sh
27-
- sleep 120
28-
- ./Shutdown.py
2927
- popd
30-
- find logs/* -exec cat {} \;
28+
- cd tests
29+
- nosetests --with-coverage --cover-package=../bin -d
3130

32-
notifications:
33-
email:
34-
on_success: change
35-
on_failure: change
31+
32+
after_success:
33+
- codecov
34+
- coveralls

Diff for: README.md

+9
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ Features
3131
* Terms, Set of terms and Regex tracking and occurrence
3232
* Many more modules for extracting phone numbers, credentials and others
3333
* Alerting to [MISP](https://github.com/MISP/MISP) to share found leaks within a threat intelligence platform using [MISP standard](https://www.misp-project.org/objects.html#_ail_leak)
34+
* Detect and decode Base64 and store files
35+
* Detect Amazon AWS and Google API keys
36+
* Detect Bitcoin address and Bitcoin private keys
37+
* Detect private keys and certificate
3438

3539
Installation
3640
------------
@@ -53,6 +57,11 @@ linux based distributions, you can replace it with [installing_deps_archlinux.sh
5357

5458
There is also a [Travis file](.travis.yml) used for automating the installation that can be used to build and install AIL on other systems.
5559

60+
Python 3 Upgrade
61+
------------
62+
63+
To upgrade from an existing AIL installation, you have to launch [python3_upgrade.sh](./python3_upgrade.sh), this script will delete and create a new virtual environment. The script **will upgrade the packages but won't keep your previous data** (neverthless the data is copied into a directory called `old`). If you install from scratch, you don't require to launch the [python3_upgrade.sh](./python3_upgrade.sh).
64+
5665
Docker Quick Start (Ubuntu 16.04 LTS)
5766
------------
5867

Diff for: bin/ApiKey.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env python3
2+
# -*-coding:UTF-8 -*
3+
4+
"""
5+
The ApiKey Module
6+
======================
7+
8+
This module is consuming the Redis-list created by the Categ module.
9+
10+
It apply API_key regexes on paste content and warn if above a threshold.
11+
12+
"""
13+
14+
import redis
15+
import pprint
16+
import time
17+
import re
18+
19+
from packages import Paste
20+
from packages import lib_refine
21+
from pubsublogger import publisher
22+
23+
from Helper import Process
24+
25+
26+
def search_api_key(message):
27+
filename, score = message.split()
28+
paste = Paste.Paste(filename)
29+
content = paste.get_p_content()
30+
31+
aws_access_key = regex_aws_access_key.findall(content)
32+
aws_secret_key = regex_aws_secret_key.findall(content)
33+
google_api_key = regex_google_api_key.findall(content)
34+
35+
if(len(aws_access_key) > 0 or len(aws_secret_key) > 0 or len(google_api_key) > 0):
36+
37+
to_print = 'ApiKey;{};{};{};'.format(
38+
paste.p_source, paste.p_date, paste.p_name)
39+
if(len(google_api_key) > 0):
40+
print('found google api key')
41+
print(to_print)
42+
publisher.warning('{}Checked {} found Google API Key;{}'.format(
43+
to_print, len(google_api_key), paste.p_path))
44+
45+
if(len(aws_access_key) > 0 or len(aws_secret_key) > 0):
46+
print('found AWS key')
47+
print(to_print)
48+
total = len(aws_access_key) + len(aws_secret_key)
49+
publisher.warning('{}Checked {} found AWS Key;{}'.format(
50+
to_print, total, paste.p_path))
51+
52+
53+
msg = 'apikey;{}'.format(filename)
54+
p.populate_set_out(msg, 'alertHandler')
55+
#Send to duplicate
56+
p.populate_set_out(filename, 'Duplicate')
57+
58+
if __name__ == "__main__":
59+
publisher.port = 6380
60+
publisher.channel = "Script"
61+
62+
config_section = 'ApiKey'
63+
64+
p = Process(config_section)
65+
66+
publisher.info("ApiKey started")
67+
68+
message = p.get_from_set()
69+
70+
# TODO improve REGEX
71+
regex_aws_access_key = re.compile(r'(?<![A-Z0-9])=[A-Z0-9]{20}(?![A-Z0-9])')
72+
regex_aws_secret_key = re.compile(r'(?<!=[A-Za-z0-9+])=[A-Za-z0-9+]{40}(?![A-Za-z0-9+])')
73+
74+
regex_google_api_key = re.compile(r'=AIza[0-9a-zA-Z-_]{35}')
75+
76+
while True:
77+
78+
message = p.get_from_set()
79+
80+
if message is not None:
81+
82+
search_api_key(message)
83+
84+
85+
else:
86+
publisher.debug("Script ApiKey is Idling 10s")
87+
time.sleep(10)

Diff for: bin/Attributes.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python
1+
#!/usr/bin/env python3
22
# -*-coding:UTF-8 -*
33

44
"""
@@ -33,7 +33,7 @@
3333
PST = Paste.Paste(message)
3434
else:
3535
publisher.debug("Script Attribute is idling 1s")
36-
print 'sleeping'
36+
print('sleeping')
3737
time.sleep(1)
3838
continue
3939

@@ -45,6 +45,6 @@
4545
# FIXME Not used.
4646
PST.store.sadd("Pastes_Objects", PST.p_path)
4747
except IOError:
48-
print "CRC Checksum Failed on :", PST.p_path
48+
print("CRC Checksum Failed on :", PST.p_path)
4949
publisher.error('Duplicate;{};{};{};CRC Checksum Failed'.format(
5050
PST.p_source, PST.p_date, PST.p_name))

Diff for: bin/Base64.py

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/env python3
2+
# -*-coding:UTF-8 -*
3+
"""
4+
Base64 module
5+
6+
Dectect Base64 and decode it
7+
"""
8+
import time
9+
import os
10+
import datetime
11+
12+
from pubsublogger import publisher
13+
14+
from Helper import Process
15+
from packages import Paste
16+
17+
import re
18+
import base64
19+
from hashlib import sha1
20+
import magic
21+
import json
22+
23+
import signal
24+
25+
class TimeoutException(Exception):
26+
pass
27+
28+
def timeout_handler(signum, frame):
29+
raise TimeoutException
30+
31+
signal.signal(signal.SIGALRM, timeout_handler)
32+
33+
34+
def search_base64(content, message):
35+
find = False
36+
base64_list = re.findall(regex_base64, content)
37+
if(len(base64_list) > 0):
38+
39+
for b64 in base64_list:
40+
if len(b64) >= 40 :
41+
decode = base64.b64decode(b64)
42+
43+
type = magic.from_buffer(decode, mime=True)
44+
#print(type)
45+
#print(decode)
46+
47+
find = True
48+
hash = sha1(decode).hexdigest()
49+
50+
data = {}
51+
data['name'] = hash
52+
data['date'] = datetime.datetime.now().strftime("%d/%m/%y")
53+
data['origin'] = message
54+
data['estimated type'] = type
55+
json_data = json.dumps(data)
56+
57+
save_base64_as_file(decode, type, hash, json_data)
58+
print('found {} '.format(type))
59+
60+
if(find):
61+
publisher.warning('base64 decoded')
62+
#Send to duplicate
63+
p.populate_set_out(message, 'Duplicate')
64+
#send to Browse_warning_paste
65+
msg = ('base64;{}'.format(message))
66+
p.populate_set_out( msg, 'alertHandler')
67+
68+
def save_base64_as_file(decode, type, hash, json_data):
69+
70+
filename_b64 = os.path.join(os.environ['AIL_HOME'],
71+
p.config.get("Directories", "base64"), type, hash[:2], hash)
72+
73+
filename_json = os.path.join(os.environ['AIL_HOME'],
74+
p.config.get("Directories", "base64"), type, hash[:2], hash + '.json')
75+
76+
dirname = os.path.dirname(filename_b64)
77+
if not os.path.exists(dirname):
78+
os.makedirs(dirname)
79+
80+
with open(filename_b64, 'wb') as f:
81+
f.write(decode)
82+
83+
with open(filename_json, 'w') as f:
84+
f.write(json_data)
85+
86+
87+
88+
89+
if __name__ == '__main__':
90+
# If you wish to use an other port of channel, do not forget to run a subscriber accordingly (see launch_logs.sh)
91+
# Port of the redis instance used by pubsublogger
92+
publisher.port = 6380
93+
# Script is the default channel used for the modules.
94+
publisher.channel = 'Script'
95+
96+
# Section name in bin/packages/modules.cfg
97+
config_section = 'Base64'
98+
99+
# Setup the I/O queues
100+
p = Process(config_section)
101+
max_execution_time = p.config.getint("Base64", "max_execution_time")
102+
103+
# Sent to the logging a description of the module
104+
publisher.info("Base64 started")
105+
106+
regex_base64 = '(?:[A-Za-z0-9+/]{4}){2,}(?:[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=|[A-Za-z0-9+/][AQgw]==)'
107+
re.compile(regex_base64)
108+
109+
# Endless loop getting messages from the input queue
110+
while True:
111+
# Get one message from the input queue
112+
message = p.get_from_set()
113+
if message is None:
114+
115+
publisher.debug("{} queue is empty, waiting".format(config_section))
116+
time.sleep(1)
117+
continue
118+
119+
filename = message
120+
paste = Paste.Paste(filename)
121+
122+
signal.alarm(max_execution_time)
123+
try:
124+
# Do something with the message from the queue
125+
#print(filename)
126+
content = paste.get_p_content()
127+
search_base64(content,message)
128+
129+
# (Optional) Send that thing to the next queue
130+
#p.populate_set_out(something_has_been_done)
131+
132+
except TimeoutException:
133+
print ("{0} processing timeout".format(paste.p_path))
134+
continue
135+
else:
136+
signal.alarm(0)

0 commit comments

Comments
 (0)