Aggregator
Assuming Bias and Responsible AI
Pursuit for Frictionless BFSI App Experience At The Cost Of Security
攻击3389之PTH
【报名通道开启】VIPKID SRC助力贝壳找房2020 ICS安全技术峰会
【VK技术分享】数据安全怎么做—个人信息保护法解读
对一款Golang弱口令爆破工具代码的分析及改进
开源信息收集周报#67
Abusing Application Layer Gateways (NAT Slipstreaming)
ThreatSource:Google BeyondProd安全架构详解
19年RSA创新沙盒决赛产品ShiftLeft解析
企业开发安全工具该如何选型-三类开发安全工具详细对比
Using LL-HLS with Byte-Range Addressing to Achieve Interoperability in Low Latency Streaming
跨平台C2-Mythic不明觉厉教程
记一次攻防演习渗透过程
记一次攻防演习渗透过程
记录一次攻防演习渗透过程,文章仅写关于「打点」环节的部分,也就是拿到靶标的Webshell为止。
任务: 拿到XXX业务系统权限…
过程靶标是一个www的域名,简单看了下有机会硬啃(商业源码),但时间不多,先找找脆弱点,常规一套流程,收集子域、C段…
脆弱点发现在对子域的常规扫描后,发现存在.git泄露:
以及发现了phpMyAdmin应用和一些phpinfo()信息泄漏:
看到这些,不由得兴奋了起来,接下来只要按照预期的想法: 通过.git拿到数据库账号密码(源码中一般会有),登录phpMyAdmin,然后拿到Webshell…
但…转折点来了,尝试使用GitHack等一系列常见工具去恢复.git,发现恢复的文件只有一些图片,看Logs发现有很多文件恢复失败,既然不能当一个ScriptKid一把梭哈,那就自己来手动恢复吧~
Git原理与恢复基本概念
Git有三个概念词需要了解: 1.工作区 2.版本库 3.暂存区
工作区就是正常的目录(你的项目位置);版本库就是在工作区内的一个隐藏目录.git;如果你曾经注意过这个目录你会发现里面有许多东西,在该目录下会存在一个index文件,这被称之为暂存区。
除以上所述之外,大家都知道每一个Git项目都会有一个默认的分支master,在.git目录下有一个文件head,它用来指向master这个分支。
当我们使用git add时,实际上就是把文件添加进暂存区;使用git commit时,才会把暂存区的内容添加到当前分支,默认是master分支。
我们可以来实际的看一下index和head这两个文件:
使用Binwalk直接分析,可以很直观的看见index内有许多内容,head并没有,直接cat head发现这就是一个单纯的文本内容:
ref: refs/heads/master前面了解到这是一个分支指向,那我直接查看.git目录下的refs/heads/master文件,得到一串Hash值。
我们可以暂且认为这是master分支的一个记录,用于区分、比较。
大概了解了以上内容后,还需要了解有哪些文件才能够恢复.git?
首先我们来看一下.git目录内的一般结构:
名称 类型 作用 .git/index 文件 暂存区 .git/config 文件 Git配置文件 .git/description 文件 GitWeb专用的描述文件 .git/info 文件夹 里面就一个exclude文件(与.gitignore互补),排除指定文件不用做Git提交 .git/hooks 文件夹 存放一些钩子脚本 .git/HEAD 文件 记录分支 .git/objects 文件夹 存放所有数据 .git/refs 文件夹 存放提交对象的指针知道结构及其作用后,挑重点关注objects这个目录,但一看,全都是一些Hash命名的文件,根本不知道其对应关系:
并且这些文件都没办法看:
查阅相关资料得知此类文件是将原文件内容经过zlib的deflate压缩后存储的( https://mirrors.edge.kernel.org/pub/software/scm/git/docs/user-manual.html#object-details ):
而使用zlib进行解压查看文件内容时是这样的:
这个文件更像是记录了一个目录结构,而关于此就又需要查阅资料了,具体请看: https://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-Git-%E5%AF%B9%E8%B1%A1
git中的对象(对象对应文件).git/objects包含了:
- SHA(所有用来表示项目历史信息的文件,是通过一个40个字符的(40-digit)“对象名”来索引的)
- Blob对象(用来存储文件的内容)
- Tree对象(有一串bunch指向Blob对象或是其它Tree对象的指针,一般表示内容之间的目录层次关系)
- Commit对象(指向一个Tree对象, 并且带有相关的描述信息.)
(注: 图片来自 git-scm.com )
猜测: 按照这个逻辑,我们需要先获取Commit对象对应文件找到Tree对象对应文件再通过其获得Blob对象对应文件,最后解压即可获得源文件内容。
那这些对象内容都存储在哪里呢?通过之前使用Binwalk分析,显而易见,在.git/index文件中。
但是在这里.git/index文件无法直接查看,直接套用GitHack的( https://github.com/lijiejie/GitHack/blob/master/lib/parser.py )解析代码就行:
获得SHA1: a797b1973fd62dc34a691c7fe3bce33a504f2b74,但是找了半天没找到这个对应文件,后来尝试搜索前几位和后几位,发现搜索到了后几位:
对比发现文件名和获取的SHA1值少了2位:
搜索发现原来前两位是作为了目录名:
但在这里,我们使用zlib去解压缩,发现存储在.git/index的SHA1值实际上就是一个blob对象的值,也就根本不需要获取commit、tree对象的值了,表示之前的顺序逆推逻辑是错误的:
接下来按照这个思路去编写脚本恢复源码即可。
编写与恢复
由于项目时间原因简单了解原理之后,没有过多的去研究,也不打算使用原生方法去恢复,还是采用最暴力的方法,使用命令行去恢复.git,想要让Git回退历史,使用git reset --hard commit_id命令,进行版本回退。
基于这个命令,我需要获取网站的这几个文件/目录:
- .git/index
- .git/logs
- .git/head
- .git/objects
- .git/refs
先下载.git/index、.git/head、.git/refs、.git/logs(文件目录都是固定的无需考虑其他情况)而后解析index获取索引,根据索引依次下载.git/objects内的文件,最后全部下载完毕,获取master分支(refs/heads/master文件)对应的值带入该命令git reset --hard commit_id即可恢复:
但发现除此之外,发现恢复的文件寥寥无几,后来下载.git/logs/head发现该.git项目还有其他分支:
这个记录中有两个SHA1的值,master对应前者,shop对应后者,简单修改命令git reset --hard shop_commit_id,还是那一套流程,恢复shop这个分支的源码即可。
获取子域 Webshell获得源码之后翻数据库账号密码:
由于之前我们已经有了一个phpinfo()探针,网站绝对路径已知,所以直接上phpMyAdmin登录,尝试使用into outfile,有--secure-file-priv限制无法写入:
转而使用Mysql Log日志存储的方式进行写入:
set global general_log=on; set global_log_file='/xxx/www/xxx.php'; select '<?php @eval($_REQUEST["xxx"]);?>';访问相关文件却提示我无法访问(403/AccessDefined):
遇到这种情况尝试以下几种方法:
- 修改后缀访问,判断是否是只针对脚本后缀进行限制(上传.htaccess文件)
- 修改内容访问,判断是否有安全防护对内容进行限制
- 如若以上均未访问成功,则可以考虑覆盖原文件写入
这里我的情况是第三种,大概推测可能是因为新建的文件没有执行权限所导致,因为这里我们已经有源码了所以可以直接找已有的文件(建议选择非业务相关的文件)进行写入(记得事后恢复):
执行phpinfo();函数可以,但无法直接使用管理工具连接,抓包发现目标网站上了云WAF,对请求内容拦截了(该WAF还挺弱),这种情况还是有很多中方式:
- 配合Cknife、蚁剑等自定义修改传输内容(Base64编码等等),但需要修改PHP文件内容配合解码
- 直接上冰蝎、哥斯拉的马就行了
为图方便,选择冰蝎3,使用file_put_contents写入连接就行(这都不拦,WAF堪忧):
瞄准靶标进入子域的Webshell发现内网无机器、就是一个云服务器,一开始误以为打中靶标,因为在主战发现一个路径泄漏:
而子域服务器上也有对应目录并且文件一模一样,但是修改文件却没反应不生效,猜测很有可能主战业务曾经在这个子域服务器上,但后期进行了转移,原Web文件还留着。
尝试翻翻源码,找密码,后来找到了几个有用的东西:1.Adminer文件 2.数据配置信息
Adminer(类似phpMyAdmin的数据库管理工具)文件是随机的: adminerxxxxxxxxx.php,完全无法扫到,数据库配置密码与子域完全一样。
使用数据配置密码无法登录,但是这里Adminer可以直接连外网的Mysql数据库,使用脚本( https://github.com/Gifts/Rogue-MySql-Server )伪造一个Mysql服务端读取对应文件就好,这边以/etc/passwd为例:
如上图所示是成功读取到的,而我们在子域上也知道了对应的配置文件路径,直接伪造读取即可。
再使用Adminer登录进去时,使用如下几种方法尝试获取Webshell:
- into outfile -> 失败
- Mysql log -> 失败
- Adminer是最新版本无漏洞 -> 失败
- 获取管理员密码无法解密 -> 失败
最终选择添加新管理员登录:
登录之后寻找对应上传点(以最短攻击路径的方式进行GetWebShell):
测试如下后缀及服务器结果:
Key.jpg -> 上传成功 Key.php -> 上传失败WAF拦截 Key.phtml -> 上传失败文件类型不允许我们在已经有源码的情况下,找到对应的代码进行审计就行,发现这里是白名单设置无法绕过:
直接关键词寻找上传功能,发现函数:xxx_upload_file存在任意文件上传
后续构建请求包以及使用回车直接绕过CloudWAF,上传成功:
至此靶标拿到,结束。
文末很多时候还是需要去探寻事物的本质和原理,才能更加清晰明了的了解这个事物,否则什么东西都是现有的成品一把梭,遇到梭不了,容易出现惯性思维,可能就直接略过了。