freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

带你走入CTF之路
2019-03-16 19:33:12

CTF是一种流行的信息安全竞赛形式,从今天开始我们将慢慢步入CTF之路,探求安全领域中的某些薄弱环节。直接进入主题:

一、FALSE

在我初步拿到一道WEB类型的CTF题目时,不管页面是什么样,我都会首先右击查看网页源代码,看是否有可以提示以及利用的信息。如下图所示:该页面是FALSE这道题的页面,我们发现最下方有一句提示“view the source code”的信息,它把源代码给我们展示出来。我们可以就此分析。

图片.png图片.png

很显然,这是用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

此时又有一个问题:在输入框中,怎么才能传入数组类型的值呢?

图片.png因为通过GET方式接收参数,所以我们直接在URL中就可以将变量name和password加上数组类型的标志,然后传入不一样的值就OK。如下,成功获取flag。

图片.png

附上本题链接:http://www.shiyanbar.com/ctf/1787


二、实验吧天网管理系统

图片.png在我们进入一道WEB类型的CTF试题的时候,首先要观察页面内容,然后尝试去右击查看页面源代码!当我们进入该题目时,会发现,页面上已经显示账户和密码,我们尝试登入系统,发现没有反应,此时查看源代码发现:(不做别的,就先去查看源代码)

图片.png

要点一: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的字符串后,我们在页面得到一些提示信息,如图所示:

图片.png

会有一串标红的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[]=

 

备注:上述自己整理的过程比较详细,希望能从根本上让大家去解决每一个不懂的地方,当然网上也能搜到相关的解题思路和过程。以后会不断更新。


# CTF
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者