Information
| Points | Category | Level | 
|---|---|---|
| 500 | General Skills | Hard | 
Challenge
Can you understand the language and answer the questions to retrieve the flag? Connect to the service with
nc 2018shell.picoctf.com 7866
Hint
Maybe try writing a python script?
Solution
So after connecting to the service this massage showed up:
Rules:
() + () = ()()                                      => [combine]
((())) + () = ((())())                              => [absorb-right]
() + ((())) = (()(()))                              => [absorb-left]
(())(()) + () = (())(()())                          => [combined-absorb-right]
() + (())(()) = (()())(())                          => [combined-absorb-left]
(())(()) + ((())) = ((())(())(()))                  => [absorb-combined-right]
((())) + (())(()) = ((())(())(()))                  => [absorb-combined-left]
() + (()) + ((())) = (()()) + ((())) = ((()())(())) => [left-associative]
Example: 
(()) + () = () + (()) = (()())
Let's start with a warmup.
(()) + (()()()) = ???
So there is a 8 rules and it’s like a math problem, so for understanding the rules.
I just tried to answer some questions and if I got wrong, the right answer   showed up to show me where I was wrong.
After some tries I thought I understood the rules and here they are:
- Combine - the max depth of each part are equal => combine them
example: ()()()(()) + (())() = ()()()(())(())()
part1 part2 answer value ()()()(()) (())() ()()()(())(())() max depth 2 2 2 
- Absorb left (and right) - if the max depth of the left part is more than >the max left of the right part => put the right part right before closing the left part
example: (()) + () = (()())
part1 part2 answer value (()) () (()()) max depth 2 1 2 
- the absorb right it’s symmetric
- Left associative - start from the 2 left parts, do the + between them and take >the result + the third part
example: () + (()) + ((())) = ((()())(()))
part1 part2 part3 part1+part2 result+part3 value () (()) ((())) (()()) ((()())(())) max depth 1 2 3 2 3 
So I wrote this python script:
import re
#Count the max depth of a str.
#Each '(' add one, each ')' sub one.
def depth (str):
	max = 0
	curr = 0
	for c in str:
		if c == '(':
			curr+= 1
			if curr > max:
				max = curr
		if c == ')':
			curr-= 1
	return max
#AbsorbLeft (when the left part depth is more than the right part.
#Set all the left part without the closing ')' at the end, insert right part and close by ')'
def absorbLeft(left,right):
	return left[:-1]+right+left[-1]
#Symmertic to the absorbLeft
def absorbRight(left,right):
	return right[0] + left + right[1:]
def splitProblem(question):
	#Split by "?" and "=" and "+"
	question = re.split('[= + ?]', question)
	#Remove empty strings from the list
	return filter(None, question)	
def solveProblem(question):
	#Split the question to parts.
	parts = splitProblem(question)
	print "answer:"
	result = parts[0]
	for i in range(1,len(parts)):
		#The depth is equal for both, just add after the first part
		if(depth(result) == depth(parts[i])):
			result += parts[i]
			continue
		#Left part depth is less than the right part depth - 
		#Absorb right
		if(depth(result) < depth(parts[i])):
			result = absorbRight(result,parts[i])
			continue
		#else, left part depth is more than the right part depth - 
		#Absorb left
		result = absorbLeft(result,parts[i])
	return result
if __name__ == "__main__":
	text = raw_input("Enter question: ")
	while(text != "exit"):
		print solveProblem(text)
		text = raw_input("Enter question: ")
*Comments speaks for themselves
So I print each question I got from the shell to the script, got the answer and print it back in the shell,and after 5 questions I got the key.
Flag
picoCTF{5cr1pt1nG_l1k3_4_pRo_45ca3f85}
