抗疫抗疫!来自安全人员的行动!
Web-easy-hash 考察md5强比较、弱比较以及md5碰撞,本题是掘安杯的audit题改的,参考getfly师傅的博客 。
解题 进入题目,给出了源码如下:
<?php highlight_file(__FILE__ ); error_reporting(0 ); $val1 = @$_GET['val1' ]; $val2 = @$_GET['val2' ]; $val3 = @$_GET['val3' ]; $val4 = @$_GET['val4' ]; $val5 = (string)@$_POST['val5' ]; $val6 = (string)@$_POST['val6' ]; $val7 = (string)@$_POST['val7' ]; if ( $val1 == $val2 ){ die ('val1 OR val2 no no no' ); } if ( md5($val1) != md5($val2) ){ die ('step 1 fail' ); } if ( $val3 == $val4 ){ die ('val3 OR val4 no no no' ); } if ( md5($val3) !== md5($val4)){ die ('step 2 fail' ); } if ( $val5 == $val6 || $val5 == $val7 || $val6 == $val7 ){ die ('val5 OR val6 OR val7 no no no' ); } if (md5($val5) !== md5($val6) || md5($val6) !== md5($val7) || md5($val5) !== md5($val7)){ die ('step 3 fail' ); } if (!($_POST['a' ]) and !($_POST['b' ])){ echo "come on!" ; die (); } $a = $_POST['a' ]; $b = $_POST['b' ]; $m = $_GET['m' ]; $n = $_GET['n' ]; if (!(ctype_alnum($a)) || (strlen($a) > 5 ) || !(ctype_alnum($b)) || (strlen($b) > 6 )){ echo "a OR b fail!" ; die (); } if ((strlen($m) > 1 ) || (strlen($n) > 1 )){ echo "m OR n fail" ; die (); } $val8 = md5($a); $val9 = strtr(md5($b), $m, $n); echo PHP_EOL;echo "<p>val8 : $val8</p>" ;echo PHP_EOL;echo "<p>val9 : $val9</p>" ;echo PHP_EOL;if (($val8 == $val9) && !($a === $b) && (strlen($b) === 5 )){ echo "nice,good job,give you flag:" ; echo file_get_contents('/var/www/html/flag.php' ); }
分析代码可以看到,我们需要找到满足md5弱比较
条件的val1
和val2
,这个网上有很多:
0 e开头的md5和原值:QNKCDZO 0e830400451993494058024219903391 s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387a 0e848240448830537924465865611904 s214587387a 0e848240448830537924465865611904 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s1885207154a 0e509367213418206700842008763514 s1502113478a 0e861580163291561247404381396064 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s155964671a 0e342768416822451524974117254469 s1184209335a 0e072485820392773389523109082030 s1665632922a 0e731198061491163073197128363787 s1502113478a 0e861580163291561247404381396064 s1836677006a 0e481036490867661113260034900752 s1091221200a 0e940624217856561557816327384675 s155964671a 0e342768416822451524974117254469 s1502113478a 0e861580163291561247404381396064 s155964671a 0e342768416822451524974117254469 s1665632922a 0e731198061491163073197128363787 s155964671a 0e342768416822451524974117254469 s1091221200a 0e940624217856561557816327384675 s1836677006a 0e481036490867661113260034900752 s1885207154a 0e509367213418206700842008763514 s532378020a 0e220463095855511507588041205815 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s214587387a 0e848240448830537924465865611904 s1502113478a 0e861580163291561247404381396064 s1091221200a 0e940624217856561557816327384675 s1665632922a 0e731198061491163073197128363787 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s1665632922a 0e731198061491163073197128363787 s878926199a 0e545993274517709034328855841020
然后需要利用md5强比较
绕过对val3
和val4
的判断,由于没有要求是字符串,因此利用数据进行绕过:
再往下看,对val5
、val6
和val7
进行了(string)
的限制,这里的判断是真正需要进行md5碰撞
了,网上能找到很多数据有微小差别但是md5值相同的例子,但是都是两个一对的,但是本题有三个变量,需要借助这个工具 来生成值不同但是md5相同的文件。
然后是对a
、b
、m
和n
的判断:ctype_alnum($a\b)
判断a\b
是否是字母和数字或字母数字的组合; 同时要求m
和n
长度不能超过1
。
然后令$val8 = md5($a)
,$val9 = strtr(md5($b), $m, $n)
将md($b)
中与$m
相同的值替换为$n
的值。 最后还需要满足($val8 == $val9) && !($a === $b) && (strlen($b) === 5)
,这个地方利用md5
弱碰撞就行,利用QNKCDZO/0e830400451993494058024219903391
类的字符串,找一个长度为5
且md5值以0e
开头后面全是数字的字符串$a
,另找一个0e
开头后面为纯数字/一位字母的字符串$b
,若0e
后面是一个字母和其他的数字,利用strtr()
函数将其md5值中字母改为数字即可。
难点就在于找满足要求的$a
和$b
的值了,这里参考getfly师傅的脚本来爆破:
import stringimport itertoolsimport hashlibdic = string.ascii_lowercase + string.ascii_uppercase + string.digits time = 0 for n in itertools.permutations(dic, 5 ): print('trying' , time) time += 1 i = '' .join(n) li = [0 ] * 26 count = 0 strs = hashlib.md5(str(i).encode('utf-8' )).hexdigest() if strs[:2 ] == '0e' : for j in strs[2 :]: if ord(j) >= 97 : li[ord(j)-97 ] += 1 for k in li: if k != 0 : count += 1 if count < 1 : print(i) break
最后利用构造好的payload写脚本拿flag。
解题脚本 import requestsurl = 'http://183.129.189.60:10004/?val1=QNKCDZO&val2=s878926199a&val3[]=1&val4[]=2&m=a&n=1' file1 = open('out_test_000.txt' , 'rb' ).read() file2 = open('out_test_001.txt' , 'rb' ).read() file3 = open('out_test_002.txt' , 'rb' ).read() data = {'val5' :file1, 'val6' :file2, 'val7' :file3, 'a' :'byGcY' , 'b' :'aOtm2' } s = requests.post(url, data) print(s.text)
Crypto-古典密码 进入题目,分别给了一组凯撒密码
加密的字符串、一组morse码
、一组栅栏密码
加密的字符串,分别解密即可。
Crypto-RSA 跟前两天Ichunqiu的抗疫赛中的一道RSA题一样,考察共模攻击
解题 附件代码如下:
from flag import flagfrom Crypto.Util.number import *p=getPrime(1024 ) q=getPrime(1024 ) e=65537 n=p*q m=bytes_to_long(flag) c=pow(m,e,n) print c,e,ne=11187289 n=p*q m=bytes_to_long(flag) c=pow(m,e,n) print c,e,n''' 3398498381912395819190972489172462865619978412426461006637853132394421358554444085509204376417687407497725837275868696481008111895766215578504776574832032556271718345687763315140723387608016365200919607751172500433727679269003098314988424638473027123820847847826679169000817669427223462669128173658466684135284118199815059085013479646863344355311315928713888347485004116168388822942797985291207722712351376891776564431593839662958249777540851019964959285093222467104765037231393043482615879794268339523066822738215251088897330388858109680412562153811860413533184870172160079371279534423386236128033224501238509297353 65537 21550279102644053137401794357450944302610731390301294678793250727396089358072700658571260795910112265309568014296122288384516447895827201111531054386530016432904989927216701507587366446802666848322853781729905492728655474832512381505627940555854308364578108265962388044363133246414753768229564846275154311898383993892293297122428661960946207950994560898964054913194462187242818633295970027741085201122155726130759045957757833942616544066055081600792366411691979350744894938994915328874600229684477533220240489600171746943849179803693122081888324258987779131223150589953248929679931142134208151043000793272520874205933 3466733921305804638105947202761163747472618602445995245253771384553216569474005211746398256742813639292824489920799418551206486872148557599625985549276697777903434273072767901043963396047653458242735767809413051298636887840641872939342025101757793615068691040228073377366562557622977332819376942596081135968249279010542277871138668977160241877260538203101507006391433015105607006204397243716334344883925947719719479074061998068934050946968531874465924912747079003982022188875112147185558223515367430238618463189740762128953957802291125793882636020335117593003197811477506533564676975831899876919568948425610130348710 11187289 21550279102644053137401794357450944302610731390301294678793250727396089358072700658571260795910112265309568014296122288384516447895827201111531054386530016432904989927216701507587366446802666848322853781729905492728655474832512381505627940555854308364578108265962388044363133246414753768229564846275154311898383993892293297122428661960946207950994560898964054913194462187242818633295970027741085201122155726130759045957757833942616544066055081600792366411691979350744894938994915328874600229684477533220240489600171746943849179803693122081888324258987779131223150589953248929679931142134208151043000793272520874205933 '''
明显地看出是使用相同的模数n
、两个不同的e
生成了两个密文c
,直接上POC:
import sysimport binasciisys.setrecursionlimit(1000000 ) def egcd (a, b) : if a == 0 : return (b, 0 , 1 ) else : g, y, x = egcd(b % a, a) return (g, x - (b // a) * y, y) def modinv (a, m) : g, x, y = egcd(a, m) if g != 1 : raise Exception('modular inverse does not exist' ) else : return x % m n = 21550279102644053137401794357450944302610731390301294678793250727396089358072700658571260795910112265309568014296122288384516447895827201111531054386530016432904989927216701507587366446802666848322853781729905492728655474832512381505627940555854308364578108265962388044363133246414753768229564846275154311898383993892293297122428661960946207950994560898964054913194462187242818633295970027741085201122155726130759045957757833942616544066055081600792366411691979350744894938994915328874600229684477533220240489600171746943849179803693122081888324258987779131223150589953248929679931142134208151043000793272520874205933 e1 = 65537 e2 = 11187289 c1 = 3398498381912395819190972489172462865619978412426461006637853132394421358554444085509204376417687407497725837275868696481008111895766215578504776574832032556271718345687763315140723387608016365200919607751172500433727679269003098314988424638473027123820847847826679169000817669427223462669128173658466684135284118199815059085013479646863344355311315928713888347485004116168388822942797985291207722712351376891776564431593839662958249777540851019964959285093222467104765037231393043482615879794268339523066822738215251088897330388858109680412562153811860413533184870172160079371279534423386236128033224501238509297353 c2 = 3466733921305804638105947202761163747472618602445995245253771384553216569474005211746398256742813639292824489920799418551206486872148557599625985549276697777903434273072767901043963396047653458242735767809413051298636887840641872939342025101757793615068691040228073377366562557622977332819376942596081135968249279010542277871138668977160241877260538203101507006391433015105607006204397243716334344883925947719719479074061998068934050946968531874465924912747079003982022188875112147185558223515367430238618463189740762128953957802291125793882636020335117593003197811477506533564676975831899876919568948425610130348710 s = egcd(e1, e2) s1 = s[1 ] s2 = s[2 ] if s1<0 : s1 = - s1 c1 = modinv(c1, n) elif s2<0 : s2 = - s2 c2 = modinv(c2, n) m=(pow(c1,s1,n)*pow(c2,s2,n)) % n print (binascii.unhexlify(hex(m)[2 :].strip("L" )))
Misc-lemonEssence 考察CRC爆破
解题 下载压缩包解压出如下一张PNG
图片: 缩略图可以看,但是放大之后看不了,猜测是对其高或宽进行了更改,需要进行CRC爆破
以获得原来的宽和高,修改回去就行了。 利用Winrar拿到其CRC,然后利用下面的脚本爆破:
import zlibimport structcrc32key = 0x986B9E93 data = bytearray(b'\x49\x48\x44\x52\x00\x00\x01\x69\x00\x00\x01\x25\x08\x02\x00\x00\x00' ) n = 4095 for w in range(n): width = bytearray(struct.pack('>i' , w)) for h in range(n): height = bytearray(struct.pack('>i' , h)) for x in range(4 ): data[x+4 ] = width[x] data[x+8 ] = height[x] crc32result = zlib.crc32(data) if crc32result == crc32key: print(width,height) exit(0 )
把爆破出地结果与图片数据对比,发现高的部分被更改了,如图更改回去即可看到flag: