2024-02-29 15:49:20 +00:00
|
|
|
#!/usr/bin/python3
|
|
|
|
#
|
|
|
|
# smtp.py
|
2024-07-12 01:14:39 +00:00
|
|
|
# SMTP mail sender over HTTP/S
|
2024-02-29 15:49:20 +00:00
|
|
|
#
|
2024-06-20 08:21:08 +00:00
|
|
|
# Caterpillar Proxy - The simple web debugging proxy (formerly, php-httpproxy)
|
2024-02-29 15:49:20 +00:00
|
|
|
# Namyheon Go (Catswords Research) <gnh1201@gmail.com>
|
|
|
|
# https://github.com/gnh1201/caterpillar
|
|
|
|
# Created at: 2024-03-01
|
2024-07-12 01:14:39 +00:00
|
|
|
# Updated at: 2024-07-12
|
2024-02-29 15:49:20 +00:00
|
|
|
#
|
2024-07-12 01:14:39 +00:00
|
|
|
import asyncio
|
|
|
|
from aiosmtpd.controller import Controller
|
|
|
|
from email.message import EmailMessage
|
2024-07-09 08:01:25 +00:00
|
|
|
import sys
|
2024-02-29 15:44:59 +00:00
|
|
|
import requests
|
2024-07-12 01:14:39 +00:00
|
|
|
from platform import python_version
|
2024-02-29 15:53:33 +00:00
|
|
|
from decouple import config
|
2024-02-29 15:54:08 +00:00
|
|
|
from requests.auth import HTTPBasicAuth
|
2024-07-11 10:02:08 +00:00
|
|
|
from base import (
|
|
|
|
extract_credentials,
|
|
|
|
jsonrpc2_encode,
|
2024-08-31 06:48:35 +00:00
|
|
|
Logger, jsonrpc2_decode,
|
2024-07-11 10:02:08 +00:00
|
|
|
)
|
2024-07-09 08:01:25 +00:00
|
|
|
|
|
|
|
logger = Logger(name="smtp")
|
2024-02-29 15:53:33 +00:00
|
|
|
|
|
|
|
try:
|
2024-07-11 10:02:08 +00:00
|
|
|
smtp_host = config("SMTP_HOST", default="127.0.0.1")
|
|
|
|
smtp_port = config("SMTP_PORT", default=25, cast=int)
|
|
|
|
_username, _password, server_url = extract_credentials(
|
|
|
|
config("SERVER_URL", default="")
|
|
|
|
)
|
2024-02-29 15:53:33 +00:00
|
|
|
except KeyboardInterrupt:
|
2024-07-09 08:01:25 +00:00
|
|
|
logger.warning("[*] User has requested an interrupt")
|
|
|
|
logger.warning("[*] Application Exiting.....")
|
2024-02-29 15:53:33 +00:00
|
|
|
sys.exit()
|
|
|
|
|
|
|
|
auth = None
|
|
|
|
if _username:
|
|
|
|
auth = HTTPBasicAuth(_username, _password)
|
|
|
|
|
2024-08-31 05:37:21 +00:00
|
|
|
|
2024-07-12 01:14:39 +00:00
|
|
|
class CaterpillarSMTPHandler:
|
|
|
|
def __init__(self):
|
|
|
|
self.smtpd_hostname = "CaterpillarSMTPServer"
|
|
|
|
self.smtp_version = "0.1.6"
|
|
|
|
|
|
|
|
async def handle_DATA(self, server, session, envelope):
|
2024-08-31 06:48:35 +00:00
|
|
|
mail_from = envelope.mail_from
|
|
|
|
rcpt_tos = envelope.rcpt_tos
|
2024-07-12 01:14:39 +00:00
|
|
|
data = envelope.content
|
|
|
|
|
|
|
|
message = EmailMessage()
|
|
|
|
message.set_content(data)
|
2024-02-29 19:09:45 +00:00
|
|
|
|
2024-08-31 05:37:21 +00:00
|
|
|
subject = message.get("Subject", "")
|
|
|
|
to = message.get("To", "")
|
2024-02-29 15:44:59 +00:00
|
|
|
|
2024-02-29 19:36:04 +00:00
|
|
|
proxy_data = {
|
2024-07-11 10:02:08 +00:00
|
|
|
"headers": {
|
|
|
|
"User-Agent": "php-httpproxy/0.1.6 (Client; Python "
|
|
|
|
+ python_version()
|
|
|
|
+ "; Caterpillar; abuse@catswords.net)",
|
2024-02-29 19:36:04 +00:00
|
|
|
},
|
2024-07-11 10:02:08 +00:00
|
|
|
"data": {
|
2024-02-29 19:36:04 +00:00
|
|
|
"to": to,
|
2024-08-31 06:48:35 +00:00
|
|
|
"from": mail_from,
|
2024-02-29 19:36:04 +00:00
|
|
|
"subject": subject,
|
2024-07-11 10:02:08 +00:00
|
|
|
"message": data.decode("utf-8"),
|
|
|
|
},
|
2024-02-29 19:36:04 +00:00
|
|
|
}
|
2024-07-11 10:02:08 +00:00
|
|
|
_, raw_data = jsonrpc2_encode("relay_sendmail", proxy_data["data"])
|
2024-02-29 15:44:59 +00:00
|
|
|
|
|
|
|
try:
|
2024-07-12 01:14:39 +00:00
|
|
|
response = await asyncio.to_thread(
|
|
|
|
requests.post,
|
|
|
|
server_url,
|
2024-08-31 05:37:21 +00:00
|
|
|
headers=proxy_data["headers"],
|
2024-07-12 01:14:39 +00:00
|
|
|
data=raw_data,
|
2024-08-31 05:37:21 +00:00
|
|
|
auth=auth,
|
2024-07-12 01:14:39 +00:00
|
|
|
)
|
2024-02-29 15:59:36 +00:00
|
|
|
if response.status_code == 200:
|
2024-08-31 06:48:35 +00:00
|
|
|
_type, _id, rpc_data = jsonrpc2_decode(response.text)
|
|
|
|
if rpc_data["success"]:
|
2024-07-09 08:01:25 +00:00
|
|
|
logger.info("[*] Email sent successfully.")
|
2024-02-29 15:59:36 +00:00
|
|
|
else:
|
2024-08-31 06:48:35 +00:00
|
|
|
raise Exception(f"({rpc_data['code']}) {rpc_data['message']}")
|
2024-02-29 19:39:58 +00:00
|
|
|
else:
|
2024-07-12 01:14:39 +00:00
|
|
|
raise Exception(f"Status {response.status_code}")
|
2024-02-29 15:44:59 +00:00
|
|
|
except Exception as e:
|
2024-07-09 08:01:25 +00:00
|
|
|
logger.error("[*] Failed to send email", exc_info=e)
|
2024-08-31 05:37:21 +00:00
|
|
|
return "500 Could not process your message. " + str(e)
|
2024-02-29 15:44:59 +00:00
|
|
|
|
2024-08-31 05:37:21 +00:00
|
|
|
return "250 OK"
|
2024-07-12 01:14:39 +00:00
|
|
|
|
2024-02-29 15:40:54 +00:00
|
|
|
|
2024-07-12 01:14:39 +00:00
|
|
|
# https://aiosmtpd-pepoluan.readthedocs.io/en/latest/migrating.html
|
|
|
|
def main():
|
|
|
|
handler = CaterpillarSMTPHandler()
|
|
|
|
controller = Controller(handler, hostname=smtp_host, port=smtp_port)
|
|
|
|
# Run the event loop in a separate thread.
|
|
|
|
controller.start()
|
|
|
|
# Wait for the user to press Return.
|
2024-08-31 05:37:21 +00:00
|
|
|
input("SMTP server running. Press Return to stop server and exit.")
|
2024-07-12 01:14:39 +00:00
|
|
|
controller.stop()
|
|
|
|
logger.warning("[*] User has requested an interrupt")
|
|
|
|
logger.warning("[*] Application Exiting.....")
|
|
|
|
sys.exit()
|
2024-02-29 15:40:54 +00:00
|
|
|
|
2024-08-31 05:37:21 +00:00
|
|
|
|
2024-07-12 01:14:39 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|