ez_cython

from regadgets import *
ans = [4108944556, 3404732701, 1466956825, 788072761, 1482427973, 782926647, 
       1635740553, 4115935911, 2820454423, 3206473923, 1700989382, 2460803532,
       2399057278, 968884411, 1298467094, 1786305447, 3953508515, 2466099443,
       4105559714, 779131097, 288224004, 3322844775, 4122289132, 2089726849, 
       656452727, 3096682206, 2217255962, 680183044, 3394288893, 697481839, 
       1109578150, 2272036063]

def xxtea_sctf2024_shift(z, y, sum, k, p, debug = False):
    e = (sum.value >> 3) & 3
    PE = (p & 2) ^ e
    Ly = y.value << 3
    Ry = y.value >> 4
    Lz = z.value << 2
    Rz = z.value >> 3 

    LzRy = Rz ^ Ly
    LyRz = Ry ^ Lz
    SY = sum.value ^ y.value
    K = k[PE].value
    KZ = K ^ z.value
    result = (LzRy + LyRz) ^ (KZ + SY)
    return result
        
key = [0x53, 0x79, 0x43, 0x31] # Syc1

dec = xxtea_decrypt(ans, key, delta=0x9e3779b9, round_base=4, round_addi=60, shift_func=xxtea_sctf2024_shift)
print(bytes(dec))
# b'SCTF{w0w_y0U_wE1_kNOw_of_cYtH0N}'

BBox

Android
超绝一键apk混淆捏

const char *__fastcall Java_com_example_bbandroid_MainActivity_checkFlag(_JNIEnv *a1, __int64 a2, __int64 a3)
{
  time_t v5; // w22
  const char *result; // x0
  const char *v7; // x21
  unsigned int v8; // w23
  signed int v9; // w22
  __int64 v10; // x19
  __int64 v11; // x20
  char *v12; // x22
  char v13; // w0
  int v14; // w9
  signed int v15; // w8
  unsigned __int64 v16; // x10
  unsigned __int64 v17; // x11
  int v18; // w12
  int v19; // w13
  char flag[256]; // [xsp+8h] [xbp-108h] BYREF
  __int64 v21; // [xsp+108h] [xbp-8h]

  v21 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  v5 = time(0LL);
  result = (const char *)((__int64 (__fastcall *)(_JNIEnv *, __int64, _QWORD))a1->functions->GetStringUTFChars)(
                           a1,
                           a3,
                           0LL);
  if ( result )
  {
    v7 = result;
    v8 = v5 / 1000000 / 100;
    strncpy(flag, result, 0xFFu);
    flag[255] = 0;
    v9 = __strlen_chk(flag, 0x100u);
    ((void (__fastcall *)(_JNIEnv *, __int64, const char *))a1->functions->ReleaseStringUTFChars)(a1, a3, v7);
    srand(v8);
    if ( v9 >= 4 )
    {
      v10 = 0LL;
      v11 = (unsigned int)v9 >> 2;
      do
      {
        v12 = &flag[4 * v10];
        *v12 ^= rand();
        v12[1] ^= rand();
        v12[2] ^= rand();
        v13 = rand();
        v14 = 32;
        v12[3] ^= v13;
        v15 = *(_DWORD *)v12;
        do
        {
          if ( v15 >= 0 )
            v15 *= 2;
          else
            v15 = (2 * v15) ^ 0x85B6874F;
          --v14;
        }
        while ( v14 );
        *(_DWORD *)&flag[4 * v10++] = v15;
      }
      while ( v10 != v11 );
    }
    if ( flag[0] == '3' )
    {
      v16 = 0LL;
      do
      {
        v17 = v16;
        if ( v16 == 0x27 )
          break;
        v18 = (unsigned __int8)flag[v16 + 1];
        v19 = dword_B14[++v16];
      }
      while ( v18 == v19 );
      return (const char *)(v17 > 0x26);
    }
    else
    {
      return 0LL;
    }
  }
  return result;
}

Exp

from regadgets import *
from z3 import *
from copy import deepcopy
enc =  [0x33, 0xC0, 0xC8, 0xA3, 0xF3, 0xBF, 0x1D, 0x1A, 0x3B, 0x41, 
  0xB7, 0xC6, 0xF1, 0x5E, 0x86, 0x52, 0x52, 0xCF, 0x6B, 0x1E, 
  0xC5, 0xF9, 0xCB, 0xBF, 0xED, 0x7B, 0x62, 0xF1, 0xF7, 0x43, 
  0x48, 0x54, 0xFB, 0x85, 0x4C, 0xD9, 0x35, 0x30, 0xF2, 0x6E]
print(bytes(enc))
dw = byte2dword(enc)

print(dw)
s = Solver()
x = [BitVec(f"x{i}", 32) for i in range(len(dw))]
y = deepcopy(x)
for i in range(len(dw)):
    for j in range(32):
        x[i] = If(LShR(x[i], 31) == 1, 2*x[i] ^ 0x85b6874f, 2*x[i])
    s.add(x[i] == dw[i])
print(s.check())
m = s.model()
r = []
for i in y:
    r.append(m[i].as_long())
print(r)
randv = [0x49308bb9,0x3cb3ad,0xfb4e87f,0x75655103,0x6d505b9f,0x1d20580f,
         0xdcf4af1,0x3e381967,0x54bcf579,0x73c09db7,0x501b2039,0x1b8950dd,
         0x23e73393,0x2b480a88,0x6818cdae,0x61d009ea,0x44c0c5b0,0x385aff3d,
         0x5cfb2a7a,0x587f9c07,0x158172f2,0x4d334c89,0x302b76e5,0x5e17f434,
         0x692de923,0x806d155,0x3d2c61d8,0x1d09ef4e,0x7c3d83b7,0x1d7621da,
         0x2dc0a3ec,0x456e0f71,0x1db2d588,0x3d758c6c,0x3ad36074,0xb033127,0x5a95e47b,0x48a2ab65,0x493b4a8e,0x2f52d9f5 ]
randv = [i & 0xff for i in randv]

v1 = bxor(dword2byte(r)[:len(enc)], bytes(randv)[:len(enc)])
v2 = bxor_cycle(v1, b'\x1e').decode()
print(decode_b64(v2, "nopqrstDEFGHIJKLhijklUVQRST/WXYZabABCcdefgmuv6789+wxyz012345MNOP"))
# b'Y0u_@re_r1ght_r3ver53_is_easy!'

其中 randv 是通过hook得到的rand()的结果。中间是一个不安全的CRC。

easyMCU

我自认为这是一个逆向题目,所以把它放到了Reverse下。
首先,使用010Editor,打开mcu.s19,发现它直接自动给我转hex了,我们Ctrl+S保存到文件即可。
隔壁队伍使用的是bincopy convert mcu.s19 -o binary out.bin进行的转换,也是一种方法。

通过图片中的TriCore,我们可以知道固件是Tri
经过翻找,我们找到关键代码


/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */

undefined4 FUN_80000690(void)

{
  byte bVar1;
  bool bVar2;
  uint uVar3;
  undefined4 uVar4;
  int i;
  
  bVar2 = FUN_8000125a(0x6000009c,(undefined *)0x60000004,(short *)0x60000000,_DAT_80003990,
                       iRam80003994);
  if (bVar2) {
    AES_ENCRYPT(0x60000004,-0x7fffc65d,0x6000007c,0x20);
    for (i = 0; i < 0x20; i += 1) {
      uVar3 = rol((uint)*(byte *)(i + 0x6000007c),3);
      *(char *)(i + 0x6000007c) = (char)uVar3;
      bVar1 = bRam6000007c;
      if (i < 0x1f) {
        bVar1 = *(byte *)(i + 0x6000007d);
      }
      *(byte *)(i + 0x6000007c) = bVar1 ^ *(byte *)(i + 0x6000007c);
      *(byte *)(i + 0x6000007c) = *(byte *)(i + 0x6000007c) ^ 0xff;
    }
    FUN_80001278((int *)0x6000009c,(undefined *)0x6000007c,(short *)0x60000000,_DAT_80003990,
                 iRam80003994);
    uVar4 = 0;
  }
  else {
    uVar4 = 0xffffffff;
  }
  return uVar4;
}


void AES_ENCRYPT(int param_1,int param_2,int param_3,uint param_4)

{
  uint uVar1;
  undefined8 auStack_c0 [2];
  undefined key [176];
  
  FUN_800002b0(param_2,(int)key);
  for (uVar1 = 0; uVar1 < param_4; uVar1 += 0x10) {
    FUN_80003782(auStack_c0,(undefined8 *)(param_1 + uVar1),0x10);
    aes((int)auStack_c0,(int)key);
    FUN_80003782((undefined8 *)(param_3 + uVar1),auStack_c0,0x10);
  }
  return;
}


void AES_ENCRYPT(int param_1,int param_2,int param_3,uint param_4)

{
  uint uVar1;
  undefined8 auStack_c0 [2];
  undefined key [176];
  
  FUN_800002b0(param_2,(int)key);
  for (uVar1 = 0; uVar1 < param_4; uVar1 += 0x10) {
    FUN_80003782(auStack_c0,(undefined8 *)(param_1 + uVar1),0x10);
    aes((int)auStack_c0,(int)key);
    FUN_80003782((undefined8 *)(param_3 + uVar1),auStack_c0,0x10);
  }
  return;
}

写出EXP。

from regadgets import *
enc = bytes.fromhex('63 D4 DD 72 B0 8C AE 31 8C 33 03 22 03 1C E4 D3 C3 E3 54 B2 1D EB EB 9D 45 B1 BE 86 CD E9 93 D8')
print(len(enc))
key = [ 0x2e, 0x35, 0x7d, 0x6a, 0xed, 0x44, 0xf3, 0x4d, 0xad, 0xb9, 0x11, 0x34, 0x13, 0xea, 0x32, 0x4e ]
enc = list(enc)
for i in range(len(enc)):
    enc[31-i] ^= 0xff
    enc[31-i] ^= enc[(32-i) % 32]
    enc[31-i] = ror8(enc[31-i], 3)

aes = AES(key)
dec = aes.decrypt_ecb_block(enc[:16]) + aes.decrypt_ecb_block(enc[16:])
print(dec) # b'SCTF{Wlc_t0_the_wd_oF_IOT_s3cur}'

Reverse

Simple_encryption

enc = list(bytes.fromhex("47953448A41C358864168807146A3912A20A375C075A5660127625128E28"))
for i in range(len(enc)):
    if i % 3 == 2:
        enc[i] ^= 0x55
    if i % 3 == 1:
        enc[i] -= 41
    if i % 3 == 0:
        enc[i] += 31

print(bytes(enc))

ez_debug

调试后直接把enc抄出来,用CyberChef xor 0x17然后再xor_cycle ATRI
flag{y0u_ar3_g0od_@_Debu9}

ezAndroidStudy

按照题目里面的提示慢慢找就行,很有趣的一个题。

drink_TEA

标准TEA,找到key和delta即可。

Ptrace

father程序的这里修改了son程序进行ROR8的参数(4->3),我是直接全部都爆破了一遍,就看到3解出来了。
2024-10-06T18:07:50.png
顺便:
2024-10-07T09:22:07.png

ezencrypt

android题,native里面有个rc4和xor,然后可以解密出来base64(aes加密后的),然后在java里面找decrypt,开一个idea,然后运行一下就秒了。

PangBai 泰拉记(1)

密文异或了两部分,有个反调试,不看反调试检测出来后的逻辑(看下面的else for)

Dirty_flowers

直接看汇编,循环异或dirty_flower,然后随便翻一下找到密文对比
2024-10-06T18:11:42.png
抄出来解密就行

后面没写了,找个时间补上

ez_rust

x64dbg开调,搜that's,找到一块
spatchEvent(new Event("input")))}const ln=Symbol("_assign"),zi={created(e,{modifiers:{lazy:t,trim:n,number:s}},r){e[ln]=ws(r);const o=s||r.props&&r.props.type==="number";We(e,t?"change":"input",i=>{if(i.target.composing)return;let c=e.value;n&&(c=c.trim()),o&&(c=cn(c)),e[ln](c)}),n&&We(e,"change",()=>{e.value=e.value.trim()}),t||(We(e,"compositionstart",qi),We(e,"compositionend",Cs),We(e,"change",Cs))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:s,number:r}},o){if(e[ln]=ws(o),e.composing)return;const i=r||e.type==="number"?cn(e.value):e.value,c=t??"";i!==c&&(document.activeElement===e&&e.type!=="range"&&(n||s&&e.value.trim()===c)||(e.value=c))}},Ji=["ctrl","shift","alt","meta"],Yi={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>Ji.some(n=>e[`${n}Key`]&&!t.includes(n))},Qi=(e,t)=>{const n=e._withMods||(e._withMods={}),s=t.join(".");return n[s]||(n[s]=(r,...o)=>{for(let i=0;i<t.length;i++){const c=Yi[t[i]];if(c&&c(r,t))return}return e(r,...o)})},Xi=Y({patchProp:Wi},Ii);let Os;function Zi(){return Os||(Os=ri(Xi))}const ki=(...e)=>{const t=Zi().createApp(...e),{mount:n}=t;return t.mount=s=>{const r=tl(s);if(!r)return;const o=t._component;!A(o)&&!o.render&&!o.template&&(o.template=r.innerHTML),r.innerHTML="";const i=n(r,!1,el(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),i},t};function el(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function tl(e){return z(e)?document.querySelector(e):e}const nl=ve("button",{type:"submit"},"go!",-1),sl={__name:"Greet",setup(e){const t=ts(""),n=ts("");function s(o,i="secret"){for(var c="",u=i.length,d=0;d<o.length;d++){var h=o.charCodeAt(d),x=i.charCodeAt(d%u),w=h^x;c+=String.fromCharCode(w)}return c}async function r(){if(n.value===""){t.value="Please enter a name.";return}btoa(s(n.value))==="JFYvMVU5QDoNQjomJlBULSQaCihTAFY="?t.value="Great, you got the flag!":t.value="No, that's not my name."}return(o,i)=>(mr(),br(ge,null,[ve("form",{class:"row",onSubmit:Qi(r,["prevent"])},[Mo(ve("input",{id:"greet-input","onUpdate:modelValue":i[0]||(i[0]=c=>n.value=c),placeholder:"Enter a name..."},null,512),[[zi,n.value]]),nl],32),ve("p",null,Nr(t.value),1)],64))}},rl=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},Kn=e=>(bo("data-v-bacdabd6"),e=e(),yo(),e),ol={class:"container"},il=Kn(()=>ve("h1",null,"Welcome to L3HCTF!",-1)),ll=Kn(()=>ve("p",null,"Hope you have a good time playing.",-1)),cl=Kn(()=>ve("p",null,"Now please tell me a name.",-1)),fl={__name:"App",setup(e){return(t,n)=>(mr(),br("div",ol,[il,ll,cl,Ae(sl)]))}},ul=rl(fl,[["__scopeId","data-v-bacdabd6"]]);ki(ul).mount("#app");
分析可知,"JFYvMVU5QDoNQjomJlBULSQaCihTAFY=" == base64_encode(bxor_cycle(input,b'secret'))
L3HCTF{W3LC0M3_n0_RU57_AnyM0r3}

babycom

x64dbg附加,注意到中途主程序会往外写一个com(从资源里面读取)。
注意到是babycom.dll,我们直接断输入的字符串,发现进去后是一个xtea
xtea参数:
key=EA 3E D4 1C 70 CB D7 47 98 5E CA DB 53 0C 39 2B
delta=0x114514
round=32
然后经过对比发现是一个标准的。
2024-09-25T09:52:54.png
继续往下分析,xtea之后还有一个加密。
用了一个Bcrypt的加密,调API就可以解密。

#include <iostream>
#include <Windows.h>
int main()
{
    HCRYPTPROV phProv;
    HCRYPTHASH phHash;
    HCRYPTKEY phKey;
    const BYTE key[] = {
        0xEA, 0x3E, 0xD4, 0x1C, 0x70, 0xCB, 0xD7, 0x47, 0x98, 0x5E, 0xCA, 0xDB, 0x53, 0x0C, 0x39, 0x2B
    };

    const BYTE MultiByteStr[] = {0xb, 0xaf, 0x51, 0x21, 0x9c, 0x52, 0x10, 0x89,
                    0x3f, 0x2c, 0x34, 0x30, 0x87, 0x13, 0xc1, 0x4c,
                    0xc1, 0x7f, 0x81, 0x6e, 0xba, 0xbd, 0xdf, 0x43,
                    0x1a, 0xf0, 0xd7, 0xde, 0x8e, 0x66, 0xb9, 0x7c };
    DWORD pdwDataLen = 32;
    if (CryptAcquireContextA(&phProv, 0LL, 0LL, 0x18u, 0xF0000000)
        && CryptCreateHash(phProv, 32771u, 0LL, 0, &phHash)
        && CryptHashData(phHash, key, 0x10u, 0)
        && CryptDeriveKey(phProv, 0x660Eu, phHash, 1u, &phKey))
    {
        CryptDecrypt(phKey, 0LL, 0, 0, (BYTE*)MultiByteStr, &pdwDataLen);
    }
    return 0;
/* Decrypted
2a b4 c1 74 d6 59 aa 05 73 10 7f 9c 40 49 99 62
3c 84 51 8f 3f 37 ab f1 0e fe 61 96 45 ad 41 6a
*/
}

综上所述

from regadgets import *
encc = pack_dword(byte2dword(bytes.fromhex("""
2a b4 c1 74 d6 59 aa 05 73 10 7f 9c 40 49 99 62
3c 84 51 8f 3f 37 ab f1 0e fe 61 96 45 ad 41 6a
""")))
key = byte2dword(b"\xEA\x3E\xD4\x1C\x70\xCB\xD7\x47\x98\x5E\xCA\xDB\x53\x0C\x39\x2B")
r = b''
for i in encc:
    result = xtea_decrypt(i, key, delta=0x114514, rounds=32)
    r += dword2byte(list(result))
print(r)
# L3HCTF{C0M_Th3C0d3_1s_FuN!!!!!!}

丢一个Ctypes版本的(纯python解决)

from regadgets import *
from ctypes import *
lib_advapi32 = windll.LoadLibrary('advapi32.dll')
pfunc_CryptAcquireContextA = lib_advapi32.CryptAcquireContextA
pfunc_CryptCreateHash = lib_advapi32.CryptCreateHash
pfunc_CryptHashData = lib_advapi32.CryptHashData
pfunc_CryptDeriveKey = lib_advapi32.CryptDeriveKey
pfunc_CryptDecrypt = lib_advapi32.CryptDecrypt
phProv = c_uint64(0)
phHash = c_uint64(0)
phKey = c_uint64(0)
pdwDataLen = c_uint32(32)
if pfunc_CryptAcquireContextA(pointer(phProv), 0, 0, 0x18, 0xF0000000) == 0:
    print("failed 0")
    exit(0)
if pfunc_CryptCreateHash(phProv, 32771, 0, 0, pointer(phHash)) == 0:
    print("failed 1")
    exit(0)
key = b"\xEA\x3E\xD4\x1C\x70\xCB\xD7\x47\x98\x5E\xCA\xDB\x53\x0C\x39\x2B"
if pfunc_CryptHashData(phHash, create_string_buffer(key), 0x10, 0) == 0:
    print("failed 2")
    exit(0)
if pfunc_CryptDeriveKey(phProv, 0x660E, phHash, 1, pointer(phKey)) == 0:
    print("failed 3")
    exit(0)

correct = b"\x0B\xAF\x51\x21\x9C\x52\x10\x89\x3F\x2C\x34\x30\x87\x13\xC1\x4C\xC1\x7F\x81\x6E\xBA\xBD\xDF\x43\x1A\xF0\xD7\xDE\x8E\x66\xB9\x7C"
buf = create_string_buffer(correct)
pfunc_CryptDecrypt(phKey, 0, 0, 0, buf, pointer(pdwDataLen))

encc = pack_dword(byte2dword(buf.raw), padding=True)
r = b''
for i in encc:
    result = xtea_decrypt(i, byte2dword(key), delta=0x114514, rounds=32)
    r += dword2byte(list(result))
print(r)

# b'L3HCTF{C0M_Th3C0d3_1s_FuN!!!!!!}\xa0\xbf\xbc\xcf>\xb1\x194'