IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> 代码审计基础流程及常见漏洞 -> 正文阅读

[PHP知识库]代码审计基础流程及常见漏洞

  • 辅助工具:nodepad++
    seay源代码审计系统
  • 编辑器:ultraedit
  • 代码审计工具:RIPS(能根据漏洞自动生成payload)

前期准备:本地搭建网站,一边审计一边调试

审计基本流程

1.查看网站结构,根据网站功能查看大概存在的漏洞
2.看index.php,再根据index.php涉及的代码进行审计,看出每个文件有什么大致作用,找出哪个文件是共享的安全函数文件
3.寻找配置文件,保存一些数据库相关信息。首先查看数据库编码。如果是gbk则可能存在宽字节注入。如果变量的值用双引号则可能存在双引号解析代码执行的问题
4.过滤功能,查看各个过滤入口,过滤方式是替换还是正则,有无GPC,有没有addslasher()处理

但是上述方法很麻烦,把人都整麻,一般都采用敏感函数参数回溯的方式来逆向追踪参数的传递过程。因为大多数漏洞都是是由于函数的使用不当造成的。

seay源代码审计软件就主要利用了正则匹配一些高危函数,关键函数以及敏感关键字。然后就可以分析判断敏感函数的上下文,追踪参数源头。但是使用此法挖不到逻辑漏洞

关键函数

安全相关

  1. htmlspecialchars(html实体化编码)看到就可以基本确定没有XSS了
  2. mysql_real_escape_string()过滤,转义单引号双引号括号等,主要针对sql注入
  3. file_get_content()可能存在任意文件读取
    file_put_content()任意写文件
    fwrite
  4. 配置选项:php.ini: display_error:On开启显示错误信息,增大注入风险
xsssql injectioncode execcommand execFileOther
echomysql_queryassertpassthrufreadextract
print*mysqli_queryevalsystemcopyparse_str
mysqli:querypreg_replacepopenfuputsunserialize
PDO:queryinclude*shell_execunlink
require*

unlink是删除文件(任意文件删除漏洞)

除OWASP TOP10外的常见漏洞

覆盖安装漏洞

一般php程序都有一个初始安装的功能。这个安装的功能可能会有以下漏洞:

  1. 无验证功能,任意重装覆盖
  2. $_GET[‘step’]跳过限制步骤
  3. 变量覆盖导致重装
  4. 判断lock后跳转无exit
  5. 解析install.php.bak漏洞

无验证功能导致任意重装覆盖
因为安装网站时,会相应生成install.lock,后期在安装页面时会判断install.lock是否存在,不存在就可覆盖重装,也就是说此漏洞要搭配任意文件删除漏洞使用
安装后删除install.lock再次访问首页会跳转至install.php
在这里插入图片描述判断lock后跳转无exit
审计代码:
在index.php内会include(./sys/config.php),而在config.php内有以下一段代码

if(!file_exists($_SERVER["DOCUMENT_ROOT"].'/sys/install.lock'))
{
	header("Location:/install/install.php");
	exit;
}

install.php源码:

if(file_exists($_SERVER["DOCUMENT_ROOT"].'/sys/install.lock'))
{
	header("Location:../index.php");
}
function check_writeable($file){
....}
...
//安装过程

可以看到install.php内如果验到有install.lock会跳转至index.php,虽然跳转了但是后续安装代码依然会执行,原因就是没有exit

安装有以下一段代码:

$dbhost=$_POST["dbhost"];
$dbuser=$_POST["dbuser"];
$dbpass=$_POST["dbpass"];
$dbname=$_POST["dbname"];

$con = mysql_connect($dbhost,$dbuser,$dbpass);
if(!$con){
	die('数据库链接出错,请检查账号密码及地址是否正确'.mysql_error());
}
$result=mysql_query('show database;') or die (mysql_error());
while($row=mysql_fetch_assoc($result)){
	$data[]=$row['database'];
}//如果有数据库,按行的取结果显示出来
unset($result,$row);
if(in_array(strtolower($dbname),$data)){
	mysql_close();
	echo "<script>if(!alert('数据库已存在')){window.history.back(-1);)</script>";
	exit();
}//判断数据库名是否存在,存在则弹窗并退回上一步
mysql_query("create database $dbname",$con) or die (mysql_error());//创建数据库

$str_tmp="host=\"dbhost\";\r\n\$username=\"dbuser\";\r\n\$password=\"dbpass\";\r\n\$database=\"dbname\"\r\n"
$fp=fopen("../sys/config.php","w");
fwrite($fp,$str_tmp);
fclose($fp);//把数据库相关信息写入配置文件

在上面代码中,创建数据库对dbname没有任何过滤,对写入文件内容没有任何过滤,所以四个参数都可能存在代码注入,但是在创建数据库之前需要先登录数据库,所以dbhost,dbuser,dbpass三个参数一定要是正确的参数,这三个参数就不能注入。所以但对dbname就可能存在sql注入和写马,但在写马的时候要注意,写马成功的条件一定是sql语句先要执行成功,所以这个地方应该只存在sql

OWASP TOP 100

命令注入

相关函数分类:

  • 第一类(最常见):system(),exec(),shell_exec(),passthru()–可以直接传入命令执行并返回结果
  • 第二类:popen(),proc_open()–使用这类函数传入命令时,命令会执行,但不会返回执行结果
  • 第三类:pcntl_exec()–需要开启pcntl扩展

高危漏洞推荐用敏感函数回溯法,管道符&,|,&&,||,;分别在windows和linux下的功能不再赘述

ping.php的代码:

<?php
	if( isset( $_POST[ 'submit' ]))//通过isset函数判断是否为POST提交过来的值
		$target = $_POST['target'];//将POST过来的值传递给target变量,但是没有经过任何的过滤
	if (stristr(php_uname('s’ ),‘Windows NT’))
	{
	//判断是不是windows系统
		$cmd = 'ping ' . $target; //是windows系统,进行ping操作
	} 
	else {
		$cmd = 'ping -c 3 '. $target,//不是windows系统进行ping-c 3操作}
$res = shell_exec($cmd);} ?>//最后使用shell_exec执行cmd

可惜看到对post过来的数据没有任何过滤

修复方式:

1.使用正则表达式来对用户输入的POST值进行过滤验证

if(preg_match('/^(?=^.{3,255]$)[a-zA-Z0-9][-a-zA-Z0-9][0,62]L.[a-zA-Z0-9][-a-zA-Z0-9][0,62))+$/^(25[0-5][2[0-4]d|[01]?\d\d?)($|(?!\.$L))(4}$/',$target)){

2.判断输入过来的值是否为ip

$octet = explode( ".", $target );
if ( is_numeric( $octet[0] )) && ( is_numeric( $octet[1]))&& ( is_numeric( $octet[2] )) &8 ( is_numeric( $octet[3] ))8& ( sizeof( $octet )== 4))
{ $target = $octet[0] .'.'. $octet[1].'.'. $octet[2] . '.'. $octet[3];}
//根据点分割字符判断是否为数字再拼接,并且更加完美的话判断数字是否在0-255内

XSS

XSS的关键就是寻找参数未过滤的输出函数。常见的输出函数有:ehco,printf,print,print_r,sprintf,die,var_dump,var_export等
mysql_real_escape_string()不对xss进行过滤,htmlspecialchars才对尖括号等内容进行html实体化编码
如果在输入的时候不过滤而在输出的时候实体化编码也是不存在xss的

  • 一般http头的数据是可控的,而如remote_addr是系统生成的,是不可控内容。$_SERVER是全局变量,所以代码公用
function get_client_ip(){
	if($_SERVER["HTTP_CLIENT_IP"]&&strcasecmp($_SERVER["HTTP_CLIENT_IP"],"unknown")){
		$ip=$_SERVER["HTTP_CLIENT_IP"];//获取http头的client_ip
	}else if($_SERVER["X-FORWARDED_FOR"]&&strcasecmp($_SERVER["X-FORWARDED_FOR"],"unknown")){
		$ip=$_SERVER["X-FORWARDED_FOR"];//根据x-forwarded-for获取ip
	}else if($_SERVER["REMOTE_ADDR"]&&strcasecmp($_SERVER["REMOTE_ADDR"],"unknown")){
		$ip=$_SERVER["REMOTE_ADDR"];//如果前两项都没有获取到ip,则系统生成remote_addr获取ip
	}else if(isset($_SERVER["REMOTE_ADDR"])&&$_SERVER["REMOTE_ADDR"]&&strcasecmp($_SERVER["REMOTE_ADDR"],"unknown")){
		$ip=$_SERVER["REMOTE_ADDR"];
	}else $ip="unknown";
	return($ip);
}

上面两个可控内容如果输出(比如管理界面要显示已登录用户的ip)没有过滤很明显也有xss

修复建议:可控输出基本应该用htmlspecialchars过滤

sql注入

sql的重点就是没有过滤可控参数进入数据库执行
审计sql建议正向审计,在拿到源码时先找到它的过滤注入函数,判断:

  1. 如果没有过滤可以直接注入
  2. 如果调用了addslashes()函数,还可能存在数字型注入
  3. 如果设置了set character_set_client=gbk开启了gbk编码,就会存在宽字节注入

str_ireplace(“select”,“sqlwaf”,$str);忽略大小写把select替换为sqlwaf
现有如下场景:
comment表有四列,过滤了_,admin表有三列(id,admin_user,admin_pass),现在要查询admin表的admin_user

select * from comment where id =1 union select *,4 from admin;

联合查询,用*直接代替被过滤的字段,这种应用必须要求后面查询表的字段数小于原查询表的字段数

修复建议:使用PDO::PARAH_INT

文件包含

漏洞原理:服务器开启allow_url_include,利用url进行动态包含文件,且对要包含的来源文件没有审查
相关函数:include(),include_once(),require(),require_once()
文件包含取后缀名白名单:

$extend=explode(".",$file_name);//1.php.jpg -> extend[0]='1' extend[1]='php' extend[2]='jpg' 以点分割生成数组
$va=count($extend)-1;//取最后一位后缀
if($extend[$va]=='jpg'||$extend[$va]=='jpeg'||$extend[$va]=='png'||$extend[$va]=='gif'{
	return 1;
else return 0;

php伪协议学习参考
修复:不要动态包含文件

二次注入

利用mysql数据库出库值反转义功能,多次与数据库交互造成的注入问题
二次注入流程

  • 在数据第一次进入数据库时,对其转移后存储,数据未经过滤、转义被取出后再次放到sql语句中
  • 开发者对函数不理解导致,比如is_numeric

比如向数据库中插入’hack\’,入库变成hack’,拼接到sql语句就单引号闭合前面字符造成注入
二次注入关键在于要先insert\update,再select调用,关键在于select是否直接来自数据库而不是动态传参进来,且对该数据没过滤

任意文件读取

file_get_content()动态读取
现在有如下代码:

$avater = $uploaddir.'/u_'.time().'_'.$_FILES['upfile']['name'];
if(move_upload_file($_FILE['upfile']['tmp_name'],$avatar)){
//更新用户信息
	$query = "update users set user_avatar = '$avatar' where user_id = '($_SESSION['user_id'])'";
	mysql_close($conn);
	$_SESSION['avatar'] = $avatar;
}
file_get_content($_SESSION['avatar']);

上述代码在进行存储时将文件名与时间戳和字符串拼接,要通过修改文件名进行任意文件读取几乎是不可能的,但是在进入字符串的时候没有进行任何过滤,不仅存在sql注入。还可以使文件名name=’/u_20220123_1,user_avater=“config.php” ';
后面的变量覆盖前面的造成任意文件读取
$_FILE[‘upfile’][‘name’]有个问题,比如a/b/c/1.jpg,该变量获取的文件名就只是1.jpg,不会获取整个,但是mysql可以读1十六进制,要读其他文件就十六进制编码一下

功能代码

  • move_upload_file()把上传的临时文件拷贝到网站根目录,上传的文件会先保存为临时文件,一般在/tmp目录下
  • stripslashes()去掉\
  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2022-01-25 10:23:28  更:2022-01-25 10:23:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 4:47:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计