首页
社区
课程
招聘
[原创]跟着crownless学Web之(4)extract变量覆盖
发表于: 2019-1-26 11:40 7817

[原创]跟着crownless学Web之(4)extract变量覆盖

2019-1-26 11:40
7817

本文备份于我的博客
大家好,我是Web安全板块的新版主crownless。最近我将以CTF赛题讲解的形式介绍一系列的Web基础知识,讲解的顺序将是循序渐进,因此不需要读者有任何基础知识。希望能吸引更多人关注看雪的Web安全板块,为板块增加人气和活力。
如果你还没有阅读第一篇教程第三篇教程,建议你先阅读之后再阅读本文。
在这篇文章中,你将学到:

话不多说,让我们开始吧。首先打开这次的CTF赛题网站:
http://139.224.220.67:23900/dmsj/level2/
你会发现一片空白,网页的源代码也为空。这里,我提供php后端的源代码供你审计:

首先,flag变量被设置为'xxx',一个简单的字符串。
接着,后端运行了extract函数,从$_GET数组中将变量导入到当前的符号表。什么意思呢?其实很简单。比如如果我们访问了http://139.224.220.67:23900/dmsj/level2/?sixstars=1,那么$_GET["sixstars"]的值为字符串1。执行extract($_GET);时,就相当于执行了$sixstars='1'
然后,程序将会执行isset($sixstars)。我们看到,为了获取flag,必须执行到echo 'flag{xxx}';,所以isset($sixstars)的返回值必须为 TRUE。所以,我们必须通过extract($_GET);sixstars变量设置为任意值,即使是空字符串也可以。也就是说,即使访问http://139.224.220.67:23900/dmsj/level2/?sixstars=也是可以的。但绝对不能不包含sixstars参数。
接着,程序将会执行$content=trim(file_get_contents($flag));。我们分步看。首先会执行file_get_contents($flag)。正常情况下,如果你不通过URL传入flag参数,那么,因为程序的最开始已经执行过$flag='xxx';,所以到了这里将会执行file_get_contents('xxx')file_get_contents函数可以“将整个文件读入一个字符串”。比如如下代码可以将http://www.example.com/网站的源代码读取到homepage变量中并显示出来。

接着,php又会执行trim函数,它将会“去除字符串首尾处的空白字符(或者其他字符)”。
最后,php将会执行if ($sixstars==$content),如果为TRUE,那么将会显示flag。
读到这里,你想必已经知道了我们该怎么做:首先,给sixstars变量传入一个值,比如1。然后,给flag变量传入一个我们能控制的网站的地址,并让这个我们能控制的网站的源代码设置为1。由于extract能起到“变量覆盖”的作用,在extract后,flag变量就会被覆盖为我们能控制的网站的地址,而不再是'xxx',这样当执行到file_get_contents时php后端将会从我们能控制的网站上读取到1,并将其和sixstars变量比较,并返回TRUE,然后就能打印flag。
虽然这个方法是可行的,但是今天我要教你一个更简单的方法,那就是php伪协议。我们可以直接给flag变量传入data://text/plain,1。意思是明文1。这样file_get_contents('data://text/plain,1')将会直接返回1,就不需要我们在公网上开一台服务器了。
所以,最后我们的payload是:

这里再强调一下,给后端传参的方法是:在?后跟变量名字,不同的变量之间用&隔开。
关于伪协议,我们以后有机会还会碰到。请大家继续关注看雪Web安全板块crownless的CTF赛题讲解。

<?php
$flag='xxx';
extract($_GET);
if(isset($sixstars)) {
    $content=trim(file_get_contents($flag));
    if ($sixstars==$content) {
        echo 'flag{xxx}';
    } else {
        echo 'Oh.no';
    }
}
?>
<?php
$homepage = file_get_contents('http://www.example.com/');
echo $homepage;
?>

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2019-1-26 12:39 被crownless编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (12)
雪    币: 403
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
2019-1-26 12:46
0
雪    币: 271
活跃值: (3248)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
2019-1-26 12:53
0
雪    币: 4366
活跃值: (353)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
4

学习了 请教一下为什么这个payload不行:

http://139.224.220.67:23900/dmsj/level2/?sixstars=139.224.220.67&flag=http://www.ifconfig.me
2019-1-26 17:07
0
雪    币: 2157
活跃值: (12639)
能力值: ( LV12,RANK:312 )
在线值:
发帖
回帖
粉丝
5
自己学习笔记贴一下:

有一些疑问
1、extract读取了整个&Get(包含我们输入的参数),所以变量flag会被覆盖成我们传入的变量?
2、根据php伪协议的特性,利用返回为1(可控),进而与我们sixstars相符合所以成功?
3、php伪协议 data://— 数据(RFC 2397),是其中的一种 ?是不是换一种格式就达不到这种效果了?
看了一下关于data的伪协议还是不清楚干什么用的,file=data:text/plain这种也可以。
是不是控制了了file_get_contents 返回值为,也能相对应的成功?
2019-1-26 17:54
0
雪    币: 2282
活跃值: (426)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
6
心许雪 学习了 请教一下为什么这个payload不行: ``` http://139.224.220.67:23900/dmsj/level2/?sixstars=139.224.220.67&f ...
你没有理解file_get_contents函数的意义,其真正作用是将其参数所指向的文件的##内容##读取到一个字符串中。如果你想让你的payload生效,那么你应该修改flag参数,让其指向一个网站,其源代码仅仅是“139.224.220.67”这个字符串,而不是现在这样包含另外的杂七杂八的东西。或者你应该修改sixstars参数,让其等于139.224.220.67这台主机读取http://www.ifconfig.me的内容,然而,由于http://www.ifconfig.me是一个动态页面,这是不可能做到的。所以你只能尝试修改flag参数,让其指向一个网站,其源代码仅仅是“139.224.220.67”这个字符串。
2019-1-26 18:04
0
雪    币: 2282
活跃值: (426)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
7
理想小青年 自己学习笔记贴一下:有一些疑问1、extract读取了整个&amp;Get(包含我们输入的参数),所以变量flag会被覆盖成我们传入的变量?2、根据php伪协议的特性,利用返回为1(可控),进 ...
1、是的,flag的原值会被覆盖
2、是的,需要同时控制sixstars和flag变量
3、data://text/plain,1顾名思义是“明文数据1”的意思。关于伪协议,以后我们还会再讲。
你也可以在外网开一台服务器http://a.b.c.d/,让其源代码是“1”,然后控制flag变量为http://a.b.c.d/,这样也能达到相同的效果。
2019-1-27 10:05
0
雪    币: 2157
活跃值: (12639)
能力值: ( LV12,RANK:312 )
在线值:
发帖
回帖
粉丝
8
crownless 1、是的,flag的原值会被覆盖 2、是的,需要同时控制sixstars和flag变量 3、data://text/plain,1顾名思义是“明文数据1”的意思。关于伪协议,以后我们还会再讲。 ...
谢谢版主 
2019-1-27 20:17
0
雪    币: 4366
活跃值: (353)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
9
crownless 你没有理解file_get_contents函数的意义,其真正作用是将其参数所指向的文件的##内容##读取到一个字符串中。如果你想让你的payload生效,那么你应该修改flag参数,让其指向一个网站 ...
感谢回复。php中file_get_contents('http://ifconfig.me') 返回的就是当前server的出口的ip地址,似乎是不需要指定flag参数的。
file_get_contents(string$filename[,bool$use_include_path=FALSE[,resource$context[,int$offset= 0[,int$maxlen]]]] ) :string
我本地测试过了是可以的,因此怀疑是不是服务器的出口ip不是139.224.220.67呢?
➜  webroot cat pediy.php
<?php
$flag='xxx';
extract($_GET);
if(isset($sixstars)) {
    $content=trim(file_get_contents($flag));
    echo $content;
    if ($sixstars==$content) {
        echo 'flag{xxx}';
    } else {
        echo 'Oh.no';
    }
}
?>
➜  webroot curl 'http://localhost:10080/pediy.php?sixstars=45.124.66.212&flag=http://www.ifconfig.me'
45.124.66.212flag{xxx}%
最后于 2019-1-28 17:54 被心许雪编辑 ,原因:
2019-1-28 17:49
1
雪    币: 2282
活跃值: (426)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
10
心许雪 crownless 你没有理解file_get_contents函数的意义,其真正作用是将其参数所指向的文件的##内容##读取到一个字符串中。如果你想让你的p ...
有可能是的,服务器不是我配置的,所以我也不是很清楚。
2019-1-29 09:57
1
雪    币: 4366
活跃值: (353)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
11
crownless 有可能是的,服务器不是我配置的,所以我也不是很清楚。
thanks~
2019-1-29 10:06
0
雪    币: 230
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
心许雪 crownless 你没有理解file_get_contents函数的意义,其真正作用是将其参数所指向的文件的##内容##读取到一个字符串中。如果你想让你的p ...
应该是服务器出口地址和题目IP不一样导致的吧,我这边看到通过file_get_contents,访问到我的地址是202.120.234.78,并不是题目地址
2019-2-3 22:49
0
雪    币: 73
活跃值: (923)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
继续学习
2019-2-15 09:58
0
游客
登录 | 注册 方可回帖
返回
//