今年省赛比去年难度大点,用的安恒的平台,前2小时原地坐牢。体验了一波flag交不上,附件下不了。后期有了些体验感……有个吐槽点就是不能联网……unicorn的题一出我直接傻眼,本地没有头文件,根本不知道常量符号。
Rev
crackPYC
手工反编译字节码
翻译即可
# -*- coding:utf-8 -*- """ @Author: Mas0n @File: zjctf1.py @Time: 2021-10-23 12:38 @Desc: It's all about getting better. """ def keyinit(): num = 0 key = [] for i in range(8): num = (num - 7508399208111569251) % 4294967295 key.append((num >> 24)) print(key) return key str = "0" * 32 text = [108, 17, 42, 226, 158, 180, 96, 115, 64, 24, 38, 236, 179, 173, 34, 22, 81, 113, 38, 215, 165, 135, 68, 7, 119, 97, 45, 254, 250, 172, 43, 62] st = list(str) key = keyinit() for i in range(32): st[i] = ((text[i]) ^ key[i % len(key)]) print("".join([chr(i) for i in st])) print(st)
Triple Language
赛时没网,赛后复现吧……套娃unicorn题
也算是入门unicorn了
先看第一个sub_1400012B0
看到第一个约束条件
LOBYTE(v11) = raw[6] - raw[14]; BYTE1(v11) = raw[7] - raw[15]; BYTE2(v11) = raw[8] - raw[16]; BYTE3(v11) = raw[9] - raw[17]; BYTE4(v11) = raw[10] - raw[18]; BYTE5(v11) = raw[11] - raw[19]; BYTE6(v11) = raw[12] - raw[20]; HIBYTE(v11) = raw[13] - raw[21]; if ( v11 == 0x3EBB0EFAF301FCi64 ) ……
而后进入unicorn执行
简单分析以下各参数的常量
可以知道运行架构为MIPS X86
,dump下代码,放IDA,选择小端序
根据unicorn相关传参手动创建ROM
转换成代码后,逻辑还是很清楚的
其中t1~t6对应的是输入的前6个字节raw[0:6]
,byte_11000
则对应之前uc_mem_write
所加载的zjgcjy
进入hook回调verify1
,会发现其在对应地址获取t0~t6
寄存器的值并进行check
前六字节
# Part1 raw1 = [0] * 6 key = [ord(i) for i in "zjgcjy"] result = [0x2F2E, 0x282A, 0x2C42, 0x2A8A, 0x13E0, 0x36D4] for i in range(6): raw1[i] = result[i] // key[i] flag1 = "".join([chr(i) for i in raw1])
在MIPS代码执行完毕后,会取出t0~t
8寄存器的值进行check
结合上面得到的第一个约束条件,和MIPS汇编,求出之后的8字节
import z3 checkBox = [194, 195, 215, 196, 218, 165, 160, 0xBE] checkBox2 = list(int.to_bytes(0x3EBB0EFAF301FC, length=8, byteorder="little")) raw2 = [z3.BitVec(f"a{str(i)}", 8) for i in range(8)] raw3 = [z3.BitVec(f"b{str(i)}", 8) for i in range(8)] slo = z3.Solver() for i in range(8): slo.add(raw2[i] + raw3[i] == checkBox[i]) slo.add(raw2[i] - raw3[i] == checkBox2[i]) assert slo.check() == z3.sat rlt = slo.model() flag2 = "".join([chr(rlt.eval(i).as_long()) for i in raw2]) flag3 = "".join([chr(rlt.eval(i).as_long()) for i in raw3]) # print(flag1 + flag2 + flag3) # LOBYTE(v11) = raw[6] - raw[14]; # BYTE1(v11) = raw[7] - raw[15]; # BYTE2(v11) = raw[8] - raw[16]; # BYTE3(v11) = raw[9] - raw[17]; # BYTE4(v11) = raw[10] - raw[18]; # BYTE5(v11) = raw[11] - raw[19]; # BYTE6(v11) = raw[12] - raw[20]; # HIBYTE(v11) = raw[13] - raw[21]; # t1 == 194 && t2 == 195 && t3 == 215 && t4 == 196 && t5 == 218 && t6 == 165 && t7 == 160 && t8 == 0xBE
而后是第二部分sub_140001A90
首先校验了长度,而后进行check
代码如下
__int64 sub_1400019F0() { __int64 v0; // rcx unsigned int v1; // er8 char *i; // r9 char v3; // al char Destination[8]; // [rsp+20h] [rbp-28h] BYREF __int16 v6; // [rsp+28h] [rbp-20h] *(_QWORD *)Destination = 0i64; v6 = 0; strncpy(Destination, input, 4ui64); v0 = 0xFFFFFFFFFFFFFFFFui64; do ++v0; while ( Destination[v0] ); v1 = -1; for ( i = Destination; (_DWORD)v0; LODWORD(v0) = v0 - 1 ) { v3 = *i++; v1 = (v1 >> 8) ^ dword_1400034B0[(unsigned __int8)(v3 ^ v1)]; } return ~v1; }
这里首先能够想到爆破
# Part2 import string import itertools dword_1400034B0 = [0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, 0xD76AA478] table = string.digits + string.ascii_letters maps = itertools.product(table, table, table, table) flag4 = "" for m in maps: key = "".join(m) v1 = 0xffffffff for v3 in key: v1 = (v1 >> 8) ^ dword_1400034B0[(ord(v3) ^ v1) & 0xff] v1 &= 0xffffffff if ~v1 & 0xffffffff == 0xCAFABCBC: flag4 = key break # print(flag4)
后来想了想也可Z3
# Part2 import z3 dword_1400034B0 = [0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, 0xD76AA478] sol = z3.Solver() flag4 = [z3.BitVec(f"a{str(i)}", 8) for i in range(4)] mapping = z3.Array("mapping", z3.BitVecSort(32), z3.BitVecSort(32)) for i in range(len(dword_1400034B0)): sol.add(mapping[i] == dword_1400034B0[i]) # 太慢 # for i, v in enumerate(dword_1400034B0): # mapping = z3.Store(mapping, i, v) v1 = z3.BitVecVal(0xFFFFFFFF, 32) for i in range(4): idx = (z3.ZeroExt(24, flag4[i]) ^ v1) & 0xff v1 = z3.LShR(v1, 8) ^ mapping[idx] sol.add(~v1 & 0xffffffff == 0xCAFABCBC) assert sol.check() == z3.sat ros = sol.model() flag4 = "".join([chr(ros.eval(j).as_long()) for j in flag4]) print(flag4)
而后又是模拟执行
与之前相同,其架构为ARM X86
dump后放进IDA进行Rebase
这里可以创建多个节区,方便IDA分析
C转换为汇编后,选中所有代码,P创建函数
这里的135204
指向的是最后16个字节首地址
在对应地址创建变量char raw4[0x1d]
,按U和之前的办法重建函数
分析hook回调sub_140001680
显而易见是动态修改了密文
当代码运行完毕,取出R0
寄存器的值进行最终的判断
# Part3 import z3 key3 = list(b")8FP>6^B=G6@>X*P<G=B)1 ") key3[0] += 15 key3[1] ^= 0x6f key3[2] -= 12 key3[3] ^= 0x12 key3[4] -= 5 key3[5] += 33 key3[6] -= 12 key3[7] ^= 0xd key3[8] -= 3 key3[9] += 15 key3[10] ^= 0x68 key3[11] ^= 0xa key3[12] -= 5 key3[13] -= 33 key3[14] += 48 key3[15] ^= 0x18 key3[16] += 2 key3[17] -= 16 key3[18] ^= 0x1b key3[19] += 6 key3[20] ^= 0x13 flag5 = "" for i in range(0, len(key3), 4): sol = z3.Solver() if i < 5 * 4: raw4 = [z3.BitVec(f"a{str(j)}", 8) for j in range(3)] sol.add(((raw4[0] >> 2) + 33) == key3[i]) sol.add(((16 * raw4[0]) & 0x30 | (raw4[1] >> 4) & 0xff) + 33 == key3[i + 1]) sol.add(((4 * raw4[1]) & 0x3C | (raw4[2] >> 6) & 0xff) + 33 == key3[i + 2]) sol.add((raw4[2] & 0x3F) + 33 == key3[i + 3]) else: raw4 = [z3.BitVec(f"a{str(j)}", 8) for j in range(1)] sol.add((raw4[0] >> 2) + 33 == key3[i]) sol.add(((16 * raw4[0]) & 0x30) + 33 == key3[i+1]) assert sol.check() == z3.sat ros = sol.model() flag5 += "".join([chr(ros.eval(j).as_long()) for j in raw4 if isinstance(j, z3.BitVecRef)]) # print(flag5)
最终拼接,md5
print(flag1 + flag2 + flag3 + flag4 + flag5)
Crypto
EasyCrypto
给了ELF
没去符号……函数名就能知道是AES,魔改过
简单分析一下GenIV
生成的两个其实都指向同一个地址,所以key和iv相同
后面也能看到限制了输入文本不能包含admin
if ( std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::find(v54, "admin", 0LL) != -1 || (std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length(v54) & 0xF) != 0 ) { v11 = std::operator<<<std::char_traits<char>>(&std::cout, "no no no"); std::ostream::operator<<(v11, &std::endl<char,std::char_traits<char>>); exit(0); }
与后文解密后明文开头adminadmin
产生互斥
v38 = (unsigned int)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::compare( v54, "adminadmin") == 0; std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v54); if ( v38 ) { v39 = std::operator<<<char>(&std::cout, &flag[abi:cxx11]); std::ostream::operator<<(v39, &std::endl<char,std::char_traits<char>>); }
然而程序包含了encode
和decode
,由于是对称加密,直接nc拿到回显的AES IV
IDA调试,patch下iv
# -*- coding:utf-8 -*- """ @Author: Mas0n @File: ida_quick_script.py @Time: 2021-08-17 10:41 @Desc: It's all about getting better. """ addr = 0x055CAA9008300 # patch address test = "b949b7688a7ab3bc26862d161312831e" # patch hex data ps = [i for i in b''.fromhex(test)] for i, v in enumerate(ps): ida_bytes.patch_qword(addr+i * 8, v)
选择 1. register
,输入文本adminadmin
然后随机字符填充至16位(原因后面讲)
直接跳过包含admin
判断,执行encode(__int64 key, __int64 iv, __int64 cipher, int strlen)
进入正常流程
std::operator<<<std::char_traits<char>>(&std::cout, "Here is your token: "); for ( k = 0; ; ++k ) { v19 = k; if ( v19 >= std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length(v54) ) // 输入文本的长度 break; v20 = std::ostream::operator<<(&std::cout, std::hex); v21 = std::setfill<char>(48LL); v22 = std::operator<<<char,std::char_traits<char>>(v20, v21); v23 = std::setw(2); v24 = std::operator<<<char,std::char_traits<char>>(v22, v23); v25 = std::bitset<8ul>::to_ulong(8LL * k + v51); std::ostream::operator<<(v24, v25); } std::ostream::operator<<(&std::cout, &std::endl<char,std::char_traits<char>>); std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v54);
从中可以知道加密后的密文长度由输入文本长度决定,因此填充到16位,或者硬改循环16次
login提交
Easy Railfence
变种的W型栅栏密码,多了个偏移
标准W型栅栏脚本改下就行
# -*- coding:utf-8 -*- """ @Author: Mas0n @File: zjctf2.py @Time: 2021-10-23 13:42 @Desc: It's all about getting better. """ import hashlib import math def npmyG(string, n): '''将字符排列成w型''' array = [['.'] * len(string) for i in range(n)] row = 0 upflag = False for col in range(len(string)): array[row][col] = string[col] if row == n - 1: upflag = True if row == 0: upflag = False if upflag: row -= 1 else: row += 1 return array def decode(string, n): '''解密''' array = npmyG(string, n) sub = 0 for row in range(n): for col in range(len(string)): if array[row][col] != '.': array[row][col] = string[sub] sub += 1 msg = [] for col in range(len(string)): for row in range(n): if array[row][col] != '.': msg.append(array[row][col]) return msg def getArrs(c, rails, offset): c = '$' * offset + c length = len(c) result = {x: "" for x in range(rails)} for a in range(length): width = rails * 2 - 2 num = a % width # {0: '$g941d6', 1: '$a{1ffd4de049', 2: '$la0ec5daad1f}', 3: 'f44db28'} if (num < rails): result.update({num: result[num] + c[a]}) else: ll = 2 * rails - 2 - num result.update({ll: result[ll] + c[a]}) # d = "" arr = [] for k in range(rails): # d = d + result[k] arr.append(len(result[k])) # print(d) # d = d.replace('$', '') # print(result) return arr def encrypt(c,rails,offset): c = '$' * offset + c length = len(c) result = {x: "" for x in range(rails)} for a in range(length): width = rails * 2 - 2 num = a % width if (num < rails): result.update({num: result[num] + c[a]}) else: ll = 2 * rails - 2 - num result.update({ll: result[ll] + c[a]}) d = "" for k in range(rails): d = d + result[k] d = d.replace('$','') return d def decrypt(c, rails, offset, decarr): length = len(c) + offset rawWidth = math.ceil(len(c) / rails) result = {x: "" for x in range(rails)} for a in range(offset): num = a % rails result.update({num: result[num] + '$'}) arrs = [] for a in range(rails): arrs.append(c[a * rawWidth: (a + 1) * rawWidth]) # print(arrs) # print(result) data = "".join(arrs) index = 0 endArr = [] for k in result: tmp = decarr[k] - len(result[k]) endArr.append(result[k] + data[index:index+tmp]) index += tmp return "".join(endArr) m, Rail, Offset = "flag{a4019fe4cf4d5dd41dabaed0d21469019fe4cf4d51dabaed0d21469f8}", 13, 5 test = encrypt(m, Rail, Offset) decarrs = getArrs(m, Rail, Offset) # print(decrypt(test, Rail, Offset, decarrs)) d = "reetdrvhns0eutbftafmeon}linnd=a1cOh!gcedos{neuwkYav0irOceytounw" decrypt(d, Rail, Offset, decarrs) for rail in range(2, 20): for offset in range(20): decarrs = getArrs(m, rail, offset) string = decrypt(d, rail, offset, decarrs) flag = ''.join(decode(string, rail)).replace("$", "") if flag.startswith("flag") and flag.endswith("}"): print(flag) flag = hashlib.md5(flag.encode()).hexdigest() print(flag) exit()
发表回复