c4f3b4b3 - XCTF
type: channel
link: https://blog.hxzzz.asia/category/XCTF
description: XCTF 联赛
items: SCTF2024 Reverse
items: L3HCTF2024 Reverse 复现
items: SekaiCTF2024 Reverse
items: RCTF 2022 Reverse 复现
items: DubheCTF 2024 Reverse 复现
items: [RCTF 2024] Re

SCTF2024 Reverse
type: item
date: 2024-09-30T12:49:00+08:00
description: ez_cythonfrom 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}'BBoxAndroid超绝一键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];…

L3HCTF2024 Reverse 复现
type: item
date: 2024-09-25T17:09:00+08:00
description: ez_rustx64dbg开调，搜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.len…

SekaiCTF2024 Reverse
type: item
date: 2024-09-21T00:24:00+08:00
description: x64_extensionAES-256 密钥扩增魔改from regadgets import * k = bytes([0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f]) iv = bytes([0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0]) a = AES(k) data = open('flag.txt.enc', 'rb').read() print(a.decrypt_cbc(data, iv)) # b"Hey Sekai CTF Player, I hope you are fine and are enjoying the CTF. Keep going, here is your reward! The flag is SEKAI{Pl34Se_It'5_jUs7_@_wAaaarmUp}\n"SEKAI{Pl34Se_It'5_jUs7_@_wAaaarmUp}

RCTF 2022 Reverse 复现
type: item
date: 2024-09-17T00:41:00+08:00
description: picStore(re)https://impartial-poinsettia-a05.notion.site/Lua-953ca64d37c9478b82d394ea2f2a0ca1#ce05742c1bd04285ba87bf4d398a861cdump 后 用 https://luadec.metaworm.site/在线反编译-- filename: -- version: lua53 -- line: [0, 0] id: 0 menu = function() -- line: [2, 12] id: 1 print("-------------------Pictrue Store System-------------------") print("1. upload") print("2. download") print("3. delete") print("4. list") print("5. check") print("6. exit") io.write("choice>> ") end upload_impl = function() -- line: [14, 21] id: 2 local r0_2 = a_f3_9a7nhRC() if r0_2 ~= nil then io.write("img data: ") a_1sV7zC5yL_(r0_2) end end download_impl = function() -- line: [23, 31] id: 3 io.write("link: ") local r0_3 = io.read("*number") if a_IjKn_GF3FE(r0_3) == 1 then io.write("img data: ") a_TUBSK2FAhN(r0_3) end end delete_impl = function() -- line: [33, 41] id: 4 io.write("link: ") if a_8jzNK8OZ4i(io.read("*number")) == 0 then print("error") end end list_impl = function() -- line: [43, 57] id: 5 print("-------------------img list-------------------") local r0_5 = 0 local r1_5 = 1 while r0_5 < 30 do if a_IjKn_GF3FE(r0_5) == 1 then r1_5 = r1_5 + 1 print(string.format("%d. pic_%04d. link: http://%d\n", r1_5, r0_5, r0_5)) end r0_5 = r0_5 + 1 end end check_impl = function() -- line: [59, 84] id: 6 local r0_6 = 0 local r1_6 = 0 local r2_6 = "" local r3_6 = false while r0_6 < 30 do local r4_6 = a_IjKn_GF3FE(r0_6) if r0_6 % 2 == 0 and r4_6 == 1 then r1_6 = r1_6 + 1 local r5_6 = a_Cc_ClWQsa5(r0_6) if #r5_6 ~= 2 then r3_6 = true end r2_6 = r2_6 .. r5_6 end r0_6 = r0_6 + 1 end if r1_6 == 15 and #r2_6 == 30 and r3_6 == false and check_func(r2_6) == true then print("now, you know the flag~") print(r2_6) else print("you fail!") end end main_logic = function() -- line: [86, 108] id: 7 while true do menu() local r0_7 = io.read("*l") if r0_7 == "1" then upload_impl() elseif r0_7 == "2" then download_impl() elseif r0_7 == "3" then delete_impl() elseif r0_7 == "4" then list_impl() elseif r0_7 == "5" then check_i…

DubheCTF 2024 Reverse 复现
type: item
date: 2024-08-21T01:51:00+08:00
description: Destination挂上TitanHide，注意到NtSetInformationThread, NtGetContextThread这两个反调试x64dbg断下后在线程开始ret即可。NtSetInformationThread会使当前线程从调试器隐藏，调试器跑飞NtGetContextThread可以获取到当前线程的寄存器状况，用来检测DR寄存器来反硬件断点还有一个反调试是我进入后发现的，主线程卡住，但是线程窗口里面有一个线程一直在Sleep(1);，于是干掉就行了。于是我们就得到了第一个patch的附件，我们以这个附件为基础继续调。注意到我们输入完flag之后给我们来了个int3，导致进入SEH流程，如下图所示。图中框起来的是SEH处理函数，我们进去后，显然是似了。我们观察到，这些花指令由2种构成1.call $+5; add [esp], 5; retn2.jnz addr; jz addr显然第一种可以化简为nop，第二种我们可以化简为jmp addr处理脚本如下from pwn import u32, u8 binfile = open("Destination_patched_2.exe","rb").read() founds = [] # find all junkcode index = 0 while True: index = binfile.find(b'\xE8\x00\x00\x00\x00\x83\x04\x24\x05\xC3',index+1) #! index+1 ! 不然死循环了... if index == -1: break founds.append(index) print(index) binfile = bytearray(binfile) for i in founds: print(binfile[i:i+10]) for j in range(i,i+10): binfile[j] = 0x90 print(binfile[i:i+10]) # find all junkcode index = 0 while True: i = binfile.find(b'\x0f\x84',index+1) index = i if i == -1: break if binfile[index+6:index+8] == b'\x0f\x85' and u32(binfile[index+2:index+6]) - u32(binfile[index+8:index+12]) == 6: binfile[i] = 0x90 binfile[i+1] = 0xe9 binfile[i+7] = 0x66 binfile[i+8] = 0x0f binfile[i+9] = 0x18 binfile[i+10] = 0x20 binfile[i+11] = 0x90 index = 0 while True: i = binfile.find(b'\x74',index+1) index = i if i == -1: break if binfile[i+2] == 0x75 and binfile[i+1] - binfile[i+3] == 2: binfile[i] = 0xeb binfile[i+2] = 0x90 binfile[i+3] = 0x90 binfile[i+4] = 0x90 # replace all matches print(open("Destination_p3.exe","wb").write(binfile))处理完花指令后，我们进入Ghidra，直接当成Func，然后手动处理一点东西，就得到了： void xxtea(void) { uint e; uint sum; uint z; uint i; int round; uint y; round = 50; sum = 0; z = src[0xb]; do { sum += 0xa4b46062; e = sum >> 2 & 3; src[0xb] = z; for (i = 0; i < 11; i += 1) { y = src[i + 1]; z = src[i] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (key[i & 3 ^ e] ^ z)); src[i] = z; } z = src[0xb] + ((z >> 5 ^ src[0] << 2) + (src[0] >> 3 ^ z << 4) ^ (sum ^ src[0]) + (key[i & 3 ^ e] ^ z)); src[0xb] …

[RCTF 2024] Re
type: item
date: 2024-05-30T16:08:00+08:00
description: PPTT首先，通过Hook VirtualProtect函数，可以注意到程序有动态代码段修改行为，且调用者是RCTF.exe（主程序段），再通过栈回溯可以注意到，strcmp函数被修改，后续调用的strcmp会让第二个参数的一个确定的字节+1。通过IDA里面的分析，可以了解到，在最后的大IF语句中，有一个strcmp，Str2是用户输入经过打乱后的值（只取11个字节以后），Str1则是字符串常量值，经过动态调试（IDA里面静态无法进行观察），可以发现strcmp对Str1进行了一些修改，通过反着打乱值，并且通过RCTF{}这样的模式，我们可以确定flag是RCTF{sj***emqrp****tyua}，注意，s字符是r字符在strcmp函数中+1而来的。所以我们可以了解，flag只有7位需要知道了，由于在已知中没有大写字符和数字，我们推测全部都是小写字符（并且如果加上所有字符，那么复杂度是非常大的），下面我们观察对于flag的其他判定规则。经过反复动态调试和确认后，我们可以注意到上下两个图，v10的LODWORD和HIDWORD分别表示了两个开关，当v10不为0但是v10低位为0的时候，才能通过最后的IF判定，所以我们可以确定，下图第一个if的条件是假的，不能成立的。拿到打乱的顺序列表后，我们有z3-solverfrom z3 import * from Crypto.Util.number import * from copy import deepcopy from typing import List def solve(): s = Solver() x = z3_create_bvs("x", 3, 64) v23 = x[0] v24 = x[1] v25 = x[2] v20 = v24 & v23 v19 = (v24 & v23 | v25 & v23) + 65670 v18 = (v25 & v23 ^ v25 & v24) - 1131796 v17 = v24 & v23 ^ v25 & v23 s.add((v24 & v23 & (~(v24 | v23) | v25 & v23 | v25 & v24 & ~v18) | v25 & v24 & v18) != 1732474390) s.add((v23 ^ (v20 & ~v18 | v20 & ~v19 | v17 & v19 | v25 & v23 & ~v18)) == 0x400010000622000) s.add((v18 ^ (v19 - v20)) == 0x2100A0203EFBB8B) s.add((v17 ^ v19 ^ v20) == 0x4083102108E) s.add((v19 ^ v17) - v18 == 0x1551566F3C6485ED) s.add((v18 ^ v19 ^ v25 & v24) == 0x40836ECAB9A) s.add((v17 ^ v20) - v18 == 0x3E51566F3C718563) s.add(v23 - v24 == 0x1AEFF6FDFC121BF1) s.add((v25 + v24 + v23) % 10 == 8) z3_all_bv_is_printable(s, [v23, v24, v25]) v23_s = '*p*qyeam' v24_s = 'sT*u{**R' v25_s = '}CtF*js*' for i in range(8): if v23_s[i] != '*': s.add(v23 & (0xff << (i*8)) == ord(v23_s[i]) << (i*8)) if v24_s[i] != '*': s.add(v24 & (0xff << (i*8)) == ord(v24_s[i]) << (i*8)) if v25_s[i] != '*': s.add(v25 & (0xff << (i*8)) == ord(v25_s[i]) << (i*8)) # answers while s.check() == sat: m = s.model() z3_exclude(s, x, m) result = z3_concat_bv_aslong(x, m).decode() sbox = [15, 17, 9, 19, 12, 8, 21, 23, 13, 20, 5, 7, 3, 22, 1, 2, 0, 10, 14, 18, 4, 11, 6, 16] assert(len(sbox) == len(result)) for i in range(len(result)): print(result[…