比赛地点:UTCTF 2025
比赛时间:15 Mar 2025 07:00 CST - 17 Mar 2025 07:00 CST
复现的题目用🔁标注
Misc
Trapped in Plain Sight 1
可以看到flag.txt的文件权限为-r-x------
先运行find / -perm -4000 -type f 2>/dev/null查找具有 SUID 权限的文件

在这里找到了xxd
xxd 主要用于将文件内容以十六进制和 ASCII 的形式显示出来。它通常用于调试、分析二进制文件或查看文件的原始数据。
因此这里直接使用xxd flag.txt就可以查看这个文档里的内容了

🔁 Trapped in Plain Sight 2

ls -lah发现文件的权限是----r-----+
这里的 + 表示该文件或目录启用了访问控制列表(ACL, Access Control List) 。这意味着除了标准的文件权限外,还有一些额外的权限设置。

getfacl flag.txt查看文件的ACL配置,发现用户secretuser对该文件有读权限

cat /etc/passwd发现GECOS 字段(注释字段)藏有信息hunter2,这很可能是一个提示信息或某种隐藏线索
因此尝试切换到 secretuser 用户 su secretuser,密码就尝试hunter2,发现成功了

直接cat就能拿到flag了
Forensics
Streamified
附件如下
1111111000011110101111111100000100110101100100000110111010110110111010111011011101010101001101011101101110101001010010101110110000010100101111010000011111111010101010101111111000000001011110100000000010111110001110110011111000111010101100000010100000100011110111100101110111100000100001010100010000011000001000000001011011111100010001010111011100011010100010101001111100110111011100001001100110000011100001100110101011111111100000000110000001000110101111111001111001101010011100000101101001010001000010111010111100011111111011011101011001110011010011101110101010011110010010110000010011011001011100011111111010101010000010111数了下有 625 个,也就是25*25个,不难发现这是一个 25*25 的二维码,写个脚本把它画出来就好了
bitstring = "1111111000011110101111111100000100110101100100000110111010110110111010111011011101010101001101011101101110101001010010101110110000010100101111010000011111111010101010101111111000000001011110100000000010111110001110110011111000111010101100000010100000100011110111100101110111100000100001010100010000011000001000000001011011111100010001010111011100011010100010101001111100110111011100001001100110000011100001100110101011111111100000000110000001000110101111111001111001101010011100000101101001010001000010111010111100011111111011011101011001110011010011101110101010011110010010110000010011011001011100011111111010101010000010111"# print(len(bitstring)) # 625 from PIL import Image def generate_image_from_binary(binary_str, pixel_size=25): width = pixel_size height = len(binary_str) // pixel_size image = Image.new("1", (width, height), color=1) for i, bit in enumerate(binary_str): if bit == '1': x = i % width # 列索引 y = i // width # 行索引 image.putpixel((x, y), 0) return image image = generate_image_from_binary(bitstring)image.show()得到如下二维码

扫码即可得到flag
utflag{b!t_by_b!t}🔁Forgotten Footprints
Challenge
Forgotten Footprints
I didn’t want anyone to find the flag, so I hid it away. Unfortunately, I seem to have misplaced it.
https://drive.google.com/file/d/1L75zJ1ha1-myAM3vL_C6lpT8VJe1XQHB/view?usp=sharing
by Caleb (@eden.caleb.a on discord)
Solution
非预期解
用010打开,搜索flag{的十六进制666c61677b


然后把这一块都十六进制转字符

utflag{d3l3t3d_bu7_n0t_g0n3_4ever}Crypto
Crypto 是拿 AI 一把梭的,所以只有 AI 给的过程和 exp
RSA
题目如下
RSA
Idk why people make e so large for rsa… it’s so much easier to just use 3. Why use big number when small number do trick?
by jocelyn (@jocelyn3270 on discord)
附件如下
n: 21507386633439519550169998646896627263990342978145866337442653437291500212804540039826669967421406761783804525632864075787433199834243745244830254423626433057121784913173342863755047712719972310827106310978325541157116399004997956022957497614561358547338887866829687642469922480325337783646738698964794799137629074290136943475809453339879850896418933264952741717996251598299033247598332283374311388548417533241578128405412876297518744631221434811566527970724653020096586968674253730535704100196440896139791213814925799933321426996992353761056678153980682453131865332141631387947508055668987573690117314953760510812159e: 3c: 6723702102195566573155033480869753489283107574855029844328060266358539778148984297827300182772738267875181687326892460074882512254133616280539109646843128644207390959955541800567609034853为了破解这个RSA加密,我们利用小指数攻击。由于加密指数e=3,如果明文m的三次方小于模数n,那么密文c即为m³,直接对c开三次方即可得到明文m。
步骤如下:
- 验证条件:检查密文c的三次方根是否为整数。
- 计算三次方根:使用Python的gmpy2库中的
iroot函数计算c的三次方根。 - 转换明文:将得到的整数转换为十六进制,并解码为ASCII字符串。
代码实现:
import gmpy2 c = 6723702102195566573155033480869753489283107574855029844328060266358539778148984297827300182772738267875181687326892460074882512254133616280539109646843128644207390959955541800567609034853 # 计算c的三次方根m, is_exact = gmpy2.iroot(c, 3) # 确保结果为整数if is_exact: # 转换为十六进制并去除前缀'0x' hex_str = hex(m)[2:] # 补零确保偶数长度 if len(hex_str) % 2 != 0: hex_str = '0' + hex_str # 转换为字节并解码为ASCII flag = bytes.fromhex(hex_str).decode('utf-8') print(flag)else: print("无法直接开三次方根")结果:
运行代码后,得到的明文为:
utflag{hmm_maybe_bad_idea}DCΔ
题目如下
DCΔ
Due to a national shortage of primes, the US Department of Agriculture is rationing all citizens to a limit of one generated prime number per CTF challenge.
By Sasha (@kyrili on discord)
附件如下
n = 399956368360808862373914258335185223080849636197711424060797090309268643429064461492550414549161330948819635837600839124910339139212025975705016633767495247163243281423582407941339197895052969960664399531226116807938480610953640675838340969642399505783577667601230289640157854573282615113017817753471366212008719316238931155299741896658264134636523008018510523774126757209492757800553768281613227711738371473830681563493341816035127889532515105148615575695347672918819305383651095344758737833444302556494599778991752161562622963652164008980839152347260377969421014616624263631920322958235478733540894255954351848359580013695597870908080170511403061620632540407634608773118202473287854599776791229532885611074739079107324575619148211269673210431496846247978541032947073060592123529635361112170678347924377962162254827262375685704046691718585952854410058401794022674628779309507437739620598639589987596443373586284136126401843497367142210715014480599609277532331148988390798073713743339823218981940779096432112651466716648010370850152213399051968069102663753404120592506704133217642671853086570223710424683386625314802805217882906873879240914022607713870946351691046929143491841506422542038315876506588525639983398522454145866029283449e = 65537c = 22644125297186385803212285721101686380290089858624593588464228942417644877688212364383835956263619653769244324906844180248816686517049952319431524113838480708352331162026595736354019259708442449783760846242702532176456117138374450898213788623580234048867117546091028843127595147910526821835855070663317466469650577618010308109119812464711010326075908158768138773973732088207030977470605554056485614676156104134673446546446752627654287202815354367643042773923258958887865030737447323798382020847653880886311162447594373201951226217556835030816588457674298560260109378271244834215832992407457137601161490484862135147963942227371690835380497920998286827898323068399708168699403459009009580152834747843780155917438758224782364193716322974594031272100820264364860227674838730962348140555980411714722361909800417953974064469599278274083750031569853934963716467881656073359393449142980936480726005445774158733389270553554093627622406166942859792490275434896108377393648278975530519769034633686070931694499857110956537102727286491854314244036392929790997824274724196292688659782806587688964714529943288954314300861531138101192901942534064757877725334672680909389193357725470116673323012331269218651347104807494994267835408427908717684178629为了破解这个RSA加密,利用题目中提到的“每个CTF挑战只能生成一个质数”的漏洞,推测模数
步骤如下:
- 验证
是否为平方数:使用 gmpy2.isqrt计算的平方根,并检查平方是否等于原数。 - 计算欧拉函数
:若 ,则 。 - 求私钥
:计算 。 - 解密密文:计算
。 - 转换明文:将整数
转换为十六进制并解码为ASCII字符串。
代码实现:
import gmpy2 n = 399956368360808862373914258335185223080849636197711424060797090309268643429064461492550414549161330948819635837600839124910339139212025975705016633767495247163243281423582407941339197895052969960664399531226116807938480610953640675838340969642399505783577667601230289640157854573282615113017817753471366212008719316238931155299741896658264134636523008018510523774126757209492757800553768281613227711738371473830681563493341816035127889532515105148615575695347672918819305383651095344758737833444302556494599778991752161562622963652164008980839152347260377969421014616624263631920322958235478733540894255954351848359580013695597870908080170511403061620632540407634608773118202473287854599776791229532885611074739079107324575619148211269673210431496846247978541032947073060592123529635361112170678347924377962162254827262375685704046691718585952854410058401794022674628779309507437739620598639589987596443373586284136126401843497367142210715014480599609277532331148988390798073713743339823218981940779096432112651466716648010370850152213399051968069102663753404120592506704133217642671853086570223710424683386625314802805217882906873879240914022607713870946351691046929143491841506422542038315876506588525639983398522454145866029283449e = 65537c = 22644125297186385803212285721101686380290089858624593588464228942417644877688212364383835956263619653769244324906844180248816686517049952319431524113838480708352331162026595736354019259708442449783760846242702532176456117138374450898213788623580234048867117546091028843127595147910526821835855070663317466469650577618010308109119812464711010326075908158768138773973732088207030977470605554056485614676156104134673446546446752627654287202815354367643042773923258958887865030737447323798382020847653880886311162447594373201951226217556835030816588457674298560260109378271244834215832992407457137601161490484862135147963942227371690835380497920998286827898323068399708168699403459009009580152834747843780155917438758224782364193716322974594031272100820264364860227674838730962348140555980411714722361909800417953974064469599278274083750031569853934963716467881656073359393449142980936480726005445774158733389270553554093627622406166942859792490275434896108377393648278975530519769034633686070931694499857110956537102727286491854314244036392929790997824274724196292688659782806587688964714529943288954314300861531138101192901942534064757877725334672680909389193357725470116673323012331269218651347104807494994267835408427908717684178629 p = gmpy2.isqrt(n)assert p * p == n, "n is not a perfect square" phi = p * (p - 1)d = gmpy2.invert(e, phi)m = pow(c, d, n) # Convert to flaghex_str = hex(m)[2:]if len(hex_str) % 2 != 0: hex_str = '0' + hex_strflag = bytes.fromhex(hex_str).decode('utf-8')print(flag)结果:
运行代码后,得到的明文为:
utflag{th3_t0t13nt_funct10n_uns1mpl1f13d}Autokey Cipher
题目如下
Autokey Cipher
I know people say you can do a frequency analysis on autokey ciphers over long text, but the flag is short so it’ll be fine.
lpqwma{rws_ywpqaauad_rrqfcfkq_wuey_ifwo_xlkvxawjh_pkbgrzf}
by jocelyn (@jocelyn3270 on discord)
忘记是怎么解的了,好像是维吉尼亚密码的变种,下面是exp
import string # 定义字母表ALPHABET = string.ascii_lowercase # 解密函数:自动密钥解密def decrypt_autokey(ciphertext, key): plaintext = [] key = list(key) # 将密钥转换为列表以便动态扩展 for i, c in enumerate(ciphertext): if c.lower() not in ALPHABET: # 如果字符不在字母表中(如空格或标点符号),直接保留 plaintext.append(c) continue # 获取当前密钥字符 current_key = key[i] if i < len(key) else plaintext[i - len(key)] # 计算解密字符:(密文 - 密钥) mod 26 c_idx = ALPHABET.index(c.lower()) k_idx = ALPHABET.index(current_key) decrypted_char = ALPHABET[(c_idx - k_idx) % 26] plaintext.append(decrypted_char) # 动态扩展密钥:将解密后的字符添加到密钥中 if i >= len(key): key.append(decrypted_char) return ''.join(plaintext) # 主程序ciphertext = "lpqwmarwsywpqaauadrrqfcfkqwueyifwoxlkvxawjhpkbgrzf"initial_key = "rwllmuvputflagwhyfrequencyanalysiswhenknowbeginning" # 解密密文decrypted_text = decrypt_autokey(ciphertext, initial_key) # 输出结果print(f"Initial Key: {initial_key}")print(f"Decrypted Text: {decrypted_text}")结果:
运行代码后,得到的明文为:
utflag{why_frequency_analysis_when_know_beginning_letters}