CTF学习笔记(三)php部分
三、常见PHP用法与漏洞
(〇)php的备份文件与phps
php的备份文件一般是*.php.bak,在根目录下输入/index.php.bak, 下载 备份文件。
phps文件就是php的源代码文件,通常用于提供给用户(访问者)查看php代码,因为用户无法直接通过Web浏览器看到php文件的内容,所以需要用phps文件代替。其实,只要不用php等已经在服务器中注册过的MIME类型为文件即可,但为了国际通用,所以才用了phps文件类型。
(一)php_文件包含
文件包含的函数的参数没有经过过滤或者是严格的定义,并且参数可以被用户所控制,这样就可能包含非预期的文件。
1.文件包含漏洞常见的函数(默认都以php脚本为准啊)
①include: 包含并运行指定的文件,Include在出错的时候产生警告,脚本会继续运行
②include_once:在脚本执行期间包含并运行指定文件。该函数和include 函数类似,两者唯一的区别是 使用该函数的时候,php会加检查指定文件是否已经被包含过,如果是,则不会再被包含。
③require :包含并运行指定文件。require在出错的时候产生E_COMPLE_ERROR级别的错误,导致脚本终止运行。
④require_once: 和require函数完全相同。区别类似include和include_once。
文件包含漏洞示例(文件名称include.php)
无限制:没有为包含文件指定特定的前缀或者.php .html 等扩展名
<?php
$filename=$_GET['filename'];
Include($filename);
?>
有限制:(随便加一个扩展名上去)
<?php
$filename=$_GET['filename'];
Include($filename.".html");
?>
2.本地包含漏洞
①无限制本地包含漏洞 1)常见的敏感信息路径
window系统: \boot.ini 系统版本信息
\php.ini PHP配置信息
\my.ini MYSQL配置信息
\httpd.conf Apache配置信息
linux系统:
/etc/passwd linux系统账号信息
/etc/httpd/conf/httpd.conf Apache配置信息
/etc/my.conf MYSQL配置信息
/usr/etc/php.ini PHP配置信息 2)漏洞利用
读取文件内容(还未纠正)
通过目录遍历可以获取系统中的文件:
http://XXX.X.X.X./include.php?finame= (传路径即可)
例:我们要访问四级目录中的1.php文件
那就是 http://XXX.X.X.X./include.php?finame=../../../1.php
利用无限制本地包含漏洞执行代码
利用无限制本地包含漏洞,可以通过文件包含功能执行扩展名的文件中的代码
Os:学到这里的时候终于解惑之前的一个疑惑:在做文件上传的题目时,为什么我上传一个图片马,访问该图片用蚁剑无法连接。原因当然是:图片马里面的php代码没有办法解析,如果要解析的话可以配合文件包含漏洞,那样就可以解析图片马里面的php代码(死靶文件随便加加减减呗)
例:Test.txt文件内容是<?php phpinfo(); ?>
利用文件包含漏洞test.txt 文件,就可以执行文件中的php代码并输出phpinfo信息
②有限制本地包含漏洞
如下:
绕过方法: 1)%00截断文件包含
漏洞利用条件: php版本要低于5.3.4
Magic_quotes_gpc=off
测试:http://127.0.0.1/include.php?filename=1.txt%00 2)路径长度截断文件包含
操作系统存在最大路径长度的限制。可以通过输入超过最大路径的长度的目录,这样系统就会将后面的的路径给舍弃,导致扩展名截断。
漏洞利用条件:
window系统目录下的最大路径长度是256B
Linux系统目录下的最大路径长度是4096B
测试:http://127.0.0.1/include.php?finame=1.txt/../../../../../../../../../../../../../../../../../../../../../../../../../../../(省略不想打了) 3)点号截断文件包含
和‘路径长度文件截断文件包含’同理
3.远程包含漏洞
①无限制远程文件包含漏洞
无限制远程文件包含是指包含文件的位置并不是在本地服务器,而是通过URL的形式包含其他服务器上的文件,执行文件中的恶意代码。
漏洞利用条件:
allow_url_fopen=on
allow_url_include=on 漏洞利用:
直接传参文件的url即可,就不做演示了。 ②有限制远程文件包含漏洞(后面再补图)
绕过方法: 1)问号绕过
可以在问好(?)后面添加HTML字符串,问号后面的扩展名.html会被当成查询,从而绕或扩展名过滤 2)井号绕过
可以在井号(#)后面添加HTML字符串,#号会截断后面的扩展名.html,从而逃过扩展名过滤。#号的URL编码为%23 3)空格绕过
在payload的最后对空格进行URL编码 %20 四.PHP伪协议 ①常见的php伪协议
1)file:// 访问本地文件系统
2)http:// 访问HTTP(S)网址
3)ftp:// 访问FTP(S)URL
4)php:// 访问各个输出输入流
5)zlib:// 处理压缩流
6)data:// 读取数据
7)glob:// 查找匹配的文件路径模式
8)phar:// PHP归档
9)rar:// RAR数据压缩 ②php://伪协议
php://伪协议是php提供的一些输入输出流访问功能,允许访问php的输入输出流,标准输入输出和错误描述符,内存中,磁盘备份的临时文件流,以及可以操作其他读取和写入文件的过滤器。
1)php://filter
php://filter是元封装器,设计用于了数据流打开时的筛选过滤应用,对本地磁盘文件进行读写。
以下两种用法相同:
名称 描述 resource=<要过滤的数据流> 该参数是必需的。指定要过滤的数据流 read=<读链的筛选器列表> 该参数可选。可以设定一个或者多个筛选器名称,以管道符(|分隔 write=<写链的筛选器列表> 该参数可选。可以设定一个或者多个筛选名称,以管道符(|)分隔
(二)MD5绕过
MD5消息摘要算法,属Hash算法一类。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要(32位的数字字母混合码)。
md5()函数有一个漏洞,如果md5函数的参数是一个数组值,会导致函数返回false。除了md5之外sha1函数也有这个特性。 则这里get一个a[]=1 post一个b[]=1即可。
除了利用md5函数的漏洞,还可以构造md5值相同的俩条不同数据。md5值相同的字符串没有找到,但可以构造md5值相同的二进制数据
附:常见MD5 0e开头的字符串
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020
240610708
0e462097431906509019562988736854
314282422
0e990995504821699494520356953734
571579406
0e972379832854295224118025748221
903251147
0e174510503823932942361353209384
1110242161
0e435874558488625891324861198103
1320830526
0e912095958985483346995414060832
1586264293
0e622743671155995737639662718498
2302756269
0e250566888497473798724426794462
2427435592
0e067696952328669732475498472343
2653531602
0e877487522341544758028810610885
3293867441
0e471001201303602543921144570260
3295421201
0e703870333002232681239618856220
3465814713
0e258631645650999664521705537122
3524854780
0e507419062489887827087815735195
3908336290
0e807624498959190415881248245271
4011627063
0e485805687034439905938362701775
4775635065
0e998212089946640967599450361168
4790555361
0e643442214660994430134492464512
5432453531
0e512318699085881630861890526097
5579679820
0e877622011730221803461740184915
5585393579
0e664357355382305805992765337023
6376552501
0e165886706997482187870215578015
7124129977
0e500007361044747804682122060876
7197546197
0e915188576072469101457315675502
7656486157
0e451569119711843337267091732412
QLTHNDT
0e405967825401955372549139051580
QNKCDZO
0e830400451993494058024219903391
EEIZDOI
0e782601363539291779881938479162
TUFEPMC
0e839407194569345277863905212547
UTIPEZQ
0e382098788231234954670291303879
UYXFLOI
0e552539585246568817348686838809
IHKFRNS
0e256160682445802696926137988570
PJNPDWY
0e291529052894702774557631701704
ABJIHVY
0e755264355178451322893275696586
DQWRASX
0e742373665639232907775599582643
DYAXWCA
0e424759758842488633464374063001
GEGHBXL
0e248776895502908863709684713578
GGHMVOE
0e362766013028313274586933780773
GZECLQZ
0e537612333747236407713628225676
NWWKITQ
0e763082070976038347657360817689
NOOPCJF
0e818888003657176127862245791911
MAUXXQC
0e478478466848439040434801845361
MMHUWUV
0e701732711630150438129209816536
注意:php8不支持数组绕过
(三)is_numeric漏洞
会忽视0x这种十六进制的数
容易引发sql注入操作,暴漏敏感信息
echo json_encode([
is_numeric(233333),
is_numeric('233333'),
is_numeric(0x233333),
is_numeric('0x233333'),
is_numeric('233333abc'),
]);
结果如下
16进制数0x61646D696EASII码对应的值是admin
如果我们执行了后面这条命令的话:SELECT * FROM tp_user where username=0x61646D696E,结果不言而喻
[
true,
true,
true,
false,
false
]
(四)in_array漏洞
in_array中是先将类型转为整形,再进行判断
转换的时候,如果将字符串转换为整形,从字符串非整形的地方截止转换,如果无法转换,将会返回0
<?php
var_dump(in_array("2%20and%20%", [0,2,3]));
结果如下
bool(true)
(五)switch漏洞
switch中是先将类型转为整形,再进行判断
转换的时候,如果将字符串转换为整形,从字符串非整形的地方截止转换,如果无法转换,将会返回0
(六)命令注入攻击
PHP中可以使用下列5个函数来执行外部的应用程序或函数 system、exec、passthru、shell_exec、“(与shell_exec功能相同) 函数原型 string system(string command, int &return_var) command 要执行的命令 return_var 存放执行命令的执行后的状态值 string exec (string command, array &output, int &return_var) command 要执行的命令 output 获得执行命令输出的每一行字符串 return_var 存放执行命令后的状态值 void passthru (string command, int &return_var) command 要执行的命令 return_var 存放执行命令后的状态值 string shell_exec (string command) command 要执行的命令
漏洞实例
例1: //ex1.php
<?php
$dir = $_GET["dir"];
if (isset($dir))
{
echo "<pre>";
system("ls -al ".$dir);
echo "</pre>";
}
?>
我们提交http://www.sectop.com/ex1.php?dir=| cat /etc/passwd 提交以后,命令变成了 system(“ls -al | cat /etc/passwd”);
(七)常见的弱类型比较绕过
<?php
echo` `0 == ``'a'` `;``// a 转换为数字为 0 重点注意
// 0x 开头会被当成16进制54975581388的16进制为 0xccccccccc
// 十六进制与整数,被转换为同一进制比较
'0xccccccccc'` `== ``'54975581388'` `;
// 字符串在与数字比较前会自动转换为数字,如果不能转换为数字会变成0
1 == ``'1'``;
1 == ``'01'``;
10 == ``'1e1'``;
'100'` `== ``'1e2'` `;
// 十六进制数与带空格十六进制数,被转换为十六进制整数
'0xABCdef'` `== ``' 0xABCdef'``;
echo` `'0010e2'` `== ``'1e3'``;
// 0e 开头会被当成数字,又是等于 0*10^xxx=0
// 如果 md5 是以 0e 开头,在做比较的时候,可以用这种方法绕过
'0e509367213418206700842008763514'` `== ``'0e481036490867661113260034900752'``;
'0e481036490867661113260034900752'` `== ``0'` `;
var_dump(md5(``'240610708'``) == md5(``'QNKCDZO'``));
var_dump(md5(``'aabg7XSs'``) == md5(``'aabC9RqS'``));
var_dump(sha1(``'aaroZmOk'``) == sha1(``'aaK1STfY'``));
var_dump(sha1(``'aaO8zKZF'``) == sha1(``'aa3OFF9m'``));
?>
(八)通配符在文件查询中的妙用
通配符是一种特殊语句,主要有星号()和问号(?),用来模糊搜索文件。当查找文件夹时,可以使用它来代替一个或多个真正字符;当不知道真正字符或者懒得输入完整名字时,常常使用通配符代替一个或多个真正的字符。 实际上用“Not?pad”可以对应Notepad\MyNotepad【*可以代表任何字符串;?仅代表单个字符串,但此单字必须存在】;Notep[ao]d可以对应Notepad\Notepod【ao代表a与o里二选一】,其余以此类推。
(九)Linux下内部分隔符${IFS}可以代替空格
(十)反序列化漏洞
1.什么是序列化和反序列化
序列化是将对象转换为字符串以便存储传输的一种方式。而反序列化恰好就是序列化的逆过程,反序列化会将字符串转换为对象供程序使用。在PHP中序列化和反序列化对应的函数分别为serialize()和unserialize()。
2.什么是反序列化漏洞
当程序在进行反序列化时,会自动调用一些函数,例如wakeup(),destruct()等函数,但是如果传入函数的参数可以被用户控制的话,用户可以输入一些恶意代码到函数中,从而导致反序列化漏洞。
3.序列化函数(serialize)
当我们在php中创建了一个对象后,可以通过serialize()把这个对象转变成一个字符串,用于保存对象的值方便之后的传递与使用。
测试代码
<?php
class Stu{
public $name = 'aa';
public $age = 18;
public function demo(){
echo "你好啊";
}
$stu = new Stu();
echo "<pre>";
print_r($stu);
//进行序列化
$stus = serialize($stu);
print_r($stus);
}
?>
查看结果:
4.反序列化(unserialize)
unserialize()可以从序列化后的结果中恢复对象(object)为了使用这个对象,在下列代码中用unserialize重建对象.
测试代码:
<?php
//定义一个Stu类
class Stu
{
//定义成员属性
public $name = 'aa';
public $age = 19;
//定义成员方法
public function demo()
{
echo '你吃了吗';
}
}
//实例化对象
$stu = new Stu();
//进行序列化
$stus = serialize($stu);
print_r($stus);
echo "<br><pre>";
//进行反序列化
print_r(unserialize($stus));
?>
5.PHP魔术方法
魔术方法是PHP面向对象中特有的特性。它们在特定的情况下被触发,都是以双下划线开头,利用魔术方法可以轻松实现PHP面向对象中重载(Overloading即动态创建类属性和方法)。 问题就出现在重载过程中,执行了相关代码。
1、__get、__set
这两个方法是为在类和他们的父类中没有声明的属性而设计的
__get( $property ) 当调用一个未定义的属性时访问此方法
__set( $property, $value ) 给一个未定义的属性赋值时调用
这里的没有声明包括访问控制为proteced,private的属性(即没有权限访问的属性)
2、__isset、__unset
__isset( $property ) 当在一个未定义的属性上调用isset()函数时调用此方法
__unset( $property ) 当在一个未定义的属性上调用unset()函数时调用此方法
与__get方法和__set方法相同,这里的没有声明包括访问控制为proteced,private的属性(即没有权限访问的属性)
3、__call
__call( $method, $arg_array ) 当调用一个未定义(包括没有权限访问)的方法是调用此方法
4、__autoload
__autoload 函数,使用尚未被定义的类时自动调用。通过此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
注意: 在 __autoload 函数中抛出的异常不能被 catch 语句块捕获并导致致命错误。
5、__construct、__destruct
__construct 构造方法,当一个对象被创建时调用此方法,好处是可以使构造方法有一个独一无二的名称,无论它所在的类的名称是什么,这样你在改变类的名称时,就不需要改变构造方法的名称
__destruct 析构方法,PHP将在对象被销毁前(即从内存中清除前)调用这个方法
默认情况下,PHP仅仅释放对象属性所占用的内存并销毁对象相关的资源.,析构函数允许你在使用一个对象之后执行任意代码来清除内存,当PHP决定你的脚本不再与对象相关时,析构函数将被调用.
在一个函数的命名空间内,这会发生在函数return的时候,对于全局变量,这发生于脚本结束的时候,如果你想明确地销毁一个对象,你可以给指向该对象的变量分配任何其它值,通常将变量赋值勤为NULL或者调用unset。
6、__clone
PHP5中的对象赋值是使用的引用赋值,使用clone方法复制一个对象时,对象会自动调用__clone魔术方法,如果在对象复制需要执行某些初始化操作,可以在__clone方法实现。
7、__toString
__toString方法在将一个对象转化成字符串时自动调用,比如使用echo打印对象时,如果类没有实现此方法,则无法通过echo打印对象,否则会显示:Catchable fatal error: Object of class test could not be converted to string in,此方法必须返回一个字符串。
在PHP 5.2.0之前,__toString方法只有结合使用echo() 或 print()时 才能生效。PHP 5.2.0之后,则可以在任何字符串环境生效(例如通过printf(),使用%s修饰符),但 不能用于非字符串环境(如使用%d修饰符)
从PHP 5.2.0,如果将一个未定义__toString方法的对象 转换为字符串,会报出一个E_RECOVERABLE_ERROR错误。
8、__sleep、__wakeup
__sleep 串行化的时候用
__wakeup 反串行化的时候调用
serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。
使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。
相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。
9、__set_state
当调用var_export()时,这个静态 方法会被调用(自PHP 5.1.0起有效)。本方法的唯一参数是一个数组,其中包含按array(’property’ => value, …)格式排列的类属性。
10、__invoke
当尝试以调用函数的方式调用一个对象时,__invoke 方法会被自动调用。PHP5.3.0以上版本有效
11、__callStatic
它的工作方式类似于 __call() 魔术方法,__callStatic()