250517_BYUCTF learning record

【全栈ctfer计划中,会持续复现学习与更新该文章】

赛事信息

image.png 组织者:CTFtime.org / BYU Cyberia

战队排名情况

排名:23 image.png

题目附件

web

Red This

考察知识点:redis的基本认识

比赛时的临时笔记

页面初探

image.png image.png 查看名言的功能对应POST请求。

分析架构

image.png 可以知道web应用是用flask框架搭建的,以及数据库采用redis

分析路由

image.png 尝试注册并登录,除了多了一个session外,其他没什么变化: image.png 且注意到token是以JWT的格式展示: image.png 头部只有用户名字段,且需要key来验证签名。在main.py中似乎可以发现这个key: image.png

分析admin相关条件

反复出现了adminOptions关键词,重点关注: image.png 如果用户名是admin,可以返回admin相关选项信息,被存储在redis中。且注意到username是来自于session中的字段。

分析数据库

大致看一下redis都做了什么: image.png image.png 接着定位到redis存储的数据: image.png set后是键值对形式来存储数据,且发现真正的flag藏在这里,且与管理员选项有关。

分析flag相关条件

image.png person来自于页面列表中选择的作者,如果其中包含“flag”,且用户名如果是admin,就会调用getData返回对应的键值对。 image.png 尝试修改jwt中的username,但由于没有密钥,发现无法对它进行编辑,且被提示payload字段不符合规则,那就只能想其他办法成为admin。可以继续尝试redis数据库中的其他键值对,因为根据以上代码分析,我们可以知道传递给getData的值是可控的,如果不包含“flag”是否也能返回对应的值? image.png 显然这就是漏洞存在的地方,成功拿到了管理员密码。接下来只要登录它就可以拿到flag。

getflag

image.png 发现admin用户的列表选项多了flag。 image.png

Willy Wonka Web

考察知识点:apache反向代理、http头注入

比赛时的临时笔记

页面初探

image.png 纯静态,没有robots,源代码也没有隐藏信息。

分析架构

image.png 采用node-js作为后端,且bookworm和express值得关注,可能是采用的框架、组件。

分析express请求处理

image.png 如果请求头中的a字段为admin,则后端返回给前端的请求包含打开flag.txt操作;否则查询请求中的name字段,并过滤一些标签,看着是用来防范xss的。 尝试: image.png 没有成功。

分析apache配置文件

注意到前端有个apache的配置文件: image.png 第一个功能是作为反向代理(规则中定义的[P]),将客户端的请求转发到后端服务器,这样做的目的是隐藏后端真实端点,比如访问https://fronthost.com/name/admin时,相当于向后端端点发送请求https://backend.com:3000/?name=admin;第二个功能则是将请求头中特定请求过滤了,所以上面尝试注入a请求头没有效果。到这里就没有思路了。

Solved by 0xfun-dr.kasbr

image.png

1
curl -g "https://wonka.chal.cyberjousting.com/name/foo%0d%0aA:%20admin%0d%0aX-Ignore:%20yes"

forensics

Are You Looking Me Up?

考察知识点:原始网络日志分析、dns协议过滤特征

赛后学习

过滤协议特征

image.png 这是一个原始的网络日志,题目要求我们定位的条目是DNS协议,从结构来看,首先需要过滤协议名,注意同时考虑协议号(比如某些条目可能未标注协议名而只有协议号,如果只考虑过滤其中一种,可能导致遗漏关键条目),也别忘了过滤UDP(DNS传输大多情况下基于此),协议号没办法直接用grep,因为同样的数字能代表多个含义,会引入其他不相关的条目,而每个条目的各项几乎都是对应的位置,所以通过awk,以逗号分隔来筛选协议号那一列。当然,还要考虑dns的端口号。(总之就是尽可能把dns协议相关的特征都考虑好,作为日志的过滤条件) 最后,dns服务器是负责接收dns请求的,所以最终需要的数据是目标IP,即第20列,所以:

1
cat logs.txt | grep udp | awk -F ',' '$16 == 17 && $22 == 53 {print $20}'

数据排序与统计

1
cat logs.txt | grep udp | awk -F ',' '$16 == 17 && $22 == 53 {print $20}' | sort | uniq -c

第一列是每个IP出现的总次数,根据题目显然需要出现最多的,也就是172.16.0.1image.png 如果需要更完美一点,可以进一步排序让次数最多的在最上方:

1
cat logs.txt | grep udp | awk -F ',' '$16 == 17 && $22 == 53 {print $20}' | sort | uniq -c | sort -nr | head
  • -n:按数值大小排序
  • -r:降序排列 image.png

Mine Over Matter

赛后学习

思路总结

先确认矿工(src)连接了哪些矿池(dest),获取其域名IP映射信息,再到原日志中根据映射信息表与目标IP比对,相同的则为挖矿相关流量,通过逆向思维的方式找到对应的连接矿工(src)。

确定数据存储方案

日志内容如下: image.png 首先,要寻找受加密挖矿病毒影响的主机,我们需要知道它的源IP和目标IP,不需要统计所以需要对所有IP进行查重,所以集合用来存储ip最为合适,集合可以实现自动过滤重复元素。接着,由于挖矿病毒必须连接矿池才能开始工作,因此会频繁与矿池的域名/IP通信,因此也需要为其分配存储,由于IP和域名数据类型有差异,且除了知道矿池域名还要知道对应的IP,需要建立映射关系,显然字典最合适,字典支持不同的数据类型且可变。所以:

1
2
3
4
inputFile = "logs.txt" 
uniqueIPsDest = set()
uniqueIPsSrc = set()
ipDomainMap = {}

提取目标IP

接着打开日志文件,以逗号分隔: image.png 发现返回是列表类型,索引从0开始,所以fields[19]是目标IP所在的列,而所有条目中不一定都含有目标IP,因此要对条目的长度先进行判断,必须至少大于20,才能提取出fields[19]image.png

反向解析筛选出潜在矿池

接下来,需要从获取到的目标IP列表中,通过IP反向查找域名(可以通过工具nslookup来实现,需要新建一个子进程运行它),查看是否存在可能与挖矿相关的域名,比如关键词minepoolxmrcrypto等。 首先通过subprocess模块为nslookup创建子进程,并获取执行结果的标准输出与标准错误: image.png text可以让输出结果以字符串返回而不是字节序列,因为还需要进一步对返回结果做提取,字节序列不支持,然后check用来捕获异常。 image.png 在进一步筛选之前,先看看nslookup返回的结果: image.png

解决clash TUN带来的DNS污染问题

发现指向了一个内网ip的服务器,猜测是本地环境中开启了clash代理导致的,查看clash创建的TUN网卡发现其dns服务器IP正好就是这个: image.png 解决方案很简单,将其改为谷歌dns8.8.8.8,然后ip选择自动获取即可: image.png 重新反向解析发现解析到了许多域名: image.png 包括本地中NAT的kali虚拟机此时也能正常用nslookup了: image.png

筛选矿池域名

image.png 找到了一个矿池域名,尝试访问: image.png 当然标准输出的显示更整洁些: image.png 显然,我们需要提取的是域名相关的项,满足一定规则,可以用正则匹配。先判断这里的冒号是否为中文字符,复制后放在notepad++: image.png 是英文字符。所以匹配如下: image.png 注意如果在linux中运行nslookup且系统语言为英文,结果中域名的末尾可能还会有.符号,显示格式有些不同,需要修改正则匹配为name\s*=\s*(.+)\. 接着将获取到的矿池域名和IP分别放入字典做映射: image.png

定位矿工

最后,根据获取到的矿池IP域名映射信息,重新打开日志,检索出目标IP符合映射中的IP的条目,即挖矿流量部分,此时的src就是受害者miner机器了: image.png

exp

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
import re  
import subprocess

inputFile = "logs.txt"
uniqueIPsDest = set()
uniqueIPsSrc = set()
ipDomainMap = {}

with open(inputFile, 'r', encoding='utf-8') as file:
for line in file:
fields = line.strip().split(',')
if len(fields) >= 20:
destIP = fields[19]
uniqueIPsDest.add(destIP)
#print(uniqueIPsDest)

for ip in uniqueIPsDest:
try:
result = subprocess.run(['nslookup', ip], capture_output=True, text=True, check=True)
# print(result.stdout)
if 'mine' in result.stdout.strip():
match = re.search(r'名称\s*:\s*(\S+)', result.stdout)
if match:
domain = match.group(1)
#print(domain)
ipDomainMap[ip] = domain
print("矿池映射关系如下:")
print(f"{ip} -> {domain}")
else:
print("Nothing matched!")
except subprocess.CalledProcessError as e:
pass

with open(inputFile, 'r', encoding='utf-8') as file:
for line in file:
fields = line.strip().split(',')
if len(fields) >= 20:
destIP = fields[19]
for ip,domain in ipDomainMap.items():
if ip == destIP:
miner = fields[18]
uniqueIPsSrc.add(miner)
for ip in uniqueIPsSrc:
print(f"受害的矿工机器:" + ip)

Wimdows 1

pwn

Minecraft YouTuber

比赛时的临时笔记

检查保护

image.png 全保护。

这是一道UAF的堆利用题,待学习。

MIPS