2019国赛西南赛区部分WEB WP
前言
- 国赛区域赛打完了,太菜了,就当公费旅游了。趁这几天有空复现了一下几道题。
day1
- 划水并且上别人的车。源码忘了拷,血亏。只做出一道yml反序列化的题,还是上的别人的车。
day2 web1
- 先膜一发evoA师傅,感谢大师傅给的思路。
- 这题思路很骚,虽然做题点都学过,但是思路很巧妙。 考点:htaccess文件写入
- 首先,提示是文件上传,但是文件上传处被过滤的死死的;整个目录中相对宽松的地方就只有login-lock.php处的代码了,通过post time参数可以写入任意代码:
12345678
if (isset($_POST["time"])) { $time = $_POST["time"]; $lock = fopen("files/" . $_SESSION["name"], "w"); fwrite($lock, $time); fclose($lock); sleep(2);//假装处理要消耗不少时间 让动画好看一点 echo "files/" . $_SESSION["name"];}
但是,生成的文件名使用的name是用户名,而在注册用户时,用户名过滤比较严格:
1 |
preg_match('/(.+)(?=\.)/', $name, $matches); //只要发现.前面有东西就干死 |
其实回过头来才看出来作者是在提示:.前面有东西就干死 :),那前面没东西不就好了。
所以这里可以创建一个用户名为.htaccess
的用户,在其中将jpg文件解析为php;然后再创一个正常用户,上传一个图片马即可getshell(不能用.htaccess用户是因为php默认不解析包含htaccess关键字的文件,而上传的图片名也为用户名)
.htaccess内容为:
1 |
AppType application/x-httpd-php .jpg |
一个意外发现的点
- 这个点是队友想出来的,既然可以直接写入没有文件名而只有后缀的文件,是不是可以直接写入
.php
文件呢? - 在不同的系统上尝试,发现在本机的windows中可以直接解析
.php
文件,而在ubuntu系统中则无法解析。 - 原因是apache在linux下解析文件时,对隐藏文件(开头为.号)的文件是不给访问权限的,所以无法直接写入
.php
文件getshell。
day2 web2
- 此题源码泄露+多行匹配绕过
-
首先扫描路径获得swp文件(做题时自己字典太菜了,居然没扫到,很难受),还原得源码,关键代码:
12345678910111213141516171819
0); $file_name = $_POST["path"];if(preg_match("/flag/",$file_name)){die("请不要输入奇奇怪怪的字符!");}if(is_array($file_name)){$file_name=implode($file_name);}if(!preg_match("/^[a-zA-Z0-9-s_]+.rar$/m", trim($file_name))) { echo trim($file_name).'<br>';echo "请输入正确的文件名";}else { echo "/usr/bin/md5sum " . $file_name;echo( exec("/usr/bin/md5sum " . $file_name));}
error_reporting( -
可以看到有命令执行,第一处的preg_match用传入数组绕过,第二处的preg_match用多行匹配%0a绕过(多行匹配对每一行进行匹配,只要有一行满足就返回1)。 payload:
1
path[]=1.rar%0acat /flag
day2 web3
- 吐槽一下,这题是真的辣鸡,出题人出错了题,主办方也不好好审一下。
- 比赛的时候一眼看出来是南邮CTF的一道题的改版,直接拿当时的脚本怼,不出结果。再查看注释,发现要输入一个比 1000000大的最小的素数,查了一下是1000003,拿脚本继续跑,各种改,跑了一上午都不出flag;这时候看看全场,居然没有一支队伍做出来,肯定遇到坑了,就没做了。
- 最后fix环节的时候才发现题给错了,应该是比 10000000大的最小的素数,为 10000019。拿脚本又打了一遍,出flag了,手动微笑,建议把出题的打死
- 此题几乎照搬NCTF“小绿草之最强大脑”,考点:会写脚本解析网页,直接上脚本:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
#calc.pyimport redef jia(*args): ''' 加法解析 :param args: :return: ''' # print('jia:', args) res = 0 for i in args: #解决*-和/-的情况 #i = i.replace('*-','#').replace('/-','@') jian_list = i.split('-') # 减号的拆分要解决负号的情况:把负号拆分后列表中所有为空字符串的元素替换成'0' # 还要把*-和/-替换回来 for id,j in enumerate(jian_list): if j=='': jian_list[id] = '0' else: jian_list[id] = j.replace('#','*-').replace('@','/-') res += jian(*jian_list) return resdef jian(*args): ''' 减法解析 :param args: :return: ''' # print('jian:', args) #减法需要先算出第一个式子,拿第一个式子去减后面的式子 res = args[0:1] res = chen(*res[0].split('*')) for i in args[1:]: chen_list = i.split('*') res -= chen(*chen_list) return resdef chen(*args): ''' 乘法解析 :param args: :return: ''' # print('chen:',args) res = 1 for i in args: chu_list = i.split('/') res *= chu(*chu_list) return resdef chu(*args): ''' 除法解析 :param args: :return: ''' # print('chu:', args) #除法需要先取出第一个,拿第一个除以后面的 res = args[0:1] res = int(res[0]) for i in args[1:]: i = int(i) res /= i return resdef simpleCalc(input_str): ''' 不带括号的表达式解析 :param input_str: :return: ''' # 去掉最外层的括号 input_str = input_str.strip('()') # 处理 --、+- 的情况,还有 *-、/- 的情况没处理 input_str = input_str.replace(' ','').replace('--','+').replace('+-','-').replace('*-','#').replace('/-','@') #print(input_str) #计算加减乘除 jia_list = input_str.split('+') res = jia(*jia_list) return res #return str(eval(input_str))def calc(input_str): ''' 计算器入口 :param input_str: :return: ''' if len(input_str) == 0: # print('Wrong input') exit(0) #print(input_str) #查找是否还有括号 m = re.search('\([^()]+\)', input_str) brackets_exists = False #print(m) if m == None:#不再有括号了,就直接计算 simple_calc_str = input_str#需要计算的值的字符串就是传入的表达式 else:#还有括号,就把找到的括号中的表达式计算的值替换括号所在位置 brackets_exists = True simple_calc_str = m.group()#需要计算值的字符串是找到的括号中的表达式 simple_res = str(simpleCalc(simple_calc_str)) if brackets_exists:#还有括号,就把找到的括号中的表达式计算的值替换括号所在位置,进入迭代 return calc(input_str.replace(simple_calc_str,simple_res,1)) else:#没有括号就直接把计算结果返回 return simple_resif __name__ == '__main__': # input_str = '3 * 4 + (-4 / 2 - 8 - 3 * 2 + ( 4 - 5 / 2 + 11 - ( 2 * 3 - 9 ) - 12 )) + 20 - 3 * 2 - ( 5 + 8 / 4)' # input_str = '3/(-1) - (4*-2)/(1+1)/(1+1)' input_str = '1-2*30000000000000000000000000000000000000000' result = calc(input_str) print(result) |
12345678910111213141516171819202122232425262728293031323334353637383940414243 |
#get_flag.pyimport requestsimport refrom calculator import calcfrom bs4 import BeautifulSoupimport timeurl="http:/localhost:801/ctf_test/guosai_xx/source/web3//index.php"sess=requests.session()res = sess.post(url)for i in range(5): vstr = res.text soup = BeautifulSoup(vstr,'lxml') form = soup.text form = form.strip('\n') form = form.strip('\r') # form = form.replace('\t','') print('原:',form) # 原 form = ''.join(re.findall('([0-9\-*+])', form)) print(form) # 原 if(i!=0): form=form[1:] form=form[1:] print('提取算式,剪切',form) # 提取算式,剪切 form = '10000019+(' + form+')' #1000003 print('算式'+form) result = calc(form) print(result) data={'input': '10000019', 'ans': result} time.sleep(2) res = sess.post(url,data=data) # print(res.text) print(res.headers)print(res.text)print(res.headers) |
结语
- 第一天还有很多道题没来得及拷出来,不知道能不能在网上找到WP;自己的水平也很菜,继续学习才能赶上大部队。
- 最后附上本文中题的源码:https://github.com/HACHp1/hackable_cms_store/tree/master/guosai_xx
- source:hachp1.github.io
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论