├── LICENSE ├── OP.jpg ├── README.md ├── TODO ├── mailpl0it.py └── terminal.jpg /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vaibhav Choudhari 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /OP.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bad-bit/mailpl0it/8c4a7feece7574a7503f0c055fe55ec89a1e80af/OP.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mailpl0it 2 | 3 | Mailpl0it is a small utility that hunts the homepage of [exploit-db](https://www.exploit-db.com/) looking for user supplied quer(y/ies) and notifies the user via email if an exploit is found for the supplied query. 4 | 5 | Please note that the utility has only been made for Gmail inboxes. The utility uses Python's libraries to send emails, so in order to receive emails on the mailbox - the user will have to toggle [this](https://myaccount.google.com/lesssecureapps) switch. 6 | 7 | Please refer the "Points to note" section below for more details. 8 | 9 | _________________________ 10 | 11 | Mailpl0it was made: 12 | - To get notified only for user-specified, specific class of exploits on the mailbox. 13 | - Out of pure curiosity while playing around with the requests library (Already aware of exploit-db's [RSS](https://www.exploit-db.com/rss.xml) feed, still, import requests, because why not!). 14 | 15 | 16 | ## Installation 17 | 18 | Built on native libraries with zero dependencies. 19 | Clone and launch! 20 | 21 | ```bash 22 | git clone https://github.com/bad-bit/mailpl0it.git 23 | ``` 24 | ## Usage 25 | 26 | ``` 27 | python mailpl0it.py -l "Remote Code Execution, Citrix, Privilege Escalation" -m mailid@gmail.com -p passw0rd 28 | ``` 29 | ![alt text](https://github.com/bad-bit/mailpl0it/blob/master/terminal.jpg?raw=true) 30 | 31 | > OUTPUT in the mailbox. 32 | 33 | ![alt text](https://github.com/bad-bit/mailpl0it/blob/master/OP.jpg?raw=true) 34 | ___ 35 | ``` 36 | 37 | > Help message: 38 | 39 | mailpl0it.py [-h] -l WORDLIST [-s SLEEPTIME] -m EMAIL [-p PASSWORD] 40 | 41 | optional arguments: 42 | -h, --help show this help message and exit 43 | -l WORDLIST, --list WORDLIST 44 | Comma seperated words to hunt on exploit-db. Example: 45 | mailpl0it.py -l "LPE, RCE" 46 | -s SLEEPTIME, --sleep SLEEPTIME 47 | Time to sleep in seconds before checking exploit-db 48 | for new results. Default is 3600s / 1 hour. 49 | -m EMAIL, --email EMAIL 50 | Your email-id to receive notification emails. 51 | -p PASSWORD, --password PASSWORD 52 | Your email-id's password. 53 | ``` 54 | It is recommended to launch the utility from a tmux or a Byobu session on a VPS for a seamless experience and infinite hunting! :D 55 | 56 | # Points to note 57 | - Since the utility relies on the native "email.message" library, it is inevitable to avoid using password for authentication to the mailing server. 58 | The user will have to either pass the recipient email's password as an argument (-p) or for the more paranoid ones - hardcode the credentials of the recipient email by editing a single line (line 130) inside the script. It is recommended to create a throwaway account for this utility which you can dedicate only for this purpose without having to worry about harcoding your credentials in clear text! :D 59 | 60 | - The utility has been tested only on Gmail. By default, Gmail doesn't allow Python to send emails to your mailbox. The user can however manually enable it by visiting [https://myaccount.google.com/lesssecureapps](https://myaccount.google.com/lesssecureapps). This setting can't be enabled for accounts having 2FA. Again, it is recommended to create a throwaway account for this utility which you can dedicate only for this purpose without having to worry about harcoding your credentials in clear text! :D 61 | 62 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 1. Add a checker routine if user query not found and password not set as in that case the user will only be notified when a query is found and he checks the terminal 2 | -------------------------------------------------------------------------------- /mailpl0it.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Developed in Python3. Tested on Win10, Arch 3 | Author - Vaibhav Choudhari 4 | Twitter - _badbit_ 5 | ''' 6 | 7 | import requests 8 | import argparse 9 | import smtplib 10 | import time 11 | import datetime 12 | from email.message import EmailMessage 13 | 14 | now = datetime.datetime.now() 15 | curr_time = now.strftime("%d-%m-%Y %H:%M:%S") 16 | 17 | vulnApp = [] 18 | sQuery = [] 19 | comp = [] 20 | 21 | 22 | def main(): 23 | 24 | global sleeptime 25 | global words 26 | global email 27 | global password 28 | 29 | words = [] 30 | 31 | parser = argparse.ArgumentParser() 32 | parser.add_argument("-l", "--list", help="Comma seperated words to hunt on exploit-db. Example: mailpl0it.py -l \"LPR, RCE\" ", dest='wordlist', type=str) 33 | parser.add_argument("-s", "--sleep", type = int, help="Time to sleep in seconds before checking exploit-db for new results. Default is 3600s / 1 hour.", default=3600, dest='sleeptime') 34 | parser.add_argument("-m", "--email", help="Your email-id to receive notification emails.", dest='email', type=str) 35 | parser.add_argument("-p", "--password", help="Your email-id's password.", dest='password', type=str) 36 | 37 | args = parser.parse_args() 38 | 39 | sleeptime = args.sleeptime 40 | email = args.email 41 | password = args.password 42 | 43 | 44 | 45 | try: 46 | for items in args.wordlist.split(','): 47 | words.append(items) 48 | except Exception as e: 49 | print("[-] Please input coma seperated words in quotes. Refer help.") 50 | exit() 51 | 52 | words = [x.lower() for x in words] 53 | 54 | feed() 55 | 56 | def feed(): 57 | print("\n\n") 58 | print(''' 59 | _ _ _ ___ _ _ 60 | _ __ ___ __ _(_) |_ __ | |/ _ \\(_) |__ 61 | | '_ ` _ \\ / _` | | | '_ \\| | |\\| | | |__| 62 | | | | | | | (_| | | | |_) | | |_| | | |_ 63 | |_| |_| |_|\\__,_|_|_| .__/|_|\\___/|_|\\__| 64 | |_| 65 | \n\n''') 66 | 67 | print("[+] Began execution at - "+curr_time+"\n"+"[+] Mailspl0it will check exploit-db every "+str(sleeptime)+"s"+"\n") 68 | 69 | url = "https://www.exploit-db.com/?draw=1&columns%5B0%5D%5Bdata%5D=date_published&columns%5B0%5D%5Bname%5D=date_published&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=download&columns%5B1%5D%5Bname%5D=download&columns%5B1%5D%5Bsearchable%5D=false&columns%5B1%5D%5Borderable%5D=false&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=application_md5&columns%5B2%5D%5Bname%5D=application_md5&columns%5B2%5D%5Bsearchable%5D=true&columns%5B2%5D%5Borderable%5D=false&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=verified&columns%5B3%5D%5Bname%5D=verified&columns%5B3%5D%5Bsearchable%5D=true&columns%5B3%5D%5Borderable%5D=false&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B4%5D%5Bdata%5D=description&columns%5B4%5D%5Bname%5D=description&columns%5B4%5D%5Bsearchable%5D=true&columns%5B4%5D%5Borderable%5D=false&columns%5B4%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B4%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B5%5D%5Bdata%5D=type_id&columns%5B5%5D%5Bname%5D=type_id&columns%5B5%5D%5Bsearchable%5D=true&columns%5B5%5D%5Borderable%5D=false&columns%5B5%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B5%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B6%5D%5Bdata%5D=platform_id&columns%5B6%5D%5Bname%5D=platform_id&columns%5B6%5D%5Bsearchable%5D=true&columns%5B6%5D%5Borderable%5D=false&columns%5B6%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B6%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B7%5D%5Bdata%5D=author_id&columns%5B7%5D%5Bname%5D=author_id&columns%5B7%5D%5Bsearchable%5D=false&columns%5B7%5D%5Borderable%5D=false&columns%5B7%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B7%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B8%5D%5Bdata%5D=code&columns%5B8%5D%5Bname%5D=code.code&columns%5B8%5D%5Bsearchable%5D=true&columns%5B8%5D%5Borderable%5D=true&columns%5B8%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B8%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B9%5D%5Bdata%5D=id&columns%5B9%5D%5Bname%5D=id&columns%5B9%5D%5Bsearchable%5D=false&columns%5B9%5D%5Borderable%5D=true&columns%5B9%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B9%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=9&order%5B0%5D%5Bdir%5D=desc&start=0&length=15&search%5Bvalue%5D=&search%5Bregex%5D=false&author=&port=&type=&tag=&platform=&_=1580233510556" 70 | 71 | #Mozilla user agent as exploit-db rejects raw Python get requests. 72 | headers = { 73 | 'Accept-Encoding': 'gzip, deflate', 74 | 'Accept-Language': 'en-US,en;q=0.5', 75 | 'Connection': 'keep-alive', 76 | 'Cookie': 'CookieConsent=-1; _ga=GA1.3.795532176.1579801588', 77 | 'Host': 'www.exploit-db.com', 78 | 'Referer': 'https://www.exploit-db.com/', 79 | 'TE': 'Trailers', 80 | 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0', 81 | 'Accept': 'application/json, text/javascript, */*; q=0.01', 82 | 83 | 'Accept-Encoding': 'gzip, deflate', 84 | 85 | 'X-Requested-With': 'XMLHttpRequest' 86 | } 87 | 88 | try: 89 | request = requests.get(url, headers = headers) 90 | status = request.status_code 91 | except Exception as e: 92 | print('[-] %s could not be reached. Please check your connection. \n\n[-] Printing exception:\n\n%s' % ("exploit-db", e)) 93 | exit() 94 | 95 | resp = request.text 96 | 97 | if status == '200' or '301': 98 | data = resp.split("\"") 99 | data = [x.lower() for x in data] 100 | 101 | for lines in data: 102 | for all_words in words: 103 | if all_words in lines: #check user input in the response 104 | vulnApp.append(lines) #list of words identified in response 105 | sQuery.append(all_words) #list of words found from user inputs in the response 106 | 107 | call_mailer(vulnApp) 108 | #Send mail iteration one 109 | 110 | def call_mailer(vulnApp): 111 | 112 | res = "" 113 | 114 | for num, app in enumerate(vulnApp, 1): 115 | res = res + "{}. {}".format(num, app) + "\n" 116 | 117 | if not vulnApp: 118 | timer = str(datetime.datetime.now()) 119 | print("Results for your search query not found as on "+timer+" on exploit-db.\n\n") 120 | else: 121 | print("[+] Search query identified. Sending email..\n\n") 122 | 123 | try: 124 | msg = EmailMessage() 125 | msg.set_content("[+] Query spotted on exploit-db.\n\nRESULTS:\n\n"+res) 126 | 127 | msg['Subject'] = "Mailploit | Exploit found" 128 | msg['From'] = email 129 | msg['To'] = email 130 | 131 | server = smtplib.SMTP('smtp.gmail.com', 587) 132 | server.starttls() 133 | # If you want to hardcode your credentials and not type on command line: 134 | # 1. Please uncomment below line and type your password if you want to hardcode your password. 135 | # 2. Also please comment the line below it. 136 | #server.login(email, "type your password here inside the quotes") 137 | server.login(email, password) 138 | server.send_message(msg) 139 | print("Mailed:\n"+res) 140 | print("\n\n") 141 | except Exception as e: 142 | print('''[-] Email delivery failed. Please confirm your email and credentials.\n\t - If using gmail, please visit the link: https://myaccount.google.com/lesssecureapps and toggle ON. 143 | \n[-] Printing exception to debug:\n%s''' %(e)) 144 | exit() 145 | 146 | comp.extend(vulnApp) # Update compare list with mailed results 147 | vulnApp.clear() # Clear identified search queries (or mailed results) list to allocate new results 148 | compare(comp) # Pass updated compare list i.e. mailed results to compare function 149 | 150 | def compare(comp): 151 | 152 | # Compares already mailed results with newly identified results. Loops if same, mails new results if different. 153 | 154 | while True: 155 | 156 | url = "https://www.exploit-db.com/?draw=1&columns%5B0%5D%5Bdata%5D=date_published&columns%5B0%5D%5Bname%5D=date_published&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=download&columns%5B1%5D%5Bname%5D=download&columns%5B1%5D%5Bsearchable%5D=false&columns%5B1%5D%5Borderable%5D=false&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=application_md5&columns%5B2%5D%5Bname%5D=application_md5&columns%5B2%5D%5Bsearchable%5D=true&columns%5B2%5D%5Borderable%5D=false&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=verified&columns%5B3%5D%5Bname%5D=verified&columns%5B3%5D%5Bsearchable%5D=true&columns%5B3%5D%5Borderable%5D=false&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B4%5D%5Bdata%5D=description&columns%5B4%5D%5Bname%5D=description&columns%5B4%5D%5Bsearchable%5D=true&columns%5B4%5D%5Borderable%5D=false&columns%5B4%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B4%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B5%5D%5Bdata%5D=type_id&columns%5B5%5D%5Bname%5D=type_id&columns%5B5%5D%5Bsearchable%5D=true&columns%5B5%5D%5Borderable%5D=false&columns%5B5%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B5%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B6%5D%5Bdata%5D=platform_id&columns%5B6%5D%5Bname%5D=platform_id&columns%5B6%5D%5Bsearchable%5D=true&columns%5B6%5D%5Borderable%5D=false&columns%5B6%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B6%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B7%5D%5Bdata%5D=author_id&columns%5B7%5D%5Bname%5D=author_id&columns%5B7%5D%5Bsearchable%5D=false&columns%5B7%5D%5Borderable%5D=false&columns%5B7%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B7%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B8%5D%5Bdata%5D=code&columns%5B8%5D%5Bname%5D=code.code&columns%5B8%5D%5Bsearchable%5D=true&columns%5B8%5D%5Borderable%5D=true&columns%5B8%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B8%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B9%5D%5Bdata%5D=id&columns%5B9%5D%5Bname%5D=id&columns%5B9%5D%5Bsearchable%5D=false&columns%5B9%5D%5Borderable%5D=true&columns%5B9%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B9%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=9&order%5B0%5D%5Bdir%5D=desc&start=0&length=15&search%5Bvalue%5D=&search%5Bregex%5D=false&author=&port=&type=&tag=&platform=&_=1580233510556" 157 | 158 | headers = { 159 | 'Accept-Encoding': 'gzip, deflate', 160 | 'Accept-Language': 'en-US,en;q=0.5', 161 | 'Connection': 'keep-alive', 162 | 'Cookie': 'CookieConsent=-1; _ga=GA1.3.795532176.1579801588', 163 | 'Host': 'www.exploit-db.com', 164 | 'Referer': 'https://www.exploit-db.com/', 165 | 'TE': 'Trailers', 166 | 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0', 167 | 'Accept': 'application/json, text/javascript, */*; q=0.01', 168 | 169 | 'Accept-Encoding': 'gzip, deflate', 170 | 171 | 'X-Requested-With': 'XMLHttpRequest' 172 | } 173 | 174 | try: 175 | request = requests.get(url, headers = headers) 176 | status = request.status_code 177 | except Exception as e: 178 | print('[-] %s could not be reached. Please check your connection. \n[-] Printing exception to debug:\n%s' % (url2, e)) 179 | exit() 180 | 181 | resp = request.text 182 | 183 | if status == '200' or '301': 184 | data = resp.split("\"") 185 | data = [x.lower() for x in data] 186 | 187 | for lines in data: 188 | for all_words in words: 189 | if all_words in lines: 190 | vulnApp.append(lines) 191 | sQuery.append(all_words) 192 | 193 | if vulnApp == comp: # If newly identified results same as already mailed - sleep 194 | timer = str(datetime.datetime.now()) 195 | print("Results still same as of "+timer+". Sleeping for "+str(sleeptime)+"s") 196 | #make the script run every jitter hours from user input 197 | time.sleep(sleeptime) 198 | vulnApp.clear() #Clear identified results to allocate new results 199 | else: #If newly identified results different than the already mailed - pass flow to mailer function 200 | timer = str(datetime.datetime.now()) 201 | print("Results updated on : "+timer+". Sending notification.") 202 | comp.clear() #clear compare function to allocate space for newly updated identified results 203 | call_mailer(vulnApp) 204 | 205 | 206 | if __name__ == '__main__': 207 | main() 208 | -------------------------------------------------------------------------------- /terminal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bad-bit/mailpl0it/8c4a7feece7574a7503f0c055fe55ec89a1e80af/terminal.jpg --------------------------------------------------------------------------------