-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Added IMAP support for checking reported emails #1612
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Really nice and useful feature - haven't looked at the code yet, but I have been thinking about a feature such as this. |
So first off, that looks really neat, I really like the entire workflow there to be honest. I'm not sure if you need a realtime count for last checked in the email settings, but thats just me 😄. Other than that, this is pretty fantastic and works better than how I have my reporting set up. On another note, I've been butting my head against IMAP in Go for ages now and have never managed to get it to work properly. Any chance you'd be willing to field a few questions I have about parsing .msg attachments? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @glennzw!
Wow! You've done a stellar job with this PR! I really appreciate you taking the time to send this in. Very exciting stuff.
I like the approach and the way you've architected things. I think across the board you're spot on.
I've left some comments from an initial pass. It's possible there's more to review later, but I wanted to start giving feedback ASAP. Let me know your thoughts and we can work through this to get it in great shape and get it merged.
Thanks again so, so much for taking the time to send this over! Looking forward to adding this to Gophish!
controllers/api/imap.go
Outdated
log.Error(err) | ||
} | ||
if len(ss) > 0 { | ||
ss[0].LastLoginFriendly = humanize.Time(ss[0].LastLogin) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the comment in the IMAP
struct about the LastLoginFriendly
attribute.
controllers/imapmon.go
Outdated
|
||
log "github.com/gophish/gophish/logger" | ||
|
||
"github.com/glennzw/eazye" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I always get a bit nervous anytime we introduce a new dependency into Gophish and try to avoid it where possible.
In this case, I totally understand that this is your package so please know this is just a blanket policy that helps me sleep better at night 😛 It appears that the eazye
functionality we're using is fairly low-ish footprint. What are your thoughts around doing some restructuring like this:
- Create a new
github.com/gophish/gophish/imap
package to hold all of this code. This file specifically could be inmonitor.go
. We would then be able to change naming to beMonitor
instead ofImapMonitor
, etc. - We could create
imap.go
where we port over the needed functionality fromeazye
. To make things easier, we might be able to then adjust the parts that handle parsing the emails to use theemail.NewReader
function from myemail
library already used here.
Those are just some thoughts off the top of my head. I do feel that this functionality probably doesn't belong in controllers/
since that package is typically reserved for the web handlers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah totally agree, additional 3rd party packages make us all nervous!
So to be clear, github.com/glennzw/eazye is my fork of https://github.com/jprobinson/eazye with added functionality (so it's not really my package). I agree with your idea to create a github.com/gophish/gophish/imap
package to avoid nasties creeping in.
I'd like to move away from eazye
at some point (as it uses outdated/unmaintained packages) and use imap-go
but this was the quickest way to get up and running.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've created the gophish\imap
package and moved functionality there. (I just copied in the single eazye.go
file and added the ValidateIMAP()
from the controller).
Also renamed ImapMonitor
to just Monitor
.
Next up: remove unused functionality in the new imap.go
file and try use your email.NewReader
to parse emails.
Commit: glennzw@7ddba13
Just an update, here's how to create a new SQL migration. First, you need to install
Then, in the
Then you can add the relevant SQL statements to the new migration file. These will execute when Gophish is run, since we compare the version in the database with the latest migration file. This means that you'll want to create a backup of your database when developing migrations so that you can easily roll back to a previous state. |
Hi @jordan-wright, thanks so much for the quick response and positive feedback! I'll address each of your comments individually but they all seem to make sense. I'll work on getting everything in line to make a merge! I'm sure more issues will crop up as you look closer at the code too. I'll ping you if I get stuck with goose too, thanks! @S0larflare; I feel ya, IMAP is a pain. I can't give more advice than the example code on the go-imap repo for parsing attachments. I used eazye in the end as it's a super simple wrapper (but doesn't support attachments; I actually spent about a day trying to add that support!). |
Why is LastLoginFriendly “omitonempty” rather than “omitempty”?
Sent from my iPhone
On 11 Oct 2019, at 21:05, Glenn Wilkinson <notifications@github.com> wrote:
@glennzw commented on this pull request.
________________________________
In models/imap.go<#1612 (comment)>:
+
+// IMAP contains the attributes needed to handle logging into an IMAP server to check
+// for reported emails
+type IMAP struct {
+ UserId int64 `json:"-" gorm:"column:user_id"`
+ Enabled bool `json:"enabled"`
+ Host string `json:"host"`
+ Port uint16 `json:"port,string,omitempty"`
+ Username string `json:"username"`
+ Password string `json:"password"`
+ TLS bool `json:"tls"`
+ Folder string `json:"folder"`
+ RestrictDomain string `json:"restrict_domain"`
+ DeleteCampaign bool `json:"delete_campaign"`
+ LastLogin time.Time `json:"last_login,omitempty"`
+ LastLoginFriendly string `json:"last_login_friendly,omitonempty"`
I initially tried to handle this purely in the frontend, but couldn't get moment.js to play nicely. It was a while ago now and I can't remember the specific issue but will dig into it again.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#1612?email_source=notifications&email_token=ACEGR3ONTNN3UHNAEWE22VLQODMAHA5CNFSM4I6DPTFKYY3PNVWWK3TUL52HS4DFWFIHK3DMKJSXC5LFON2FEZLWNFSXPKTDN5WW2ZLOORPWSZGOCHXWFCY#discussion_r334155121>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ACEGR3KP4LCSWZTQSR77VOLQODMAHANCNFSM4I6DPTFA>.
|
I think the |
Yup, fixed! |
Each user now has their own IMAP monitor, and can set their own polling frequency
Thanks for your patience on getting these fixes in, I'm sure you're all very familiar with squeezing in open source projects in evenings and weekends 🙂 I've modified the IMAP polling logic (glennzw@8cd7c07) so that each user has their own IMAP monitoring Go routine, for which they can set their own polling frequency via the web UI advanced settings. The backend logic is:
Took a while to settle on this logic, but I think it makes the most sense. I've run a bunch of tests adding and removing users, adding/enabling/disabling IMAP settings. Open to hear your feedback. |
Hey @glennzw, This is looking good! It seems like there's still some outstanding review items (moving things to Keep up the great work! This is really quickly getting in great shape. |
Hi @jordan-wright, I've resolved all the reviews I was able to. Looking for comments on:
Thanks! |
Addressed the new issues, let me know if you find any more 🙂 |
Hey @glennzw! This is still looking great. We're definitely in the home stretch. I've added a few more comments for your review, but things are really coming along nicely. Thank you so much for all your great work on this! |
Addressed the new issues, some sloppy ones on my side there! |
Hey @glennzw! Sorry for the delay- things have been quite busy over here. I should have time to review this today or tomorrow. I think the only outstanding item is removing the minified JS from the commits. I'm honestly not sure what the easiest way is to do that. I think there's a way to reset (or just checkout again) the files from master and then re-commit. I'll do some digging on my end tomorrow if you haven't found an answer by then. I'm sure we can figure it out together 😄 Thanks so much for your patience! |
Hey @jordan-wright! No worries at all, that's the beauty of OSS projects, we give when we have time :) I did a checkout against the .min.js files from the original branch I forked in my repo, hopefully that works 😬
|
Hey @glennzw, I left a few comments on the diff- things like a bug in the MySQL migration and some small nits. And it looks like all of the minified JS is gone except for vendor.min.js, so if we could remove that as well that'd be great. With these things out of the way, I think we'll be in a position where we can merge this in 🎊 |
Co-Authored-By: Jordan Wright <jmwright798@gmail.com>
Hi @jordan-wright, Thanks for spotting those little mistakes, I really should have caught them! Hmm for the
(I ran the command But it looks like the latest modification to I ran |
Looks like that worked! The very last thing I noticed was that we'll probably want to update the filename of the SQL migrations. It's my understanding that our migrations library, goose, works based on the timestamp. Since we added webhook support and those migrations have the timestamp Once that's done, things are good to merge! Sorry for all the back and forth. I really appreciate all your patience here! |
Hi @jordan-wright , whoop almost there! I renamed the two database files 👍 No worries on the back and forth, it's been a great learning experience for me and I've enjoyed it! |
This works for me! There might be some small tweaks in the future, but that's stuff we can figure out later. I think this is a stellar first pass. Thank you so much for all the hard work and patience! |
Whooop, that's brilliant, I'm so happy to have contributed to the project! Thanks for all the guidance and code reviews! I hope it's a feature people find useful 😃 Also yes I'm sure there will be more tweaks and fixes once people start using it - I'll keep an eye on it! |
I downloaded 0.90 and tried this new feature. But I got this error "tls: first record does not look like a TLS handshake". |
This is quite a big pull request, with front end and back end changes. It was a tonne of work to be honest 🙂 This pull request allows you to set an IMAP server in Gophish that will be continuously monitored for Gophish campaigns that have been forwarded to it by users. If a campaign email is found, it's reported.
The logic is as follows:
Account Settings > Report Settings
(see screenshot below)rid=?
tag, and reports it if foundHere's a story illustrating the process:
Here's a video of it in action:
https://youtu.be/D3rAYvAthdI
There are some advanced configuration options;
There's decent error checking / testing too:
Some notes on implementation and configuration:
In
config.json
we can set the frequency of IMAP checking:The IMAP structure is defined in
models\imap.go
:The actual IMAP account monitoring is done by
controllers/imapmon.go
. A separate worker is launched for each IMAP account (ie each Gophish user could have a different IMAP server set). This ensures against one account/server denying resources to others. IMAP connectivity is done with eazye. It uses outdated libraries, but was really easy to get up and running. I should ideally switch to go-imap at some point, but it'll be a bit more work (IMAP is a tricksy hobbit). Also need to add backing off logic, and maybe proper worker code.Sticking with Gophish convention the management of IMAP settings is handled via an API, as you can see in
controllers/api/imap.go
. The endpoints are:The endpoints are accessible via JavaScript calls (implemented in
static/js/src/app/gophish.js
) . e.g: callingapi.IMAP.get()
:The IMAP monitor is launched in
gophish.go
along with the adminServer and phishServer:There's probably a bit of work to be done on how I handled this.
Finally the
settings.js
front end code probably needs some tidying in terms of code reuse and naming conventions.Overall I've done a lot of testing and it seems to work very well. Also, watch this space for my Chrome and Outlook email reporting plugins.