本篇文章基于学习CTF中遇上的编码问题和代码审计进行学习。
第一:准备好靶场环境
第二:常看web页面了解功能,发现此页面为静态页面,无任何功能可以交互,那就从扫描其他目录看看能不能获取有效信息,以及查看网页源代码获取解题关键。
发现其中这段源码,分析其中$_SERVER["QUERY_STRING"] 和俩段if语句:
1.$_SERVER["QUERY_STRING"]:
获取查询语句,实例中可知,获取的是?后面的值;
2.第一个if 中substr_count() 函数计算子串在字符串中出现的次数,为“或”语句:
if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 )
即不能存在_,这里用%5f url编码绕过也被过滤了,但是可以使用空格代替_来进行绕过;
3.第二个if需要同时满足两个条件:
if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t']))
preg_match函数用于匹配正则表达式。GET提交参数,由上者得参数不能含_,用 . 代替,然后过滤正则表达式加%0A,%0A是回车的url编码,可以满足不强等于,同时满足含有特定字符串。
构造一个payload:b.u.p.t=23333%0a
第三:根据提示,我们来访问下secrettw.php。
此时我们得到一个响应为一串编码的字符,根据明显特征我们百度搜索得到这是一段jsfuck编码。
第四:我们这时候来解码看看,这里推荐大家使用(http://codertab.com/JsUnFuck);
第五:可以看到需要我们post传参一个Merak参数,我们根据提示去尝试。
第六、其中又获得了新的源代码,此时我们进行进一步的分析;
对于getIp();此处一般只有XFF和Client-ip这两种方法,并且ip必须为127.0.0.1;此处传入参数2333需要恒等于todat is a happy day并且file_get_contents() 函数把整个文件读入一个字符串中,因为后面是单引号,又用===判断全等,用data://text/plain进行转换,并且get传参参数file为flag.php,
构造payload为?2333=data:text/plain,todat is a happy day&file=flag.php,访问得到:
第七、发现我们并没有直接获取到有效信息,实际file_get_content函数不是直接使用的$_GET[‘file’]的值,而是用到了上面说到的change函数来转换的:
首先$v = base64_decode($v);是使用 base64解$v;
$re .= chr ( ord ($v[$i]) + $i*2 );$v的每一个字母的ascii加上2*i再转换为此时值对应的ascii字符,然后与之前的$re拼接;
并且ord()函数是chr()函数(对于8位的ASCII字符串)或unichr()函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数, 返回对应的ASCII 数值 或者 Unicode数值,如果所给的Unicode字符超出了你的Python定义范围,则会引发一个TypeError的异常。
我们尝试反写flag.php,exp如下并运行:
得到flag.php为ZmpdYSZmXGI=;并且对todat is a happy day进行base64编码为dG9kYXQgaXMgYSBoYXBweSBkYXk=
此时我们继续构造payload为
?2333=data://text/plain;base64,dG9kYXQgaXMgYSBoYXBweSBkYXk=&file=ZmpdYSZmXGI=
总结下此道题目我们需要注意学习的点:编码和代码审计函数的重要性。
1.编码:
对于我们平常耳熟能详的莫过于base64编码了,但也会有我们不常遇见的,这时候我们需要积累丰富自己的知识,对于一些编码形式需要我们能够知道了解。
2.代码审计:
代码审计其实更多关注于对于危险函数的使用方式,我们对于以后看见不熟悉的方法我们可以多去了解如何使用的,此处我们需要对于change()方法和file_get_contents()函数进行分析,对于change()方法我们需要知道如何可以反写,如同base64编码解码一样,对于file_get_contents()函数,我们需要了解可以把整个文件读入一个字符串中。
至此,我们学习编码和代码审计就结束了。