跳过正文
  1. Writeups/

SUCTF2025 Reverse

·606 字·3 分钟·
CTF Reverse
目录

BBRE
#

主函数先调用 function2, 只检验了flag的前16字节。从另一个角度来看,它也只加密了16字节。

但是输入的要求是 %19s,而且还有一个始终没被调用的 function1,怎么想都觉得有点奇怪吧。

此事在deepseek中亦有记载

su_bbre_ai

实际上是分段加密并检验。中间通过隐蔽的栈溢出来劫持返回地址,改变控制流。

分析 function0,其参数是经过 function2 加密后的字符串指针,内部调用包含漏洞的 strcpy 。简单分析一下栈帧,dstebp - 0x0c 的位置。

su_bbre_overflow

输入的16字节刚好覆盖完ebp,接下来4字节将覆盖返回地址。结合题目的各种暗示也能想到,这里应该返回到为调用的 function1,其地址 0x40223D 按小端序对应 ="@,刚好补齐19字节。

完整的调用流如下:

main
--function2		  //encrypt-and-check
----function5		// RC4 
------function3		// RC4 KSA
------function4		// RC4 PRGA
--function0
----(ret2)function1	// sub index

RC4解密,得到第一部分flag: We1com3ToReWorld="@

第二部分只需简单分析下 function1,逐字符与索引相减,写出逆运算求解:

data=[0x41,0x6D,0x62,0x4D,0x53,0x49,0x4E,0x29,0x28]
for i in range(len(data)):
    data[i]+=i
print(bytes(data))
#b'AndPWNT00'

mineswepper
#

sub_1277 对输入的字节重新编码,经过分析是通过 sub_122B 实现换表hex

su_minesweeper

abcdef0123456789

后面 sub_1432 是变种扫雷,给出每格以自身为中心3x3的雷数,用编码后的输入布雷。

感觉和算法题有点像,写一个z3脚本

from z3 import *
import hashlib

data = [
	0x03, 0x04, 0xFF, 0xFF, 0xFF, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x04, 0xFF, 0xFF, 0xFF, 
	0xFF, 0x02, 0xFF, 0xFF, 0x04, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x04, 0x06, 0x06, 0xFF, 0xFF, 0xFF, 
	0xFF, 0x06, 0x05, 0x06, 0x04, 0xFF, 0x05, 0xFF, 0x04, 0x07, 0xFF, 0x08, 0xFF, 0x06, 0xFF, 0xFF, 
	0x06, 0x06, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0x03, 0xFF, 0x05, 0x06, 0x06, 
	0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x05, 0x04, 0x05, 0x07, 0x06, 0xFF, 0xFF, 0x04, 0xFF, 0x02, 0x01, 
	0xFF, 0xFF, 0xFF, 0x03, 0x04, 0xFF, 0xFF, 0x05, 0x04, 0x03, 0xFF, 0xFF, 0x07, 0x04, 0x03, 0xFF, 
	0xFF, 0x01, 0x01, 0xFF, 0xFF, 0x04, 0x03, 0xFF, 0x02, 0xFF, 0x04, 0x03, 0xFF, 0xFF, 0x02, 0xFF, 
	0x05, 0x04, 0xFF, 0xFF, 0x02, 0x02, 0xFF, 0xFF, 0x04, 0xFF, 0x04, 0xFF, 0x03, 0x05, 0x06, 0xFF, 
	0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0x01, 0x04, 0xFF, 0xFF, 0x07, 0x05, 0xFF, 
	0xFF, 0x03, 0x03, 0x02, 0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0x05, 0x07, 0xFF, 0x03, 0x02, 0x04, 0x04, 
	0xFF, 0x07, 0x05, 0x04, 0x03, 0xFF, 0xFF, 0x04, 0xFF, 0x02, 0x04, 0x05, 0xFF, 0xFF, 0x06, 0x05, 
	0x04, 0xFF, 0x02, 0xFF, 0xFF, 0x07, 0x04, 0xFF, 0xFF, 0x03, 0xFF, 0x04, 0x04, 0xFF, 0xFF, 0xFF, 
	0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x03, 0x02, 0x02, 0xFF, 0xFF, 0x02, 0x04, 0x03, 0x05, 0xFF, 0xFF, 
	0x05, 0xFF, 0x04, 0xFF, 0x06, 0xFF, 0xFF, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0x04, 
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0xFF, 0x06, 0x06, 0xFF, 0x07, 0x06, 0x04, 0xFF, 0x04, 0x03, 
	0xFF, 0x04, 0x03, 0x05, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x06, 0x07, 0xFF, 
	0xFF, 0x04, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0x05, 0xFF, 0x05, 0xFF, 0xFF, 0x06, 0x07, 0x07, 0xFF, 
	0x05, 0x06, 0x06, 0xFF, 0xFF, 0x02, 0x04, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0xFF, 0xFF, 
	0x07, 0x07, 0x06, 0xFF, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0x03, 0x05, 0xFF, 0x07, 0xFF, 
	0x05, 0xFF, 0x06, 0xFF, 0x05, 0xFF, 0xFF, 0x07, 0x08, 0xFF, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0xFF, 
	0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x05, 0x03, 0xFF, 0x04, 
	0x05, 0x05, 0x03, 0xFF, 0xFF, 0x06, 0x05, 0x05, 0x06, 0xFF, 0x06, 0x05, 0x02, 0x04, 0x03, 0x04, 
	0xFF, 0xFF, 0x03, 0x04, 0x04, 0x06, 0x05, 0xFF, 0x03, 0xFF, 0x05, 0x05, 0x05, 0xFF, 0xFF, 0x05, 
	0xFF, 0xFF, 0x04, 0xFF, 0xFF, 0x04, 0xFF, 0x07, 0x07, 0x08, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 
	0xFF, 0xFF, 0xFF, 0x04, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x03]


minemap = [0 for count in range(400)]
s = Solver()
for i in range(20):
	for j in range(20):
		minemap[20*i+j] = Int("x{:0>2d}_{:0>2d}".format(i,j))
		s.add(minemap[20*i+j] >= 0)
		s.add(minemap[20*i+j] <= 1)


def getElement(i,j):
	if i>=0 and j>=0 and i<=19 and j<=19:
		return minemap[20*i+j]
	else:
		return 0
	
def addEq(i,j):
	eq = []
	for x in range(-1,2,1):
		for y in range(-1,2,1):
			eq.append(getElement(i+x,y+j))
	return sum(eq)
			
for i in range(20):
	for j in range(20):
		num = data[20*i+j]
		if num != 0xFF:
			s.add(addEq(i,j) == num)


if s.check() == sat:
	byte_map = []
	result = s.model()

	for count in range(400):
		minemap[count] = result[minemap[count]].as_binary_string()
	for i in range(0,400,8):
		
		byte_str = "".join(minemap[i:i+8])[::-1]
		byte = int(byte_str,2)
		byte_map.append(hex(byte)[2:].zfill(2))
			
	hex_table = "0123456789abcdef"
	new_table = "abcdef0123456789"
	trans = str.maketrans(hex_table,new_table)
		
	flag_input = "".join(byte_map)
	flag_input = flag_input.translate(trans)
	flag = hashlib.md5(flag_input.encode()).hexdigest()
		
	print(flag_input)
	print("SUCTF{" + flag + "}")

相关文章

DASCTF2024系列赛 Reverse
·1551 字·8 分钟
CTF Reverse
reverse writeup of DASCTF2024 series
第十七届CISCN初赛&华东北分区赛
·509 字·3 分钟
CTF AWDP Reverse Pwn
writeup and reproduction of 17th CISCN, reverse & pwn
LitCTF2024 Reverse
·163 字·1 分钟
CTF Reverse
reverse writeup of LitCTF(NSS) 2024