php代码审计分享
ming9 发表于 山东 漏洞分析 1700浏览 · 2024-05-21 02:20

php代码审计

0x01环境

搭建web服务器环境的软件有很多,使用最多的还是phpstudy以及宝塔面板,本文采用的是phpstudy。请注意,无论使用phpstudy还是宝塔面板,都需要按照网站源码的设计要求,修改环境配置,不然网站会搭建失败。

0x02思路

审计一个源码,最重要的是路由问题。一个功能点,如果找不到对应的功能代码,那谈何审计?

当然,对于没有路由设置的源码,直接通过url找目录路径文件就可以了

举个例子

一个网站的登录接口为 http://127.0.0.1/admin/login.php ,那么对应的源码就在admin目录下的login.php内

那如果使用了框架,情况就复杂起来了,需要了解这个源码使用框架的目录结构,thinkphp8.0框架的目录结构如下(源配置路径:https://doc.thinkphp.cn/v8_0/directory_structure.html),接口函数基本上在app下的controller文件夹下

www  WEB部署目录(或者子目录)
├─app           应用目录
│  ├─controller      控制器目录
│  ├─model           模型目录
│  ├─ ...            更多类库目录
│  │
│  ├─common.php         公共函数文件
│  └─event.php          事件定义文件
│
├─config                配置目录
│  ├─app.php            应用配置
│  ├─cache.php          缓存配置
│  ├─console.php        控制台配置
│  ├─cookie.php         Cookie配置
│  ├─database.php       数据库配置
│  ├─filesystem.php     文件磁盘配置
│  ├─lang.php           多语言配置
│  ├─log.php            日志配置
│  ├─middleware.php     中间件配置
│  ├─route.php          URL和路由配置
│  ├─session.php        Session配置
│  ├─trace.php          Trace配置
│  └─view.php           视图配置
│
├─view            视图目录
├─route                 路由定义目录
│  ├─route.php          路由定义文件
│  └─ ...   
│
├─public                WEB目录(对外访问目录)
│  ├─index.php          入口文件
│  ├─router.php         快速测试文件
│  └─.htaccess          用于apache的重写
│
├─extend                扩展类库目录
├─runtime               应用的运行时目录(可写,可定制)
├─vendor                Composer类库目录
├─.example.env          环境变量示例文件
├─composer.json         composer 定义文件
├─LICENSE.txt           授权说明文件
├─README.md             README 文件
├─think                 命令行入口文件

举个接口例子

开源网站源码yylAdmin的管理员登录接口,我点击登录这个按钮,浏览器会向/admin/admin.Login/login路径下发送用户名以及密码

(ming.com是我phpstudy上设置的网站域名,会指向我的本地),但它对应的代码却在app/admin/controller/admin/Login.php文件里的 Login类的login函数

如果按照没有框架的思路来看,接口url应该是/admin/controller/admin/login.php,完全不同

在这里

  • admin 表示控制器的命名空间或模块
  • admin.Login 表示控制器的类名
  • login 表示控制器的方法名

这便是thinkphp的命名规则

0x03审计(thiknphp框架之base64上传漏洞)

目录结构

该源码的目录结构也就表明是一个thinkphp框架站点

.env有可能是数据库配置文件,app包含网站源码,public是运行目录

文件上传漏洞点

在根目录下的common.php文件中创建了base64_upload函数

function base64_upload($base64, $path = 'uploads/images/', $filename = '') {
    $admin = \app\web\model\User::get(['sid' => session('admin_sid')]);
    if ($admin['id'] != 1)
        return '';
    $filename = $filename ? $filename : uniqid(); //文件名
    $base64_image = str_replace(' ', '+', $base64);
    if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image, $result)) {
        if ($result[2] == 'jpeg') {
            $image_name = $filename . '.jpg';
        } else {
            $image_name = $filename . '.' . $result[2];
        }
        $image_file = $path . $image_name;
        if (file_put_contents($image_file, base64_decode(str_replace($result[1], '', $base64_image)))) {
            return '/' . $path . $image_name;
        } else {
            return '';
        }
    } else {
        return '';
    }
}

base64_upload函数接收两个参数,一个是base64编码后的数据,一个是filename,也就是文件的名字

这个函数首先判断session,判断请求接口时用户有没有登录,然后会将filename赋值,如果filename没有赋值,那么使用uniqid函数赋值文件名

然后将传入的base64编码后的数据进行替换,将字符替换为+

然后将image/;中间的数据提取出来,如果等于jpeg,那么之后保存的文件名后缀为jpg,否则,文件名后缀为image/;中间的数据

后缀可控,那不就是妥妥的文件上传漏洞?

漏洞复现

使用notepad++在源码中搜索base64_upload关键字,发现admin目录下的control层中有很多源码文件都会调用这个函数

寻找了一个设置logo的功能点尝试利用上传漏洞

public function setLogo($base64_data) {
    $url = '/static/images/logo.png';
    $setting = Setting::set('logo_url', $url . '?_v=' . time());
    $path = base64_upload($base64_data, './static/images/', 'logo') . '?t=' . time();
    return ['code' => 1, 'data' => $path];
}

使用burp的编码模块base64编码一下<?php phpinfo(); ?>

构造payload

data%3aimage%2fphp%3bbase64%2cPD9waHAgcGhwaW5mbygpOyA/Pg==

url解码后的payload

data:image/php;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==

报文重发,回显文件路径

打开文件,上传漏洞利用成功

0x04审计(无框架)

审计源码为rapdicms(1.3.1版本)https://github.com/OpenRapid/rapidcms

安装

输入本地的数据库信息,设置密码,安装完成

提示后台地址,那我们就在admin管理接口处搞起!

进来之后一个登录界面,打开burp,点击确认来锁定登录接口代码文件

发现使用post请求向runlogin.php这个文件传递了两个参数,那么关键的代码文件就找到了

未授权

这个代码先使用include引用了variable.php的代码

使用file_get_contents读取了sql.json文件,然后连接了数据库,进而步入登录逻辑代码,sql.json蕴含着数据库的账号 密码信息,它使用file_get_contents读取,

那我们能不能直接访问获取到这个数据库信息呢,会不会有未授权漏洞呢?

直接访问http://ming.com/install/sql-config/sql.json

进入后台之后,跟随它的功能点去审计代码

文件上传*2

基本设置处图标文件上传

新增文章处文件上传

upload.php没有限制

sql注入*N

新增分类处insert注入

查看分类处存在delete注入

查看分类处存在update注入

用户处有update注入

用户处有delete注入

新增文章处存在insert注入

查看文章处存在update注入

查看文章处存在delete注入

普通用户评论文章处存在sql注入

普通用户点赞评论处存在sql注入

删除评论处存在sql注入

登录逻辑绕过

让我们认真的分析以下这串登录代码,首先是通过执行sql语句获取了name的password值,赋给了$pa,然后进行判断,如果这串值和 POST请求接收的password值的md5加密、sha1加密、 md5加密后的值相同,那么setcookie

if ($link) {
      $select = mysqli_select_db($link, $dataxxx['dbname']);
      if ($select) {

            $name = $_POST["username"];
            $password = $_POST["password"];
            if ($name == "" || $password == "") {
                  sendalert("请填写正确的信息");
                  exit;
            }
            //编写SQL语句并运行
            $str = "select password from `rapidcmsuser` where username=" . "'" . "$name" . "'";
            $str1 = "select yhxx from `rapidcmsuser` where username=" . "'" . "$name" . "'";
            $result1 = mysqli_query($link, $str1);
            $result = mysqli_query($link, $str);
            $pass = mysqli_fetch_row($result);
            $pass1 = mysqli_fetch_row($result1);
            $pa = $pass[0];
            $pas = $pass1[0];
            $password11 = md5(sha1(md5($password)));
            if ($pa == $password11) {

                  //设置Cookie,直接返回
                  setcookie("user", encode($name, $password11), time() + 3600000, '/');
                  setcookie("name", $name, time() + 3600000, '/');
                  sleep(2);
                  sendalert("登录成功");
            } else {
                  sendalert("登录失败");
            }
      }
}

其实这里是由绕过方法的

使用联合注入带出注入的值,而这个值确是password经过md5、sha1、md5加密后的值

传入以下两个参数

username=admin1' union select '021c6cd3a69730ac97d0b65576a9004f' --

password=1

$str="select password from `rapidcmsadmin` Where username = 'admin'";

直接绕过

修改密码处存在未授权访问

没有任何的cookie校验,可以直接修改密码

其实这里也有csrf,只不过影响相比于未授权差太少了

插件设置处存在任意删除

id=../admin即可删除网站下的admin目录

0 条评论
某人
表情
可输入 255