This repository has been archived by the owner on Jan 18, 2025. It is now read-only.
forked from thinkst/canarytokens
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchannel_input_mysql.py
92 lines (71 loc) · 3.37 KB
/
channel_input_mysql.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from twisted.logger import Logger
from twisted.internet.protocol import Protocol, Factory
from twisted.application import internet
from channel import InputChannel
from tokens import Canarytoken
from canarydrop import Canarydrop
from queries import get_canarydrop
from exception import NoCanarytokenFound
from constants import INPUT_CHANNEL_MYSQL
import struct
log = Logger()
MYSQL_RSP = b'\x5b\x00\x00\x00\x0a\x38\x2e\x30\x2e\x32\x36\x2d\x30\x75\x62\x75\x6e\x74\x75\x30\x2e\x32\x30\x2e\x30\x34\x2e\x32\x00\x13\x00\x00\x00\x14\x37\x06\x5c\x3c\x26\x2a\x01\x00\xff\xf7\xff\x02\x00\xff\xcf\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x50\x3c\x16\x61\x26\x60\x49\x4f\x4b\x6d\x7a\x37\x00\x63\x61\x63\x68\x69\x6e\x67\x5f\x73\x68\x61\x32\x5f\x70\x61\x73\x73\x77\x6f\x72\x64\x00'
MIN_LENGTH = 60
class CanaryMySQLProtocol(Protocol):
def __init__(self):
self.buf = b''
def connectionMade(self):
self.transport.write(MYSQL_RSP)
def dataReceived(self, data):
try:
self.buf += data
if len(self.buf) < MIN_LENGTH:
return
self.handleQuery()
except (NoCanarytokenFound, Exception) as e:
log.error('Error: {}'.format(e))
self.transport.loseConnection()
def handleQuery(self):
peer = self.transport.getPeer()
src_host = peer.host
capability_flags, max_packet_sz, char_set, username = \
struct.Struct("!4s4sc27x25s").unpack_from(self.buf)
log.info('MySQL Query from {}'.format(src_host))
additional_info = self.additionalInfo()
self.factory.dispatch_alert(username, src_host, additional_info)
def additionalInfo(self):
try:
start_of_locale = MIN_LENGTH + 1
end_of_locale = start_of_locale + 4
locale = self.buf[start_of_locale:end_of_locale + 1]
hostname = ""
for c in self.buf[end_of_locale + 1:]:
if c == b'\x00':
break
hostname += c
return {"MySQL Client": {"Hostname": [hostname], "Locale": [locale]}}
except Exception as e:
log.error('Error getting additional info: {}'.format(e))
return None
class CanaryMySQLFactory(Factory, InputChannel):
protocol = CanaryMySQLProtocol
CHANNEL = INPUT_CHANNEL_MYSQL
def __init__(self, switchboard=None):
InputChannel.__init__(self, switchboard=switchboard, name=self.CHANNEL)
def dispatch_alert(self, username, src_host, additional_info):
token = Canarytoken(value=username)
canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value()))
self.dispatch(canarydrop=canarydrop, src_ip=src_host, additional_info=additional_info)
def format_additional_data(self, **kwargs):
additional_report = ''
if 'Hostname' in kwargs and kwargs['Hostname']:
additional_report += 'Hostname: {hostname}\r\n'.format(
hostname=kwargs['Hostname'])
if 'Locale' in kwargs and kwargs['Locale']:
additional_report += 'Locale: {locale}\r\n'.format(
locale=kwargs['Locale'])
return additional_report
class ChannelMySQL():
def __init__(self, port=3306, switchboard=None):
self.service = internet.TCPServer(
port, CanaryMySQLFactory(switchboard=switchboard))