【代码审计】--- php代码审计方法

article/2025/10/9 21:52:24

代码审计需要掌握的点

  • PHP编程语言的特性和基础
  • Web前端编程基础
  • 漏洞形成原理
  • 代码审计思路
  • 不同系统、中间件之间的特性差异

代码审计思路

  • 方法一 ---- 检查敏感函数的参数,然后回溯变量,判断变量是否可控,并且有没有经过严格的过滤,这是一个逆向追踪的过程
  • 方法二 ---- 找出哪些文件在接收外部传入的参数,然后跟踪变量的传递过程,观察是否有变量传入到高危函数里面,或者传递的过程是否有逻辑漏洞,这是一种正向追踪的方式
  • 方法三 ---- 直接挖掘功能点漏洞,根据自身经验判断该类应用通常在哪些功能中会出现漏洞,直接全篇阅读该功能代码
  • 方法四 ---- 通读全文代码

(1) 方法一

  • 检查敏感函数的参数,然后回溯变量,判断变量是否可控,并且有没有经过严格的过滤,这是一个逆向追踪的过程
  • 说明:由于大多数漏洞都是由于函数的使用不当造成的。而非函数使用不当的漏洞,比如sql注入,也有一些关键字特征:如 select、insert等。再结合fromwhere等关键字,即可以判断其是否是一条sql语句。再有比如说:http头中的HTTP_CLIENT_IPHTTP_X_FORWARDED_FOR字段,有时在没有过滤的情况下就拼接到了sql语句中,并且由于他们是在$_SERVER变量中的,不受GPC的控制。so,我们可以专门去查找http_client_ip 或者 http_x_forwarded_for字段,快速的判断是否有漏洞存在。
  • 优点:只需要搜索关键字,可以快速地挖掘出想要的漏洞,可以定向挖掘漏洞。
  • 缺点:没有通读代码对程序的整体框架不了解,无法挖掘出逻辑漏洞。在挖掘漏洞时定位漏洞利用点会花费一些时间。

下面介绍一个使用方法一挖掘出来的sql注入漏洞(参考了seay大佬的《代码审计》一书)
espcms注入挖掘案例,使用的版本是:ESPCMS V6.6.15.12.09。通过Seay源代码审计系统导入cms的源代码
在这里插入图片描述
进行自动审计
在这里插入图片描述
选择第26条内容进行审计($parentid变量可能存在sql注入漏洞,且通过列表中的漏洞详细信息来看这是一个数字型注入点),双击这一行可以直接定位到代码所在地。选中$parentid变量后在下方可以看到变量的传递信息
在这里插入图片描述
可以看到$parentid通过:$parentid = $this->fun->accept('parentid', 'R'); 这条代码获得。定位accept函数的位置
在这里插入图片描述
跳转到了class_function.php函数中
在这里插入图片描述
其中的代码如下所示
在这里插入图片描述
accept函数的功能是获取通过GETPOST或者COOKIE方法,传递的变量的值。然后通过daddslashes函数(实际上是包装的addslashes函数,功能差不多)对传进来的单引号等值进行转义(我们前面说过这是一个数字型注入点,并不需要闭合单引号,因此这个过滤是没有用的)。再通过htmldecode函数解编码返回传入的数据。这里很明显存在数字型sql注入点。变量的整个传递过程大概是这样的
在这里插入图片描述
确定了存在漏洞之后就要确定漏洞的利用点了。在citylist.php文件中可以看到该语句$parentid = $this->fun->accept('parentid', 'R');位于oncitylist函数中,该函数又位于important类中。
在这里插入图片描述
选中important类,右键点击全局搜索
在这里插入图片描述
可以看到/adminsoft/index.php文件中有实例化该类
在这里插入图片描述
打开查看文件的内容
在这里插入图片描述
主要的代码如下所示

$archive = indexget('archive', 'R'); //indexget函数 用来获取通过GET、POST和COOKIE传递的名为archive的参数
$archive = empty($archive) ? 'adminuser' : $archive;
$action = indexget('action', 'R'); //indexget函数 用来获取通过GET、POST和COOKIE传递的名为action的参数
$action = empty($action) ? 'login' : $action;include admin_ROOT . adminfile . "/control/$archive.php"; // 由于在获取 $archive变量 时经过了indexdaddslashes的过滤因此无法产生文件包含漏洞。因此我们让其包含citylist.php文件
$control = new important(); // 实例化 important类
$action = 'on' . $action; // 给$action 拼接一个 on ,刚好对应了citylist.php中的important类中的oncitylist函数
if (method_exists($control, $action)) { // 检查实例化后的 $control中是否存在oncitylist函数,肯定是存在的$control->$action(); 
} else {exit('错误:系统方法错误!');
}

关键点:

  • 需要通过GET或者POST方式传进来三个参数:archive(用于包含citylist.php文件)action(用于检测实例化后的对象是否存在oncitylist函数)parentid(写注入语句),让archiveaction等于citylist。
  • 构造EXPhttp://localhost/espcms/adminsoft/index.php?archive=citylist&action=citylist&parentid=-1 and 1=1 这样去注入即可

(2) 方法二

  • 找出哪些文件在接收外部传入的参数,然后跟踪变量的传递过程,观察是否有变量传入到高危函数里面,或者传递的过程是否有逻辑漏洞,这是一种正向追踪的方式

(3) 方法三

  • 直接挖掘功能点漏洞,根据自身经验判断该类应用通常在哪些功能中会出现漏洞,直接全篇阅读该功能代码
  • 审计方法 ---- 安装好并运行程序,看程序有哪些功能,寻找到实现这些功能的程序文件分别是怎样的。是独立的模块,还是插件,还是写在了一个通用类中。了解了这些功能的存在形式之后,可先找到经常会出现问题的功能点,黑盒测试一下,如果没有发现常见的漏洞,就去读该功能的代码,进行审计。
  • 相关功能点经常会出现的漏洞
    • 文件上传功能:文件上传在很多功能点都会有,如:文件编辑、资料编辑、头像上传、附件上传等。该功能点最常见的漏洞就是任意文件上传漏洞。除了任意文件上传之外还经常发生sql注入漏洞,因为程序员一般都不会注意到对文件名进行过滤,但是文件名有时又会保存到数据库中,所以可以通过文件名实现sql注入攻击。
    • 文件管理功能:在文件管理功能中,如果程序将文件名或者文件路径直接在参数中传递,那就有可能存在任意文件操作漏洞,如任意文件读取,利用../或者..\来跳转路径。还可能存在xss漏洞,程序会在页面中输出文件名,此时如果没有对存入数据库的文件名进行过滤的话就有可能存在xss漏洞。
    • 登录认证功能:程序将当前登录的用户账号的认证信息放到cookie中,当操作需要认证信息时直接从cookie中读取用户信息。如果这段cookie没有加salt一类的东西,就可以导致任意用户登录漏洞,只要知道用户的部分信息,即可生成认证令牌。有的程序甚至会直接把用户名明文放到Cookie中,从而导致越权漏洞
    • 找回密码功能:找回密码功能的漏洞有很多利用场景,常见的是验证码爆破。还有验证凭证的算法,这只有在代码中才能看到,在代码审计时可以看这个算法是否可信。

(4) 方法四

  • 直接通读全文代码
  • 方法:通读全文代码也有一定的技巧,而非抓住一个文件逐句读完就行了。首先我们要看程序的大体代码结构,如:主目录的文件模块目录的文件插件目录的文件。除了看有哪些目录还要看文件的大小创建时间。根据文件名就可以推断出文件实现了哪些功能。
  • 在看程序目录时需要特别注意的几个文件
    • 函数集文件,命名中包含 functions 或者 common等关键字。其中写的是一些公用函数,是给其他文件统一调用的,大部分的文件中都会在开头包含这些文件。寻找这些文件的方法:打开index.php或者一些功能文件,在其头部会包含这些文件。
    • 配置文件,命名中通常包含 config 关键字。从其中可以了解到程序的小部分功能。在看配置文件时要看清楚其中参数的值是使用单引号还是双引号括起来的,如是双引号则可能存在代码执行漏洞
    • 安全过滤文件,命名中有filtersafecheck等关键字。文件的作用是对参数进行过滤。常见的是对:sql注入XSS文件路径执行的系统命令参数的过滤。很多的程序会在参数传入时使用addslashes()进行一次过滤。
    • index文件,他是程序的入口文件,读一遍index文件即可大致了解:程序的架构运行的流程包含的文件核心文件等信息。不同目录的index文件有不同的实现方式,应当将几个核心目录下的index文件都读一遍。

案例:骑士CMS代码审计,版本:3.5.1
第一步:查看应用文件结构
文件目录结构如下所示
在这里插入图片描述
首先要看有那些文件和文件夹,寻找名称中带:api,admin,manage,include关键字的文件,这里有admininclude文件夹
在这里插入图片描述
查看admin文件夹中的内容,其中有一个api文件夹
在这里插入图片描述
再查看include文件夹中的内容,include文件夹很重要,其中一般会保存比较核心的文件,供其他文件包含。在这里插入图片描述
第二步:查看关键文件代码
查看include文件夹下的文件
在这里插入图片描述
其中有很多php文件,可以看到有一个名为common.fun.php的文件。前面说过common关键字多用来命名函数集文件,该文件就是一个定义了许多基础函数的文件。


打开文件第一个函数是addslashes_deep()

function addslashes_deep($value)
{if (empty($value)){return $value;}else{if (!get_magic_quotes_gpc()) // 获取magic_quotes_gpc的值{$value=is_array($value) ? array_map('addslashes_deep', $value) : mystrip_tags(addslashes($value));}else{$value=is_array($value) ? array_map('addslashes_deep', $value) : mystrip_tags($value);}return $value;}
}

相关函数:

  • get_magic_quotes_gpc() ---- 获取当前magic_qoutes_gpc的配置选项设置。本函数自 PHP 7.4.0 起废弃。强烈建议不要使用本函数。返回0表示magic_quotes_gpc关闭,返回1代表开启。
  • array_map() ---- 为数组的每个元素应用回调函数

该函数首先会判断magic_qoutes_gpc是否开启,没有开启的话会使用addslashes注意:在挖掘sql注入漏洞时除非有宽字节注入或者二次注入等特殊情况,只要参数在拼接到sql语句之前调用了addslashes进行了过滤,就不能进行注入了】进行一次过滤。如果传进的值是数组的话会将数组中的每一个元素作用于addslashes_deep函数,实际会调用mystrip_tags函数。


mystrip_tags函数的内容如下。

function mystrip_tags($string)
{$string = new_html_special_chars($string);$string = remove_xss($string);return $string;
}

将传入的值分别作用于new_html_special_chars函数remove_xss函数,这两个函数都是用来过滤XSS的。


首先看看new_html_special_chars函数中的内容

function new_html_special_chars($string) {$string = str_replace(array('&amp;', '&quot;', '&lt;', '&gt;'), array('&', '"', '<', '>'), $string);$string = strip_tags($string);return $string;

相关函数:

  • strip_tags() ---- 从字符串中去除 HTML 和 PHP 标记

该函数的作用是对输入字符串中的& " > <进行html实体编码,然后还使用了strip_tags函数进行了二次过滤。


remove_xss函数中的内容如下

function remove_xss($string) { $string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S', '', $string);$parm1 = Array('javascript', 'union','vbscript', 'expression', 'applet', 'xml', 'blink', 'link', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');$parm2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload','style','href','action','location','background','src','poster');$parm3 = Array('alert','sleep','load_file','confirm','prompt','benchmark','select','update','insert','delete','alter','drop','truncate','script','eval');$parm = array_merge($parm1, $parm2, $parm3); for ($i = 0; $i < sizeof($parm); $i++) { $pattern = '/'; for ($j = 0; $j < strlen($parm[$i]); $j++) { if ($j > 0) { $pattern .= '('; $pattern .= '(&#[x|X]0([9][a][b]);?)?'; $pattern .= '|(&#0([9][10][13]);?)?'; $pattern .= ')?'; }$pattern .= $parm[$i][$j]; }$pattern .= '/i';$string = preg_replace($pattern, '****', $string); }return $string;
}

相关函数:

  • array_merge() ---- 合并一个或多个数组

该函数对标签关键字($parm1)事件关键字($parm2)敏感函数关键字($parm3)进行了过滤


总结:看到这里出现了:addslashes_deep(用addslashes过滤输入)、mystrip_tags(调用new_html_special_chars和remove_xss过滤xss)、new_html_special_chars(过滤xss)、remove_xss(过滤xss)这些函数


在往下审计会看到一个名为getip的函数,该函数是用来获取客户端的真实IP的,函数内容如下

function getip()
{if (getenv('HTTP_CLIENT_IP') and strcasecmp(getenv('HTTP_CLIENT_IP'),'unknown')) {$onlineip=getenv('HTTP_CLIENT_IP');}elseif (getenv('HTTP_X_FORWARDED_FOR') and strcasecmp(getenv('HTTP_X_FORWARDED_FOR'),'unknown')) {$onlineip=getenv('HTTP_X_FORWARDED_FOR');}elseif (getenv('REMOTE_ADDR') and strcasecmp(getenv('REMOTE_ADDR'),'unknown')) {$onlineip=getenv('REMOTE_ADDR');}elseif (isset($_SERVER['REMOTE_ADDR']) and $_SERVER['REMOTE_ADDR'] and strcasecmp($_SERVER['REMOTE_ADDR'],'unknown')) {$onlineip=$_SERVER['REMOTE_ADDR'];}preg_match("/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/",$onlineip,$match);return $onlineip = $match[0] ? $match[0] : 'unknown';
}

相关函数:

  • getenv() ---- 取得系统的环境变量
  • strcasecmp(string $str1 , string $str2 ) ---- 二进制安全比较字符串(不区分大小写)。如果str1 < str2 返回 < 0,如果str1 > str2 返回 > 0,如果str1 = str2 返回 0

该函数通过请求头中的HTTP_CLIENT_IPHTTP_X_FORWARDED_FORREMOTE_ADDR这些字段和$_SERVER["REMOTE_ADDR"]来获取客户端的IP地址, 并通过strcasecmp函数来判断IP地址是否二进制安全,最后使用正则表达式判断IP地址的格式是否正确。 这里只是可以伪造IP地址, 不能利用IP地址来注入。但是许多应用都在获取IP地址时没有验证IP地址的格式而导致存在注入漏洞, 这一点我们要格外注意。


下面有两个sql查询统一操作函数:inserttable()updateable(),大多数sql语句的执行都会经过这两个函数,inserttable函数的内容如下:

// $tablename --- 表名;$insertsqlarr --- 查询数据
function inserttable($tablename, $insertsqlarr, $returnid=0, $replace = false, $silent=0) {global $db; // 定义一个全局变量$insertkeysql = $insertvaluesql = $comma = ''; // 定义三个变量// 取出$insertsqlarr数组中的元素,键由反引号包裹,值由单引号包裹foreach ($insertsqlarr as $insert_key => $insert_value) {$insertkeysql .= $comma.'`'.$insert_key.'`';$insertvaluesql .= $comma.'\''.$insert_value.'\'';$comma = ', ';}// 判断是执行REPLACE还是INSERT$method = $replace?'REPLACE':'INSERT';// 执行查询语句$state = $db->query($method." INTO $tablename ($insertkeysql) VALUES ($insertvaluesql)", $silent?'SILENT':'');// 如果执行的是insert操作且$returnid为真,就返回插入数据的主键值。否则直接返回$stateif($returnid && !$replace) {return $db->insert_id();}else {return $state;} 
}

相关函数:

  • $db->insert_id() ---- 执行数据库插入时的插入ID号。应该是一个自定义函数。

该函数会执行两种sql操作,REPLACE或者INSERT


updateable()函数内容如下

// $tablename --- 表名;$setsqlarr --- 数组
function updatetable($tablename, $setsqlarr, $wheresqlarr, $silent=0) {global $db; // 一个全局变量$setsql = $comma = '';// 得到$setsqlarr中的元素,键用反引号包裹,值用单引号包裹foreach ($setsqlarr as $set_key => $set_value) {if(is_array($set_value)) {$setsql .= $comma.'`'.$set_key.'`'.'=\''.$set_value[0].'\'';} else {$setsql .= $comma.'`'.$set_key.'`'.'=\''.$set_value.'\'';}$comma = ', ';}// 取得$wheresqlarr中的元素,作为sql查询中where关键字后面的内容$where = $comma = '';if(empty($wheresqlarr)) {$where = '1';} elseif(is_array($wheresqlarr)) {foreach ($wheresqlarr as $key => $value) {$where .= $comma.'`'.$key.'`'.'=\''.$value.'\'';$comma = ' AND ';}} else {$where = $wheresqlarr;}// 执行sql语句return $db->query("UPDATE ".($tablename)." SET ".$setsql." WHERE ".$where, $silent?"SILENT":"");
}

该函数会执行UPDATE操作


再往下走会看到一个wheresql函数

function wheresql($wherearr='')
{$wheresql="";if (is_array($wherearr)){$where_set=' WHERE ';// 拼接 $wherearr中的值foreach ($wherearr as $key => $value){$wheresql .=$where_set. $comma.$key.'="'.$value.'"';$comma = ' AND ';$where_set=' ';}}return $wheresql; // 得到 :WHERE a="1" AND b="2"....
}

该函数用于拼接sql查询语句的where条件,其中的参数都用单引号包裹。


下面还有一个生成访问令牌的函数:asyn_userkey函数

function asyn_userkey($uid)
{global $db; // 全局变量$sql = "select * from ".table('members')." where uid = '".intval($uid)."' LIMIT 1";$user=$db->getone($sql); // 执行自定义函数取出一个结果// 返回md5摘要后的结果return md5($user['username'].$user['pwd_hash'].$user['password']);
}

该函数通过将:用户名密码salt密码拼接在一起,取一次md5,作为访问的令牌。访问时只要在GET参数的key值中加上这个令牌即可验证用户的身份和权限。通常该令牌用在注册、找回密码等需要验证用户身份的地方。
我们对该函数进行全局搜索可以看到在很多与用户相关的文件都调用了该函数。
在这里插入图片描述
这些函数先不进行审计,先了解程序的其他结构。


第三步:查看配置文件
前面说过配置文件的文件名一般都是以config命名的,在主目录下搜索config
在这里插入图片描述
可以搜索出多个文件,根据经验可以判断data目录下的config.phpcache_config.php才是真正的配置文件(PS:这里需要安装好cms之后data目录下才有这两个文件,否则没有这两个文件),查看/data/config.php中的内容,该文件是数据库配置文件
在这里插入图片描述
这里的配置文件的参数是使用双引号包裹的,所以很有可能存在前面提到的双引号解析代码执行问题。一般这些配置是在安装系统时设置的,或者后台也有设置的地方。另外还要关注的一点是QISHI_DBCHARSET常量,其值是GBK,说明数据库编码是GBK。因此可能存在宽字节注入,不过需要找到数据库连接时设置的编码。可以找到连接mysql数据库的代码在/include/mysql.class.php文件的connect()函数
在这里插入图片描述
函数内容如下

    function connect($dbhost, $dbuser, $dbpw, $dbname = '', $dbcharset = 'gbk', $connect=1){$func = empty($connect) ? 'mysql_pconnect' : 'mysql_connect';// 执行mysql_connect函数连接数据库if(!$this->linkid = @$func($dbhost, $dbuser, $dbpw, true)){$this->dbshow('Can not connect to Mysql!');} else {// 数据库的版本 > 4.1 会执行SET NAMES gbkif($this->dbversion() > '4.1'){mysql_query( "SET NAMES gbk");// 数据库的版本 > 5.0.1 if($this->dbversion() > '5.0.1'){mysql_query("SET sql_mode = ''",$this->linkid);mysql_query("SET character_set_connection=".$dbcharset.", character_set_results=".$dbcharset.", character_set_client=binary", $this->linkid);}}}// 如果传进了库名会使用传进的库名if($dbname){if(mysql_select_db($dbname, $this->linkid)===false){$this->dbshow("Can't select MySQL database($dbname)!");}}}

这段代码的问题就在于,如果mysql数据库的版本在4.1到5.0.1之间的话会执行SET NAMES gbk,其就相当于:SET character_set_connection='gbk', character_set_results='gbk', character_set_client='gbk';这就会导致character_set_client没有设置成binary,存在宽字节注入。(PS:关于宽字节注入的防御可以参见 — 宽字节)


第四步:跟读首页文件
通过读取系统文件,已经对程序有了大概的了解。现在需要跟读index.php文件,看看程序运行时会调用那些文件和函数。

// 判断程序是否已经安装,没有安装的话就跳转到install/index.php目录下
if(!file_exists(dirname(__FILE__).'/data/install.lock')) header("Location:install/index.php");
// 定义一个常量
define('IN_QISHI', true);
$alias="QS_index";
// 包含/include/common.inc.php文件,这里我们跟进该文件
require_once(dirname(__FILE__).'/include/common.inc.php');// 判断终端类型
if(browser()=="mobile" && $_GET['iswap']==""){header("location:".$_CFG['wap_domain']);
}if($mypage['caching']>0){$smarty->cache =true;$smarty->cache_lifetime=$mypage['caching'];}else{$smarty->cache = false;}
$cached_id=$_CFG['subsite_id']."|".$alias.(isset($_GET['id'])?"|".(intval($_GET['id'])%100).'|'.intval($_GET['id']):'').(isset($_GET['page'])?"|p".intval($_GET['page'])%100:'');// 判断是否已经缓存,使用display函数输出页面
if(!$smarty->is_cached($mypage['tpl'],$cached_id))
{
require_once(QISHI_ROOT_PATH.'include/mysql.class.php');
$db = new mysql($dbhost,$dbuser,$dbpass,$dbname);
unset($dbhost,$dbuser,$dbpass,$dbname);
$smarty->display($mypage['tpl'],$cached_id);
}
else
{
$smarty->display($mypage['tpl'],$cached_id);
}
unset($smarty);
?>

/include/common.inc.php中的代码如下所示

if(!defined('IN_QISHI')) exit('Access Denied!');
define('QISHI_ROOT_PATH',dirname(dirname(__FILE__)).'/'); // 根目录
error_reporting(E_ERROR);
ini_set('session.save_handler', 'files');
session_save_path(QISHI_ROOT_PATH.'data/sessions/');
session_start();
require_once(QISHI_ROOT_PATH.'data/config.php');  // 数据库配置文件
header("Content-Type:text/html;charset=".QISHI_CHARSET);
require_once(QISHI_ROOT_PATH.'include/common.fun.php');  // 基础函数文件
require_once(QISHI_ROOT_PATH.'include/74cms_version.php');  // 应用版本文件$QSstarttime=exectime();  // 返回一个时间// 过滤GET、POST、COOKIE
if (!empty($_GET))
{
$_GET  = addslashes_deep($_GET);
}
if (!empty($_POST))
{
$_POST = addslashes_deep($_POST);
}
$_COOKIE   = addslashes_deep($_COOKIE);
$_REQUEST  = addslashes_deep($_REQUEST);date_default_timezone_set("PRC"); // 设置时区
$timestamp = time(); // 返回Unix的时间戳
$online_ip=getip();  // 获取IP
$ip_address=convertip($online_ip); // 对IP进行处理// 包含/data/cache_xxx.php文件
$_NAV=get_cache('nav');
$_PAGE=get_cache('page');
$_CFG=get_cache('config');
$_PLUG=get_cache('plug');// 从cache_config.php文件中读取相关配置文件进行设置
$_CFG['main_domain'] = $_CFG['site_domain'].$_CFG['site_dir'];
$_CFG['wap_domain'] = $_CFG['wap_domain']==""?$_CFG['main_domain']."wap":$_CFG['wap_domain'];
$_CFG['version']=QISHI_VERSION;
$_CFG['web_logo']=$_CFG['web_logo']?$_CFG['web_logo']:'logo.gif';
$_CFG['upfiles_dir']=$_CFG['main_domain']."data/".$_CFG['updir_images']."/";
$_CFG['thumb_dir']=$_CFG['main_domain']."data/".$_CFG['updir_thumb']."/";
$_CFG['resume_photo_dir']=$_CFG['main_domain']."data/".$_CFG['resume_photo_dir']."/";
$_CFG['resume_photo_dir_thumb']=$_CFG['main_domain']."data/".$_CFG['resume_photo_dir_thumb']."/";
$_CFG['teacher_photo_dir']=$_CFG['main_domain']."data/train_teachers/";
$_CFG['teacher_photo_dir_thumb']=$_CFG['main_domain']."data/train_teachers/thumb/";
$_CFG['hunter_photo_dir']=$_CFG['main_domain']."data/hunter/";
$_CFG['hunter_photo_dir_thumb']=$_CFG['main_domain']."data/hunter/thumb/";
$_CFG['subsite_id']=0;
subsiteinfo($_CFG);
$_CFG['site_template']=$_CFG['main_domain'].'templates/'.$_CFG['template_dir'];
$mypage=$_PAGE[$alias];
$mypage['tag']?$page_select=$mypage['tag']:'';// 包含include/tpl.inc.php文件
require_once(QISHI_ROOT_PATH.'include/tpl.inc.php');// 调用实例化后Template_Lite类的相关方法if ($_CFG['isclose']){$smarty->assign('info',$_CFG['close_reason']=$_CFG['close_reason']?$_CFG['close_reason']:'站点暂时关闭...');$smarty->display('warning.htm');exit();}if ($_CFG['filter_ip'] && check_word($_CFG['filter_ip'],$online_ip)){$smarty->assign('info',$_CFG['filter_ip_tips']);$smarty->display('warning.htm');exit();}
?>

相关函数:

  • error_reporting(E_ERROR) ---- 设置应该报告何种 PHP 错误
  • ini_set() ---- 为一个配置选项设置值
  • session_save_path() ---- 读取/设置当前会话的保存路径
  • session_start() ---- 启动新会话或者重用现有会话
  • microtime() ---- 返回当前 Unix 时间戳和微秒数
  • explode() ---- 使用一个字符串分割另一个字符串
  • date_default_timezone_set() ---- 设定用于一个脚本中所有日期时间函数的默认时区
  • time() ---- 返回当前的 Unix 时间戳

该文件主要用来读取参数和配置文件。其中还包含了其他的文件,跟进审计即可。接下来跟进审计其他功能入口文件,即可完成代码通读


http://chatgpt.dhexx.cn/article/JlEWB9du.shtml

相关文章

DAY31:代码审计基础( PHP 篇)

DAY31&#xff1a;代码审计基础( PHP 篇) 1、PHP 代码审计基础 1.1、代码审计概述 ​ 代码审计&#xff08;Code audit&#xff09;是一种以发现程序错误&#xff0c;安全漏洞和违反程序规范为目标的源代码分析。软件代码审计是对编程项目中源代码的全面分析&#xff0c;旨在…

PHP代码审计(全)

前言 官方文档&#xff1a;php.net php官方文档是非常详情&#xff0c;好用的&#xff0c;在遇到不清楚作用的函数时可以进行查询 白盒测试做代码审计最主要的知识是要去了解一个漏洞应该有哪些防御方式&#xff0c;因为大部分的漏洞都是因为修复没有做的全面&#xff0c;或…

PHP代码审计——PHP中常见的敏感函数列表

文章目录 前言一、PHP中的敏感函数——命令注入漏洞 1&#xff09;exec() 2&#xff09;system () 3&#xff09;passthru () 4&#xff09;shell_exec () 5&#xff09;popen() **/** proc_open() 二、PHP中的敏感函数——代码注入漏洞 1&#xff09;…

Idea快速选中一行的四种方式

一、鼠标连续点三下 二、end键将光标移到行尾 &#xff0c; ctrlw 选中行 三、end键将光标移到行尾 &#xff0c; shift home 选中行 四、home 键 光标移到行首、然后 点击shift end

Xcode快捷键修改 复制一行、删除一行

快速目录 Xcode快捷键修改 复制一行、删除一行0.移动选中行1.修改权限2.修改快捷键配置文件复制一行删除一行 3.设置修改Xcode快捷键4.其它注意参看 Xcode快捷键修改 复制一行、删除一行 主要是用Android Studio 开发习惯了&#xff0c;在Xcode上又没有&#xff0c;比如复制当…

竖行选中快捷键

今天选中代码时需要竖行选中&#xff0c;就回顾了一下竖行选中的快捷键 这是个很实用的快捷键。 在myeclipse中竖行选中是AltShiftA&#xff0c;进入竖行选中状态&#xff0c;按Esc退出 在idea中竖行选中的快捷键是Alt鼠标选中

idea 删除当一行或者选中行的快捷键

之前前端开发一直使用VSCode&#xff0c;常用快捷键删除一行或者当前选中的几行代码&#xff0c;使用idea的时候发现快捷键并不相同&#xff0c;查看发现idea的快捷是&#xff1a;Ctrl Y&#xff0c;比手动删除代码方便很多。 通过File->Setttings->Keymap可以查看已经…

java开发银行柜员业务绩效考核系统

导读:当今社会己进入信息社会时代,信息己经受到社会的广泛关注,被看作社会和科学技术发展的三大支柱(材料、能源、信息)之一。信息是管理的基础,是进行决策的的基本依据。在一个组织里,信息己作为人力、物力、财力之外的第四种能源,占有重要的地位。然而,信息是一种非…

Python模拟银行管理系统(面向对象)# 谭子

一、系统需求说明 本项目计划实现一个银行管理系统&#xff0c;包括开户、查询、取款、存款、转账、锁定、解锁和退出功能。 银行管理系统一览表 序号 模块 子模块 说明 1 菜单模块 显示菜单 验证管理员身份&#xff0c;显示功能菜单 2 开户模块 注册&#xff0c;生…

核心银行系统 之一 历史与发展

核心银行系统是银行信息系统中实现客户关系管理、产品与服务、业务流程、财务核算与管理、风险管控、辅助管理与决策等银行业务最核心功能的系统&#xff0c;是银行信息系统的基础和核心。 核心银行系统的英文名字 CORE Banking System&#xff0c;其中CORE是Centralized Onli…

银行信贷系统java_java毕业设计_springboot框架的银行信贷系统

这是一个基于java的毕业设计项目,毕设课题为springboot框架的银行信贷系统, 是一个采用b/s结构的javaweb项目, 开发工具eclipsei/eclipse, 项目框架jspspringbootmybatis, 银行信贷系统采用mysql进行数据存储, 并基于mybatis进行了orm实体关系映射, 该银行信贷系统系统通过模块…

支付系统开发

支付系统开发 一、工程结构 pay-common-parent 项目的Maven父配置工程 pay-common 公共工程&#xff0c;所有项目均可引用 pay-common-config 公共配置工程 pay-common-core 公共核心工程&#xff0c;service工程共用 pay-common-web 公共…

手把手搭建Java网上银行系统【附源码】(毕设)

一、项目简介 本课程演示的是一套基于Java的SSH框架实现的网上银行系统 或 银行管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的java人群。 详细介绍了网上银行系统的实现&#xff0c;包括&#xff1a; 1.项目介绍 2.环境搭建 3.系统功能…

银行综合前置系统IFS

&#xff08;布尔公司简介&#xff09; 法国布尔集团是一家国际性综合IT集团&#xff0c;业务及分支机构遍及全球100多个国家。布尔公司重点面向四大行业&#xff0c;即金融、电信、公共事业和制造业&#xff0c;为其提供量身定作的解决方案。 &#xff08;产品概述&#xff0…

C语言版的银行管理系统

C语言版的银行管理系统。可以模拟ATM及柜台操作&#xff0c;实现用户登录、查询、取款、存款、开户、销户等一系列操作&#xff0c;代码清晰简洁&#xff0c;注释详细明了。 下面废话不多说&#xff0c;上代码啦。 void main() {//cc22052402char userName[8];char userPWD[7]…

银行核心系统是什么?

银行核心系统是什么? 2011-01-03 csdn 银行核心系统是什么 银行核心系统的英文原意CORE Banking, CORE其实不是“核心”的意思这么简单&#xff0c;它的全称是: Centralized Online Real-time Exchange &#xff08;集中式在线实时交互&#xff09;。注意两个重要的关键词“集…

python实现银行ATM系统

通过简单的python程序来实现ATM系统&#xff0c;其功能包括&#xff0c;存取款&#xff0c;余额查明以及退出功能&#xff0c;这些功能通过函数来封装&#xff0c;最后在写出窗口功能和循环 #银行ATM系统 salary int(input("请输入你当月的工资&#xff1a;")) #这…

Python银行取款系统

目 录 一、系统说明 二、用户信息 三、取款系统 一、系统说明 请你编写一个银行取款系统程序&#xff0c;要求具备以下几点功能。 1.开户业务 一个证件号码只可以绑定一个账号&#xff0c;系统首先验证用户证件号码&#xff0c; 如证件已在系统存在则不提供开户业务…

银行系统

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 本文链接&#xff1a; https://blog.csdn.net/wu2374633583/article/details/80731961 1 轧差 轧差指的是当日A和B银行有资金来往&#xff0c;早…

java银行管理系统源码

目录 一、项目包含知识点 二、项目需求 三、系统模块设计 3. 1、模块介绍 32、银行管理系统技术分析如图 3.3银行管理系统界面展示 四、银行管理系统源码 4.1Account类 4.2ATMSystem类 一、项目包含知识点 面向对象编程 : 要求使用面向兑现思想进行编程&#xff0c;…