查看原文
其他

跟着crownless学Web之strcmp、extract变量覆盖

crownless 看雪学院 2019-05-25


简介:


本文由Web安全版块的新版主crownless原创讲解。下文将以CTF赛题讲解的形式为大家介绍一系列的Web基础知识,讲解的顺序将是循序渐进,因此不需要读者有任何基础知识。希望能吸引更多人关注看雪的Web安全版块,为版块增加人气和活力。


本篇为『跟着crownless学Web系列』的第三和第四部分,建议没有了解前两部分的同学可以先了解学习前面两部分的内容,具体学习入口见下:


点击即可阅读:


跟着crownless学Web之(1)神奇的计算器


跟着crownless学Web之(2)calc2


跟着crownless学Web之(3)

在这篇文章中,你将学到:


  1. php isset函数

  2. php strcmp函数

  3. php die函数


话不多说,让我们开始吧。首先打开这次的CTF赛题网站:


http://139.224.220.67:23900/dmsj/level0/


你会发现一片空白,网页的源代码也为空。这里,我提供php后端的源代码供你审计:

<?php

$flag = "flag{xxxxx}";

if (isset($_GET['a'])) {

   if (strcmp($_GET['a'], $flag) == 0)

       die('Flag: '.$flag);

   else

       print 'No';

}

?>


首先,flag变量被设置为flag{xxxxx}。当然,这是一个假的flag,真实运行的后端中的flag变量才是真的flag,需要我们去夺取。


接着,isset函数判断HTTP GET请求中的参数
a是否已设置并且非NULL。strcmp函数将a参数与flag相比较,如果一致,则调用die函数。die函数的作用是打印die函数的参数,并立即停止该php后端的运行。那么我们的目标很明显,就是要让php执行到die函数,让flag显示出来。


那么我们怎么给php后端传参呢?在第一篇教程中,我们可以通过在输入框中输入内容并点击提交按钮,由浏览器帮助我们自动传参。现在,我们必须要手动传参了。其实也很简单,只要访问
http://139.224.220.67:23900/dmsj/level0/?a=123即可给a参数传入123


接下来难题来了,你根本不知道flag是什么,又怎么让strcmp函数返回0,即比较相等呢?


查看strcmp的介绍页面,我们可以发现下方有一条注释:


If you rely on strcmp for safe string comparisons, both parameters must be strings, the result is otherwise extremely unpredictable.

 

即,如果我们给strcmp传入非字符串的参数,那么结果是非常未知的。
下面还给出了一些例子:

strcmp("5", 5) => 0

strcmp("15", 0xf) => 0

strcmp(61529519452809720693702583126814, 61529519452809720000000000000000) => 0

strcmp(NULL, false) => 0

strcmp(NULL, "") => 0

strcmp(NULL, 0) => -1

strcmp(false, -1) => -2

strcmp("15", NULL) => 2

strcmp(NULL, "foo") => -3

strcmp("foo", NULL) => 3

strcmp("foo", false) => 3

strcmp("foo", 0) => 1

strcmp("foo", 5) => 1

strcmp("foo", array()) => NULL + PHP Warning

strcmp("foo", new stdClass) => NULL + PHP Warning

strcmp(function(){}, "") => NULL + PHP Warning


怎么样,是不是让人大开眼界呢?这就是“世界上最好的语言”——php。


事实上,我们可以给
a参数传入一个数组。比如,如果我们访问:


http://139.224.220.67:23900/dmsj/level0/?a[0]=123


那么我们就相当于给a参数传入了一个数组,该数组的第0个元素是123字符串。


试试看访问:


http://139.224.220.67:23900/dmsj/level0/?a[0]=123


你会惊喜地发现打印出了flag。当php将一个数组变量和一个字符串进行比较时会意外地返回0,即相等,是不是很让人惊讶呢?


好了,以上就是『跟着crownless学Web』的第三部分内容。




接下来,一起进入第四部分的学习吧~


跟着crownless学Web之(4)

在这篇文章中,你将学到:


  1. php extract函数

  2. php trim函数

  3. php file_get_contents函数

  4. php伪协议data://


话不多说,让我们开始吧。首先打开这次的CTF赛题网站:
http://139.224.220.67:23900/dmsj/level2/


你会发现一片空白,网页的源代码也为空。这里,我提供php后端的源代码供你审计:

<?php

$flag='xxx';

extract($_GET);

if(isset($sixstars)) {

   $content=trim(file_get_contents($flag));

   if ($sixstars==$content) {

       echo 'flag{xxx}';

   } else {

       echo 'Oh.no';

   }

}

?>


首先,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

$homepage = file_get_contents('http://www.example.com/');

echo $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是:

http://139.224.220.67:23900/dmsj/level2/?sixstars=1&flag=data://text/plain,1


这里再强调一下,给后端传参的方法是:在?后跟变量名字,不同的变量之间用&隔开。


关于伪协议,我们以后有机会还会碰到。请大家继续关注看雪Web安全板块crownless的CTF赛题讲解。


作者:周信安


看雪ID: crownless,毕业于复旦大学软件工程专业,看雪WEB安全版块 新版主,研究方向为WEB安全、Android、系统安全。


个人博客地址:

https://zhouxinan.github.io




- End -


看雪ID:crownless               

https://bbs.pediy.com/user-833800.htm


本文由看雪论坛 crownless 原创

转载请注明来自看雪社区



热门图书推荐:



立即购买!


(点击图片即可进入)



热门技术文章:        





公众号ID:ikanxue

官方微博:看雪安全

商务合作:wsc@kanxue.com


点击下方“阅读原文” 

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存