web

一些必要的知识

网络协议
协议 主要作用
IP 标识网络中的设备,并负责数据包的寻址与传递。
TCP 建立可靠连接,尽可能确保数据完整、有序地到达。
UDP 更加轻量、速度较快,但不保证数据可靠到达。
DNS 将人类容易记忆的域名转换为 IP 地址。
HTTP 在浏览器、客户端与 Web 服务器之间传输数据。
HTTPS 使用 TLS 加密保护通信过程的 HTTP。
WebSocket 在客户端和服务器之间建立持续的双向通信。

web组成

moectf Web方向

查分系统

这题是个静态网页,而且信息全写在了html没有进行任何加密处理,直接搜索关键词moectf就找到flag了。 alt text moectf{y0u_c@n_reAd_th3_h+nn1}

Web 安全与渗透测试入门指北

这题属于一个入门题目,点击F12
alt text
moectf{W3Lc0me_t0_th3_W0rLd_0f_w3BseCur1ty!!}

归途

这题需要我们把藏在网页中的key找出来。 首先用F12先找到了Key1-N2ghNUkkTQ==,Key2-QDBtNG9k
alt text alt text 随后在burpsuite中发现可以修改GET的URL得到Key3-M0szeUVuKw==,Key4-ZXJUaDFzbGE=,Key5-ITkzdA== alt text alt text
题目提醒POST api得到Key6-ZnwxbGFA alt text 题目提醒我们需要login,随后通过修改cookie来修改登录信息得到Key7-NGFAZzY5Nmc5
alt text

访问robots.txt告诉我们flag的路径在/f13ggggg 最后合并key并且base64解码输入得到flag。 alt text
moectf{0d05161a-9df3-e79e-0c7c-656e97a724a4}

当零来敲门

这题需要在10秒内从1到500按顺序输出数字,那就是主要考察代码编写。 用python来进行POST,首先先使用burpsuite来观察是如何发送数字的。
alt text

1
2
3
4
5
6
7
8
9
# 使用requests库来进行最基本的尝试,按顺序进行连续的POST请求。
import requests

url = "http://127.0.0.1:26879/chat"
s = requests.Session()

for i in range(1, 501):
s.post(url, json={"user": "haha", "msg": i})
print(i)

这样子的话速度不够快,查了一下是因为这个库不断建立TCP连接又断开,500次的话速度特别慢。如果只有100次左右的话还是可以的。
随后尝试了asyncio+aiohttp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 使用aiohttp, asyncio进行不等相应的异步请求。
import asyncio
from aiohttp import ClientSession

url = "http://127.0.0.1:26879/chat"

async def main():
async with ClientSession() as session:
tasks = []
for i in range(1, 501):
tasks.append(session.post(url, json={"user": "haha", "msg": i}))

await asyncio.gather(*tasks)

asyncio.run(main())

但是这个异步特别难去控制顺序,而且似乎请求太快了跑不到10个数字就跑不下去了。 python 异步 I/O - 实现并发http请求 如何用Python 快速发送1000条网络请求 随后继续查找python如何建立TCP连接并且是单线程可以按顺序发送的。(这里提出一个疑问如果像是asyncio + aiohttp使用多连接并发的话有没有办法来保证是按顺序请求?) 最后发现可以使用socket库,socket可以只建立一次TCP握手然后按照顺序将请求写入TCP缓存区。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 尝试的过程中发现,如果直接发送的话因为瞬间发送量过大导致服务器处理不过来,所以加上了time.sleep()。
import socket, time

host, port = "127.0.0.1", 26879

sock = socket.socket()
sock.connect((host, port))

for i in range(1, 501):
body = f'{{"user": "haha", "msg": {i}}}'.encode()
header = f"POST /chat HTTP/1.1\r\nHost: {host}:{port}\r\nContent-Type: application/json\r\nContent-Length: {len(body)}\r\nConnection: keep-alive\r\n\r\n".encode()
sock.sendall(header + body)
time.sleep(0.001)
# socket接受的是字节流,因此使用.encode()进行转化。
sock.close()

python通过socket实现TCP客户端和服务端

alt text moectf{PyThon_LAngu@gE_15-5O_SImP1E_tHaT-W3-c4n-m4k3_sOMe-small-and-practical-tools0}

MoeCatchTheFrogs

这题还是有点难度的,因为solves不到50( 题目要求我们及其九种青蛙。我首先用连点器点了几分钟那个捕获按钮结果发现最后一种似乎是捕获不了的。 alt text 看来得考虑别的办法了。
使用抓包工具查看捕获的逻辑,还有获取flag的逻辑。
alt text
捕获的话是向/api/draw发送请求。
alt text
最后是一个验证图鉴的请求,发现cookie一直在发生变化,猜测cookie是这题的突破点。 alt text
解密发现cookie前面是控制青蛙的图鉴信息的。
尝试直接修改来查看图鉴。
alt text
看来这个cookie后面是一串类似于验证的东西然后进行了加密。搜索了一下可能是JWT格式是(Header.Payload.Signature)后面是加密的内容,应该要找个秘钥什么的,但是我连怎么解密都不知道。
然后就卡住了。
alt text
管理员特别热心😊,提示让我使用Flask签名。 这个key找了半天了实在找不下去了直接用字典了。
wordlist(rockyou) alt text
经过字典解密得到秘钥是qwe123456
alt text
随后再进行签名,使用这个cookie来获得flag。
alt text
moectf{F1@sk_c00k1es_w1+h_w3ak_k3y_1s_vu1n3r@bl3}

古籍翻阅

这题让我们从1000本书中找到隐藏的flag。
首先肯定是要先写个脚本来访问每一本书人的话也行但是要看好久
alt text 正常如果没有内容的话会回显404,通过排除这个来找到提示信息。

1
2
3
4
5
6
7
8
9
import requests

f = open('guji_catalog.txt')
for line in f:
r = requests.get(f'http://127.0.0.1:22150/read?book={line.strip()}')
if '此卷散佚' not in r.text:
print(f'找到: {line.strip()}\n{r.text}')
break
f.close()

最后跑出来的提示信息是
alt text

访问根目录得到flag。 alt text moectf{re@d_the_r00t_5utr4_w1th_path_tr4v3r5@l}

河湖小盗

这是一个sql注入的题目。
alt text
使用抓包工具来获取POST的模板。
使用sqlmap列出数据库。
alt text 访问past_paper
alt text
得到flag alt text
moectf{h3re_i5_your_7e$7_pap3r}

熊出没

题目信息:

在遥远的狗粉岭中,生活着两只可爱的熊,他们在找蜂蜜的路上发现了许多蜜罐,但是有些蜜罐似乎是猎人为了捕获他们而设置的陷阱,他们能顺利吃到蜂蜜吗?(蜂蜜在54321端口)

直接输入端口对应的url会触发陷阱
alt text
输入错误时题目提示使用gopher协议,那么可以看出是SSRF了。
alt text
使用这个协议我们可以得到提示信息
alt text
直接访问这个路径是不行的
alt text
发现这个gopher协议会忽略一个字符,那么双写一下就行了。
alt text moectf{ee5774a8-303b-c692-2f03-1f1ba5a86245}

七狗免费小说

题目信息:

php:// 是什么?小刻不知道哦。小刻知道很多很厉害的 CTFer 都会先打开 F12 看看,万一里面有宝物呢?
这个是一道php伪协议的题目。 首先F12找到题目提示
alt text
alt text 这里看出来应该是隐藏了,使用过滤器+base64
alt text 常用的几种转化都失败了。
随后发现它拦截了部分输入
alt text 看来得想想这个二进制流是什么了。
最后想到其实可以使用压缩流,它刚不包含违禁词,而且也和二进制流有关。 php://filter的各种过滤器
只要能把文本内容给转化就可以看到隐藏的内容了,所以我们在读取这个文件的时候可以调用zlib对文本进行压缩然后输出。 alt text

 lZDRToJwGMXveQrGumUghOkivOs9AiXbbLrsqtaWkRmRUs0VOlrpStSWWlvLIdTL/L8//658heAN6uJcne+c77cj5yrFCrWil7a26Q2a2S0XtH39MK8JvJTOaGwqvyqwfFqSWEEVUqworvGFTDab1kT9iFmnClqxTDObSRhmb+AO0fzi576/DC7BHmPXJLUxdlpR9xT5PjabxAgj1yJeTVb3FDBHaG7FHpgeNurL4AGePDw4wc5Uriqk/wIzG84XcGXglon8M5mrKih0yXEdap+4cYPfe7j9FUNwHE2+O3jygW8b8HqXfAvdqD1MEJwp8QZgX9MHpR2VhpYVBaOYDoWPYE/R4hnNm9GkBxNjGXSToniMv+g/pzmF+gU= 

Zlib压缩/解压缩 alt text
moectf{dc20568c-1d42-0655-2b21-3370e8996c3f}

合乎周礼

题目信息:

JavaScript是庭院中的规矩与路数,而“父亲管教儿子”这句老话,拿来比作编程里的继承与约束,倒也有几分道理。父亲要儿子行得正、走得直,代码里的父类也要让子类守好本分、不逾矩。这样看来,我在JavaScript里讲这个道理,难道不也是合情合理的吗?
这题看起来特别的简洁。 alt text
总的来说就是需要我们提权,现在权限不够获取不了flag。
alt text
这里使用burpsuite来帮助我POST,注意这里要记得打上Content-type:application/json,之前没注意这个问题搞得我一直POST不上去。 alt text
直接修改的话发现这里只能填入profile里面,改变不了inheritedProbe并且也不能获取flag
alt text 没啥思路,看看题目信息。题目信息中提到JavaScript,然后是继承机制说是儿子受到父亲的控制。那么要是能够修改父类不就可以直接提权了? 搜索发现JavaScript可以使用原链型污染
JavaScript 原型链与原型链污染全解析 alt text 不过使用之后还是不成功,但是观察右侧并没有多出新的inheritedProbe,我怀疑可能是写了判断isAdmin的语句导致如果不是Admin的话__proto__找不到可以修改的变量。
alt text 脱离了inheritedProbe的限制之后就修改成功了。
alt text
moectf{0n3_pr070type_chan9e_@|l_06j3c7$_o8ey}