defescape_html(text): """Escapes HTML special characters in the given text.""" return text.replace("&", "&").replace("<", "<").replace(">", ">").replace("(", "(").replace(")", ")")
defrender_page(name_to_display=None): """Renders the HTML page with the given name.""" templ = html_template.replace("NAME", escape_html(name_to_display or"")) template = Template(templ, lookup=lookup) return template.render(name_to_display=name_to_display, banned="&<>()")
# Parse the path and extract query parameters parsed_url = urlparse(self.path) params = parse_qs(parsed_url.query) name = params.get("name_input", [""])[0] for b in banned: if b in name: name = "Banned characters detected!" print(b)
# Render and return the page self.send_response(200) self.send_header("Content-Type", "text/html") self.end_headers() self.wfile.write(render_page(name_to_display=name).encode("utf-8"))
One fine evening, A had an important mission: pass a bunch of
critical configurations to his good friend B.
These configs were patterns—very serious, technical things—based on
segments over a neat little 3×3 grid.
But there was a problem. B was wasted. Like, “talking to the couch
and thinking it’s a microwave” level drunk. So when A carefully handed
over each configuration, B took one look at it, said, “Whoa, cool spinny
lines!”—and rotated it randomly. Then, to add insult to intoxication, he
shuffled the order of all the patterns. Absolute chaos.
Now A has a challenge: figure out which drunkenly-distorted pattern
maps back to which original configuration. If he gets it all right, B
promises (in slurred speech) to give him something very important: the
flag.
SEGMENTS = [] for i inrange(len(POINTS)): for j inrange(i+1, len(POINTS)): a, b = POINTS[i], POINTS[j] if valid_segment(a, b): A, B = sorted([a, b]) SEGMENTS.append((A, B)) SEG_INDEX = {SEGMENTS[i]: i for i inrange(len(SEGMENTS))}
defrot_point(p, k): x, y = p x0, y0 = x - 1, y - 1 for _ inrange(k % 4): x0, y0 = -y0, x0 return (x0 + 1, y0 + 1)
defrot_segment(seg, k): a, b = seg ra, rb = rot_point(a, k), rot_point(b, k) A, B = sorted([ra, rb]) return (A, B)
defcanon_bits(segs): vals = [] for k inrange(4): bits = 0 for (a, b) in segs: A, B = sorted([a, b]) rs = rot_segment((A, B), k) bits |= (1 << SEG_INDEX[rs]) vals.append(bits) returnmin(vals)
classChallengeClient: def__init__(self, host, port): self.host = host self.port = port self.sock = None self.canon_to_n = {} # 存储规范形式到N的映射 defconnect(self): """建立SSL连接""" context = ssl.create_default_context() sock = socket.create_connection((self.host, self.port)) self.sock = context.wrap_socket(sock, server_hostname=self.host) print(f"Connected to {self.host}:{self.port}") defread_line(self): """读取一行数据""" line = b"" whileTrue: char = self.sock.recv(1) if char == b"\n"ornot char: break line += char return line.decode().strip() defsend_line(self, message): """发送一行数据""" self.sock.sendall((str(message) + "\n").encode()) defphase1(self): """处理第一阶段:注册模式""" print("Starting Phase 1...") question_count = 0 whileTrue: # 读取下一行 line = self.read_line() # print(f"Received: {line}") # 检查是否是 Phase 2 开始 if line == "=== Phase 2 ===": print("Phase 2 detected!") returnTrue, question_count # 检查是否是 N 值 if line.startswith("N_"): try: # 解析 N 值 parts = line.split(":") n_value = int(parts[1].strip()) question_count += 1 # print(f"Processing {parts[0]}: {n_value}") # 创建模式:使用N的二进制位来选择线段 pattern = [] for seg_index inrange(len(SEGMENTS)): if n_value & (1 << seg_index): pattern.append(SEGMENTS[seg_index]) # 发送模式 self.send_line(len(pattern)) # 线段数量 # print(f"Send: {len(pattern)}: ",end="") for seg in pattern: a, b = seg self.send_line(f"{a[0]}{a[1]}{b[0]}{b[1]}") # print((f"{a[0]} {a[1]} {b[0]} {b[1]}")) # 读取服务器响应 response = self.read_line() # print(f"Server response: {response}") if response != "OK": if"Error"in response: print(f"Error response: {response}") returnFalse, question_count # 可能是一些警告信息,继续处理 # 存储映射关系 canon = canon_bits(pattern) self.canon_to_n[canon] = n_value except Exception as e: print(f"Error processing N value: {e}") returnFalse, question_count else: # 可能是其他消息,继续读取 print(f"Unexpected message in Phase 1: {line}") continue returnTrue, question_count defphase2(self, total_questions): """处理第二阶段:识别模式""" print("Starting Phase 2...") print(f"Total questions in Phase 2: {total_questions}") correct_count = 0 for i inrange(total_questions): # print(f"Processing question {i+1}/{total_questions}") # 读取突变模式 header = self.read_line() if header != "MutatedPattern:": print(f"Unexpected header: {header}") # 尝试继续读取,可能是错误消息 continue # 读取线段数量 seg_count_line = self.read_line() try: seg_count = int(seg_count_line) except: print(f"Invalid segment count: {seg_count_line}") returnFalse, correct_count pattern = [] # 读取所有线段 for j inrange(seg_count): line = self.read_line() try: x1, y1, x2, y2 = map(int, line.split()) pattern.append(((x1, y1), (x2, y2))) except: print(f"Invalid segment data: {line}") returnFalse, correct_count # 读取提示 prompt = self.read_line() if prompt != "Your answer for N?": print(f"Unexpected prompt: {prompt}") # 尝试继续 pass # 计算规范形式并查找对应的N try: canon = canon_bits(pattern) if canon in self.canon_to_n: answer = self.canon_to_n[canon] self.send_line(answer) # 检查答案 response = self.read_line() # print(f"Question {i+1} response: {response}") if response.startswith("OK"): correct_count += 1 elif response.startswith("Wrong"): # 继续处理下一个问题 pass else: print(f"Question {i+1}: Canonical form not found!") # 发送一个猜测值 self.send_line(1) response = self.read_line() print(f"Guess response: {response}") except Exception as e: print(f"Error processing question {i+1}: {e}") # 发送默认答案并继续 self.send_line(1) response = self.read_line() print(f"Phase 2 completed: {correct_count}/{total_questions} correct") returnTrue, correct_count defget_flag(self): """获取flag""" print("Waiting for flag...") flag = None try: whileTrue: line = self.read_line() ifnot line: break print(f"Final: {line}") if"TFCCTF{"in line: flag = line break except: pass return flag defrun(self): """运行完整挑战""" try: self.connect() # 读取欢迎信息 welcome = self.read_line() print(f"Welcome: {welcome}") # Phase 1 success, question_count = self.phase1() ifnot success: print("Phase 1 failed") return print(f"Phase 1 completed with {question_count} questions") # Phase 2 success, correct_count = self.phase2(question_count) # 获取结果 flag = self.get_flag() if flag: print(f"🎉 Flag found: {flag}") else: print(f"❌ No flag received. Correct: {correct_count}/{question_count}") except Exception as e: print(f"Error: {e}") import traceback traceback.print_exc() finally: if self.sock: self.sock.close()
The announcement shenanigans are in play again. As a small hint,
maybe bulking up on the nothingness was the best way to hide it. ;) Go
get your shovels ready!
Leave the photos alone, man! The flag is not there.
s = "0101010001000110010000110100001101010100010001100111101101101000011010010110010001100100011001010110111001011111011100110110100001100101011011100110000101101110011010010110011101100001011011100111001101111101"
for i inrange(0, len(s),8): print(chr(int(s[i:i+8],2)),end="")
去https://armconverter.com/里面把b.ne改成b.eq,复制修改后的hex(E0 07 00 54 AA 64 84 D2 E8 A7 43 A9 4A 84 B0 F2)粘贴到patch中,点击ok,然后选择Edit -> Patch Program -> Apply patch to input file,这样就得到了一个修改后的so文件。
使用apktool工具解包apktool d app-release.apk,替换里面的liboxi.so后打包apktool b app-release,注意如果电脑用户名有中文大概率会打包失败这时候就要用到
-p参数(具体可以参考这个https://blog.csdn.net/m0_63944500/article/details/133802708),然后去对齐并签名,我这里用android studio的工具