CTF是一种流行的信息安全竞赛形式,从今天开始我们将慢慢步入CTF之路,探求安全领域中的某些薄弱环节。直接进入主题:
一、FALSE
在我初步拿到一道WEB类型的CTF题目时,不管页面是什么样,我都会首先右击查看网页源代码,看是否有可以提示以及利用的信息。如下图所示:该页面是FALSE这道题的页面,我们发现最下方有一句提示“view the source code”的信息,它把源代码给我们展示出来。我们可以就此分析。
很显然,这是用PHP语言写的登录。接下来我们要对这段代码进行分析:
1、分析if (isset($_GET[‘name’]) and isset($_GET[‘password’])) :
在php语言中,isset()函数用来检测变量是否设置值。当变量不存在时返回FALSE,当变量存在返回TRUE,当变量为NULL也返回FALSE。我们想进入该if循环,必须要给name和password都赋值。
2、分析if ($_GET[‘name’] == $_GET[‘password’]):
通过GET方式获取传入的name和password的值,如果传入的值相等,页面输出“Your password cannot be your name!”,可见我们输入的name和password不可以是一样的值。
3、分析else if (sha1($_GET[‘name’]) === sha1($_GET[‘password’])):
首先我们要明白PHP语言中sha1()函数的作用,即计算字符串的SHA-1散列。该函数使用的是美国 Secure Hash算法1。如果成功则返回已计算的 SHA-1 散列,如果失败则返回 FALSE。die()函数输出一条消息并退出当前脚本。由此可见,我们要输入的name和password必须保证他们的SHA-1散列相等,才能输出flag。
问题来了:那么我们怎么才能保证输入的字符串不一样,但是计算出来的sha-1散列的值相等呢?
这是我们就要从数据的类型上去考虑,注意上述表述中标红的一句话。sha1()函数是计算字符串的值,当我们传入的不是字符串类型的值时,sha1()函数会返回false。由此可见传入的name和password在计算sha1值时如果都失败的话:false===false为真,执行else if中的内容。
所以,我们就要传入不是字符串类型的name和password。
例如:传入数组类型:name[]=1 password[]=2
此时又有一个问题:在输入框中,怎么才能传入数组类型的值呢?
因为通过GET方式接收参数,所以我们直接在URL中就可以将变量name和password加上数组类型的标志,然后传入不一样的值就OK。如下,成功获取flag。
附上本题链接:http://www.shiyanbar.com/ctf/1787
二、实验吧天网管理系统
在我们进入一道WEB类型的CTF试题的时候,首先要观察页面内容,然后尝试去右击查看页面源代码!当我们进入该题目时,会发现,页面上已经显示账户和密码,我们尝试登入系统,发现没有反应,此时查看源代码发现:(不做别的,就先去查看源代码)
要点一:md5()函数:计算字符串的md5散列。MD5 报文摘要算法将任意长度的信息作为输入值,并将其换算成一个 128 位长度的”指纹信息”或”报文摘要”值来代表这个输入值,并以换算后的值作为结果。
要点二:==(判断值是否相等)===(判断值及类型是否相等)
要点三:PHP弱类型,在某些情况下,PHP会把类数值数据(如含有数字的字符串等)转换成数值处理,== 运算符就是其中之一。在使用 == 运算符对两个字符串进行松散比较时,PHP会把类数值的字符串转换为数值进行比较,如果参数是字符串,则返回字符串中第一个不是数字的字符之前的数字串所代表的整数值。比如: ‘3’ == ‘3ascasd’结果为true。
分析这段注释代码:<!– $test=$_GET[‘username’];$test=md5($test); if($test==’0′) –>
$test=$_GET[‘username’];用test变量接收页面传参username。
$test=md5($test);使用md5()函数对$test变量进行加密,并覆盖$test值。
if($test==’0′)如果传入的值在md5加密后值为0。则执行if。
在分析过代码后,我们发现,只要保证uername的md5值开头数字是0的话,$test==’0’。
以下提供给大家一些md5首字符为0的值:
开头为0的md5值:
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a
0e545993274517709034328855841020
在成功输入md5首字符为0的字符串后,我们在页面得到一些提示信息,如图所示:
会有一串标红的URL弹出,我们尝试访问该URL,会发现有如下内容:
“$unserialize_str = $_POST[‘password’];$data_unserialize = unserialize($unserialize_str); if($data_unserialize[‘user’]== ‘???’ && $data_unserialize[‘pass’]==’???’) { print_r($flag); } 伟大的科学家php方言道:成也布尔,败也布尔。 回去吧骚年”
要点一:unserialize()函数:对单一的已序列化的变量进行操作,将其转换回 PHP 的值。如果传递的参数不可序列化,则返回FALSE。
分析这段代码:
$unserialize_str = $_POST[‘password’];unserialize_str变量接收页面传入的POST值$data_unserialize =unserialize($unserialize_str);使用反序列化函数unserializeif($data_unserialize[‘user’] == ‘???’ && $data_unserialize[‘pass’] ==’???’) { print_r($flag);}
这段码意思是把post提交的password值经过”反序列化”得到一个数组,要求数组里的user和pass都等于某个值时就打印flag。bool类型的true跟任意字符串可以弱类型相等
(a代表array,s代表string,b代表bool,而数字代表个数/长度)
构造password值为: a:2:{s:4:”user”;b:1;s:4:”pass”;b:1;}
三、one more:
ereg()函数漏洞,strlen()函数,strpos()函数
例子:
<?php
if (isset ($_GET[‘password’])) {
if (ereg (“^[a-zA-Z0-9]+$”,$_GET[‘password’]) === FALSE){
echo ‘<p>You password must bealphanumeric</p>’;}
else if (strlen($_GET[‘password’]) < 8&& $_GET[‘password’] > 9999999){
if (strpos ($_GET[‘password’], ‘*-*’) !==FALSE){
die(‘Flag: ‘ . $flag);}
else{
echo(‘<p>*-* have not beenfound</p>’);}}
else{
echo ‘<p>Invalid password</p>’;}}?>
分析:
1、isset ($_GET[‘password’])检测变量是否设置
2、ereg (“^[a-zA-Z0-9]+$”, $_GET[‘password’]) === FALSE如果想进入if判断必须保证password值是一个后者多个数字、字母大小写。
3、strlen($_GET[‘password’]) < 8 && $_GET[‘password’] >9999999 提交的password长度要小于8并且大小要大于99999999。
4、strpos ($_GET[‘password’], ‘*-*’) !== FALSE password里必须要有’-’。
因为ereg()函数存在NULL截断漏洞,导致正则过滤被绕过,所以可以用%00来截断正则匹配 ,第二个条件长度小于8大小大于99999999可以用科学计数法来绕过
则最后构造password=1e8%00*-*即可得到flag。
或者:password[]=
备注:上述自己整理的过程比较详细,希望能从根本上让大家去解决每一个不懂的地方,当然网上也能搜到相关的解题思路和过程。以后会不断更新。
来源:freebuf.com 2019-03-16 19:33:12 by: 凯信特安全团队
请登录后发表评论
注册