首先这里我自我介绍下: 我代码审计也没学多久 但是代码学的久 其实代码审计你看的代码多了 你会感觉真的蛮简单的 (这里只针对原生态的php mvc框架)
Thinkphp框架 Laravel框架这些 我也不太会审计 所以这篇文章我只说原生态php 和 mvc框架的代码审计

解读下初学代码审计的人:
学习代码审计需要 学习php 以及框架吗?
答:学习代码审计是需要学习php的
php需要学到那种程度?
答:我觉得吧学到面向对象就差不多了 可能刚开始审计的话 就感觉很懵逼
一看这么多代码 都不知道从什么地方入手
这个没关系 我也遇到过
这里我推荐你去学习云之梦的php 跟着它把项目做完就可以了 各个功能写一遍就好了然后可以去看李小双大佬的代码审计课程 它这里包含了thinkphp laravel框架审计 感觉是不错的
https://www.bilibili.com/video/BV1QJ411z714?p=2

好啦 前面就说这么说 咋们进入正题
总结出: 不要害怕代码审计 耐心看完每一个功能点 这样子会学到不少东西
代码审计分为

  1. 逆向追踪/回溯变量 主要看参数是否可控 是否有过滤? 过滤是否是全局过滤?搜索敏感的关键词 定向挖掘
  2. 正向追踪/跟踪变量 找那些文件接收外部传入的参数 跟踪变量传递过程
  3. 直接挖掘功能点漏洞 根据黑盒进行挖掘 根据自己经验来判断
  4. 通读全文 了解程序架构 函数集文件 配置文件 config 安全过滤文件 filter check等
    这里建议初学者用xdebug分析 我觉得这个工具合适蛮不错的
    这里有篇文章:
    https://www.cnblogs.com/linqingvoe/p/10907672.html
    可以跟着他来安装
    这里有两个工具 Seay源代码审计系统 rips
    这里我喜欢用Seay源代码审计系统 虽然扫的不怎么准 但是定位危险函数还是不错的 这里我们说的是原生态的 不带任何框架的 这里可以使用这款工具来定位危险函数

比如说这里我们使用Seay源代码审计系统工具扫描出来的
看到这里是疑似是一个注入


这里明显是一个函数 我们此时就要想:在哪调用这个函数 是否有过滤 变量是否可控
如果这里不是一个函数 只是一个普通的sql语句 我们需要想:前面是否有函数来进行过滤了这个变量 他有没有进行单引号包裹 数据库是使用的是GBK还是什么?

好了 废话不多说 我们进入案例 (这里只分享自己审计的思路)
二次编码注入:
如果代码前面写的是urldecode的话 我们就可以使用url二次编码然后进行绕过


可以看到这里是过滤了


我们二次编码后 他变成了%27 %27解码后是单引号

这里有个案例:
这里可以看到$_GET传过来的id 进行了mysql_real_escape_string过滤
但是下面我们可以看到这里进行了urldecode 所以这里我们可以绕过
http://127.0.0.1?id=%2527 union select 1,2,3 …
%2527解码后变成%27 %27正好是单引号
所以这里造成了二次编码注入
我们在挖掘sql注入漏洞的时候主要分这几个点:
我们用Seay源代码审计系统 扫到类似 select order 这些sql语句的时候 我们可以追溯变量 看他变量是从哪里来的 传过来之后有没有过滤之类的
比如:


这里是insert插入的一条sql语句
比如这个$data这个数组 我们看他是从哪里来的 选中右键 全局追踪


这里会有很多

这里可以看到这里作为形参传进去了
我们全局搜索看哪里调用这个函数


可以看到这里进行了调用
我们点进去 可以看到这里传入一个实参 我们这时候就要想他在传入实参之前有没有进行过滤 等等操作
代码审计其实就是一个追溯的一个过程 这里说的是函数 变量也是如此
看那个变量是从哪里过来的是 post 还是 get cookie 等等
我们看上面的截图可能看到getip() 一般getip() 是获取ip的 一般是不会对他进行过滤 我们可以查看他这个函数里面写的什么


这里看到这里进行获取ip地址
还有就是 你看他拼接sql语句的时候 有没有单引号包裹 如果没有可能造成一个int类型的注入
这里说几个函数:
遇到htmlspecialchars不要慌 看他第二个参数有没有设置
Echo htmlspecialchars($str,ENT_COMPAT) //只转换双引号
Echo htmlspecialchars($str,ENT_QUOTES) //转换双引号和单引号
Echo htmlspecialchars($str,ENT_NOQUOTES) //不转换任何引号
可能有些开发者觉得htmlspecialchars可以过滤sql注入 其实是不然的
我们可以看到如果不设置第二个参数 他是几乎没有任何作用的 只能过滤xss

还有比如说:
有些开发者喜欢使用replace进行过滤
比如:
比如:
Function test(){
$string = str_replace(‘%20’,’’,$string);
$string = str_replace(‘{’,’’,$string);

}
这里举一个例子 %2{7 这里将{替换为空 那么就变成%27 然后就能进行注入
等等

我们继续来看文件包含漏洞:
文件包含漏洞 分本地文件包含 和 远程文件包含
在我看的代码里面见的最多的可能就是本地文件包含了
挖掘文件包含漏洞的时候 我们主要看这几个函数:
require()
require_once()
include()
include_once()
主要分为这几个函数
挖掘文件包含的时候 我们还是要看可控的变量 再就是一般文件都喜欢这样子
Include DIR.$username.’php’;
像这种的他后缀有一个php的后缀
这时候我们就需要截断了
但是截断在php5.3已经修复了 所以我们要注意php的版本
截断常用的三种方式
第一种就是%00截断 %00受限于GPC 和 addslashes等函数的过滤 也就是说在开启GPC的情况下是不可用的
第二种方式就是 利用多个点进行截断 这种方式不受限于GPC先知 不过还是在php5.3修复了
Windows下需要240个点才能够截断
第三种方式是基于远程文件包含时利用问号?来伪截断 不受GPC和HTTP版本先知 只要能返回代码给包含函数 它就能执行


$metid是get提交过来的参数 如果不等于index 进行包含 所以这里需要截断

Xss漏洞 分为 反射性 dom型 存储型 我们就拿反射性和dom型来说
反射性xss:
通常是变量的直接输出
比如:
Echo $_GET[‘name’];
Echo $_SERVER[‘HTTP_REFERER’] 等等
举一个简单的例子


这是我当时挖一个cms的时候 虽然是后台的但是觉得还是不错的
这就是Echo $_SERVER[‘HTTP_REFERER’] 直接输出了

存储型xss:
挖掘存储型xss的时候 我们需要注意的点 留言板 发表评论出等等
此时我们要想 我们要想在他评论或者留言的时候进数据库的时候有没有进行过滤
并且出库的时候有没有进行过滤 这点我们是需要分析的点
我们看到留言板之后找到对应的功能文件 使用xdebug进行调试分析 看他有没有进行
Htmlspecialchars过滤等等

文件上传漏洞:
文件上传漏洞在挖掘的时候
我们需要注意这个函数 move_upload_file这个函数
move_upload_file函数直接把临时文件copy到新文件
挖掘文件上传漏洞的时候 分为这几个点:
黑名单过滤:
限制文件类型不是很全 php能够在大多数Webserver上面解析 典型的iis解析漏洞 ngix解析漏洞 等等


比如这种的我们就可以查找漏网之鱼进行文件上传
这种就是黑名单过滤不严格导致文件上传
实际中可能遇到这种的是很少的

文件头 content-type验证绕过

像这种就是content-type验证的 相信搞渗透的小伙伴们 对于这种验证肯定有了绕过了思路
没错 我们可以抓包进行更改type
还有就是程序不严谨导致绕过 可能有时候我们会发现 白名单的时候 我们无法上传文件
如果我们上传的后缀在白名单里面它会提示我们禁止上传
比如说

<script>alert(“您上传的文件不合法”)</script>
我们看到这个是不是觉得是有点问题的呢 它这里只不过是弹了一个窗 但是他还是会走后面上传的程序 所以说我们文件是上传上去了的 这里没有进行exit或者die终止后面的程序代码
所以导致上传
Pathinfo的问题
我们首先说pathinfo这个函数
pathinfo() 函数以数组的形式返回关于文件路径的信息。
返回的数组元素如下:
• [dirname]: 目录路径
• [basename]: 文件名
• [extension]: 文件后缀名
• [filename]: 不包含后缀的文件名
像这种就是content-type验证的 相信搞渗透的小伙伴们 对于这种验证肯定有了绕过了思路
没错 我们可以抓包进行更改type
还有就是程序不严谨导致绕过 可能有时候我们会发现 白名单的时候 我们无法上传文件
如果我们上传的后缀在白名单里面它会提示我们禁止上传
比如说

<script>alert(“您上传的文件不合法”)</script>
我们看到这个是不是觉得是有点问题的呢 它这里只不过是弹了一个窗 但是他还是会走后面上传的程序 所以说我们文件是上传上去了的 这里没有进行exit或者die终止后面的程序代码
所以导致上传
Pathinfo的问题
我们首先说pathinfo这个函数
pathinfo() 函数以数组的形式返回关于文件路径的信息。
返回的数组元素如下:
• [dirname]: 目录路径
• [basename]: 文件名
• [extension]: 文件后缀名
• [filename]: 不包含后缀的文件名
path 必需。规定要检查的路径。
options 可选。规定要返回的数组元素。默认是 all。
可能的值:
• PATHINFO_DIRNAME - 只返回 dirname
• PATHINFO_BASENAME - 只返回 basename
• PATHINFO_EXTENSION - 只返回 extension
• PATHINFO_FILENAME - 只返回 filename
Pathinfo它返回的是一个数组
我们再来看如下代码

$name = $_GET['name'];
    $basename = pathinfo($name,PATHINFO_EXTENSION );
    $pathname = "D:\phpStudyUser\PHPTutorial\WWW\\".$name;

    if(!in_array($basename,['php', 'php3', 'php4', 'php5', 'phtml', 'pht'],true)){

           file_put_contents($name,'<?php phpinfo()?>');

    }else{

            echo "错误";

    }

这里看到in_array进行后缀检验 pathinfo获取后缀 我们在上传的时候 如果get传过来的参数是1.php 这里肯定是不允许上传的 但是如果写成1.php/. 它会成功上传 如果我们写成1.php/. 它的exrension是一个空的值 可以成功上传

好啦文件上传就先到这里

命令执行漏洞
这里我需要关注的这几个函数

  1. system:执行一个外部的应用程序并显示输出的结果
  2. exec:执行一个外部的应用程序
  3. shell_exec:执行shell命令并返回输出的结果的字符串
  4. passthru:执行一个UNIX系统命令并显示原始的输出
  5. popen()
  6. proc_popen()
    等等
    我们来看一个案例:


这里定义了一个Factory这个类 然后in_array 进行校验 查看是否有admin的权限 然后进行file_exists进行判断是否有这个路径 最后eval执行
我们来看getA()方法里面是怎么写的


这里是从get请求方式的过来的 最后直接return 并没有任何过滤
它既然是一个类文件 我们要看它实例化这个类的文件在哪 我们全局搜索


这里进行了实例化 接下来我们需要找到包含这个文件的

可以看到这几个文件进行了文件包含 我们进行构造
www.ycccms.com/config/count.php?a=Factory();@eval($_POST[v]);//../
所以一个正常的流程是
Count.php包含了inc那个文件然后那个文件进了实例化了Factory这个类
所以如果朋友类里面有eval这些危险函数不要慌 我们先看他哪里调用了这个类 再看哪里包含了这个文件 在进行挖掘

文件删除漏洞:
这个漏洞就比较简单了
这个在实战中可能遇到最多的就是unlink了 我们可以删除.lock文件导致重装等等
接下来看一个小的案例

function delfile(){
$file=safe_url(getform('path','post'));
$type=safe_url(getform('type','post'));
$file_path=file_path($file);

echo $file_path;

// exit;
$safe_path=array('upload','template','runtime','backup');
if(arr_search($file_path,$safe_path)){
$file=str_replace('//','/',$_SERVER['DOCUMENT_ROOT'].'/'.$file);
$r=$type=='folder' ? del_folder($file) :del_file($file);
if ($r){
returnmsg('json',1,'删除成功');
}else{
returnmsg('json',0,'删除失败,请确认文件夹内是否为空,且有删除权限');
}
}
post包:
POST /admin/save.php?act=delfile HTTP/1.1
Host: www.l.com:8000
Content-Length: 53
Accept: application/json, text/javascript, /; q=0.01
Origin: http://www.l.com:8000
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://www.l.com:8000/admin/?act=imagelist&numtype=1&upfolder=sort
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Cookie: PHPSESSID=rnm3qjr3uec6lm06lodb089qk0; zzz660_adminpass=1; zzz660_adminpath=1; zzz660_adminname=admin; zzz660_admintime=1632728834; zzz660_adminface=..%2Fplugins%2Fface%2Fface01.png; XDEBUG_SESSION=PHPSTORM
Connection: close
type=file&path=upload%2F..%2Finstall%2Finstall.lock
绕过$safe_path=array('upload','template','runtime','backup');
但是$file_path = file_path($file)
如果没有这个函数 这个是可以任意删除的

// 获取路径中的路径
function file_path( $path ) {
if (strpos( $path, './' )!== false) return error ( '404,很抱歉,路径有误,不支持相对路径!',SITE_PATH);
$list=array();
$path= substr( $path, 0, strrpos( $path, '/' ));
$list=splits($path,'/');
return $list;
}
这里判断了 是否有./
但是我们通常绕过可以使用. 但是这里尝试过 它通过正则给干掉了 所以这里是一个失败的案例
有时候文件删除也需要%00截断之类的 具体看代码是怎么写的

最后我们说下审计mvc框架
MVC顾名思义是三个单词的首字母放在一起的简称,M-model(模型),V-view(试图),C-controller(控制器)
我觉得审计mvc框架
最主要的三点
熟悉路由 熟悉url上面路由地址
熟悉怎么传参的 比如说有些传参可能是?id=1 但是mvc可能是&id=1 有些可能接收参数是$_GET 有些可能是input接收 等等
熟悉数据库内核 这个是需要调试的 我们只有熟悉了数据库内核 我们才知道它到底有没有进行过滤 才能进一步的挖掘
熟悉数据库内核我们举一个小的例子
我们就用yxcms的数据库内核来做一个小小的例子
$result = model('sort')->find("id=$id");
var_dump($result);
首先查sort这个表

下断点然后进行分析

这里可以看到new sortModel 赋值给这个了
public function find($condition = '', $field = '', $order = ''
return $this->model->table($this->table, $this->ignoreTablePrefix)->field($field)->where($condition)->order($order)->find();
}
然后我们进入find函数 这里先是执行了 where 然后是 order
在就是find
我们ff7进去
Table 没什么好看的 给数据库赋值的一些东西 我们来到find

可以看到这里find函数还是调用的select函数 只不过给limit 加了一个 1

我们进入select函数

继续跟进where条件的函数 看看有没有过滤 因为id=1 我们是可控的所以 我们看下有没有过滤
$condition = "";
if(!empty($options['where'])) {
$condition = " WHERE ";
if(is_string($options['where'])) {
$condition .= $options['where'];
} else if(is_array($options['where'])) {
foreach($options['where'] as $key => $value) {
$condition .= " $key = " . $this->escape($value) . " AND ";
}
$condition = substr($condition, 0,-4);
} else {
$condition = "";
}

可以看到这里的where没有进行任何的过滤 直接拼凑给$condtion了
return $this->query("SELECT $field FROM $table $where", array(), true);
我们出来再跟进query这个函数

可以看到这里直接执行了

具体数据库内核分析 我建议使用xdebug来分析 反正我觉得蛮好用的
如果分析出数据库内核没有任何过滤 我们就去分析传递参数的时候有没有过滤 然后进行挖掘

好啦 具体文章就到这里了 又水了一篇文章 呜呜呜 大佬们别骂了 在努力学了

点击收藏 | 4 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖