2020强网杯-强网先锋-bank
bank这题首先需要nc一个ip地址,发现发现返回
sha256(XXX+yhB1iPWH3ENjHhf12) == 05401c749eee0ccb5a9cfb96eae3d8909a489113066f3a0f185580ac60a18403
Give me xxx:
#填对以后要填teamtoken
teamtoken:
#要填写一个用户名
input your name:
老密码学题了,要算出xxx的值。爆破完事。
然后试了一下,发现有时间限制,操作时间超过一定的话,就会被断开连接。所以一切都要脚本跑,手动来不及。
进去以后,继续看下面的逻辑。
>you can choose: transact, view records, provide a record, get flag, hint
#transact交易功能
>transact
>please give me the trader and the amount(for example:Alice 1)
>Alince 1
xxxxxxxxxxx(返回一个96位的字符)
#view records,查看交易记录功能
返回十条记录(不记得具体几条了)
然后英文后面才理解,是说每一条记录的金额都大于100
#provide a record功能
#输入交易记录就可以赚钱了
>My system is secure if you can give me other records, the receiver can also get the money
#get flag
提示要1000块钱才能买得起flag(初始只有10元)
#hint 最重要的提示
def transact_ecb(key, sender, receiver, amount):
aes = AES.new(key, AES.MODE_ECB)
ct = b""
ct += aes.encrypt(sender)
ct += aes.encrypt(receiver)
ct += aes.encrypt(amount)
return ct
#分析一下,大意是说每次交易记录的96位字符串,生成的时候由三部分组成,sender/receiver/amount,三部分都经过aes加密。
块加密,其实就像aes加密的ecb模式,由于每块都是完全独立的。形式类似:A给B共C元,即使不知道key,无法解密。也可以通过替换等方式进行攻击
比如把sender和receiver调换:
原来的明文:A给B共C元
修改后明文:B给A共C元
所以这题要赚钱,就是要伪造records,提供出去就能换钱了。
因此思路就是伪造交易记录:
A给B共100元
Q给R共110元
……………………
替换为:
A给我共100元
Q给我共110元
好了,我们已经知道了,receiver是中间的32位字符。现在要找到代表自己的32位加密后字符,替换掉真正的receiver就行了。李代桃僵。
通过transact,我们可以得到一条:我给Alice共xx元的信息。在这条信息中,前32位就是用户user经过加密后的身份信息!
整理一下思路:
- transact交易一次,取得前32位即代表自己的密文段
- view records,查看记录,获取到真实的交易记录
- 把交易记录中间32位代表接收者的密文段,换成1中得到的代表我自己的密文段。于是得到了伪造的交易凭证。
- 将伪造的交易凭证提供出去,进行兑换。provide records
- 赚够钱了get flag
注意view records中每笔交易的金额都大于100,因此伪造10条假记录就够了。
用了pwn库做nc连接,代码如下,非常丑陋:
#python3代码
import hashlib
import string
import pwn
def hashcollision(m,n):
strlib = string.ascii_letters + string.digits
for a in strlib:
for b in strlib:
for c in strlib:
originstr = a + b + c + m
if(n == hashlib.sha256(originstr.encode('utf-8')).hexdigest()):
return a+b+c
token = '*******'
ip = "*******"
port = ***
if __name__ == '__main__':
bank = pwn.remote(ip,port)
hashdata = bank.recv()#接收hash值
bank.recv()#接收give me xxx
hashdata = str(hashdata,encoding='utf-8')
hashdata = hashdata.split('==')
m = hashdata[0].strip()[11:-1]
n = hashdata[1].strip()
bank.sendline(hashcollision(m,n))#传入破解后的hash值
bank.sendline(token)#传入token
bank.recv()
#如果系统要求输入名字,则已经登陆成功
if('name' in str(bank.recv(),encoding='utf-8')):
print('login success')
bank.sendline('J2CGeek')#here is my name
print(str(bank.recv(),encoding='utf-8').strip('\n'))
print(str(bank.recv(),encoding='utf-8').strip('\n'))
#选择transact, view records, provide a record, get flag, hint功能
#选择transact,开始py交易
bank.sendline('transact')
print(str(bank.recv(),encoding='utf-8').strip('\n'))
bank.sendline('Alice 1')
print(str(bank.recv(),encoding='utf-8').strip('\n'))
#得到一个记录,其中前32位代表我,中间32位代表alice,后32位代表10。于是得到代表用户id的32位密文
record = str(bank.recv(),encoding='utf-8').strip('\n')
userinfo = record[0:32]
print('Get userinfo:'+ userinfo)
#选择view records,取出其中数据,伪造10条record
bank.sendline('view records')
print(str(bank.recv(),encoding='utf-8').strip('\n'))
record = str(bank.recv(),encoding='utf-8').split('\n')
fakerecord = []
for i in range(10):
fakerecord.append(record[i][:32] + userinfo + record[i][64:])
print('Get '+ str(i+1) +' fakerocord!!!')
#开始发送fake record赚钱了
for i in range(10):
bank.sendline('provide a record')
bank.sendline(fakerecord[i])
print(str(bank.recv(),encoding='utf-8').strip('\n'))
print(str(bank.recv(),encoding='utf-8').strip('\n'))
print(str(bank.recv(),encoding='utf-8').strip('\n'))
#开始购物!!!
bank.sendline('get flag')
print(str(bank.recv(),encoding='utf-8').strip('\n'))
print(str(bank.recv(),encoding='utf-8').strip('\n'))
bank.close()
思路还是挺简单的。
view records那里提示的英语好像有问题,看了半天我一直以为是说records总条数大于100,后面才发现是每笔交易金额大于100。