CTFweb学习笔记02

PHP高级

序列化和反序列化

序列化:对象(数组)=> 字符串
对象私有化成员会自动添加类名;如果是protected变量则会添加* 号,并且前缀添加空字节
目的:
1.将复杂的数组数据类型转换为字符串,方便数组存库操作
2.对象在网络上传输时
3.对象保存到文件中时

__sleep()

serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。
序列化与__sleep()魔法方法的关系:相当于对象与构造函数之间的关系。
__sleep()需要返回一个数组,数组的一个成员对应着对象的一个属性名字,默认为全部属性的名字,而我们自己创建的__sleep()函数可以剔除我们不需要的属性名字,这样在序列化时就不会返回该属性值了。
serialize()函数的参数就是__sleep()函数的返回值。

<?php
class Animal{
	public $name;
	public $age;
	public $height;
	function __construct($name,$age,$heigh){
		$this->name=$name;
		$this->age=$age;
		$this->height=$heigh;
	}
	function __sleep(){
		$this->name="小白猫";
		return ['name','age',];
	}
}
$cat=new Animal("小花猫",5,20);
var_dump(serialize($cat));
?>

在这里插入图片描述

反序列化:字符串 => 对象(数组)

__wakeup()

unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。例如重新建立数据库连接,或执行其它初始化操作。

漏洞

当传给 unserialize() 的参数可控时,我们可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数。unserialize()后会导致__wakeup() 或__destruct()的直接调用,中间无需其他过程。因此最理想的情况就是一些漏洞/危害代码在__wakeup() 或__destruct()中,从而当我们控制序列化字符串时可以去直接触发它们。

步骤

1.寻找 unserialize() 函数的参数是否有我们的可控点
2.寻找我们的反序列化的目标,重点寻找 存在 wakeup() 或 destruct() 魔法函数的类
3.一层一层地研究该类在魔法方法中使用的属性和属性调用的方法,看看是否有可控的属性能实现在当前调用的过程中触发的
4.找到我们要控制的属性了以后我们就将要用到的代码部分复制下来,然后构造序列化,发起攻击

PDO (PHP Data Objects)

PDO 应用在 12 种不同数据库中,方便在多种数据库中切换,预处理语句可以防止 SQL 注入。

连接

<?php
$servername = "localhost";
$username = "handy";
$password = "123456";
try {
    $conn = new PDO("mysql:host=$servername;", $username, $password);
    echo "连接成功"; 
}
catch(PDOException $e)
{
    echo $e->getMessage();
}
?>

创建数据库

<?php
$servername = "localhost";
$username = "handy";
$password = "123456";

try {
    $conn = new PDO("mysql:host=$servername", $username, $password);

    // 设置 PDO 错误模式为异常
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql = "CREATE DATABASE myDBPDO";

    // 使用 exec() ,因为没有结果返回
    $conn->exec($sql);

    echo "数据库创建成功<br>";
}
catch(PDOException $e)
{
    echo $sql . "<br>" . $e->getMessage();
}

$conn = null;
?> 

创建数据表


<?php
$servername = "localhost";
$username = "handy";
$password = "123456";
$dbname = "myDBPDO";
 
try {
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    // 设置 PDO 错误模式,用于抛出异常
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
    // 使用 sql 创建数据表
    $sql = "CREATE TABLE MyGuests (
    id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, 
    firstname VARCHAR(30) NOT NULL,
    lastname VARCHAR(30) NOT NULL,
    email VARCHAR(50),
    reg_date TIMESTAMP
    )";
 
    // 使用 exec() ,没有结果返回 
    $conn->exec($sql);
    echo "数据表 MyGuests 创建成功";
}
catch(PDOException $e)
{
    echo $sql . "<br>" . $e->getMessage();
}
 
$conn = null;
?>

插入数据


<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDBPDO";
 
try {
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    // 设置 PDO 错误模式,用于抛出异常
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql = "INSERT INTO MyGuests (firstname, lastname, email)
    VALUES ('John', 'Doe', 'john@example.com')";
    // 使用 exec() ,没有结果返回 
    $conn->exec($sql);
    echo "新记录插入成功";
}
catch(PDOException $e)
{
    echo $sql . "<br>" . $e->getMessage();
}
 
$conn = null;
?>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值