Skip to content

Commit 57b27f8

Browse files
committed
enh: collector_mail_attach Decrypt GPG attachments
1 parent 479114d commit 57b27f8

File tree

12 files changed

+167
-13
lines changed

12 files changed

+167
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Please refer to the [NEWS](NEWS.md) for a list of changes which have an affect o
2424

2525
### Bots
2626
#### Collectors
27+
- `intelmq.bots.collectors.mail.collector_mail_attach`: Decrypt GPG attachments (PR#2623 by Edvard Rejthar).
2728

2829
#### Parsers
2930
- `intelmq.bots.parsers.cymru.parser_cap_program`: Add mapping for TOR and ipv6-icmp protocol (PR#2621 by Mikk Margus Möll).

intelmq/bots/collectors/mail/REQUIREMENTS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
# SPDX-License-Identifier: AGPL-3.0-or-later
33

44
imbox>=0.8.5
5+
python-gnupg>=0.5

intelmq/bots/collectors/mail/collector_mail_attach.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
1111
Uses the common mail iteration method from the lib file.
1212
"""
13+
from functools import cached_property
1314
import re
1415
from intelmq.lib.utils import unzip
15-
from intelmq.lib.exceptions import InvalidArgument
16+
from intelmq.lib.exceptions import InvalidArgument, MissingDependencyError
1617

1718
from ._lib import MailCollectorBot
1819

19-
2020
class MailAttachCollectorBot(MailCollectorBot):
2121
"""Monitor IMAP mailboxes and retrieve mail attachments"""
2222
attach_regex: str = "csv.zip"
@@ -28,11 +28,19 @@ class MailAttachCollectorBot(MailCollectorBot):
2828
mail_user: str = "<user>"
2929
rate_limit: int = 60
3030
subject_regex: str = "<subject>"
31+
decrypt: bool = False
32+
""" Decrypt the attachment with GPG. """
33+
34+
gpg_passphrase: str = ""
35+
""" The private key passhrase. """
36+
37+
gpg_home: str = ""
38+
""" Change the GPG home directory. """
3139

3240
def init(self):
3341
super().init()
3442
if self.attach_regex is None:
35-
raise InvalidArgument('attach_regex', expected='string')
43+
raise InvalidArgument("attach_regex", expected="string")
3644

3745
def process_message(self, uid, message):
3846
seen = False
@@ -63,6 +71,13 @@ def process_message(self, uid, message):
6371
raw_reports = ((attach_filename, attach['content'].read()), )
6472

6573
for file_name, raw_report in raw_reports:
74+
if self.decrypt:
75+
gpg = self._gpg.decrypt(raw_report, passphrase=self.gpg_passphrase)
76+
if gpg.ok:
77+
raw_report = gpg.data
78+
else:
79+
self.logger.error('Could not decrypt attachment %s: %s', file_name, gpg.status)
80+
continue
6681
report = self.new_report()
6782
report.add("raw", raw_report)
6883
if file_name:
@@ -80,5 +95,15 @@ def process_message(self, uid, message):
8095
self.logger.info("Email report read.")
8196
return seen
8297

98+
@cached_property
99+
def _gpg(self):
100+
try:
101+
from gnupg import GPG
102+
except ImportError:
103+
raise MissingDependencyError('python-gnupg', ">=0.5")
104+
return GPG(gnupghome=self.gpg_home)
105+
106+
107+
83108

84109
BOT = MailAttachCollectorBot
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
MIME-Version: 1.0
2+
Content-Type: multipart/mixed; boundary="===============0256050913907025376=="
3+
Subject: foobar zip
4+
From: Sebastian Wagner <wagner@cert.at>
5+
To: cert@example.com
6+
Message-ID: <07ce0153-060b-f48d-73d9-d92a20b3b3aa@cert.at>
7+
Date: Tue, 3 Sep 2019 16:57:40 +0200
8+
Content-Language: en-US
9+
10+
--===============0256050913907025376==
11+
Content-Type: text/html; charset="utf-8"
12+
Content-Transfer-Encoding: 7bit
13+
14+
<html>
15+
<head>
16+
17+
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
18+
</head>
19+
<body text="#000000" bgcolor="#FFFFFF">
20+
Please look at the attachment<br>
21+
</body>
22+
</html>
23+
24+
--===============0256050913907025376==
25+
Content-Type: application/octet-stream
26+
Content-Transfer-Encoding: base64
27+
Content-Disposition: attachment; filename="foobar.txt.gpg"
28+
MIME-Version: 1.0
29+
30+
hQGMA9ig68HPFWOpAQv/fsRXK1mdmGw83CdbIOZeUlFVx2KKEONWVYIu/CHPxqxREYUWTva+XxYE
31+
LirKR9xK9lG19H6BSSZD3xXMahAShRzgs1dHH4UMxGqdpiXo5DbdVkTS7kg5+hG7QX20x+ExwsRd
32+
r76/gzY+Lmsv4hydxMHyG/w0OBsV/0mLWGAAVzer9Y8xkUP6jB16XzoSQGkfCP+7DpK224135JgU
33+
E6XSD2p+WKzALxXiET4IfinJnG8sSTHlkCQZgBp8lpDPdP2BbHo0KmvAofxaRqkvMfpVk7kUyy2W
34+
8tENKSEPu0sKEX8HZhT8Sw3X2pn8ggbAadHRjOzOO58MUvWJvwURqa1LIITA4pmyhw4svp1UzODb
35+
Q2Cd+MyWikjD4CebJ7P/JpnoDokux9qxWKnuuvmM4mqr6bvL+Sztud4V2Z60idokbzuEaJR6ZztT
36+
SBMatdh/OHcUnCaYCJiEOlrgk0hYcZ12XR5C8OBAI4St9F5eGjMB0l1tZz7CeQ6MrAoPY2pZ54XO
37+
0k0BA3PpG+K/khPOns8rW2mlYKgWfJqRdc91EasA4+iFoM+iFwyDQGBKbAdCu0BeIf9j7t5s5LOG
38+
iPWI5m2AIWf+aFNqKotGFAWXeSbMWw==
39+
40+
--===============0256050913907025376==--
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v:1:
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
This is a revocation certificate for the OpenPGP key:
2+
3+
pub rsa3072 2019-12-11 [S]
4+
3C8124A8245618D286CF871E94CE2905DB00CDB7
5+
uid Example identity 2 <envelope-example-identity-2@example.com>
6+
7+
A revocation certificate is a kind of "kill switch" to publicly
8+
declare that a key shall not anymore be used. It is not possible
9+
to retract such a revocation certificate once it has been published.
10+
11+
Use it to revoke this key in case of a compromise or loss of
12+
the secret key. However, if the secret key is still accessible,
13+
it is better to generate a new revocation certificate and give
14+
a reason for the revocation. For details see the description of
15+
of the gpg command "--generate-revocation" in the GnuPG manual.
16+
17+
To avoid an accidental use of this file, a colon has been inserted
18+
before the 5 dashes below. Remove this colon with a text editor
19+
before importing and publishing this revocation certificate.
20+
21+
:-----BEGIN PGP PUBLIC KEY BLOCK-----
22+
Comment: This is a revocation certificate
23+
24+
iQG2BCABCgAgFiEEPIEkqCRWGNKGz4celM4pBdsAzbcFAl3xFwwCHQAACgkQlM4p
25+
BdsAzbeofgv+JUQ4Qb40Z0p2ML+jciJjNiRdKYOUyhY1UKECwq6QlbW/MSkQMn4g
26+
esJfevFwGHKxaI4bw9ywFMtR/UB91YDY4D+lURm4qMuc8pFYEBSMhro0x8ToWz1E
27+
vupwAqTF484ybBrujg2UaOox9BbyhIbsiAH3ttB6wThCbXdhkxp/w6qUaWo+n5Ra
28+
5xWrtFkHJx+WIE4mzxqvnuN3RtA9tkr3L8oavw8Vy0j44lhkVE4Mrl/XDGOnryvv
29+
3WYuiHjOdTP5plb/p4veTvCfUZOcrmhTiwU8gQWMQfy3Nr1NmIhNwoXRTwB41ogt
30+
j3/mijdKVlRkzzmungIt0G3NJM8sAI9TiZ6KyaH4g3fVHU0ddfUwd5sCV3Q+UHfJ
31+
iUZeO1qHA8PA0NZwquRE2rnGdc63nHE/7AD9SjpvqIoBcvfoZCniCBm70pSmJvSP
32+
Csd2/TvaI8PQ28vAVY2LKqCX6JX1MvkiJOZbDGl+VBhCavQCQ8lR0d2b+wriDa3y
33+
2rhCXk0+ozc+
34+
=92kE
35+
-----END PGP PUBLIC KEY BLOCK-----
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
This is a revocation certificate for the OpenPGP key:
2+
3+
pub rsa3072 2019-12-11 [S]
4+
F14F2E8097E0CCDE93C4E871F4A4F26779FA03BB
5+
uid Example identity <envelope-example-identity@example.com>
6+
7+
A revocation certificate is a kind of "kill switch" to publicly
8+
declare that a key shall not anymore be used. It is not possible
9+
to retract such a revocation certificate once it has been published.
10+
11+
Use it to revoke this key in case of a compromise or loss of
12+
the secret key. However, if the secret key is still accessible,
13+
it is better to generate a new revocation certificate and give
14+
a reason for the revocation. For details see the description of
15+
of the gpg command "--generate-revocation" in the GnuPG manual.
16+
17+
To avoid an accidental use of this file, a colon has been inserted
18+
before the 5 dashes below. Remove this colon with a text editor
19+
before importing and publishing this revocation certificate.
20+
21+
:-----BEGIN PGP PUBLIC KEY BLOCK-----
22+
Comment: This is a revocation certificate
23+
24+
iQG2BCABCgAgFiEE8U8ugJfgzN6TxOhx9KTyZ3n6A7sFAl3xFtwCHQAACgkQ9KTy
25+
Z3n6A7vCwwv/U1mKrClA3lxfI+lTAecMeYwlYtYcAveDjJkMs3AtAUQyqd6B7I5F
26+
RXQL50xjiB+S+yv3WoXd4eQbT9Z2g1OnMJfSHzENM0K+yosUJS+TpN3SU7YxJ9GR
27+
4J3eDxo0IyB0mL1QFQXcsWSu92yAyQpwJnscg6S0hvxiq8ij+OyDPNctDtpxcArr
28+
orh9+rGfLBNABemtKgVgzmedjyB7fdPYjgCi/xJL8eYUxlRUgwuwCS7A3DBaSdwU
29+
bd4dGvGTvzSmKp8OrbW1j7yf4Vq91qVcSqAdv1y0EpKwnnefAPJV8TsFr4wg0GpI
30+
ocKDGMiQMPekxfeDPrZcII4jjYXlk6WRzXPTQySZcHBN6o/TKBjdanZv5iV4JktU
31+
jIvru6M7JAM0PJPFj+AwY6hLV3p741qCYYEUlFs9Yjq7j4vhoHqgdVbmZSVcditn
32+
KLcM6F7jEx0odcbL157/xLHHqsCPVoZrr9uZVuN8J6uIYw0GTXFRlpMhDEpVg+Jd
33+
mB4WSiNPkql0
34+
=rwt1
35+
-----END PGP PUBLIC KEY BLOCK-----
3.85 KB
Binary file not shown.
600 Bytes
Binary file not shown.
1.33 KB
Binary file not shown.

0 commit comments

Comments
 (0)