GoogleCTF2023 Writeup

GoogleCTF2023 Writeup

Misc

  • NPC

Crypto

  • LEAST COMMON GENOMINATOR?

Web

  • UNDER-CONSTRUCTION

NPC

A friend handed me this map and told me that it will lead me to the flag.
It is confusing me and I don’t know how to read it, can you help me out?

Attachment


使用Graphviz工具将hint.dot转换为图片,得到下图

dot -Tjpg  hint.dot -o hint.jpg
hint.jpg

分析代码:

  • USACONST.TXT中随机选择N个单词生成密码,使用passphrase.encrypt(secret, password)对flag加密

  • 对于password中的每个字母,创建一个带有唯一ID的节点,并添加到图中

  • 按照password的顺序,对密码中相邻的两个字符创建一条边

  • 向图中随机添加int(len(password) ** 1.3)条边

  • 随机打乱图中节点和边的顺序

  • 随机交换一些节点的起点和终点,由于random() % 2只有在random函数返回值为0时才为False,我们假定图中每条边的起点和终点都被交换了一遍

  • 将节点和边的信息写入到hint.dot文件中

我是思路是:

  1. 遍历words_list中的单词,从每个节点出发,使用DFS判断是否可以在图中找到,这样过滤后得到30个单词,即密码一定由该30个单词中的某几个单词组成

  2. 枚举密码中所用的单词个数N

  3. 使用组合数从这30个单词选择N个单词

  4. 判断所选的N个单词组成的字符集和hint.dot中的字符集是否一致

  5. 对N个单词进行全排列,并尝试解密 (为了提高效率,这里还用到了多进程)

当N=5时,得到passwordstandardwatersigngivenchosenflag.

代码
import concurrent.futures
import itertools
import re
from collections import Counterfrom pyrage import passphrasefrom encrypt import get_word_listclass Node:def __init__(self, letter):self.letter = letterself.adjacent = []def __str__(self) -> str:return f"{self.letter} -> {[x.letter for x in self.adjacent]}"__repr__ = __str__def build_nodes():pattern = r"\s+(\d+)\s+\[label=(\w+)\];"pattern2 = r"\s+(\d+)\s+--\s+(\d+);$"nodes = dict()with open("hint.dot", "r") as f:for line in f:if "label" in linematch = re.match(pattern, line)node_id = match.group(1)letter = match.group(2)nodes[node_id] = Node(letter)elif "--" in line:match = re.match(pattern2, line)start = match.group(1)end = match.group(2)# nodes[start].adjacent.append(nodes[end])nodes[end].adjacent.append(nodes[start])return nodesvisited = set()def dfs(node, index, word):if index == len(word):return Trueif node.letter != word[index]:return Falsevisited.add(node)for adj in node.adjacent:if adj not in visited:if dfs(adj, index + 1, word):return Truevisited.remove(node)return Falsedef check(password):with open("secret.age", "rb") as f:enc = f.read()try:print("[FLAG] is ", passphrase.decrypt(enc, password))print("Password is ", password)except Exception as e:passdef filter_words(nodes):ans = set()for word in get_word_list():visited.clear()for node in nodes.values():if dfs(node, 0, word):ans.add(word)breakprint("ans:", len(ans), ans)return ansdef main():nodes = build_nodes()letters = sorted([node.letter for node in nodes.values()])ans = filter_words(nodes)for num in range(1, len(ans) + 1):print(f"Num is {num}")for comb in itertools.combinations(ans, num):  # 组合if sorted("".join(comb)) == letters:passwords = ["".join(perm) for perm in itertools.permutations(comb, len(comb))]with concurrent.futures.ProcessPoolExecutor(max_workers=8) as executor:executor.map(check, passwords)if __name__ == "__main__":main()

flag: CTF{S3vEn_bR1dg35_0f_K0eN1g5BeRg}

参考:

  • concurrent.futures — 启动并行任务 – Python 3.11.4 文档

LEAST COMMON GENOMINATOR?

Someone used this program to send me an encrypted message but I can’t read it! It uses something called an LCG, do you know what it is? I dumped the first six consecutive values generated from it but what do I do with it?!

Attachment


generate.py
from secret import config
from Crypto.PublicKey import RSA
from Crypto.Util.number import bytes_to_long, isPrimeclass LCG:lcg_m = config.mlcg_c = config.clcg_n = config.ndef __init__(self, lcg_s):self.state = lcg_sdef next(self):self.state = (self.state * self.lcg_m + self.lcg_c) % self.lcg_nreturn self.stateif __name__ == '__main__':assert 4096 % config.it == 0assert config.it == 8assert 4096 % config.bits == 0assert config.bits == 512# Find prime value of specified bits a specified amount of timesseed = 211286818345627549183608678726370412218029639873054513839005340650674982169404937862395980568550063504804783328450267566224937880641772833325018028629959635lcg = LCG(seed)primes_arr = []dump = Trueitems = 0dump_file = open("dump.txt", "w")primes_n = 1while True:for i in range(config.it):while True:prime_candidate = lcg.next()if dump:dump_file.write(str(prime_candidate) + '\n')items += 1if items == 6:dump = Falsedump_file.close()if not isPrime(prime_candidate):continueelif prime_candidate.bit_length() != config.bits:continueelse:primes_n *= prime_candidateprimes_arr.append(prime_candidate)break# Check bit lengthif primes_n.bit_length() > 4096:print("bit length", primes_n.bit_length())primes_arr.clear()primes_n = 1continueelse:break# Create public key 'n'n = 1for j in primes_arr:n *= jprint("[+] Public Key: ", n)print("[+] size: ", n.bit_length(), "bits")# Calculate totient 'Phi(n)'phi = 1for k in primes_arr:phi *= (k - 1)# Calculate private key 'd'd = pow(config.e, -1, phi)# Generate Flagassert config.flag.startswith(b"CTF{")assert config.flag.endswith(b"}")enc_flag = bytes_to_long(config.flag)assert enc_flag < n# Encrypt Flag_enc = pow(enc_flag, config.e, n)with open ("flag.txt", "wb") as flag_file:flag_file.write(_enc.to_bytes(n.bit_length(), "little"))# Export RSA Keyrsa = RSA.construct((n, config.e))with open ("public.pem", "w") as pub_file:pub_file.write(rsa.exportKey().decode())

分析可知:

  • flag是使用RSA加密的,已知公🔑 文件,即n,e

  • 使用LCG线性同余生成器生成素数

  • 已知LCG的种子和前6个连续生成的数字

  • config.it = 8

  • config.bits = 256

LCG是伪随机数生成器和流密码的一种,递推公式是 𝑋𝑛+1=(𝑎𝑋𝑛+𝑐) 𝑚𝑜𝑑 𝑚

已知初值和随后LCG连续生成的6个值,未知增量、乘数和模数.

我们可以通过攻击得到这三个值,然后模拟原算法通过LCG得到8个素数后,进一步计算n的欧拉函数并求逆元得到d,解密即可.

题解:
import math
from functools import reduceimport gmpy2from Crypto.PublicKey import RSA
from Crypto.Util.number import bytes_to_long, isPrime, long_to_bytesdump_file = open("dump.txt")
output_values = [int(x) for x in dump_file.readlines()]  # 已知的 LCG 输出值def crack_unknown_increment(states, modulus, multiplier):"""已知:a,m,s0,s1求c"""increment = (states[1] - states[0] * multiplier) % modulusreturn modulus, multiplier, incrementdef crack_unknown_multiplier(states, modulus):"""已知:m,s0,s1,s2求a"""multiplier = ((states[2] - states[1]) * gmpy2.invert(states[1] - states[0], modulus) % modulus)  # 注意这里求逆元return crack_unknown_increment(states, modulus, multiplier)def crack_unknown_modulus(states):"""已知:s0-s6求a,c,m"""diffs = [s1 - s0 for s0, s1 in zip(states, states[1:])]zeroes = [t2 * t0 - t1 * t1 for t0, t1, t2 in zip(diffs, diffs[1:], diffs[2:])]modulus = abs(reduce(math.gcd, zeroes))return crack_unknown_multiplier(states, modulus)class LCG:def __init__(self, lcg_m, lcg_c, lcg_n, lcg_s):self.state = lcg_sself.lcg_m = lcg_mself.lcg_c = lcg_cself.lcg_n = lcg_ndef next(self):self.state = (self.state * self.lcg_m + self.lcg_c) % self.lcg_nreturn self.statem, a, c = crack_unknown_modulus(output_values)
seed = 211286818345627549183608678726370412218029639873054513839005340650674982169404937862395980568550063504804783328450267566224937880641772833325018028629959635
lcg = LCG(a, c, m, seed)
print(a, c, m)
primes_n = 1
primes_arr = []
for i in range(8):while True:prime_candidate = lcg.next()if not isPrime(prime_candidate):continueelif prime_candidate.bit_length() != 512:continueelse:primes_n *= prime_candidateprimes_arr.append(prime_candidate)breakprint(list(primes_arr))phi = 1
for k in primes_arr:phi *= k - 1key = RSA.importKey(open("public.pem", "r").read())
n = key.n
e = key.e
d = gmpy2.invert(e, phi)enc = open("flag.txt", "rb").read()flag = pow(int.from_bytes(enc, "little"), d, n)
print(long_to_bytes(flag))

flag: CTF{C0nGr@tz_RiV35t_5h4MiR_nD_Ad13MaN_W0ulD_b_h@pPy}

参考:

  • 攻击线性同余生成器(LCG) | 码农网
  • LCG(线性同余生成器)_lcg线性同余_WustHandy的博客-CSDN博客

UNDER-CONSTRUCTION

We were building a web app but the new CEO wants it remade in php.

Attachment
https://under-construction-web.2023.ctfcompetition.com
https://under-construction-php-web.2023.ctfcompetition.com


题目提供了Flask和PHP两个站点,用户可以在Flask站点进行注册,注册的账号可以同时用于登录Flask和PHP两个站点.

分析代码:

Flask会将HTTP请求原始查询参数转发到PHP应用程序中完成用户注册.

# File: /flask/authorized_routes.py
@authorized.route('/signup', methods=['POST'])
def signup_post():raw_request = request.get_data()...requests.post(f"http://{PHP_HOST}:1337/account_migrator.php", headers={"token": TOKEN, "content-type": request.headers.get("content-type")}, data=raw_request)return redirect(url_for('authorized.login'))

只有gold级别的用户,在PHP站点登录后才可以看到FLAG

# File: /php/index.php
function getResponse()
{...$response = "Login successful. Welcome " . htmlspecialchars($username) . ".";if ($tier === "gold") {$response .= " " . getenv("FLAG");}return $response;
}

Flask会对查询参数进行校验,防止创建高权限的用户.

# File: /flask/authorized_routes.py
@authorized.route('/signup', methods=['POST'])
def signup_post():...tier = models.Tier(request.form.get('tier'))if(tier == models.Tier.GOLD):flash('GOLD tier only allowed for the CEO')return redirect(url_for('authorized.signup'))...

HTTP查询参数中存在重复的key时,在Flask和PHP有不同的行为,flask会取第一个值,而PHP会取最后一个值.

因此我们可以构造如下命令,以此绕过Flask对查询参数的校验,并在PHP中注册高权限用户.

curl

curl -X POST https://under-construction-web.2023.ctfcompetition.com/signup -d "username=admin&password=admin&tier=blue&tier=gold"

然后用上述的用户名和密码去PHP站点登录即可.

flag: CTF{ff79e2741f21abd77dc48f17bab64c3d}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/50644.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VSCode切换默认终端

我的VSCode默认终端为PowerShell&#xff0c;每次新建都会自动打开PowerShell。但是我想让每次都变为cmd&#xff0c;也就是Command Prompt 更改默认终端的操作方法如下&#xff1a; 键盘调出命令面板&#xff08;CtrlShiftP&#xff09;中,输入Terminal: Select Default Prof…

Java 中的Stream流

Stream流就像工厂中的流水线操作。 如何使用Stream&#xff1f; 1、首先要获取Stream流&#xff0c;那么如何获取呢? 对于不同的数据&#xff0c;有不同的获取方法。 ①单列集合 方法名说明default Stream<E> stream()Collection接口中的默认方法 所以实现了Colle…

Multi Range Read与Covering Index是如何优化回表的?

上篇文章末尾我们提出一个问题&#xff1a;有没有什么办法可以尽量避免回表或让回表的开销变小呢&#xff1f; 本篇文章围绕这个问题提出解决方案&#xff0c;一起来看看MySQL是如何优化的 回表 为什么会发生回表&#xff1f; 因为使用的索引并没有整条记录的所有信息&…

DataEase一键部署:轻松搭建数据可视化平台

DataEase是一个开源的数据可视化和分析工具&#xff0c;旨在帮助用户轻松创建和共享数据仪表盘。它支持多种数据源&#xff0c;包括关系型数据库&#xff0c;文件数据源&#xff0c;NoSQL数据库等&#xff0c;提供强大的数据查询、处理和可视化功能。DataEase 不仅是一款数据可…

VMware虚拟机中CentOS7自定义ip地址并且固定ip

配置固定ip(虚拟机) 前提&#xff1a;虚拟机网络配置成&#xff0c;自定义网络并选择VMnet8(NAT 模式) 操作(如下图)&#xff1a;点击虚拟机–》设置–》–》硬件–》网络适配器–》自定义&#xff1a;特定虚拟网络–》选择&#xff1a;VMnet8(NAT 模式) 虚拟机网络设置 需要记…

【漏洞复现】Jenkins CLI 接口任意文件读取漏洞(CVE-2024-23897)

漏洞简介 Jenkins是一款基于JAVA开发的开源自动化服务器。 Jenkins使用args4j来解析命令行输入&#xff0c;并支持通过HTTP、WebSocket等协议远程传入命令行参数。在args4j中&#xff0c;用户可以通过字符来加载任意文件&#xff0c;这导致攻击者可以通过该特性来读取服务器上…

论文快过(图像配准|Coarse_LoFTR_TRT)|适用于移动端的LoFTR算法的改进分析 1060显卡上45fps

项目地址&#xff1a;https://github.com/Kolkir/Coarse_LoFTR_TRT 创建时间&#xff1a;2022年 相关训练数据&#xff1a;BlendedMVS LoFTR [19]是一种有效的深度学习方法&#xff0c;可以在图像对上寻找合适的局部特征匹配。本文报道了该方法在低计算性能和有限内存条件下的…

【PyTorch】基于LSTM网络的气温预测模型实现

假设CSV文件名为temperature_data.csv&#xff0c;其前五行和标题如下&#xff1a; 这里&#xff0c;我们只使用Temperature列进行单步预测。以下是整合的代码示例&#xff1a; import pandas as pd import numpy as np import torch import torch.nn as nn import torch.op…

RocketMQ消息短暂而又精彩的一生(荣耀典藏版)

目录 前言 一、核心概念 二、消息诞生与发送 2.1.路由表 2.2.队列的选择 2.3.其它特殊情况处理 2.3.1.发送异常处理 2.3.2.消息过大的处理 三、消息存储 3.1.如何保证高性能读写 3.1.1.传统IO读写方式 3.2零拷贝 3.2.1.mmap() 3.2.2sendfile() 3.2.3.CommitLog …

Redis 7.x 系列【27】集群原理之通信机制

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 概述2 节点和节点2.1 集群拓扑2.2 集群总线协议2.3 流言协议2.4 心跳机制2.5 节点握…

OpenGauss和GaussDB有何不同

OpenGauss和GaussDB是两个不同的数据库产品&#xff0c;它们都具有高性能、高可靠性和高可扩展性等优点&#xff0c;但是它们之间也有一些区别和相似之处。了解它们之间的关系、区别、建议、适用场景和如何学习&#xff0c;对于提高技能和保持行业敏感性非常重要。本文将深入探…

蓝桥强化宝典(4)Dijkstra

前言 Dijkstra算法&#xff08;迪杰斯特拉算法&#xff09;&#xff0c;又称狄克斯特拉算法&#xff0c;是由荷兰计算机科学家Edsger W. Dijkstra于1959年提出的。该算法主要用于在加权图中查找从一个起始节点到所有其他节点的最短路径&#xff0c;解决的是有权图中最短路径问题…

NLP基础知识2【各种大模型的注意力】

注意力 传统Attention存在的问题优化方向变体有哪些现在的主要变体集中在KVMulti-Query AttentionGrouped-query AttentionFlashAttention 传统Attention存在的问题 上下文约束速度慢&#xff0c;显存占用大&#xff08;因为注意力考虑整体信息&#xff0c;所以每一个位置都要…

Study--Oracle-07-ASM相关参数(四)

一、ASM主要进程 1、ASM主要后台进程 ASM实例除了传统的DBWn、LGWR、CKPT、SMON和PMON等进程还包含如下几个新后台进程: 2、牛人笔记 邦德图文解读ASM架构,超详细 - 墨天轮 二、数据库实例于ASM实例之间的交互关系 数据库实例与ASM实例之间的交互关系涉及多个步骤和过程,…

PHP家政系统自营+多商户独立端口系统源码小程序

家政行业的新篇章 引言&#xff1a;家政行业的数字化转型 近年来&#xff0c;随着科技的飞速发展和人们生活节奏的加快&#xff0c;家政服务行业也迎来了数字化转型的浪潮。为了提升服务效率、优化用户体验&#xff0c;越来越多的家政公司开始探索“家政系统自营多商户小程序…

用yoloV5做一个口罩检测的全流程实现

制作数据集 收集相关图片&#xff1a; 可以使用爬虫在百度爬取。爬虫代码如下&#xff1a; # -*- coding: UTF-8 -*-""" import requests import tqdmdef configs(search, page, number):""":param search::param page::param number::return:…

界面控件Telerik UI for WPF 2024 Q2亮点 - 全新的AIPrompt组件

Telerik UI for WPF拥有超过100个控件来创建美观、高性能的桌面应用程序&#xff0c;同时还能快速构建企业级办公WPF应用程序。UI for WPF支持MVVM、触摸等&#xff0c;创建的应用程序可靠且结构良好&#xff0c;非常容易维护&#xff0c;其直观的API将无缝地集成Visual Studio…

C++:类和对象2

1.类的默认成员函数 默认成员函数就是用户没有显示实现编译器会自动生成的成员函数称为默认成员函数。一个类&#xff0c;我们在不写的情况下编译器会默认生成6个默认成员函数&#xff0c;分别是构造函数&#xff0c;析构函数&#xff0c;拷贝构造函数&#xff0c;拷贝赋值运算…

kitti数据集转为bag

下载原始的数据集后&#xff0c;通过终端来运行&#xff1a; unzip 2011_10_03_calib.zip和 unzip 2011_10_03_drive_0047_sync.zip这样这个文件夹才算准备好&#xff1a; 然后去下载kitti2bag工具&#xff1a; pip install kitti2bag然后去2011_10_03文件夹下执行&#xf…

大疆创新2025校招内推

大疆2025校招-内推 一、我们是谁&#xff1f; 大疆研发软件团队&#xff0c;致力于把大疆的硬件设备和大疆用户紧密连接在一起&#xff0c;我们的使命是“让机器有温度&#xff0c;让数据会说话”。 在消费和手持团队&#xff0c;我们的温度来自于激发用户灵感并助力用户创作…