CISCN2024 RE 后两道 wp 复现

5. gdb_debug

其实逻辑还是挺简单的,当时没认真做

伪代码还算清晰

几个循环的加密之后判断密文

难点是前面有随机数参与加密,不过可以猜测随机数是不变的。

第一段加密

flag异或一组随机数,这里可以在异或的位置下条件断点,用idapython把随机数直接打印出来(会发现是不变的)

al = idaapi.get_reg_val("al")
print(hex(al), end=',')

得到第一段异或的随机数

第二段ptr数组直接点开看不见,鼠标悬停在上面可以看见一个地址,跳转过去0x55610C1B5AC0

跳过去取38个

第三段加密换表+异或

直接从crypto倒推,异或的tmp随机数用相同的方法打印

#gdb wp
crypto = [0x63,0x6f,0x6e,0x67,0x72,0x61,0x74,0x75,0x6c,0x61,0x74,0x69,0x6f,0x6e,0x73,0x74,0x6f,0x79,0x6f,0x75,0x63,0x6f,0x6e,0x67,0x72,0x61,0x74,0x75,0x6c,0x61,0x74,0x69,0x6f,0x6e,0x73,0x74,0x6f,0x79]

key = [ 0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73, 
  0xAC, 0xF1, 0x06, 0xBE, 0xAD, 0x88, 0x04, 0xD7, 0x12, 0xFE, 
  0xB5, 0xE2, 0x61, 0xB7, 0x3D, 0x07, 0x4A, 0xE8, 0x96, 0xA2, 
  0x9D, 0x4D, 0xBC, 0x81, 0x8C, 0xE9, 0x88, 0x78]

enc2 = [0]*38

for i in range(38):
    enc2[i] = crypto[i] ^ key[i]

xor2 = [0xde,0xaa,0x42,0xfc,0x9,0xe8,0xb2,0x6,0xd,0x93,0x61,0xf4,0x24,0x49,0x15,0x1,0xd7,0xab,0x4,0x18,0xcf,0xe9,0xd5,0x96,0x33,0xca,0xf9,0x2a,0x5e,0xea,0x2d,0x3c,0x94,0x6f,0x38,0x9d,0x58,0xea]

for i in range(38):
    enc2[i] ^= xor2[i]

ptr = [0x12, 0x0E, 0x1B, 0x1E, 0x11, 0x05, 0x07, 0x01, 0x10, 0x22, 0x06, 0x17, 0x16, 0x08, 0x19, 0x13, 
    0x04, 0x0F, 0x02, 0x0D, 0x25, 0x0C, 0x03, 0x15, 0x1C, 0x14, 0x0B, 0x1A, 0x18, 0x09, 0x1D, 0x23, 
    0x1F, 0x20, 0x24, 0x0A, 0x00, 0x21]

enc1 = [0]*38

for i in range(38):
    enc1[ptr[i]] = enc2[i]

xor1 = [0xd9,0xf,0x18,0xbd,0xc7,0x16,0x81,0xbe,0xf8,0x4a,0x65,0xf2,0x5d,0xab,0x2b,0x33,0xd4,0xa5,0x67,0x98,0x9f,0x7e,0x2b,0x5d,0xc2,0xaf,0x8e,0x3a,0x4c,0xa5,0x75,0x25,0xb4,0x8d,0xe3,0x7b,0xa3,0x64]

flag = ''

for i in range(38):
    flag += chr(enc1[i] ^ xor1[i])

print(flag)
#flag{78bace5989660ee38f1fd980a4b4fbcd}

 6. GoReverse

恶心的Golang

主函数没啥东西,调试一下

第9行 while部分会循环一会,是在分配需要的栈帧

第11行 有个反调试,patch一下

调试时遇到异常就discard掉

主逻辑应该在main_FlatControlFlow内

在里面调试,发现走到call rdx这里打印了一句话

再循环走到这里又打印出后面的

然后结束

再动调一遍发现实际上跳到了main__ptr_co6Pxq_Execute

就光打了一句话

第二次

main__ptr_B2bUPq_Execute应该是加密部分

前面是分配占空间和错误提示

注意这里调试需要flag文件作为输入

然后初始化,读取文件,一个错误处理

下面第一个加密函数main_ylFyZv

实际上就一个循环异或

第二个加密函数main_zQyveE,是一个魔改XXTEA加密

一个是改了delta

一个是改了MX

main_Q05qm6主要是做一些字符串切片

然后是main_AkuFrt

好像是个sm4

github可以搜到上面那个函数的源码gmsm/sm4/sm4.go at master · tjfoc/gmsm · GitHub

看一下汇编会发现是CTR加密

也能搜到示例代码cipher package - crypto/cipher - Go Packages,不过是个AES的示例

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/hex"
    "fmt"
    "io"
)

func main() {
    // Load your secret key from a safe place and reuse it across multiple
    // NewCipher calls. (Obviously don't use this example key for anything
    // real.) If you want to convert a passphrase to a key, use a suitable
    // package like bcrypt or scrypt.
    key, _ := hex.DecodeString("6368616e676520746869732070617373")
    plaintext := []byte("some plaintext")

    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }

    // The IV needs to be unique, but not secure. Therefore it's common to
    // include it at the beginning of the ciphertext.
    ciphertext := make([]byte, aes.BlockSize+len(plaintext))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        panic(err)
    }

    stream := cipher.NewCTR(block, iv)
    stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

    // It's important to remember that ciphertexts must be authenticated
    // (i.e. by using crypto/hmac) as well as being encrypted in order to
    // be secure.

    // CTR mode is the same for both encryption and decryption, so we can
    // also decrypt that ciphertext with NewCTR.

    plaintext2 := make([]byte, len(plaintext))
    stream = cipher.NewCTR(block, iv)
    stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])

    fmt.Printf("%s\n", plaintext2)
}

总之大致能看出来NewCipher处参数是key,NewCTR处参数是iv

而且CTR mode is the same for both encryption and decryption, so we can also decrypt that ciphertext with NewCTR.对称的加解密

然后是main_JrkmHd

CBC的AES cipher package - crypto/cipher - Go Packages

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
)

func main() {
	// Load your secret key from a safe place and reuse it across multiple
	// NewCipher calls. (Obviously don't use this example key for anything
	// real.) If you want to convert a passphrase to a key, use a suitable
	// package like bcrypt or scrypt.
	key, _ := hex.DecodeString("6368616e676520746869732070617373")
	plaintext := []byte("exampleplaintext")

	// CBC mode works on blocks so plaintexts may need to be padded to the
	// next whole block. For an example of such padding, see
	// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
	// assume that the plaintext is already of the correct length.
	if len(plaintext)%aes.BlockSize != 0 {
		panic("plaintext is not a multiple of the block size")
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	// The IV needs to be unique, but not secure. Therefore it's common to
	// include it at the beginning of the ciphertext.
	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)

	// It's important to remember that ciphertexts must be authenticated
	// (i.e. by using crypto/hmac) as well as being encrypted in order to
	// be secure.

	fmt.Printf("%x\n", ciphertext)
}

NewCipher处调用key, NewCBCENcrypter处调用iv

main_NJVCTq就是base32

总体逻辑就出来了

然后就是收集各个参数


假设结果 VPAFNU3PTHPAUQTCYUBTVJY6TGBWY3NGGKZ6OFKZ74JJBPF7LSQ3ZYO4IZLOXPVEIE7KZS46VJKNDJGRBJPUTVKTNFLZRQBLLZUD7VI=

1 xor
v24 = a5;
v19 = a1;
...
a5 = a4;  
a4 = v24;
...
v13 = *(i + v19);
...
*(result + i) = a5[i % v24] ^ v13;
a5 = D7BJLsOk9@f&1dWIn53IDlJqUS6$^WhkAk2kk*2GaqmLwiLX^bGGE$&dmqR^g5bL3lCA5^HGK$9qo5T@Bwom9vEXya0HAV3LrWW
v24 = 0x63
v13 = input

2 xxtea_kai
key 0x385E7342, 0x345A772A, 0x6F38756C, 0x6B402652
delta = 0x7FAB4CAD
MX_kai   (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y)) + ((key[(p & 3) ^ e] ^ z)))

3 SM4_CTR
key pg5g#k6Qo3L&1EzT
iv 随机生成

4 AES_CBC
key dPGWgcLpqmxw3uOXhKpKV009Cql@@XE6
iv dPGWgcLpqmxw3uOX(key前16位)

5 base32

xor的key很容易得到

xxtea的key

SM4的key

AES的key

SM4的iv是随机的,动调看看怎么个事儿

随机数在这里看到

16个字节,我们把它全改成1跟一下(C0000BC2B0)

跟到AES加密的位置,发现随机数被加到了加密数据的开头?

再从头调

再改一下随机数1111111111111111

看一下SM4输出

随机数被加到了输出的开头,也就是说密文的开头添加了随机数iv

那解密的时候把AES解密的开头16位取出就是iv了

最后解一个魔改XXTEA,然后异或一串字符即可 

#go_wp
def byte2uint32(d):
    l=[]
    for i in range(len(d)//4):
        tmp=d[i*4:i*4+4]
        l.append(tmp[3]*256**3+tmp[2]*256**2+tmp[1]*256+tmp[0])
    return l

def hexprint(arr):
    for byte in arr:
        print(hex(byte), end=', ') 
    print()

# 给定的十六进制字符串
hex_string = "69124cadc128ffe15752488b318e78c68f359d69fb2b8e4bc35ae98ee05493ca31ceb32174201bb091c9406e56430d53c046d1d128a0de5862ee5e6d"
# 将十六进制字符串转换为字节数组
byte_array = bytes.fromhex(hex_string)
# 取出前16个字节
first_16_bytes = byte_array[:16]
# 将前16个字节转换为十六进制字符串
first_16_hex_string = first_16_bytes.hex()
# 打印前16个字节的十六进制字符串
print(first_16_hex_string)

enc = [0xe9,0xd3,0xa0,0x68,0x40,0xc8,0x27,0xb6,0x29,0xaf,0x66,0x77,0x61,0xad,0xd2,0x18,0xae,0x3d,0x67,0x5c,0x85,0x9a,0x92,0x1b,0xf6,0xb8,0x5b,0x5d,0x38,0x5a,0x79,0x5e,0x00,0x53,0xde,0x67,0x20,0xe4,0x14,0x34,0x0b,0x91,0xc5,0x54]
enc32 = byte2uint32(enc)
hexprint(enc32)

from ctypes import * 

def MX(z, y, sum1, k, p, e):
    #return c_uint32(((z.value>>5^y.value<<2)+(y.value>>3^z.value<<4))^((sum1.value^y.value)+(k[(p&3)^e.value]^z.value)))
    return c_uint32(( (z.value>>5^y.value<<2)+(y.value>>3^z.value<<4)^(sum1.value^y.value)) + (k[(p&3)^e.value]^z.value))
def btea(v,k,n,delta):

    if n>1:
        sum1=c_uint32(0)
        z=c_uint32(v[n-1])
        rounds=6+52//n
        e=c_uint32(0)

        while rounds>0:
            sum1.value+=delta
            e.value=((sum1.value>>2)&3)	#e都要32位哦
            for p in range(n-1):
                y=c_uint32(v[p+1])
                #v[p]=c_uint32(v[p]+c_uint32((((z.value>>5^y.value<<2)+(y.value>>3^z.value<<4))^((sum1.value^y.value)+(k[(p&3)^e.value]^z.value)))).value).value
                v[p] = c_uint32(v[p] + MX(z,y,sum1,k,p,e).value).value
                z.value=v[p]

            y=c_uint32(v[0])
            #v[n-1]=c_uint32(v[n-1]+c_uint32((((z.value>>5^y.value<<2)+(y.value>>3^z.value<<4))^((sum1.value^y.value)+(k[((n-1)&3)^e.value]^z.value)))).value).value		#这里tmd传入的是k[((n-1)&3)啊我草,找了半天!!!
            v[n-1] = c_uint32(v[n-1] + MX(z,y,sum1,k,n-1,e).value).value
            z.value=v[n-1]
            rounds-=1

    else:
        sum1=c_uint32(0)
        n=-n
        rounds=6+52//n
        sum1.value=rounds*delta
        y=c_uint32(v[0])
        e=c_uint32(0)

        while rounds>0:
            e.value=((sum1.value>>2)&3)	#e都要32位哦
            for p in range(n-1, 0, -1):
                z=c_uint32(v[p-1])
                #y[p]=c_uint32(v[p]-c_uint32((((z.value>>5^y.value<<2)+(y.value>>3^z.value<<4))^((sum1.value^y.value)+(k[(p&3)^e.value]^z.value)))).value).value
                v[p] = c_uint32(v[p] - MX(z,y,sum1,k,p,e).value).value
                y.value=v[p]

            z=c_uint32(v[n-1])
            #v[n-1]=c_uint32(v[n-1]-c_uint32((((z.value>>5^y.value<<2)+(y.value>>3^z.value<<4))^((sum1.value^y.value)+(k[((n-1)&3)^e.value]^z.value)))).value).value		#这里tmd传入的是k[((n-1)&3)啊我草,找了半天!!!
            v[0] = c_uint32(v[0] - MX(z,y,sum1,k,0,e).value).value
            y.value=v[0]
            sum1.value-=delta
            rounds-=1

    return v

a=[0x68a0d3e9, 0xb627c840, 0x7766af29, 0x18d2ad61, 0x5c673dae, 0x1b929a85, 0x5d5bb8f6, 0x5e795a38, 0x67de5300, 0x3414e420, 0x54c5910b]
k=[0x385E7342, 0x345A772A, 0x6F38756C, 0x6B402652]
delta=0x7FAB4CAD
n=11
res=btea(a,k,-n,delta)
hexprint(res)

def uint322byte(uint32_list):
    byte_array = []
    for number in uint32_list:
        byte_array.append(number & 0xFF)
        byte_array.append((number >> 8) & 0xFF)
        byte_array.append((number >> 16) & 0xFF)
        byte_array.append((number >> 24) & 0xFF)
    return byte_array

flag_byte = uint322byte(res)
flag = ''
xor_key = 'D7BJLsOk9@f&1dWIn53IDlJqUS6$^WhkAk2kk*2GaqmLwiLX^bGGE$&dmqR^g5bL3lCA5^HGK$9qo5T@Bwom9vEXya0HAV3LrWW'
for i in range(len(flag_byte)):
    flag += chr(flag_byte[i]^ord(xor_key[i%0x63]))
print(flag)
#flag{3a4575cf-c85c-4350-90ca-baef8252425e}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/791945.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows信息收集和提权

目录 手动收集 工具收集 windows本地内核提权 本地提权 根据windows去找需要的exp进行利用 提权后结合mimikatz使用 msf提权 简单提权 生成后门 上线 BypassUAC绕过UAC提权 msf带的bypassuac模块可以尝试提权 Bypassuac提权命令操作 提权成功 ​local_exploi…

【python】随机森林预测汽车销售

目录 引言 1. 数据收集与预处理 2. 划分数据集 3. 构建随机森林模型 4. 模型训练 5. 模型评估 6. 模型调优 数据集 代码及结果 独热编码 随机森林模型训练 特征重要性图 混淆矩阵 ROC曲线 引言 随机森林&#xff08;Random Forest&#xff09;是一种集成学习方法…

全网最炸裂的5款SD涩涩模型!身体真的是越来越不好了!建议收藏,晚上自己偷偷打开看!

很多人说&#xff0c;**自从学了SD后&#xff0c;身体一天不如一天了。**今天就再接再厉&#xff0c;给大家推荐5个涩涩的模型。 【身材调节器】 顾名思义&#xff0c;这个lora可以帮你在出图时凹出想要的S型曲线。出图效果的大小由lora的权重来设定&#xff0c;权重越小越贫穷…

本地开发微信小程序,使用巴比达内网穿透

在微信小程序开发的热潮中&#xff0c;开发者常面临的一个挑战是如何在复杂的网络环境下测试和调试内网环境中的服务。巴比达正为这一难题提供了一条解决方案&#xff0c;极大简化了微信小程序与内网服务器之间通信的流程&#xff0c;加速了开发迭代周期。 以往&#xff0c;开…

3D渲染模型是白色的?问题出在以下6点,教你快速解决!

你的3D模型渲染出来是不是黑色、白色、粉色或者扭曲的&#xff1f; 出现这种情况很有可能是你的贴图纹理丢失或损坏&#xff01; 幸运的是&#xff0c;有一些常见的方法可以解决此问题并恢复纹理。在本文中&#xff0c;小编将分享如何排查和解决不同方案下的纹理问题。通常问…

小红书的大模型有点「怂」

大模型发展至今&#xff0c;各个公司都根据自己的业务发布了各自的大模型。而小红书作为种草类产品的代表&#xff0c;自研的大模型一直引而不发&#xff0c;还在内测阶段。 AI以及自研大模型的持续火热&#xff0c;让以原创内容为主导的小红书坐不住了。 近期&#xff0c;据多…

本周六!上海场新能源汽车数据基础设施专场 Meetup 来了

本周六下午 14:30 新能源汽车数据基础设施专场 Meetup 在上海&#xff0c;点击链接报名 &#x1f381; 到场有机会获得 Greptime 和 AutoMQ 的精美文创周边哦&#xff5e; &#x1f52e; 会后还有观众问答 & 抽奖环节等你来把神秘礼物带回家&#xff5e; &#x1f9c1; 更…

傅里叶级数的3D表示 包括源码

傅里叶级数的3D表示 包括源码 flyfish 傅里叶级数的基本形式 &#xff1a; y ( t ) ∑ n 1 , 3 , 5 , … N 4 A n π sin ⁡ ( n π T t ) y(t) \sum_{n1,3,5,\ldots}^{N} \frac{4A}{n\pi} \sin\left(\frac{n\pi}{T} t\right) y(t)n1,3,5,…∑N​nπ4A​sin(Tnπ​t) 其中&…

WPF/C#:在WPF中如何实现依赖注入

前言 本文通过 WPF Gallery 这个项目学习依赖注入的相关概念与如何在WPF中进行依赖注入。 什么是依赖注入 依赖注入&#xff08;Dependency Injection&#xff0c;简称DI&#xff09;是一种设计模式&#xff0c;用于实现控制反转&#xff08;Inversion of Control&#xff0…

Apache Hadoop完全分布式集群搭建指南

Hadoop发行版本较多&#xff0c;Cloudera版本&#xff08;Cloudera’s Distribution Including Apache Hadoop&#xff0c;简称CDH&#xff09;收费版本通常用于生产环境&#xff0c;这里用开源免费的Apache Hadoop原始版本。 下载&#xff1a;Apache Hadoop 版本下载&#x…

华盈生物-PhenoCycler-超多靶标揭示组织空间位置和互作关系

华盈生物获得美国Akoya公司认证的PhenoCycler-Fusion&#xff08;原CODEX&#xff09;空间单细胞蛋白组技术服务商&#xff0c;并进入该技术的全球CRO服务提供者网络&#xff1a;CRO Service Providers | Akoya Biosciences为科研工作者提供为更具有精准医学特色的服务&#xf…

Failed to start mysql.service:Unit mysql.service not found(100%成功解决问题)

问题&#xff1a;在ubuntu中安装mysql后&#xff0c;启动mysql报错 你能看到我这篇文章&#xff0c;是非常幸运的&#xff01; 安装mysql-server: 然后启动mysql报错&#xff1a; 那要怎么处理呢&#xff1f;easy&#xff0c;跟着下面的步骤操作就好了 首先&#xff0c;先卸…

算法训练营day28--134. 加油站 +135. 分发糖果+860.柠檬水找零+406.根据身高重建队列

一、 134. 加油站 题目链接&#xff1a;https://leetcode.cn/problems/gas-station/ 文章讲解&#xff1a;https://programmercarl.com/0134.%E5%8A%A0%E6%B2%B9%E7%AB%99.html 视频讲解&#xff1a;https://www.bilibili.com/video/BV1jA411r7WX 1.1 初见思路 得模拟分析出…

php快速入门

前言 php是一门脚本语言&#xff0c;可以访问服务器&#xff0c;对数据库增删查改&#xff08;后台/后端语言&#xff09; 后台语言&#xff1a;php&#xff0c;java&#xff0c;c&#xff0c;c&#xff0c;python等等 注意&#xff1a;php是操作服务器&#xff0c;不能直接在…

教学神器大比拼:SmartEDA、Multisim、Proteus,谁是你的最佳选择?

随着科技的飞速发展&#xff0c;教学工具也在不断升级。在电子设计自动化&#xff08;EDA&#xff09;和电路仿真领域&#xff0c;SmartEDA、Multisim和Proteus三款软件备受关注。那么&#xff0c;对于广大教育工作者和学生们来说&#xff0c;这三者之间该如何选择呢&#xff1…

goaccess分析json格式日志

一.安装使用yum安装&#xff0c;yum install goaccess 二.主要介绍格式问题 1.nginx日志格式如下&#xff1a; log_format main escapejson {"time_local":"$time_local", "remote_addr":"$remote_addr", "r…

解决鸿蒙开发中克隆项目无法签名问题

文章目录 问题描述问题分析解决方案 问题描述 在一个风和日丽的早晨&#xff0c;这是我学习鸿蒙开发的第四天&#xff0c;把文档过了一遍的我准备看看别人的项目学习一下&#xff0c;于是就用git去clone了一个大佬的开源项目&#xff0c;在签名的时候遇到了问题&#xff1a; h…

docker 上传镜像到hub仓库

要将 Docker 镜像上传到 Docker Hub&#xff0c;你需要按照以下步骤操作&#xff1a; 登录 Docker Hub 首先&#xff0c;你需要登录到 Docker Hub。打开终端并运行以下命令&#xff1a;docker login系统会提示你输入 Docker Hub 的用户名和密码。 如果密码忘记可以token登录&a…

SAP S4 销售组的定义和分配

spro-企业结构-定义-销售与分销-维护销售组 新增一个记录 spro-企业结构-分配-销售与分销-给销售办公室分配销售组

[leetcode]kth-smallest-element-in-a-sorted-matrix 有序矩阵中第k小元素

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:bool check(vector<vector<int>>& matrix, int mid, int k, int n) {int i n - 1;int j 0;int num 0;while (i > 0 && j < n) {if (matrix[i][j] < mid) {num i 1;j;…