安恒-抗疫月赛

安恒-抗疫月赛

抗疫抗疫!来自安全人员的行动!

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弱比较条件的val1val2,这个网上有很多:

0e开头的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强比较绕过对val3val4的判断,由于没有要求是字符串,因此利用数据进行绕过:

val3[]=1&val4[]=2

再往下看,对val5val6val7进行了(string)的限制,这里的判断是真正需要进行md5碰撞了,网上能找到很多数据有微小差别但是md5值相同的例子,但是都是两个一对的,但是本题有三个变量,需要借助这个工具来生成值不同但是md5相同的文件。

然后是对abmn的判断:
ctype_alnum($a\b)判断a\b是否是字母和数字或字母数字的组合;
同时要求mn长度不能超过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师傅的脚本来爆破:

# 爆破数字+字母,找到符合md5后为0e开头,且后面为纯数字/一位字母的字符串
import string
import itertools
import hashlib


dic = 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 requests

url = '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 flag
from 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,n

e=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 sys
import binascii
sys.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 zlib
import struct
crc32key = 0x986B9E93
data = bytearray(b'\x49\x48\x44\x52\x00\x00\x01\x69\x00\x00\x01\x25\x08\x02\x00\x00\x00') #表示宽和高部分的字节(13-29bytes)
n = 4095 #理论上0xffffffff,但考虑到屏幕实际/cpu,0x0fff就差不多了
for w in range(n): #高和宽一起爆破
width = bytearray(struct.pack('>i', w)) #q为8字节,i为4字节,h为2字节
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:

Comments


:D 一言句子获取中...

Loading...Wait a Minute!