2024年NSSCTF秋季招新赛-Reverse
Reverse
又是签到!?
NSSCTF{mobile_is_so_easy}
怎么才能看见flag呢
NSSCTF{You_Can_Carry_This}
这也是py!?
v = [ord(i) for i in '~hojutfsfuoJ`pt`th^dcnbdsxAzESBRRM'][::-1]
for i in range(17):
v[33 - i] -= 1
v[i] += 1
print(bytes(v).decode())
# NSSCTF{Bytecode_is_so_Interesting}
不是,哥们,还有签到?
from ctypes import *
dll = cdll.LoadLibrary("./rand.dll")
csd = lambda x: dll.sd(x)
crd = lambda: dll.rd()
csd(0x1BF52)
v = [0x63, 0x5E, 0x4C, 0x5A, 0x52, 0x15, 0x4A, 0x5A, 0x0D, 0x16, 0x15, 0x12, 0x76, 0x7F, 0x01, 0x33, 0x2D, 0x35, 0x17, 0x7F, 0x61, 0x0F, 0x21, 0x64, 0x3C, 0x31, 0x01, 0x40, 0x20, 0x5C, 0x59,]
for i in range(len(v)):
v[i] ^= (crd() % 100 + i)
print(bytes(v).decode())
# NSSCTF{Re_Is_Really_Too_Simple}
签到?
v = [0x00000020, 0x00000027, 0x00000026, 0x00000025, 0x0000002C, 0x0000002D, 0x0000000F, 0x00000022, 0x00000014, 0x0000001E, 0x00000021, 0x00000018, 0x00000009, 0x000000DF, 0x000000C8, 0x0000001C, 0x000000E7, 0x00000005, 0x000000E5, 0x000000E2, 0x000000EE, 0x0000001A, 0x000000E6, 0x00000004, 0x000000D9, 0x000000C9, 0x000000E3, 0x0000000A, 0x000000F5, 0x000000F1, 0x000000F8, 0x000000F3, 0x000000FA, 0x000000EA, 0x000000FF, 0x000000E7, 0x000000F5, 0x000000B9, 0x000000E4]
k = [0x00000068, 0x00000075, 0x00000075, 0x00000065, 0x00000072, 0x00000060,]
k = [(i^6) for i in k]
for i in range(len(v)):
v[i] ^= (k[i%6] + i)
print(bytes(v).decode())
# NSSCTF{Xor_is_Incredibly_Entertaining!}
flower?
自己手搓即可
NSSCTF{T9is_F1ow5r_is_Very_Be4u6if9l}
好像也是py?
def simple_add_sub_reverse(text, shift=3):
return ''.join(chr(ord(c) - shift) if c.isalpha() else c for c in text)
def case(text):
return text.swapcase()
v = 'RGtAXV59UXtqTWVbUVd4aWs='
key = b'114514'
v = base64.b64decode(v.encode()).decode()
tmp = simple_add_sub_reverse(v)
tmp = case(tmp)
enc = [ord(i) for i in tmp]
for i in range(len(enc)):
enc[i] ^= key[i % len(key)]
print(bytes(enc).decode())
# NSSCTF{PythoI_Js_so_Easy}
动态调试
两轮init,直接输入等长flag,改v2 -> v1即可,访问v1得到flag
NSSCTF{0d6f90ac-4b5e-4efb-8502-6349cf798f2e}
这来做点数学题吧
from z3 import *
v1 = [Int('v1[%d]' % i) for i in range(21)]
s = Solver()
s.add(v1[1] == 83,
v1[4] + 32 * v1[3] + 43 * v1[2] + 81 * v1[0] + 35 * v1[5] == 14565
, 23 * v1[4] + 13 * v1[5] + 78 * v1[6] == 12436
, 19 * v1[15]
+ 10 * v1[14]
+ 17 * v1[13]
+ 15 * v1[12]
+ 12 * v1[10]
+ v1[9] / 4
+ v1[7]
+ 32 * v1[6]
+ 23 * v1[8]
+ 10 * v1[16] == 12539
, 23 * v1[20]
+ 54 * v1[19]
+ 32 * v1[18]
+ 119 * v1[15]
+ 121 * v1[14]
+ 20 * v1[13]
+ 130 * v1[16]
+ 12 * v1[17]
+ 213 * v1[10] == 65168
, 1412 * v1[12]
+ 139 * v1[16]
+ 199 * v1[7]
+ 324 * v1[14]
+ 165 * v1[12]
+ 19 * v1[11]
+ 193 * v1[6]
+ 144 * v1[5]
+ 143 * v1[20] == 267159
, 867 * v1[13]
+ 654 * v1[11]
+ 678 * v1[9]
+ 175 * v1[7]
+ 45 * v1[5]
+ 21 * v1[1]
+ 13 * v1[3]
+ 100 * v1[15]
+ 24 * v1[17] == 244923
, 54 * v1[12]
+ 55 * v1[20]
+ 119 * v1[17]
+ 121 * v1[16]
+ 20 * v1[3]
+ 130 * v1[18]
+ 12 * v1[19]
+ 213 * v1[12] == 69874
, v1[7] == 90
, v1[20] == 125
, 233 * v1[10] + 134 * v1[2] + 378 * v1[4] + 133 * v1[9] + 178 * v1[6] + 443 * v1[5] + 11 * v1[1] + 543 * v1[11] == 188780
, 194 * v1[16]
+ 643 * v1[15]
+ 131 * v1[14]
+ 131 * v1[12]
+ 21 * v1[13]
+ 204 * v1[17]
+ 24 * v1[18]
+ 214 * v1[19] == 151642
, 123 * v1[18]
+ 25 * v1[16]
+ 124 * v1[13]
+ 37 * v1[14]
+ 7457 * v1[15]
+ 129 * v1[17]
+ 164 * v1[19]
+ 10 * v1[20] == 772291
, 132 * v1[16]
+ 807 * v1[15]
+ 756 * v1[14]
+ 163 * v1[13]
+ 633 * v1[12]
+ 423 * v1[11]
+ 42 * v1[10]
+ 534 * v1[17] == 346862
, 867 * v1[18]
+ 5956 * v1[13]
+ 204 * v1[12]
+ 374 * v1[10]
+ 47 * v1[9]
+ 485 * v1[15]
+ 37 * v1[16]
+ 375 * v1[20] == 740703
, 37 * v1[12]
+ 35 * v1[19]
+ 856 * v1[18]
+ 375 * v1[17]
+ 3578 * v1[16]
+ 567 * v1[3]
+ 55 * v1[20]
+ 21 * v1[4] == 436075
, 59 * v1[7] + 52 * v1[2] + 102 * v1[3] + 24 * v1[4] + 204 * v1[5] + 13 * v1[6] + 54 * v1[8] + 13 * v1[9] == 38344
, 98 * v1[7] + 85 * v1[6] + 13 * v1[4] + 19 * v1[3] + 12 * v1[1] + 166 * v1[2] + 25 * v1[5] + 23 * v1[8] == 39337
, 52 * v1[0] + 45 * v1[1] + 19 * v1[7] + 76 * v1[20] + 12 * v1[15] == 20141
, 56 * v1[1] + 34 * v1[0] + 75 * v1[7] + 80 * v1[20] + 16 * v1[15] + 19 * v1[12] == 27375
, 54 * v1[12] + 76 * v1[7] + 87 * v1[1] + 54 * v1[0] + 16 * v1[20] + 18 * v1[15] + 39 * v1[18] == 31598)
if s.check() == sat:
m = s.model()
for i in range(21):
print(chr(m[v1[i]].as_long()), end='')
# NSSCTF{Z3_Is_So_Easy}
web
v = ''
KEY = 0x4c494e
flag = 'NSSCTF{'
k = (KEY >> 7) | (KEY << 5)
for i in range(len(v) // 16):
num = int(v[i * 16:i * 16 + 16], 16)
num ^= k
num ^= KEY
flag += libnum.n2s(num).decode()
print(flag)
Reverse_or_Pwn
v = [0x0000007A, 0x00000065, 0x00000077, 0x00000064, 0x0000005C, 0x00000026, 0x0000005F, 0x0000005D, 0x00000013, 0x00000024, 0x00000020, 0x00000032, 0x0000006C, 0x00000057, 0x00000032, 0x0000007B]
k = [0x0000002E, 0x0000000D, 0x0000001E, 0x00000017, 0x00000003, 0x0000004F, 0x0000002C, 0x00000002, 0x00000061, 0x00000041, 0x00000053, 0x00000057, 0x0000001E, 0x00000021, 0x00000057, 0x00000044]
for i in range(len(v)):
v[i] ^= k[i]
print(bytes(v).decode())
# This_is_reserve?
这里有个知识点,This_is_reserve?长度为16 = 0xc+4,也就是说,在后边再次添加字符的话会修改返回地址,控制程序流走向,找到我们要返回的地址00402463,转为字符串则为c$@,结果没过,恼火
想想打栈溢出的时候出现栈平衡,向下挪一,00402464,转为字符串则为d$@,过了(32位栈平衡,没必要吧哥)
def fun(a, b):
return (a + 0x1BF52 + 16 * b - 66) & 0xffffffff
for v9 in range(0xffffffff):
v16 = v9 // 10000
v15 = v9 % 10000 // 100
v14 = v9 % 10000 % 100
v13 = fun(5 * v15, 1)
v12 = fun(v9, 11 * (v15 + v14 - 3))
v11 = v12 - 16 * v16 + v14 * v13
if (v12 & 1) != 0 or v13 <= 99 or v16 <= 999 or v15 <= 9 or v14 > 9 or (
v12 - 16 * v16 + v14 * v13) & 0xffffffff != 21241824:
continue
else:
print(v9)
break
# 20241008
alp = [
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
'+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
'6789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345',
'0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
'stuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr',
][::-1]
v = '+/1k6wlc+QFy5zN1+BVC3gVDKwx25zMd/CxU+glG4A925QVd+QRY4AQjBQF6+QFW+/J2GB5FASpuIvwb/Clu9AR1KwByCRRW/Qch+ANO+DM='
for i in range(len(alp)):
model = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
v = (base64.b64decode(v.translate(str.maketrans(alp[i], model))).decode())
print(v)
# Pwn_and_base_is_so_Easy!
NSSCTF{This_is_reserve?d$@Pwn_and_base_is_so_Easy!}
NSS茶馆!
from ctypes import *
from libnum import *
def decrypt(v, k):
v0 = c_uint32(v[0])
v1 = c_uint32(v[1])
delta = 0x114514
sum1 = c_uint32(delta * 33)
for i in range(33):
v1.value -= ((v0.value << 4) + k[2]) ^ (v0.value + sum1.value) ^ ((v0.value >> 5) + k[3])
v0.value -= ((v1.value << 4) + k[0]) ^ (v1.value + sum1.value) ^ ((v1.value >> 5) + k[1])
sum1.value -= delta
return v0.value, v1.value
flag = []
enc = [0x3A26D265, 0x81D9A0B6, 0x0E5E002A, 0x3907EFE5, 0x71B6BC57, 0xE0AC0DA2]
key = [0x0000000B, 0x00000016, 0x00000021, 0x0000002C]
for i in range(len(enc)//2):
res = decrypt(enc[i * 2:i * 2 + 2], key)
for j in res:
flag += n2s(j).decode()
print(''.join(flag))
print()
# NSSCTF{tea_is_so_easy!!}
md5也能爆破?
这道题主要实现了分块md5(改)加密,除了第一次是正常的md5加密外,其他会因为参数a1的值而改变
我的第一想法是使用idapython实现爆破过程
由于第一块是没有改的,也就是正常的md5加密,那么就可以通过md5解密得到结果
'7fb8ceb3bd59c7956b1df66729296a4c' : 1485
# 基于运行了一次,也就是已经过了第一块加密 :1485
ansflag = ''
# 保留上一次加密所用的参数
ea = 0x001A5A00
ori = [get_wide_byte(ea+i) for i in range(24)]
# 开始尝试
part_add = ea + 0x18
for i in string.printable:
patch_byte(part_add,ord(i))
for ii in string.printable:
patch_byte(part_add+1,ord(ii))
for iii in string.printable:
patch_byte(part_add+2,ord(iii))
for iiii in string.printable:
patch_byte(part_add+3,ord(iiii))
# 模拟F8
step_over()
# 获取加密后的结果32字符
ans_add = 0x001A5944
ans = [get_wide_byte(ans_add+i) for i in range(16)]
flag = ''
for i in ans:
tmp = hex(i)[2:].zfill(2)
flag += tmp
# print(flag)
# 比较结果
v = [
'7fb8ceb3bd59c7956b1df66729296a4c',
'f182395ed4eaa34bf53fa0507e124c28',
'1c2aaf4995574c11dbd2c79024d7df08',
'd5945e772e2715ae12ff75818fb0477e',
'c3c3dab8e8f8eda9c62ae676cff5b6b9',
'75cd9e91d1f4ad1bf88a964f69078d93',
'7bc0d87c4ee78bafa9fea6aba4215b89',
'c68bfbb9f793b6eeee2b985ffce1e634',
'344d233437cc2ff5f6d9f363ca54d81b',
'df8b095635311f27e22110085eaff244',
]
if flag in v:
# 获取正确的密文
for i in range(4):
ansflag += chr(get_wide_byte(part_add+i))
# 程序运行直到下一次断点 模拟F9
continue_process()
else:
# 控制EIP回到加密程序
EIP = 0x00198A17
set_reg_value(EIP,"EIP")
# 还原上一次匹配成功的参数
for i in range(24):
patch_byte(ea+i,ori[i])
可惜可能是由于IDA的问题,这个方法实现不了,每一次输出的值都是上一次成功的值,不知道是哪里的问题。
将输出错误的提示,改成输出结果
直接实现爆破脚本
v = [
'7fb8ceb3bd59c7956b1df66729296a4c',
'f182395ed4eaa34bf53fa0507e124c28',
'1c2aaf4995574c11dbd2c79024d7df08',
'd5945e772e2715ae12ff75818fb0477e',
'c3c3dab8e8f8eda9c62ae676cff5b6b9',
'75cd9e91d1f4ad1bf88a964f69078d93',
'7bc0d87c4ee78bafa9fea6aba4215b89',
'c68bfbb9f793b6eeee2b985ffce1e634',
'344d233437cc2ff5f6d9f363ca54d81b',
'df8b095635311f27e22110085eaff244',
]
input_data = "1485{tuFnYbckFWarUpPYUdXGlhOOIaPMeVsxKQ}"
num_segments = len(input_data) // 4
flag = '1485'
for i in range(1, num_segments):
for chars in itertools.product(string.digits, repeat=4):
modified_data = (input_data[:i * 4] + ''.join(chars) + input_data[(i + 1) * 4:])
exe_file_path = r"" #File directory
process = subprocess.Popen(
exe_file_path,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
stdout, stderr = process.communicate(input=modified_data)
flag_prompt = "plz input your flag:"
output_after_flag_prompt = stdout.split(flag_prompt, 1)[-1].strip() if flag_prompt in stdout else ""
ans = output_after_flag_prompt[i * 32:(i + 1) * 32]
if v[i] == ans:
flag += ''.join(chars)
print(f"[!] Updated flag: {flag}")
input_data = modified_data
break
else:
continue
# 1485059684930231436754585566745634684261
0 条评论
可输入 255 字