确实是高质量比赛,学到了很多知识、认识到了很多的不足。
任重而道远啊…
hgame_week1webClassic Childhood Game
F12检查源码,打开Events.js
发现
\x59\x55\x64\x6b\x61\x47\x4a\x58\x56\x6a\x64\x61\x62\x46\x5a\x31\x59\x6d\x35\x73\x53\x31\x6c\x59\x57\x6d\x68\x6a\x4d\x6b\x35\x35\x59\x56\x68\x43\x4d\x45\x70\x72\x57\x6a\x46\x69\x62\x54\x55\x31\x56\x46\x52\x43\x4d\x46\x6c\x56\x59\x7a\x42\x69\x56\x31\x59\x35
cyberchef解码
Show Me Your Beauty
文件上传
在一张图片内写入
上传用burpsuite抓包
修改文件名为pHp
上传成功
回到网页,右键头像打开,测试phpinfo();
)
成功,连接蚁剑,根目录下找到flag:hgame{Unsave_F1L5_SYS7em_UPL0ad!}
Become A Member
(赛后复现) 比赛时改错头了一直没回显…直接尬住
考点就是 ⼏个常规的HTTP考点+请求数据构造
题⽬提⽰⾝份证明(Cute-Bunny),尝试 User-Agent
Vidar的邀请码(code),可以看⼀开始的http请求头当中有⼀个 Set-Cookie:code=guest
,将 guest 修改为 Vidar 即可
来⾃ bunnybunnybunny.com 的申请,提⽰了请求来源,将 referer
的值修改为bunnybunnybunny.com
最后⼀个是本地请求,这个⽐较常⻅,添加 X-Forwarded-For
: 127.0.0.1 的请求头即可
然后给了 password 和 username ,按正常的json数据格式发请求数据即可(注意需要指定Content-Type 为 application/json ,请求⽅式是 GET )
)
得到flag:hgame{H0w_ArE_Y0u_T0day?}
Guess Who I Am
(赛后复现) 这是一道爬虫题,写脚本这一块还得不断加强才行啊..
F12看到hint,去GitHub把成员信息扒下来,写成json文件,改成这种形式
⽐较快捷的办法的话⽐如说⽤像vsode之类的编辑器来做批量的编辑。可以ctrl + f选中所有需要编辑的信息后,右键更改所有匹配项,让每⼀个 “avatar” 前⾯都出现光标,再⽤shift + ⽅向键,就可以⽤多个光标批量选中删除啦。
下一步我们要做的内容就是读⼊json⽂件并且解析内容,请求获取成员介绍,通过json⾥读进来的内容匹配出对应的ID,⽤这个ID去请求验证答案的接⼝,当得分超过100时去关注返回的⻚⾯看看有没有什么不⼀样的信息。
步骤一:
读⼊json⽂件并且解析内容
import jsonwith open('member.json',encoding='UTF-8') as f: member = json.load(f)print(member)
这里要加encoding='UTF-8'
,不然可能会出现UnicodeDecodeError: 'gbk' codec can't decode byte 0xa7 in position 58: illegal multibyte sequence
的编码问题
json.load()
:json文件中读取数据
步骤二:
看到正常输出了,接下来F12看⼀下⽹站的后端接⼝设计,请求对应的后端接⼝拿到所需的各种信息
提问信息的地址:http://week-1.hgame.lwsec.cn:32230/api/getQuestion
分数的地址:http://week-1.hgame.lwsec.cn:32230/api/getScore
答题的地址:http://week-1.hgame.lwsec.cn:32230/api/verifyAnswer
此处是POST
这⾥可能就会考虑⼀个问题,⽹站是怎么对于不同⽤⼾的信息进⾏判断的呢,这⾥也没有什么登陆啊,我能不能直接让服务端认为我已经拿到了100分呢?站点通过Cookie中的session来记录了⽤⼾信息,⽽session是通过Key来加密的,所以不知道Key的⽤⼾是没有办法做到在客⼾端修改分数的。
步骤三:
我们这⾥要带着session去请求 /api/getQuestion
的接⼝来获取问题。
这⾥我们获得了⼀个json格式的数据,我们的⽬标是去提取我们想要的成员介绍的内容,但是请求得到的数据类型是str,所以需要转换成Dict。
所以加上这两句
rs = json.loads(res.text)print(rs['message'])
得到
详解:
cookies: | 初始化cookies字典变量 |
---|---|
res=requests.get(“url”,cookies=cookies) | 将cookies添加到get方法中,获取到的res.content中就是我们将cookies信息添加到get中后访问网页所获取的内容 |
json.loads(): | 将str类型的数据转换为dict类型 |
res.text | 查看响应内容,response.text 返回的是Unicode格式的数据 |
步骤四:
获取到对应的成员介绍后我们就在成员信息中匹配到对应的ID
answer = ''for i in member: if i['intro'] == rs['message']: answer = i['id'] breakprint(answer)
验证答案
答案正确,可以进行下一步的脚本编写
由于后端⽤的语⾔是Golang,开发框架是Gin,鉴权⽤的session中间件是客⼾端session的形式,也就是说包括分数包括问题都是存储在session中,那么我们每次答对题⽬分数和问题都是会改变的,在⻚⾯上我们答对问题会有 set-cookie 的响应头来重新设置新的session,但是我们编写脚本就得⾃⼰来处理这个问题,需要从set-cookie中拿到新的session然后再开始新⼀轮的⾃动答题
步骤五:
获取页面的session
data = {'id':answer} res = requests.post(url+"/api/verifyAnswer",cookies=cookies,data=data) rs=json.loads(res.text) print("[*] Result: "+ rs['message']) cookies['session'] = res.cookies['session']
步骤六:
补上对于分数接⼝的请求,外层加上⼀个While循环,判断分数到达100时退出,因为后端接⼝总共
也就只有获取问题,获取分数,验证答案三个,那么我们可以判断分数到达100时肯定是从这三个接⼝会能够返回和Flag相关的信息
完整版EXP:
import jsonimport requests# 读取json⽂件并且解析with open('member.json', encoding='UTF-8') as f: member = json.load(f)cookies={}answer=''score=0# 靶机地址url="http://week-1.hgame.lwsec.cn:31628"#注意此处不要多复制‘/’,会造成‘//’现象直接报错# 当前页面的sessioncookies['session']='MTY3NDIxMjQ0OHxEdi1CQkFFQ180SUFBUkFCRUFBQU9fLUNBQUlHYzNSeWFXNW5EQTBBQzJOb1lXeHNaVzVuWlVsa0EybHVkQVFDQUF3R2MzUnlhVzVuREFnQUJuTnZiSFpsWkFOcGJuUUVBZ0FzfLcGFI3K5NeFt3s0VGWxGso8KEtNu96yx9qX70XNWqjK'while score <100: # 请求getQuestion接⼝ res=requests.get(url+"/api/getQuestion",cookies=cookies) rs = json.loads(res.text) print('[+] getQuestion:'+res.text) # 匹配对应的ID for i in member: if i['intro'] == rs['message']: answer = i['id'] break # 请求verifyAnswer接⼝ data = {'id':answer} res = requests.post(url+"/api/verifyAnswer",cookies=cookies,data=data) rs=json.loads(res.text) print("[*] Result: "+ rs['message']) cookies['session'] = res.cookies['session'] # 请求getScore接⼝ res=requests.get(url+"/api/getScore",cookies=cookies) rs=json.loads(res.text) score=rs['message'] print('[+] Score:'+str(rs['message']))
实现效果
得到flag:hgame{Guess_who_i_am^Happy_Crawler}
cryptoRSA
在线网站分解n得到p,q http://factordb.com/
p=11239134987804993586763559028187245057652550219515201768644770733869088185320740938450178816138394844329723311433549899499795775655921261664087997097294813q=12022912661420941592569751731802639375088427463430162252113082619617837010913002515450223656942836378041122163833359097910935638423464006252814266959128953
脚本解题
import gmpy2from Crypto.Util.number import *p=11239134987804993586763559028187245057652550219515201768644770733869088185320740938450178816138394844329723311433549899499795775655921261664087997097294813q=12022912661420941592569751731802639375088427463430162252113082619617837010913002515450223656942836378041122163833359097910935638423464006252814266959128953e = 65537c=110674792674017748243232351185896019660434718342001686906527789876264976328686134101972125493938434992787002915562500475480693297360867681000092725583284616353543422388489208114545007138606543678040798651836027433383282177081034151589935024292017207209056829250152219183518400364871109559825679273502274955582n=135127138348299757374196447062640858416920350098320099993115949719051354213545596643216739555453946196078110834726375475981791223069451364024181952818056802089567064926510294124594174478123216516600368334763849206942942824711531334239106807454086389211139153023662266125937481669520771879355089997671125020789phi=(p-1)*(q-1)d=gmpy2.invert(e,phi)m=gmpy2.powmod(c,d,n)print(long_to_bytes(m))
得到flag:hgame{factordb.com_is_strong!}
神秘的电话
(赛后复现)…卡最后一步上了,属实没想到北欧神话的终点是诸神黄昏的幸存神vidar…
诸神黄昏的各种简写都试了结果是这个…还是不够细啊
第一步 将encrypted_message.txt中的内容base64解码
得到
⼏个星期前,我们收到⼀个神秘的消息。但是这个消息被重重加密,我们不知道它的真正含义是什
么。唯⼀知道的信息是关于密钥的:“只有倒着翻过⼗⼋层的篱笆才能抵达北欧神话的终点”。
第二步,手翻morse.wav的摩斯电码,因为flag中字母均为小写
得到0223e_priibly__honwa_jmgh_fgkcqaoqtmfr
第三步,逆序
第四步,18层栅栏解码
第五步,维吉尼亚解码,得到flag:hgame{welcome_to_hgame2023_and_enjoy_hacking}
miscSign In
签到题,base64得flag:hgame{Welcome_To_HGAME2023!}
e99p1ant_want_girlfriend
修改图片高度得到flag:hgame{e99p1ant_want_a_girlfriend_qq_524306184}
神秘的海报
Stegsolve打开,lsb 000 看到
Sure enough, you still remember what we talked about at that time! This is part of the secret:
hgame{U_Kn0w_LSB&W I put the rest of the content here, https://drive.google.com/file/d/13kBos3Ixlfwkf3e0z0kJTEqBxm7RUk-G/view?usp=sharing, if you directly access the google drive cloud disk download in China, it will be very slow, you can try to use Scientific Internet access solves the problem of slow or inaccessible access to external network resources. This is my favorite music, there is another part of the secret in the music, I use Steghide to encrypt, the password is also the 6-digit password we agreed at the time, even if someone else finds out here, it should not be so easy to crack (( hope so
前半段flag跟wav文件下载链接,结合后文提示steghide隐写,密码是6位纯数字,用stegseek爆破
superdic.txt为6位纯数字的密码本
得到后半段:恭喜你解到这里,剩下的Flag是 av^Mp3_Stego},我们Week2见!
flag:hgame{U_Kn0w_LSB&Wav^Mp3_Stego}
Where am I
foremost分解出流量包里的压缩包,是个rar,一打开就是各种报错,缺少图片的文件头,密码以及不可预料的压缩末端。尝试用winrar修复但是不行,研究了一下,用NetworkMiner这个工具分离出的rar是有文件尾的,也防止自己手动修复时出错。
研究半天修复文件头,结果发现是rar伪加密
将24改为20即可
打开图片,在备注处看到gps信息,用https://exif.tuchong.com/ EXIF查看器更方便
得到信息:39 deg 54' 54.18" N, 116 deg 24' 14.88" E,0 m Above Sea Level
得到flag:hgame{116_24_1488_E_39_54_5418_N}
reversetest your IDA
放入IDA一打开就能看到flag
easyasm
观察发现是需要将result异或0x33后转字符串
脚本:
s='0x5b,0x54,0x52,0x5e,0x56,0x48,0x44,0x56,0x5f,0x50,0x3,0x5e,0x56,0x6c,0x47,0x3,0x6c,0x41,0x56,0x6c,0x44,0x5c,0x41,0x2,0x57,0x12,0x4e's=s.split(',')l=[]for i in s: l=int(i,16)^0x33 print(l,end='')s=[104,103,97,109,101,123,119,101,108,99,48,109,101,95,116,48,95,114,101,95,119,111,114,49,100,33,125]for i in s: i=chr(i) print(i,end='')
得到flag:hgame{welc0me_t0_re_wor1d!}
pwntest_nc
kali 中 nc 后 cat flag
IOTHelp marvin
(赛后复现)第一次做IOT的题,按照wp复现成功,刚好记录一下
给了hint知道本题为SPI协议解析 使⽤pulesview打开sr⽂件
SPI协议特性
SPI = Serial Peripheral Interface,是串行外围设备接口,是一种高速,全双工,同步的通信总线。
SPI总线包括4条逻辑线,定义如下:
MISO:Master input slave output 主设备数据输入,从设备数据输出(数据来自从机);
MOSI:Master output slave input 主设备数据输出,从设备数据输入(数据来自主机);
SCLK :Serial Clock 串行时钟信号,由主机产生发送给从机;
NSS:从机片选使能信号线。该信号由主机进行控制。在一主对多从的模式下,每一个从机都需要一个NSS,用于主机选择和那个从机进行通信(一般为低电平有效)。当一个SPI设备需要发送广播数据,它必须拉低NSS信号,以通知所有其它的设备它是主设备。NSS也可以是CE,CS或SSEL
三根线上有波形 且有根频率最⾼ 应该是4线或以上的带时钟的通信协议
D0是时钟信号 ( CLK )
D1是片段CS
D2是数据(MISO)
如图设置,即可看的SPI的数据
看到7D,直接能联系到ascii码值为}
,故解码得flag
s='34,67,61,6d,65,7b,34,5f,35,74,34,6e,67,65,5f,53,70,31,7d's=s.split(',')flag=''for i in range(len(s)): flag+=chr(int(s[i],16))print(flag)
得到flag:4game{4_5t4nge_Sp1}
hgame_week2webGit Leakage
读题目得知是git泄露
访问url/.git
下载index,打开搜索flag看到Th1s_1s-flag
去下载url/Th1s_1s-flag
得到flag:hgame{Don't^put*Git-in_web_directory}
v2board
百度到V2Board Admin.php 越权访问漏洞
GitHub搜索exp,找到了zgao264师傅写的exp
按照README.md操作,得到token
cryptorabin
Rabin算法是一种基于模平方和模平方根的非对称加密算法
import gmpy2import libnump=65428327184555679690730137432886407240184329534772421373193521144693375074983q=98570810268705084987524975482323456006480531917292601799256241458681800554123c=4086661358212073245252744496322167481491672871949606958127237667510352936336492238168574196919178461270299415887662858793221972137767350873928701793072470n=6449323225107597053933443750923454260964062647115639999185223478236611437289957562214567685539436238408656830242287962245944636381136963632264486074804909e = 2inv_p = gmpy2.invert(p, q)inv_q = gmpy2.invert(q, p)mp = pow(c, (p + 1) // 4, p)mq = pow(c, (q + 1) // 4, q)a = (inv_p * p * mq + inv_q * q * mp) % nb = n - int(a)c = (inv_p * p * mq - inv_q * q * mp) % nd = n - int(c)# 因为rabin 加密有四种结果,全部列出。aa = [a, b, c, d]for i in aa: print(i) print(libnum.n2s(int(i)))
得到flag:hgame{That'5_s0_3asy_to_s@lve_r@bin}
RSA大冒险1
这道题出的真挺不错的
给了四个挑战,打通关获得flag
第一关是最基础的rsa,通过给的p值与p*q*r值得到q*r的值,值这么小直接yafu分解,得到q值和r值
这样p,q,e,c齐全,直接解,得到第一关答案:m<n_But_also_m<p
第二关是利用欧几里得算法,运行两次得到两个n值,其中的p值是相等的
import gmpy2p=gmpy2.gcd(n1,n2)q=n1//p
这样就得到了p,q的值,现在p,q,e,c齐全,得到第二关答案:make_all_modulus_independent
第三关是小e,明显是低加密指数攻击
脚本解题
import libnumimport gmpy2c=1620135819727459374856861031843595560446547666362278256721611098300571774064092226213485034156592394325852384589395122643937335495320149363516518672591127083237362181645206738138892454081130678965267391894846777695757814984112690455549768e=3n=89205429359119794945983435440440153891896048605500448398466813204176930432316502363982420399189336214133892667017070960272307319029776828466846047959788316617559138703334632404710945248239429508995159045446455803886466666986158213938827010650078577668654313324766202011427074264152957817749714057009436177683def exp(n, e, c): k = 0 while 1: m1 = k * n + c m, t = gmpy2.iroot(m1, e) if t: print(m) print(k) print(libnum.n2s(int(m))) break k += 1exp(n, e, c)
得到第三关答案:encrypt_exponent_should_be_bigger
第四关的两次e值不同,得知是共模攻击
脚本解题
import libnumimport gmpy2n=66235966847778258236086556078519489918007499753458367888673525245830804410711231915934431942266308073011531618067138951010571129793107908204734598775186910049124825904093866926551514996215164837557886573947078401045910146184667712652713463353890419328910304579191100714494895346655422228997743287867163201599e1=105499e2=91183c1=6114296529012724857259078691024991747448962852327827400348864045083302424580717261899703658605007866073901365881990655212941056350327573395899227984885284491471483713972704047186525253301027249738411890418148826824912176701147082190936101112270993407013405680182248174829038778266977210861721974168651553374c2=0x509f556d9b19a1257fc91c284690a8e6e35e36bf1993c7b0ff21173ae015dbfcfdc0f9be257dd2400db11360f49ffb86fa3ae1f4b9f4abff43bac70f612bedb83c7b7eb5f32ebfb485077963195483ddd7df6f7e55c85bdccba88452b2546c929b68dca67df76ab0f158c383d0e187ed3bb75eb84cd4d5ac71c5b3f9d3564b46def exp_def(e1,e2,c1,c2,n): s,s1,s2 = gmpy2.gcdext(e1, e2) m = (pow(c1,s1,n) * pow(c2 ,s2 ,n)) % n return int(m) m=exp_def(e1,e2,c1,c2,n)print(libnum.n2s(m))
得到第四关答案:never_uese_same_modulus
得到最终flag:hgame{W0w_you^knowT^e_CoMm0n_&t$ack_@bout|RSA}
miscSign In Pro Max
flag分为5个部分,拼成uuid格式
part1为base套娃,base64、base58、base32得f51d3a18
part2、3 为md5得f91c
、4952
part4为sha256得a3ed
part5为ascii码位移得0bc0ea61d21c
s='0gh0jf61i21h'flag=''for i in s: if ord(i)>=97: data=chr(ord(i)-5) flag+=data else: flag+=iprint(flag)
拼接flag:hgame{f51d3a18-f91c-4952-a3ed-0bc0ea61d21c}
crazy_qrcode
(赛后复现)姿势错了orz
在https://merricx.github.io/qrazybox/中导入该二维码,在tools list
选择 Brute-force Format Info Pattern
然后将模式转为Decode Mode
,点击Decode
即可获得密码:
解开压缩包,发现是25张二维码碎片,附加文件是一个数组,猜测是每一个二维码碎片的旋转次数
尝试拼出二维码(用ppt拼的,确实好用)
扫描得到flag:Cr42y_qrc0de