HGAME 2022 week1 个人部分WP

这篇博客是作者首次参加HGAME的个人解题报告,主要涉及CTF的web、misc和crypto等领域。在web部分,作者通过分析js文件和理解http请求头来解决题目;在misc中,作者使用了压缩包破解、音频隐写和邮件分析等技巧;在crypto部分,作者接触了RSA加密并进行了实践。尽管遇到了困难,但作者通过不断学习和尝试,逐步理解了各种解题方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

寒假期间,小萌新在家瞎搞CTF,也是第一次参加HGAME,整体来说题目是简单的,但对于我这个萌新菜鸟来说,还是一头雾水,只会做一些简单的密码题,week1的web和misc还能做出几题,后面几周就完全不会了,二进制完全看不懂。。。已经坐牢有一段时间了,想想还是不要浪费时间,记录下这次比赛,也是一种学习。

本人还是个萌新,WP可能会存在很多错误,望各位大佬勿喷,也请多多指正。

web

Tetris plus

描述:据说没人能超过 3000 分。要是做题做累了,就来玩玩小游戏吧(x

这道题很明显是玩游戏,通关后得到flag(也可能通关没有flag),以前我做这种题目都是尝试着打通关,但这次比赛主要是以学习为主,分数是次要的,就尝试查看js文件

这么多js文件,一个个查看,发现这个文件的末尾比较可疑,一段jsfuc*代码,复制粘贴到控制台,回车得到flag

Fujiwara Tofu Shop

描述:昨晚我输给一辆AE86。他用惯性漂移过弯,他的车很快,我只看到他有个豆腐店的招牌。

        写WP的时候,题目环境已经打不开了,只能靠记忆和官方WP大致描述一下了。这道题考察的是http常用的几个请求头的知识。

Referer:先前网页的地址,当前请求网页紧随其后,即来路

               Referer: qiumingshan.net

User-Agent:User-Agent的内容包含发出请求的用户信息

               User-Agent : Hachi-Roku

Cookie:HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器

        cookie这里的提示是蓝莓味的曲奇,菜鸟我不知道该如何填写这个cookie了(因为英语不好。。。),后来发现原有的cookie里有一个flavor(风味)属性,又无意间看到了Raspberry(蓝莓)这个单词,就将flavor属性后的值改为了Raspberry,成了

        下一个提示是把汽油加到100,这大概是让我们自己造一个请求头吧,英语差的我再次用上了百度翻译,得到gasoline(汽油),添加请求头Gasoline : 100

        最后一个提示是让我们伪造本地ip,对于我这种菜鸟,就只知道X-Forwarded-For请求头了,但是师傅故意禁用了,本来我以为我对提示的理解出错了,后来实在想不出什么办法,就百度查找了一下有没有和XFF类似的请求头,果然找到了一大批。这里参考这位师傅的博客CTF题目中伪造IP方法_cib439的博客-CSDN博客,我是从这里一个一个试出来的。

        官方WP是这样说的:相关的请求头有 X-Forworded-For , X-RealIP , X-Client-IP 等,至于那个请求头能成功伪造 IP,得参考具体的网络环境,编程语言,服务端框 架和服务端配置。返回头里给出了后端框架: gin-gonic/gin ,预期解法是让大家去查一查 gin 是怎 样处理这些请求头的,不过好像没人去查www。(https://github.com/gin-gonic/gin/issues/1684)

蛛蛛...嘿嘿♥我的蛛蛛

描述:蛛蛛...嘿嘿...我的蛛蛛...我的蛛蛛正在满地找头???

        蛛蛛?我第一想到的和蜘蛛有关系的技术就是爬虫,但我这个菜鸟完全不会写爬虫,只能以最笨最费时的方法来做,就是一直访问这个key值,好像一直访问到101关才提示flag就在这,这里我感觉师傅有点耍心机,一般刷到第100关还没有flag,可能就放弃了。

         到这也只是提示flag就在这,但没有直接给出flag,题目描述中的“满地找头”提示我们查看请求头,最终flag在请求头中被发现

下面是官方WP的爬虫脚本:

import requests,regex
nextUrl = base = 'https://hgame-spider.vidar.club/xxxx'
while 1:
keys = regex.findall('<a href=\"(\S+)\">点我试试
</a>',requests.get(nextUrl).text)
if len(keys) == 0: break
nextUrl = base + keys[0]
print(nextUrl)
print(requests.get(nextUrl).headers)

 easy_auth

描述:尊贵的admin写了个todo帮助自己管理日常,但他好像没调试完就部署了....一个月后,当他再一次打开他的小网站,似乎忘记了密码...他的todo之前记录了很重要的东西,快帮帮他
不要爆破!

        这题是让我们登入到admin账号中,但考察的不是爆破,我就毫无头绪了,一周结束了也没做出来,在这里只能附上官方的WP来学习了。

官方WP:

标题auth提示是鉴权方面的问题,描述中的“没有调试完”说明存在弱密码之类的问问题。 问题出在前后后端交互的token

首先正常注册并登录自己的账号,获得自己的token,前往jwt解析工具进行解析,发现验证失败 当清空secret后发现验证成功

 然后修改jwt中的id和username为1和admin(题目描述已经提示admin,但是id要猜一猜)

生成的token替换本地存储的token

 刷新页面获得flag

misc

欢迎欢迎!热烈欢迎!

描述:关注“奇安信技术研究院”微信公众号,发送 HelloHGAME2022 获得flag

签到题

这个压缩包有点麻烦

 描述:这个压缩包,它真的可以打开吗?

压缩包有段英文提示:六位纯数字密码是不安全的(当时也是百度翻译得到的意思。。。),直接将压缩包拿去爆破,得到密码

解压出flag.zip和password-note.txt,这次是字典爆破,用password-note.txt作为字典爆破flag.zip,得到密码

打开压缩包,发现里面是一张图片和一个README.txt文件,README.txt文件的大小和上一个flag.zip文件里的README.txt文件一样,说明这两个文件可能是完全一样的,那就是说这次是利用明文攻击,首先我们需要靠清楚这个压缩包的压缩算法,由外部的README.txt文件内容提示,这个压缩包是以储存的方式进行压缩的,那我们就将README.txt以同样的方式压缩成zip格式,再进行明文攻击。

本来我以为明文攻击一直需要等到得出密码为止,后来上网查阅资料,得知只需要过一小会就可以停止,然后保存解密后的文件

打开flag.jpg,发现没有flag,直接拿起jpg格式图片隐写工具一顿梭,最后在binwalk中发现一个压缩包,用binwalk -e分离出来,分离出的这个压缩包还是个加密的压缩包,但这个加密只是伪加密

将这个的09改为00即可 ,打开文件就是flag

群青(其实是幽灵东京)

描述:4CTU3从小就是Yoasobi的狂热粉丝 今天它给大家带来了一首它觉得很好听的老歌 它说你要用多感官去感觉

首先是音频隐写,“用多感官去感觉”大致就是要用眼睛去看音频,将文件扔进audacity里,查看频谱图

 菜鸟我就卡在这很长一段时间,后来在文件属性里找到了提示

 那就将文件扔进silenteye里面

key就是Yoasobi

访问这个地址,下载下一个附件 ,文件名提示是SSTV,第一次接触SSTV的我,百度上查找相关文章和工具,后来在这位师傅的博客中找到了方法(Misc SSTV慢扫描电视&无线电 - LEOGG - 博客园),照着博客里的方法,先安装好虚拟声卡和RX-SSTV,再播放附件的音频,得到一张二维码,扫描即可获得flag

 好康的流量

描述:总所周知 饭卡是个LSP并十分喜欢向其他人推销他的涩图 让我们去悄悄康康他发了什么

附件是一个流量包,用wireshark打开,导出IMF对象,保存文件,得到一个邮箱文件

打开邮箱文件,里面有一张涩图(这也不涩啊),保存图片

 又是图片隐写,因为这题的主题是LSB,那这张图片的隐写也大概就是LSB了,用Stegsolve打开,得到一个条形码,扫描得到半个flag,后来我也就卡在这,导致这道题最后也没能做出来

看了官方wp后,发现后半段flag在这

 

crypto

Easy RSA

这次HGAME有很多RSA题目,也趁这次机会好好学一下RSA

RSA最基础的知识只需要记住一些概念和公式,首先是取两个大素数p和q,n=p*q,最简单的题目会给出p和q的值,有时不会给出p和q,但会给出n,如果n的大小不太大(不大于512位),可以先尝试对n进行因式分解,φ(n)=(p-1)*(q-1)=p*q-p-q+1=[p^1-p^(1-1)]*[q^1-q^(1-1)],e*d=1modφ(n),<n,e>为公钥,<n,d>为私钥

设m为明文,c为密文,加解密满足如下操作:c=m^e mod n,m=c^d mod n,(0≤m<n)

题目如下:

from math import gcd
from random import randint
from gmpy2 import next_prime
from Crypto.Util.number import getPrime
from secret import flag

def encrypt(c):
    p = getPrime(8)
    q = getPrime(8)
    e = randint(0, p * q)
    while gcd(e, (p - 1) * (q - 1)) != 1:
        e = int(next_prime(e))
    return e, p, q, pow(ord(c), e, p * q)

if __name__ == '__main__':
    print(list(map(encrypt, flag)))
    # [(12433, 149, 197, 104), (8147, 131, 167, 6633), (10687, 211, 197, 35594), (19681, 131, 211, 15710), (33577, 251, 211, 38798), (30241, 157, 251, 35973), (293, 211, 157, 31548), (26459, 179, 149, 4778), (27479, 149, 223, 32728), (9029, 223, 137, 20696), (4649, 149, 151, 13418), (11783, 223, 251, 14239), (13537, 179, 137, 11702), (3835, 167, 139, 20051), (30983, 149, 227, 23928), (17581, 157, 131, 5855), (35381, 223, 179, 37774), (2357, 151, 223, 1849), (22649, 211, 229, 7348), (1151, 179, 223, 17982), (8431, 251, 163, 30226), (38501, 193, 211, 30559), (14549, 211, 151, 21143), (24781, 239, 241, 45604), (8051, 179, 131, 7994), (863, 181, 131, 11493), (1117, 239, 157, 12579), (7561, 149, 199, 8960), (19813, 239, 229, 53463), (4943, 131, 157, 14606), (29077, 191, 181, 33446), (18583, 211, 163, 31800), (30643, 173, 191, 27293), (11617, 223, 251, 13448), (19051, 191, 151, 21676), (18367, 179, 157, 14139), (18861, 149, 191, 5139), (9581, 211, 193, 25595)]

 附上我自己写的解密脚本,因为用的是比赛前几天学的一些python写的,所有师傅们看看就行

from gmpy2 import invert

output=[(12433, 149, 197, 104), (8147, 131, 167, 6633), (10687, 211, 197, 35594), (19681, 131, 211, 15710), (33577, 251, 211, 38798), (30241, 157, 251, 35973), (293, 211, 157, 31548), (26459, 179, 149, 4778), (27479, 149, 223, 32728), (9029, 223, 137, 20696), (4649, 149, 151, 13418), (11783, 223, 251, 14239), (13537, 179, 137, 11702), (3835, 167, 139, 20051), (30983, 149, 227, 23928), (17581, 157, 131, 5855), (35381, 223, 179, 37774), (2357, 151, 223, 1849), (22649, 211, 229, 7348), (1151, 179, 223, 17982), (8431, 251, 163, 30226), (38501, 193, 211, 30559), (14549, 211, 151, 21143), (24781, 239, 241, 45604), (8051, 179, 131, 7994), (863, 181, 131, 11493), (1117, 239, 157, 12579), (7561, 149, 199, 8960), (19813, 239, 229, 53463), (4943, 131, 157, 14606), (29077, 191, 181, 33446), (18583, 211, 163, 31800), (30643, 173, 191, 27293), (11617, 223, 251, 13448), (19051, 191, 151, 21676), (18367, 179, 157, 14139), (18861, 149, 191, 5139), (9581, 211, 193, 25595)]

def decrypt(output):
    e,p,q,c=output
    d=invert(e,p*q-p-q+1)
    m=pow(c,d,p*q)
    return chr(m)

print("".join(map(decrypt, output)))

 运行脚本,得到flag

 

English Novel

加密过程如下:

def encrypt(data, key):
    assert len(data) <= len(key)
    result = ""
    for i in range(len(data)):
        if data[i].isupper():
            result += chr((ord(data[i]) - ord('A') + key[i]) % 26 + ord('A'))
        elif data[i].islower():
            result += chr((ord(data[i]) - ord('a') + key[i]) % 26 + ord('a'))
        else:
            result += data[i]
    return result

 这道题我的解题思路是,先在大量文件中找到明文和密文相互对应的两个文件,然后写了一个爆破的脚本,将明文经过加密后与密文对比,得出key,由于空格等符号不参与加密过程,所以需要多选择几份文件,来互相填补每份文件符号位,并且明文和密文的长度要大于等于flag加密后的长度,因为我写的代码太过于蹩脚,没有任何参考和学习价值,这里就不放出来了,下面附上官方的解题脚本:

import os
import encrypt
# 获取字符串特征字符串
def get_feature(s):
return "".join(['*' if c.isalpha() else c for c in s])
if __name__ == "__main__":
# 以未被加密的字符作为特征值,进行配对
matches = {}
for root, dirs, files in os.walk("original"):
for file in files:
ori = open(os.path.join(root, file)).read()
feature = get_feature(ori)
if feature not in matches:
matches[feature] = {"ori": [], "enc": []}
matches[feature]["ori"].append(ori)
for root, dirs, files in os.walk("encrypt"):
for file in files:
enc = open(os.path.join(root, file)).read()
feature = get_feature(enc)
if feature not in matches:
matches[feature] = {"ori": [], "enc": []}
matches[feature]["enc"].append(enc)
keys = [-1] * max(map(len, matches.keys()))
# 通过已知明文攻击获取秘钥
for feature, pair in matches.items():
if len(pair["ori"]) == 1 and len(pair["enc"]) == 1:
for i in range(len(feature)):
if keys[i] == -1 and feature[i] == "*":
keys[i] = (ord(pair["enc"][0][i]) - ord(pair["ori"][0][i])) %
26
if all([key >= 0 for key in keys]):
break
# 解密获得 flag
print(encrypt.encrypt(open("flag.enc").read(), [-key for key in keys]))

第一次写博客,如有不合规的地方,立删

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值