mirror of
https://github.com/gnh1201/caterpillar.git
synced 2025-05-18 15:41:06 +00:00
commit
feb7cff398
14
base.py
14
base.py
|
@ -8,9 +8,8 @@
|
||||||
# Euiseo Cha (Wonkwang University) <zeroday0619_dev@outlook.com>
|
# Euiseo Cha (Wonkwang University) <zeroday0619_dev@outlook.com>
|
||||||
# https://github.com/gnh1201/caterpillar
|
# https://github.com/gnh1201/caterpillar
|
||||||
# Created at: 2024-05-20
|
# Created at: 2024-05-20
|
||||||
# Updated at: 2024-07-11
|
# Updated at: 2024-07-12
|
||||||
#
|
#
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
@ -48,10 +47,18 @@ def jsonrpc2_create_id(data):
|
||||||
def jsonrpc2_encode(method, params=None):
|
def jsonrpc2_encode(method, params=None):
|
||||||
data = {"jsonrpc": "2.0", "method": method, "params": params}
|
data = {"jsonrpc": "2.0", "method": method, "params": params}
|
||||||
id = jsonrpc2_create_id(data)
|
id = jsonrpc2_create_id(data)
|
||||||
data["id"] = id
|
id = data.get('id')
|
||||||
return (id, json.dumps(data))
|
return (id, json.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
|
def jsonrpc2_decode(text):
|
||||||
|
data = json.loads(text)
|
||||||
|
type = 'error' if 'error' in data else 'result' if 'result' in data else None
|
||||||
|
id = data.get('id')
|
||||||
|
rpcdata = data.get(type) if type else None
|
||||||
|
return type, id, rpcdata
|
||||||
|
|
||||||
|
|
||||||
def jsonrpc2_result_encode(result, id=""):
|
def jsonrpc2_result_encode(result, id=""):
|
||||||
data = {"jsonrpc": "2.0", "result": result, "id": id}
|
data = {"jsonrpc": "2.0", "result": result, "id": id}
|
||||||
return json.dumps(data)
|
return json.dumps(data)
|
||||||
|
@ -61,7 +68,6 @@ def jsonrpc2_error_encode(error, id=""):
|
||||||
data = {"jsonrpc": "2.0", "error": error, "id": id}
|
data = {"jsonrpc": "2.0", "error": error, "id": id}
|
||||||
return json.dumps(data)
|
return json.dumps(data)
|
||||||
|
|
||||||
|
|
||||||
def find_openssl_binpath():
|
def find_openssl_binpath():
|
||||||
system = platform.system()
|
system = platform.system()
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
python-decouple
|
python-decouple
|
||||||
requests
|
requests
|
||||||
|
aiosmtpd
|
86
smtp.py
86
smtp.py
|
@ -1,23 +1,23 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
#
|
#
|
||||||
# smtp.py
|
# smtp.py
|
||||||
# SMTP over HTTP gateway
|
# SMTP mail sender over HTTP/S
|
||||||
#
|
#
|
||||||
# Caterpillar Proxy - The simple web debugging proxy (formerly, php-httpproxy)
|
# Caterpillar Proxy - The simple web debugging proxy (formerly, php-httpproxy)
|
||||||
# Namyheon Go (Catswords Research) <gnh1201@gmail.com>
|
# Namyheon Go (Catswords Research) <gnh1201@gmail.com>
|
||||||
# https://github.com/gnh1201/caterpillar
|
# https://github.com/gnh1201/caterpillar
|
||||||
# Created at: 2024-03-01
|
# Created at: 2024-03-01
|
||||||
# Updated at: 2024-05-20
|
# Updated at: 2024-07-12
|
||||||
#
|
#
|
||||||
|
import asyncio
|
||||||
import asyncore
|
from aiosmtpd.controller import Controller
|
||||||
from smtpd import SMTPServer
|
from aiosmtpd.handlers import Message
|
||||||
|
from email.message import EmailMessage
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
|
from platform import python_version
|
||||||
from decouple import config
|
from decouple import config
|
||||||
from requests.auth import HTTPBasicAuth
|
from requests.auth import HTTPBasicAuth
|
||||||
from base import (
|
from base import (
|
||||||
|
@ -45,28 +45,22 @@ auth = None
|
||||||
if _username:
|
if _username:
|
||||||
auth = HTTPBasicAuth(_username, _password)
|
auth = HTTPBasicAuth(_username, _password)
|
||||||
|
|
||||||
|
class CaterpillarSMTPHandler:
|
||||||
|
def __init__(self):
|
||||||
|
self.smtpd_hostname = "CaterpillarSMTPServer"
|
||||||
|
self.smtp_version = "0.1.6"
|
||||||
|
|
||||||
class CaterpillarSMTPServer(SMTPServer):
|
async def handle_DATA(self, server, session, envelope):
|
||||||
def __init__(self, localaddr, remoteaddr):
|
mailfrom = envelope.mail_from
|
||||||
self.__class__.smtpd_hostname = "CaterpillarSMTPServer"
|
rcpttos = envelope.rcpt_tos
|
||||||
self.__class__.smtp_version = "0.1.6"
|
data = envelope.content
|
||||||
super().__init__(localaddr, remoteaddr)
|
|
||||||
|
|
||||||
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
|
message = EmailMessage()
|
||||||
message_lines = data.decode("utf-8").split("\n")
|
message.set_content(data)
|
||||||
subject = ""
|
|
||||||
to = ""
|
subject = message.get('Subject', '')
|
||||||
for line in message_lines:
|
to = message.get('To', '')
|
||||||
pos = line.find(":")
|
|
||||||
if pos > -1:
|
|
||||||
k = line[0:pos]
|
|
||||||
v = line[pos + 1 :]
|
|
||||||
if k == "Subject":
|
|
||||||
subject = v
|
|
||||||
elif k == "To":
|
|
||||||
to = v
|
|
||||||
|
|
||||||
# build a data
|
|
||||||
proxy_data = {
|
proxy_data = {
|
||||||
"headers": {
|
"headers": {
|
||||||
"User-Agent": "php-httpproxy/0.1.6 (Client; Python "
|
"User-Agent": "php-httpproxy/0.1.6 (Client; Python "
|
||||||
|
@ -82,27 +76,41 @@ class CaterpillarSMTPServer(SMTPServer):
|
||||||
}
|
}
|
||||||
_, raw_data = jsonrpc2_encode("relay_sendmail", proxy_data["data"])
|
_, raw_data = jsonrpc2_encode("relay_sendmail", proxy_data["data"])
|
||||||
|
|
||||||
# send HTTP POST request
|
|
||||||
try:
|
try:
|
||||||
response = requests.post(
|
response = await asyncio.to_thread(
|
||||||
server_url, headers=proxy_data["headers"], data=raw_data, auth=auth
|
requests.post,
|
||||||
|
server_url,
|
||||||
|
headers=proxy_data['headers'],
|
||||||
|
data=raw_data,
|
||||||
|
auth=auth
|
||||||
)
|
)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
type, id, method, rpcdata = jsonrpc2_decode(response.text)
|
type, id, rpcdata = jsonrpc2_decode(response.text)
|
||||||
if rpcdata["success"]:
|
if rpcdata['success']:
|
||||||
logger.info("[*] Email sent successfully.")
|
logger.info("[*] Email sent successfully.")
|
||||||
else:
|
else:
|
||||||
raise Exception(
|
raise Exception(f"({rpcdata['code']}) {rpcdata['message']}")
|
||||||
"(%s) %s" % (str(rpcdata["code"]), rpcdata["message"])
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
raise Exception("Status %s" % (str(response.status_code)))
|
raise Exception(f"Status {response.status_code}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("[*] Failed to send email", exc_info=e)
|
logger.error("[*] Failed to send email", exc_info=e)
|
||||||
|
return '500 Could not process your message. ' + str(e)
|
||||||
|
|
||||||
|
return '250 OK'
|
||||||
|
|
||||||
|
|
||||||
# Start SMTP server
|
# https://aiosmtpd-pepoluan.readthedocs.io/en/latest/migrating.html
|
||||||
smtp_server = CaterpillarSMTPServer((smtp_host, smtp_port), None)
|
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.
|
||||||
|
input('SMTP server running. Press Return to stop server and exit.')
|
||||||
|
controller.stop()
|
||||||
|
logger.warning("[*] User has requested an interrupt")
|
||||||
|
logger.warning("[*] Application Exiting.....")
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
# Start asynchronous event loop
|
if __name__ == "__main__":
|
||||||
asyncore.loop()
|
main()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user