Skip to content

Instantly share code, notes, and snippets.

@HorlogeSkynet
Last active October 23, 2023 10:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save HorlogeSkynet/054e363ade6093e24dd97ea19debff9e to your computer and use it in GitHub Desktop.
Save HorlogeSkynet/054e363ade6093e24dd97ea19debff9e to your computer and use it in GitHub Desktop.
A simple SSH hook for OpenSSH and Discord
#!/usr/bin/env python3
"""
@author : Samuel FORESTIER
@date : Created on 26/10/2017
@version : 1.2.1
@url : https://samuel.forestier.app/blog/security/a-ssh-monitoring-platform-with-discord
"""
# Packages required :
# * python3
# * python3-requests
# * dnsutils
import signal
import requests
from os import getenv
from subprocess import check_output, DEVNULL, \
TimeoutExpired, CalledProcessError
# Discord Web-hook information go here
WEBHOOK_ID = 'YOUR_WEBHOOK_ID'
WEBHOOK_TOKEN = 'YOUR_WEBHOOK_TOKEN'
# ____________________________________
# Free Mobile SMS API credentials go here
SEND_SMS_ON_FAIL = False
FREE_USERNAME = 'YOUR_FREE_USERNAME'
FREE_PASSWORD = 'YOUR_FREE_PASSWORD'
# _______________________________________
if __name__ == '__main__':
# Before anything else, we set signal handlers...
# ... to keep the attacker from stopping this script with its keyboard
signal.signal(signal.SIGINT, signal.SIG_IGN) # Disable CTRL + C (^C)
signal.signal(signal.SIGTSTP, signal.SIG_IGN) # Disable CTRL + Z (^Z)
signal.signal(signal.SIGQUIT, signal.SIG_IGN) # Disable CTRL + \ (^\)
# Here we get the IP address of the inner connection
remote_ip = getenv('SSH_CONNECTION', 'Unknown').split(' ')[0]
# Here we (try to) do a reverse DNS request on the address IP
try:
reverse = check_output(['dig', '-x', remote_ip, '+short'],
stderr=DEVNULL,
timeout=1
).decode().split('\n')[0].replace('*', '\*')
# If the reverse DNS did not bring any result...
reverse = reverse or remote_ip
except (FileNotFoundError, TimeoutExpired, CalledProcessError):
# If `dig` is not available, or the DNS query was too long...
reverse = remote_ip
# Which session has been opened ?
whoami = check_output(['whoami']).decode().rstrip().replace('*', '\*')
# Which server is accessed ?
hostname = check_output(['hostname']).decode().rstrip().replace('*', '\*')
# Execute the query !
try:
requests.post(
'https://discordapp.com/api/webhooks/{0}/{1}'.format(
WEBHOOK_ID,
WEBHOOK_TOKEN
),
json={
'content': 'The session **{0}** has just been opened on'
' **{1}** by **{2}** !'
.format(whoami, hostname, reverse)
},
headers={
'content-type': 'application/json'
},
timeout=2
).raise_for_status()
except (requests.exceptions.HTTPError, requests.exceptions.Timeout):
# The request couldn't be posted as well. Are we sending a SMS now ?
if SEND_SMS_ON_FAIL:
try:
requests.post(
'https://smsapi.free-mobile.fr/sendmsg',
params={
'user': FREE_USERNAME,
'pass': FREE_PASSWORD,
'msg': 'The session {0} has just been opened on {1}'
' by {2} !'.format(whoami, hostname, reverse)
},
timeout=3
)
except requests.exceptions.Timeout:
# In this case, it's complicated to inform the sys-admin :'(
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment