PHP代码审计之实战审代码篇1

发布时间:2023年12月17日

本章代码来之各种php的cms历史漏洞源码,供小伙伴们学习, 本次三题

1. 仔细观察如下代码,思考代码有什么缺陷,可能由此引发什么样的问题?
//检测旧密码是否正确
if($password != '')
{
    $oldpassword = md5(md5($oldpassword));
    $r = $dosql->GetOne("SELECT `password` FROM `#@__member` WHERE `username`='$c_uname'");
    if($r['password'] != $oldpassword)
    {
        ShowMsg(msg: '抱歉,旧密码错误!', gourl: '-1');
        exit();
    }
}
$sql = "UPDATE `#@__member` SET";
if($password != '')
{
    $password = md5(md5($password));
    $sql .= "password='$password',";
}
@$sql .= "question='$question', answer='$answer', cnname='$cnname', enname='$enname', sex='$sex', birthtype='$birthtype', birth_year='$birth_year', birth_month='$birth_month', birth_day='$birth_day', astro='$astro', bloodtype='$bloodtype', trade='$trade', live_prov='$live_prov', live_city='$live_city', live_country='$live_country', home_prov='$home_prov', home_city='$home_city', home_country='$home_country', cardtype='$cardtype', cardnum='$cardnum', intro='$intro', email='$email', qqnum='$qqnum', mobile='$mobile', telephone='$telephone', address_prov='$address_prov', address_city='$address_city', address_country='$address_country', address='$address', zipcode='$zipcode' WHERE id='$id' AND `username`='$c_uname'";
if($dosql->ExecNoneQuery($sql))
{
    ShowMsg(msg: '资料更新成功', gourl: '?c=edit');
    exit();
}

第一个if判断的作用是“判断用户提交的新密码是否为空”,在用户提交的新密码不为空的情况下,才会进行‘旧密码的比对’,如果提交的旧密码和数据库的查询结果不一致,代码退出执行结束。第二个if判断的作用仍为“判断用户提交的新密码是否为空”,在用户提交的新密码不为空的情况下,对新密码进行哈希运算,随后进行SQL语句的拼接

一定要password有值才可以吗?如果设置为空,你会惊奇地发现sql语句为我们准备了,而且其他的参数一定程度上可控,随后也执行了,if条件语句好像没那么重要!,————由此可能会引发两个漏洞

一是在不知道旧密码的情况下修改密码
? ? ? ? 新密码设置为空,绕过两个if。在之后sql语句中找一个可控参数用sql拼接的方式将password字段加上。完成所有字段的更新

二是越权,我们不对password的字段进行处理,而是在后面的sql语句中将cnnam改成其他用用户的(对应用户的id也改变),sql语句执行是不是就把别人的信息改了!

2.仔细观察如下代码,思考代码有什么缺陷,可能由此引发什么样的问题?
<?php
require '../../inc/zzz_class.php';
$backurl=getform('backurl','get');
$path =is_mobile() ?  SITE_PATH.'wap/' :  SITE_PATH;
$url =conf('runmode')==1 ? $path.'index.php?location=user&backurl='.$backurl.'&act=' : $path.'?location=user&backurl='.$backurl.'&act=' ;
if ((get_session('uid')>0)){
   echo('document.write("  <a href='.$url.'userinfo><i class=\'ico login\'></i> 会员中心</a><a href='.$url.'loginout><i class=\'ico reg\'></i> 登出</a>")');
}else{
   echo('document.write("  <a href='.$url.'login><i class=\'ico login\'></i> 登录</a><a href='.$url.'reg><i class=\'ico reg\'></i> 注册</a>")');
}
?>

追入getform函数发现$backur是get传参,为可控参数。拼接到$url中,打印回显到前端,造成XSS漏洞

原句 <a href='.$url.'login>

document.write(" <a href=/zzzphp_jb51/?location=user&backurl=123&act=login><i class='ico login'></i> 登录</a><a href=/zzzphp_jb51/?location=user&backurl=123&act=reg><i class='ico reg'></i> 注册</a>")

攻击输出1 οnmοuseοver=alert(/document.domain/) y=

document.write(" <a href=/zzzphp_jb51/?location=user&backurl=1 οnmοuseοver=alert(/d0cument.domain/) y=&act=login><i class='ico login'></i> 登录</a><a href=/zzzphp_jb51/?location=user&backurl=1 οnmοuseοver=alert(/d0cument.domain/) y=&act=reg><i class='ico reg'></i> 注册</a>")

浏览器在执行document.write的时候会适当地增加引号

3.仔细观察如下代码,思考代码有什么缺陷,可能由此引发什么样的问题?
<?php
require '../../../inc/zzz_admin.php';
$CONFIG = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents("config.json")), true);
$action = safe_word(getform('action','get'));
$upfolder = safe_word(getform('upfolder','get'));
switch ($action) {
    case 'config':
        $result = json_encode($CONFIG);
        break;    
    /* 上传图片 */
    case 'uploadimage':
		$result =tojson(upload($_FILES['upfile'],'image',$upfolder));
        break;   
    /* 上传涂鸦 */
    case 'uploadscrawl':   
		$upfile=getform('upfile','post');
    	$result =tojson(up_base64($upfile,$upfolder));
        break;   
    /* 上传文件 */
    case 'uploadfile':
       $result =tojson(upload($_FILES['upfile'],'file',$upfolder));
        break;    
    /* 上传视频 */
	case 'uploadvideo':
		$result =tojson(upload($_FILES['upfile'],'video',$upfolder));
        break;  
	 /* 列出图片 */
    case 'listimage':
		$size=safe_word(getform('size','get'));
		$start=safe_word(getform('start','get'));
		$uporder=safe_word(getform('uporder','get'));
		$end = $start + $size;
		$allowFiles=str_replace(",","|",conf('imageext'));
		$path = UPLOAD_DIR.$upfolder.'/';
		$files = getfiles($path, $allowFiles);
		foreach($files as $k=>$v){
			$sizes[$k] = $v['size'];
			$times[$k] = $v['mtime'];
			$names[$k] = $v['name'];
		}
		switch($uporder){
			case'size1'	: array_multisort($sizes,SORT_DESC,SORT_STRING, $files);break;
			case'size2'	: array_multisort($sizes,SORT_ASC,SORT_STRING, $files);break;	
			case'name1'	: array_multisort($names,SORT_DESC,SORT_STRING, $files);break;
			case'name2'	: array_multisort($names,SORT_ASC,SORT_STRING, $files);break;	
			case'mtime2'	: array_multisort($times,SORT_ASC,SORT_STRING, $files);break;		
			default		: array_multisort($times,SORT_DESC,SORT_STRING, $files);break;
		}	
		if (! count($files)) {
			return json_encode(array(
				"state" => "no match file",
				"list" => array(),
				"start" => $start,
				"total" => count($files)
			));
		}
		$len = count($files);

		for ($i =$start,$list = array(); $i <= $len-1 &&  $i <= $end; $i ++) {
			$list[] = $files[$i];			
		}
		$result = json_encode(array(
			"state" => "SUCCESS",
			"list" => $list,
			"start" => $start,
			"total" => count($files)
		));		
        break;
    /* 列出文件 */
    case 'listfile':
        $result = getfiles();
        break;
    
    /* 抓取远程文件 */
    case 'catchimage':
		$source=getform('source','post');
		$list = array();
		$state='ERROR';
     	foreach ($source as $imgUrl) {
			$info =down_url(safe_url($imgUrl),$upfolder); 
			if ($info['state']=="SUCCESS"){
				$state="SUCCESS";
				array_push($list, array(			
					"state" => "SUCCESS",				
					"title" => $info["title"],
					"url" => $info["url"],
					"source"=>$imgUrl
				));
			}else{
				array_push($list, array(			
					"state" => $info['state'],				
					"title" => $info["msg"]
				));
			}
		}
		$result =  json_encode(array(
			'state' =>$state,
			'list' => $list
		));
        break;
    default:
        $result = json_encode(array(
            'state' => '请求地址出错'
        ));
        break;
}
/* 输出结果 */
if (isset($_GET["callback"])) {
    if (preg_match("/^[\w_]+$/", $_GET["callback"])) {
        echo htmlspecialchars($_GET["callback"]) . '(' . $result . ')';
    } else {
        echo json_encode(array(
            'state' => 'callback参数不合法'
        ));
    }
} else {
    echo($result);
}

?重要逻辑代码

$action = safe_word(getform('action','get'));

safe_word // 安全过滤字符串,仅仅保留 [a-zA-Z0-9_]

getform //get得到action参数返回

switch ($action) { //判断action执行流

/* 抓取远程文件 */
    case 'catchimage':
		$source=getform('source','post');
		$list = array();
		$state='ERROR';
     	foreach ($source as $imgUrl) {
			$info =down_url(safe_url($imgUrl),$upfolder); 
			if ($info['state']=="SUCCESS"){
				$state="SUCCESS";
				array_push($list, array(			
					"state" => "SUCCESS",				
					"title" => $info["title"],
					"url" => $info["url"],
					"source"=>$imgUrl
				));

post得到source 值,根据后面的foreach判断$source可为数组

safe_url() *// 使用正则表达式匹配允许的字符,/[a-zA-Z0-9,.:=@?_\/\s]/u 默认最大长度255

down_url 从远程下载文件并保存到本地,

重点关注文件扩展名的处理,进入down_url

重点关注$file_ext = file_ext( $url ) ?: 'jpg'; //如果无法获取到扩展名则默认为'jpg

后面对扩展名做了检测

$allext=conf('imageext').','.conf('fileext').','.conf('videoext');
if(!in_array($file_ext,splits($allext,','))){
	return array( 'msg' => '创建文件失败,禁止创建'.$file_ext.'文件!', 'state' => 'ERROR',  'error' => 5 );
}

?后面一顿翻找最终找到了这个允许的全局类

//图片上传限制 'imageext'=>'jpg,jpeg,gif,png',

//附件上传限制 'fileext'=>'pdf,txt,doc,docx,xls,xlsx,zip,rar',

//视频上传限制 'videoext'=>'mp4,flv,swf',//请注意空间90%以上不允许上传视频,或不支持视频格式

这些文件都可以上传,有什么思考?

1.用pdf打xss,用swf打xss

2.用压缩包钓鱼,用docx钓鱼,压缩包炸弹

3.用文件打服务器空间

4.可以结合文件包含漏洞打入php马

文章来源:https://blog.csdn.net/shelter1234567/article/details/135051416
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。