2024数信杯北部赛区wp
2024数信杯
战队名:西柚喵帕斯
排名:16
数据安全
Drinktea
python字节码,分析转换成python源码
from ctypes import c_uint32
import struct
def encrypt(v, key):
v0 = c_uint32(v[0]).value
v1 = c_uint32(v[1]).value
delta = 555885348
total = c_uint32(0).value
for i in range(32):
v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (total + key[total & 3] ^ v1)
total += delta
v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (total + key[total >> 11 & 3] ^ v0)
return [v0, v1]
key = [1900550021, 2483099539, 2205172504, 1359557939]
arr = [
[392252415, 2941946969],
[1122976151, 1335193774],
[815478816, 2529100980],
[2237049875, 188954780]
]
flag = input('please input flag: ')
encry = []
encryted = []
for i in range(len(flag) // 8):
encry.append(struct.unpack('<I', flag[i*8:(i+1)*8].encode('utf-8'))[0])
encry.append(struct.unpack('<I', flag[i*8+4:(i+1)*8].encode('utf-8'))[0])
encrypted = encrypt(encry, key)
encryted.append(encrypted)
if encryted == arr:
print('yes~')
else:
print('no~')
简单的xtea加密,把每一段结果拼起来包flag就可以
from ctypes import *
import struct
def encrypt(v,k):
v0=c_uint32(v[0])
v1=c_uint32(v[1])
sum1=c_uint32(0)
delta=0x9e3779b9
for i in range(32):
v0.value+=(((v1.value<<4)^(v1.value>>5))+v1.value)^(sum1.value+k[sum1.value&3])
sum1.value+=delta
v1.value+=(((v0.value<<4)^(v0.value>>5))+v0.value)^(sum1.value+k[(sum1.value>>11)&3])
return v0.value,v1.value
def decrypt(v,k):
v0=c_uint32(v[0])
v1=c_uint32(v[1])
delta=555885348
sum1=c_uint32(delta*32)
for i in range(32):
v1.value-=(((v0.value<<4)^(v0.value>>5))+v0.value)^(sum1.value+k[(sum1.value>>11)&3])
sum1.value-=delta
v0.value-=(((v1.value<<4)^(v1.value>>5))+v1.value)^(sum1.value+k[sum1.value&3])
return v0.value,v1.value
a1=[392252415, 2941946969]
a2=[1122976151, 1335193774]
a3=[815478816, 2529100980]
a4=[2237049875, 188954780]
k = [1900550021, 2483099539, 2205172504, 1359557939]
res1=decrypt(a1,k)
res2=decrypt(a2,k)
res3=decrypt(a3,k)
res4=decrypt(a4,k)
print(struct.pack('<I',res1[0]))
print(struct.pack('<I',res1[1]))
print(struct.pack('<I',res2[0]))
print(struct.pack('<I',res2[1]))
print(struct.pack('<I',res3[0]))
print(struct.pack('<I',res3[1]))
print(struct.pack('<I',res4[0]))
print(struct.pack('<I',res4[1]))
# acb8739759dc496ccc945703037e037f
Rrrccc
upx壳,直接脱脱不掉,winhex打开发现把”UPX”改成了”upx”,改回来就能直接upx -d
ida打开看一下是SMC代码自修改,动调
反调试,patch一下修改跳转条件
cipher很明显直接写出来了
过了一遍流程推测flag和cipher长度应该是相等,直接拿cipher作输入
动调跑完拿到输入的第一层加密结果,和输入异或就能得到key1
第二层异或的key2直接动调出
exp:
cipher = "Whatareyourencryption&decryptionbasics"
flag = []
#先用key2解第二层
key2 = [0x1C, 0x0CB, 0x0F5, 0x53, 0x91, 0x0CC, 0x3B, 0x66, 0x4, 0x7D, 0x0BA, 0x0D2, 0x56, 0x0CE, 0x14, 0x0A4, 0x0E8, 0x7F, 0x0C2, 0x0C4, 0x2B, 0x86, 0x32, 0x0F0, 0x0F7, 0x0EA, 0x0FB, 0x0F0, 0x78, 0x34, 0x9A, 0x3, 0x13, 0x0A2, 0x91, 0x37, 0x48, 0x66]
for i in range(38):
flag.append(ord(cipher[i]) ^ key2[i])
#求key1
cipher1 = [0x7A, 0xA7, 0x94, 0x34, 0xEA, 0xA8, 0x08, 0x02, 0x66, 0x4B,
0x83, 0xB3, 0x65, 0xFA, 0x75, 0x91, 0xD9, 0x1B, 0xF5, 0xA1,
0x1A, 0xE2, 0x00, 0xC3, 0x93, 0xDC, 0xC9, 0xC1, 0x4D, 0x0D,
0xAA, 0x3B, 0x21, 0x95, 0xF2, 0x07, 0x79, 0x1B,]
input = "Whatareyourencryption&decryptionbasics"
key1 = []
for i in range(len(cipher1)):
key1.append(cipher1[i] ^ ord(input[i]))
#最后把第二层解密结果用key1解
for i in range(len(flag)):
flag[i] ^= key1[i]
print(chr(flag[i]),end='')
#flag{d3db69a34a51d7e1d23d621590827c01}
Magic Audio
拿到一个wav文件 先看文件尾 有个压缩包 提取出来
发现有密码 听一下这个音频 慢扫描电视 用sstv直接转
sstv -d ctf.wav -o out.png
得到out.png
使用这个菜就多练作为密码进行解压
数据分析
不安全的U盘1
请提交小明电脑中的test账户的密码(格式为hash对应的明文,长度为9)
直接lsadump获得强密码
.\volatility.exe -f E:\Desktop\数信杯\file1\不安全的U盘_3ba0c570fac7eef3e90acc3eaabb5c8d\1.raw --profile=Win7SP1x64 lsadump
hahaha123
不安全的U盘2(赛后复盘)
答案要求是去掉空格后是56位字符
最令我无语的一道题 当时已经把那个程序路径找到了 但是因为sb txt文档给我显示一共是57列 自己数的时候不知道为什么死活数不出来56位 最后错失一题的分数
展示一下当时的做题截图 我真的是把可能的所有情况都列出来了 但其实第一个就是正确答案
下面简单说一下做法 首先根据题干 我们得知是因为一个pdf文件导致系统被入侵 我们直接在r-studio中进行寻找并导出
将这个README.pdf
放入沙箱进行分析 看到执行流程中存在AcroRd32.exe
在vol中搜索一下这个程序
直接在红框前面加上盘符再去掉空格就是正确答案
C:\Program Files (x86)\Adobe\Reader 9.0\Reader\AcroRd32.exe
C:\ProgramFiles(x86)\Adobe\Reader9.0\Reader\AcroRd32.exe
不安全的U盘3
请提交控制小明的服务器地址:端口(格式为”ip:port”,长度为19)
netscan查看网络连接情况
.\volatility.exe -f E:\Desktop\数信杯\file1\不安全的U盘_3ba0c570fac7eef3e90acc3eaabb5c8d\1.raw --profile=Win7SP1x64 netscan
找外网ip
不安全的U盘4(赛后复盘)
找到外联地址
直接使用vol查看.exe
文件
.\volatility.exe -f E:\Desktop\比赛\2024数信杯\数据分析\file1\不安全的U盘_3ba0c570fac7eef3e90acc3eaabb5c8d\1.raw --profile=Win7SP1x64 filescan | findstr ".exe"
看到两个比较可疑的文件 都提取出来看看
放入沙箱分析
hh.exe的通信并不是外部地址
但是f.exe同文件夹下有个toml软件程序配置文件
提取出来 看一下内容
[common]
serverAddr = "118.180.126.13"
serverPort = 6770
[plugin_socks]
type = "tcp"
remote_port = 32124
plugin = "socks5"
plugin_user = "admin"
plugin_passwd = "admin123@qwe"
use_encryption = true
use_compression = true
所以外联地址是
118.180.126.13
也可以直接在镜像文件中搜索remote_port
这种配置文件中常出现的信息
网站数据绝对安全1
系统中存在的用户名是什么?
多亏后面补充了提交次数 一个个试都试出来了
网站数据绝对安全2
key3的的值是什么?
在http导出中提取出来一个safe.html
但是使用浏览器打开是
发现直接复制不行 手动输入可以
后面看了一下源码 大概率是和这个字体有关系
Bitcoin1(赛后复盘)
附件拿到的是一个Computer.ad1镜像文件 使用FTK Imager可以进行挂载
挂载的过程实在是太难受了 4.5版本的死活挂不上 后面用4.2的才挂上
在挂载的时候 一定要注意 先选择Add Evidence Item
将镜像添加为证据项
在添加的证据项出选择挂载镜像
成功挂载上
挂载好后使用火眼分析磁盘中的文件夹 选择添加文件集合检材 在ShimCache中可以看到一个比特币钱包的安装程序的最后修改时间 那这个应该就是 2022-01-05 10:21:16
Bitcoin2(赛后复盘)
打开powershell 使用findwallet这个工具来查找加密比特币钱包文件
安装
npm install findwallet -g
使用
findwallet -i [inputPath/inputFile] -o [outputFile]
-i : Required. Specify which path(s) to scan directly or through a newline separated file.
-o : Specify optional output file where to store wallet paths if any exist.
-h : Displays this message.
在前面加上盘符
C:\Windows\System32\config\systemprofile\AppData\Roaming\Microsoft\SystemCertificates\My\AppContainerUserCertRead.sys
Bitcoin3(赛后复盘)
在Users\Daddy\Downloads
文件夹下发现了bitcoin钱包程序的安装包bitcoin-22.0-win64-setup.exe
导出安装一下
打开之后新建一个钱包test
将上面bitcoin2导出的钱包文件替换掉Bitcoin\bitcoin\wallets\test\wallet.dat
注意要将上面找到的AppContainerUserCertRead.sys
改名为wallet.dat
再次重启软件 直接点隐藏
点击交易记录 第二条
找到钱包地址
bc1qf3lta6zr9k4kt9q25sz47vdcnn73zyzk0m5gvz
Bitcoin4
在合约CTF.sol中存在一处漏洞,该漏洞是由哪一函数造成的(比如:exec)?
gpt做题法 算是非预期解 直接喂合约的完整代码进行分析
在这个合约文件中存在一处漏洞,由transferFrom函数造成。具体来说,这个漏洞出现在以下代码段:
solidityCopy code
function transferFrom(address from, address to, uint256 value) public notFrozen(from) returns (bool) {
require(msg.sender == owner);
return super.transferFrom(from, to, value);
}
在这段代码中,漏洞是由于require语句的条件不够严格导致的。当前的transferFrom函数实现要求调用者必须是owner,但是并没有检查调用者是否具有足够的授权来执行转账操作。因此,任何拥有owner权限的地址都可以调用transferFrom函数,而无需经过持有者的授权。