Skip to content

Instantly share code, notes, and snippets.

@arush15june
Created September 19, 2018 16:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arush15june/d44efc6af73d81cc4aa5a3a560c8fa82 to your computer and use it in GitHub Desktop.
Save arush15june/d44efc6af73d81cc4aa5a3a560c8fa82 to your computer and use it in GitHub Desktop.
bin_t - CSAW CTF 2018 Quals
import random, math
from pwn import *
def random_data_generator (max_r):
for i in xrange(max_r):
yield random.randint(0, max_r)
class Node():
def __init__(self, key):
self.key = key
self.parent = None
self.leftChild = None
self.rightChild = None
self.height = 0
def __str__(self):
return str(self.key) + "(" + str(self.height) + ")"
def is_leaf(self):
return (self.height == 0)
def max_children_height(self):
if self.leftChild and self.rightChild:
return max(self.leftChild.height, self.rightChild.height)
elif self.leftChild and not self.rightChild:
return self.leftChild.height
elif not self.leftChild and self.rightChild:
return self.rightChild.height
else:
return -1
def balance (self):
return (self.leftChild.height if self.leftChild else -1) - (self.rightChild.height if self.rightChild else -1)
class AVLTree():
def __init__(self, *args):
self.rootNode = None
self.elements_count = 0
self.rebalance_count = 0
if len(args) == 1:
for i in args[0]:
self.insert (i)
def height(self):
if self.rootNode:
return self.rootNode.height
else:
return 0
def rebalance (self, node_to_rebalance):
self.rebalance_count += 1
A = node_to_rebalance
F = A.parent #allowed to be NULL
if node_to_rebalance.balance() == -2:
if node_to_rebalance.rightChild.balance() <= 0:
"""Rebalance, case RRC """
B = A.rightChild
C = B.rightChild
assert (not A is None and not B is None and not C is None)
A.rightChild = B.leftChild
if A.rightChild:
A.rightChild.parent = A
B.leftChild = A
A.parent = B
if F is None:
self.rootNode = B
self.rootNode.parent = None
else:
if F.rightChild == A:
F.rightChild = B
else:
F.leftChild = B
B.parent = F
self.recompute_heights (A)
self.recompute_heights (B.parent)
else:
"""Rebalance, case RLC """
B = A.rightChild
C = B.leftChild
assert (not A is None and not B is None and not C is None)
B.leftChild = C.rightChild
if B.leftChild:
B.leftChild.parent = B
A.rightChild = C.leftChild
if A.rightChild:
A.rightChild.parent = A
C.rightChild = B
B.parent = C
C.leftChild = A
A.parent = C
if F is None:
self.rootNode = C
self.rootNode.parent = None
else:
if F.rightChild == A:
F.rightChild = C
else:
F.leftChild = C
C.parent = F
self.recompute_heights (A)
self.recompute_heights (B)
else:
assert(node_to_rebalance.balance() == +2)
if node_to_rebalance.leftChild.balance() >= 0:
B = A.leftChild
C = B.leftChild
"""Rebalance, case LLC """
assert (not A is None and not B is None and not C is None)
A.leftChild = B.rightChild
if (A.leftChild):
A.leftChild.parent = A
B.rightChild = A
A.parent = B
if F is None:
self.rootNode = B
self.rootNode.parent = None
else:
if F.rightChild == A:
F.rightChild = B
else:
F.leftChild = B
B.parent = F
self.recompute_heights (A)
self.recompute_heights (B.parent)
else:
B = A.leftChild
C = B.rightChild
"""Rebalance, case LRC """
assert (not A is None and not B is None and not C is None)
A.leftChild = C.rightChild
if A.leftChild:
A.leftChild.parent = A
B.rightChild = C.leftChild
if B.rightChild:
B.rightChild.parent = B
C.leftChild = B
B.parent = C
C.rightChild = A
A.parent = C
if F is None:
self.rootNode = C
self.rootNode.parent = None
else:
if (F.rightChild == A):
F.rightChild = C
else:
F.leftChild = C
C.parent = F
self.recompute_heights (A)
self.recompute_heights (B)
def sanity_check (self, *args):
if len(args) == 0:
node = self.rootNode
else:
node = args[0]
if (node is None) or (node.is_leaf() and node.parent is None ):
# trival - no sanity check needed, as either the tree is empty or there is only one node in the tree
pass
else:
if node.height != node.max_children_height() + 1:
raise Exception ("Invalid height for node " + str(node) + ": " + str(node.height) + " instead of " + str(node.max_children_height() + 1) + "!" )
balFactor = node.balance()
#Test the balance factor
if not (balFactor >= -1 and balFactor <= 1):
raise Exception ("Balance factor for node " + str(node) + " is " + str(balFactor) + "!")
#Make sure we have no circular references
if not (node.leftChild != node):
raise Exception ("Circular reference for node " + str(node) + ": node.leftChild is node!")
if not (node.rightChild != node):
raise Exception ("Circular reference for node " + str(node) + ": node.rightChild is node!")
if ( node.leftChild ):
if not (node.leftChild.parent == node):
raise Exception ("Left child of node " + str(node) + " doesn't know who his father is!")
if not (node.leftChild.key <= node.key):
raise Exception ("Key of left child of node " + str(node) + " is greater than key of his parent!")
self.sanity_check(node.leftChild)
if ( node.rightChild ):
if not (node.rightChild.parent == node):
raise Exception ("Right child of node " + str(node) + " doesn't know who his father is!")
if not (node.rightChild.key >= node.key):
raise Exception ("Key of right child of node " + str(node) + " is less than key of his parent!")
self.sanity_check(node.rightChild)
def recompute_heights (self, start_from_node):
changed = True
node = start_from_node
while node and changed:
old_height = node.height
node.height = (node.max_children_height() + 1 if (node.rightChild or node.leftChild) else 0)
changed = node.height != old_height
node = node.parent
def add_as_child (self, parent_node, child_node):
node_to_rebalance = None
if child_node.key < parent_node.key:
if not parent_node.leftChild:
parent_node.leftChild = child_node
child_node.parent = parent_node
if parent_node.height == 0:
node = parent_node
while node:
node.height = node.max_children_height() + 1
if not node.balance () in [-1, 0, 1]:
node_to_rebalance = node
break #we need the one that is furthest from the root
node = node.parent
else:
self.add_as_child(parent_node.leftChild, child_node)
else:
if not parent_node.rightChild:
parent_node.rightChild = child_node
child_node.parent = parent_node
if parent_node.height == 0:
node = parent_node
while node:
node.height = node.max_children_height() + 1
if not node.balance () in [-1, 0, 1]:
node_to_rebalance = node
break #we need the one that is furthest from the root
node = node.parent
else:
self.add_as_child(parent_node.rightChild, child_node)
if node_to_rebalance:
self.rebalance (node_to_rebalance)
def insert (self, key):
new_node = Node (key)
if not self.rootNode:
self.rootNode = new_node
else:
if not self.find(key):
self.elements_count += 1
self.add_as_child (self.rootNode, new_node)
def find_biggest(self, start_node):
node = start_node
while node.rightChild:
node = node.rightChild
return node
def find_smallest(self, start_node):
node = start_node
while node.leftChild:
node = node.leftChild
return node
def inorder_non_recursive (self):
node = self.rootNode
retlst = []
while node.leftChild:
node = node.leftChild
while (node):
retlst += [node.key]
if (node.rightChild):
node = node.rightChild
while node.leftChild:
node = node.leftChild
else:
while ((node.parent) and (node == node.parent.rightChild)):
node = node.parent
node = node.parent
return retlst
def preorder(self, node, retlst = None):
if retlst is None:
retlst = []
retlst += [node.key]
if node.leftChild:
retlst = self.preorder(node.leftChild, retlst)
if node.rightChild:
retlst = self.preorder(node.rightChild, retlst)
return retlst
def inorder(self, node, retlst = None):
if retlst is None:
retlst = []
if node.leftChild:
retlst = self.inorder(node.leftChild, retlst)
retlst += [node.key]
if node.rightChild:
retlst = self.inorder(node.rightChild, retlst)
return retlst
def postorder(self, node, retlst = None):
if retlst is None:
retlst = []
if node.leftChild:
retlst = self.postorder(node.leftChild, retlst)
if node.rightChild:
retlst = self.postorder(node.rightChild, retlst)
retlst += [node.key]
return retlst
def as_list (self, pre_in_post):
if not self.rootNode:
return []
if pre_in_post == 0:
return self.preorder (self.rootNode)
elif pre_in_post == 1:
return self.inorder (self.rootNode)
elif pre_in_post == 2:
return self.postorder (self.rootNode)
elif pre_in_post == 3:
return self.inorder_non_recursive()
def find(self, key):
return self.find_in_subtree (self.rootNode, key )
def find_in_subtree (self, node, key):
if node is None:
return None # key not found
if key < node.key:
return self.find_in_subtree(node.leftChild, key)
elif key > node.key:
return self.find_in_subtree(node.rightChild, key)
else: # key is equal to node key
return node
def remove (self, key):
# first find
node = self.find(key)
if not node is None:
self.elements_count -= 1
# There are three cases:
#
# 1) The node is a leaf. Remove it and return.
#
# 2) The node is a branch (has only 1 child). Make the pointer to this node
# point to the child of this node.
#
# 3) The node has two children. Swap items with the successor
# of the node (the smallest item in its right subtree) and
# delete the successor from the right subtree of the node.
if node.is_leaf():
self.remove_leaf(node)
elif (bool(node.leftChild)) ^ (bool(node.rightChild)):
self.remove_branch (node)
else:
assert (node.leftChild) and (node.rightChild)
self.swap_with_successor_and_remove (node)
def remove_leaf (self, node):
parent = node.parent
if (parent):
if parent.leftChild == node:
parent.leftChild = None
else:
assert (parent.rightChild == node)
parent.rightChild = None
self.recompute_heights(parent)
else:
self.rootNode = None
del node
# rebalance
node = parent
while (node):
if not node.balance() in [-1, 0, 1]:
self.rebalance(node)
node = node.parent
def remove_branch (self, node):
parent = node.parent
if (parent):
if parent.leftChild == node:
parent.leftChild = node.rightChild or node.leftChild
else:
assert (parent.rightChild == node)
parent.rightChild = node.rightChild or node.leftChild
if node.leftChild:
node.leftChild.parent = parent
else:
assert (node.rightChild)
node.rightChild.parent = parent
self.recompute_heights(parent)
del node
# rebalance
node = parent
while (node):
if not node.balance() in [-1, 0, 1]:
self.rebalance(node)
node = node.parent
def swap_with_successor_and_remove (self, node):
successor = self.find_smallest(node.rightChild)
self.swap_nodes (node, successor)
assert (node.leftChild is None)
if node.height == 0:
self.remove_leaf (node)
else:
self.remove_branch (node)
def swap_nodes (self, node1, node2):
assert (node1.height > node2.height)
parent1 = node1.parent
leftChild1 = node1.leftChild
rightChild1 = node1.rightChild
parent2 = node2.parent
assert (not parent2 is None)
assert (parent2.leftChild == node2 or parent2 == node1)
leftChild2 = node2.leftChild
assert (leftChild2 is None)
rightChild2 = node2.rightChild
# swap heights
tmp = node1.height
node1.height = node2.height
node2.height = tmp
if parent1:
if parent1.leftChild == node1:
parent1.leftChild = node2
else:
assert (parent1.rightChild == node1)
parent1.rightChild = node2
node2.parent = parent1
else:
self.rootNode = node2
node2.parent = None
node2.leftChild = leftChild1
leftChild1.parent = node2
node1.leftChild = leftChild2 # None
node1.rightChild = rightChild2
if rightChild2:
rightChild2.parent = node1
if not (parent2 == node1):
node2.rightChild = rightChild1
rightChild1.parent = node2
parent2.leftChild = node1
node1.parent = parent2
else:
node2.rightChild = node1
node1.parent = node2
# use for debug only and only with small trees
def out(self, start_node = None):
if start_node == None:
start_node = self.rootNode
space_symbol = "*"
spaces_count = 80
out_string = ""
initial_spaces_string = space_symbol * spaces_count + "\n"
if not start_node:
return "AVLTree is empty"
else:
level = [start_node]
while (len([i for i in level if (not i is None)])>0):
level_string = initial_spaces_string
for i in xrange(len(level)):
j = (i+1)* spaces_count / (len(level)+1)
level_string = level_string[:j] + (str(level[i]) if level[i] else space_symbol) + level_string[j+1:]
level_next = []
for i in level:
level_next += ([i.leftChild, i.rightChild] if i else [None, None])
level = level_next
out_string += level_string
return out_string
if __name__ == "__main__":
NC_URL = 'misc.chal.csaw.io'
NC_PORT = 9001
conn = remote(NC_URL, NC_PORT)
print(conn.recvline())
data = conn.recvline()
print(conn.recvline())
TREE_DATA = [int(d) for d in data.decode().split(',')]
print(len(TREE_DATA))
print(TREE_DATA)
tree = AVLTree(TREE_DATA)
preorder = tree.preorder(tree.rootNode)
SEND = ''
for val in preorder:
SEND += str(val)+','
SEND = SEND[:-1]
print(SEND)
conn.sendline(SEND)
conn.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment