tinytracer

  • 实践
    • CTF
    • 项目实践
  • 技术
    • C++
    • 逆向与汇编
    • 区块链安全
  • 探索
    • OWASP汉化
    • SQL
    • Kali
TinyTracer
In solitude, where we were at least alone.
  1. 首页
  2. 实践
  3. CTF
  4. 正文

2018强网杯线上赛——个人WP与总结

2018年3月27日 7728点热度 7人点赞 0条评论

签到

  • 打开题目直接获取到flag,真·签到

Welcome:

  • 下载得到一个无后缀的文件,binwalk查看是bmp位图
  • 拖进Stegsolve使用偏移工具得flag

调查问卷

  • 填写问卷得flag,真·水题

Streamgame三连

Streamgame1:

  • 下载下来是一个包含加密脚本和加密后key的压缩包
  • 首先观察下加密脚本
from flag import flag
assert flag.startswith("flag{")
assert flag.endswith("}")
assert len(flag)==25

def lfsr(R,mask):
    output = (R << 1) & 0xffffff
    i=(R&mask)&0xffffff
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)

R=int(flag[5:-1],2)
mask    =   0b1010011000100011100

f=open("key","ab")
for i in range(12):
    tmp=0
    for j in range(8):
        (R,out)=lfsr(R,mask)
        tmp=(tmp << 1)^out
    f.write(chr(tmp))
f.close()

分析

  • 这个脚本无法单独运行,题目没有给出flag.py废话,但是我们可以从前四行代码分析出flag的特点
assert flag.startswith("flag{")
assert flag.endswith("}")
assert len(flag)==25

这三个断言表达式提供了如下信息:flag的形式是flag{....},长度是25位。再往下看

R=int(flag[5:-1],2)

R的值是将flag的5至倒数第一位转换成的二进制值。注意,int(x,2)中x为二进制数字符串,如'101010'。推断出flag的形式为flag{19位二进制}

  • 算法内容大致浏览后没发现突破口,于是写了个脚本爆破,2^19在可接受范围内
#原加密算法
def lfsr(R,mask):
    output = (R << 1) & 0xffffff
    i=(R&mask)&0xffffff
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)

#打开key获取加密后的数据
f=open("key","rb")
data = bytearray()
data+=f.read()
print(data)
f.close()
flag = 0

#爆破
while flag <= 0b1111111111111111111 :
    print('try:',flag)
    byte=bytearray()
    flag1 = bin(flag)
    R=int(flag1[2:],2)
    mask    =   0b1010011000100011100

    for i in range(12):
        tmp=0
        for j in range(8):
            (R,out)=lfsr(R,mask)
            tmp=(tmp << 1)^out
        byte+=(tmp).to_bytes(1,byteorder='big')

# 将key中数据与当前循环加密后的数据进行比对,匹配则输出flag
    if byte == data:
        print('success:'+'flag{'+bin(flag[2:])+'}')
        break
    flag = flag+1
  • 时间:15min

Streamgame2:

  • 与第一题一模一样的套路,先上加密源码:
from flag import flag
assert flag.startswith("flag{")
assert flag.endswith("}")
assert len(flag)==27

def lfsr(R,mask):
    output = (R << 1) & 0xffffff
    i=(R&mask)&0xffffff
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)


R=int(flag[5:-1],2)
mask=0x100002

f=open("key","ab")
for i in range(12):
    tmp=0
    for j in range(8):
        (R,out)=lfsr(R,mask)
        tmp=(tmp << 1)^out
    f.write(chr(tmp))
f.close()

分析:

  • 与上题的区别在于增加了中间二进制位的长度,算法是没改变的,2^19时间为15min,2^21预计在1小时左右,依然是可接受的,二话不说开爆
def lfsr(R,mask):
    output = (R << 1) & 0xffffff
    i=(R&mask)&0xffffff
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)

f=open("key","rb")
data = bytearray()
data+=f.read()
print(data)
f.close()
flag = 0
flag=0b111111111111111111111
while flag >= 0 :
    print('try:',flag)
    byte=bytearray()
    flag1 = bin(flag)
    R=int(flag1[2:],2)
    mask=0x100002

    for i in range(12):
        tmp=0
        for j in range(8):
            (R,out)=lfsr(R,mask)
            tmp=(tmp << 1)^out
        byte+=(tmp).to_bytes(1,byteorder='big')

    if byte == data:
        print('success:'+'flag{'+bin(flag[2:])+'}')
        break
    flag-=1

一套脚本跑两题...我好咸鱼....
- 时间:30min

Streamgame4:

  • 相比前两题,大幅增加了key的计算复杂度key的大小从几十b暴涨到1M,先上源码
from flag import flag
assert flag.startswith("flag{")
assert flag.endswith("}")
assert len(flag)==27

def nlfsr(R,mask):
    output = (R << 1) & 0xffffff
    i=(R&mask)&0xffffff
    lastbit=0
    changesign=True
    while i!=0:
        if changesign:
            lastbit &= (i & 1)
            changesign=False
        else:
            lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)

R=int(flag[5:-1],2)
mask=0b110110011011001101110

f=open("key","ab")
for i in range(1024*1024):
    tmp=0
    for j in range(8):
        (R,out)=nlfsr(R,mask)
        tmp=(tmp << 1)^out
    f.write(chr(tmp))
f.close()

分析

  • 移位加密函数nlfsr增加了状态切换
def nlfsr(R,mask):
    output = (R << 1) & 0xffffff
    i=(R&mask)&0xffffff
    lastbit=0
    changesign=True
    while i!=0:
        if changesign:
            lastbit &= (i & 1)
            changesign=False
        else:
            lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)
  • 写入数据的次数大幅增加
for i in range(1024*1024):
    tmp=0
    for j in range(8):
        (R,out)=nlfsr(R,mask)
        tmp=(tmp << 1)^out
    f.write(chr(tmp))
  • 一开始本想如法炮制直接开爆,但相比起前两题的文件写入次数(8),本题加密的写入次数为1024*1024,爆破一个数字的时间约1分钟

那还爆个P啊,但不会逆向算法只能干拉啊

  • 加密算法没复杂多少,只是个简单的状态切换。但文件写入却复杂了几个数量级。会不会key有重复的部分?使用010Editor查看下文件hex果然有收获
  • 猜想正确,果然是有很多重复的部分。将重复的部分提取出来,修改下爆破脚本继续不是美滋滋?
  • 提取后大小减少了不少,通过修改加密脚本写入部分可以减少比对的次数来减少复杂度。二话不说开爆,速度为每秒10个。掐指一算,两天不够

那还爆个P啊,但不会逆向算法只能干拉啊

  • 既然全文比对会复杂度爆炸,那么局部比对呢?取前64个字节的数据,容量有2^67,而需要爆破的内容量只有2^21,虽然有碰撞的风险,但在比赛时这种用精度换取速度的方式是可行的(2^21/2^64=1/2^43.....还不是因为撸不出逆算法)
  • 将key前64位提取出来

    修改爆破脚本
def nlfsr(R,mask):
    output = (R << 1) & 0xffffff
    i=(R&mask)&0xffffff
    lastbit=0
    changesign=True
    while i!=0:
        if changesign:
            lastbit &= (i & 1)
            changesign=False
        else:
            lastbit^=(i&1)
        i=i>>1
    output^=lastbit
    return (output,lastbit)

f=open("key","rb")
data = bytearray()
data+=f.read()
f.close()
flag = 0b111111111111111111111



while flag >= 0:
    byte=bytearray()
    print('try: ',flag)
    flag1 = bin(flag)
    R=int(flag1[2:],2)
    mask=0b110110011011001101110

#修改循环加密次数
    for i in range(64):
        tmp=0
        for j in range(8):
            (R,out)=nlfsr(R,mask)
            tmp=(tmp << 1)^out
        byte+=(tmp).to_bytes(1,byteorder='big')
    if byte == data:
        print('success:'+'flag{'+bin(flag[2:])+'}')
        input()
    flag = flag-1

一套脚本跑三题...题好咸鱼....
- 修改后速度大为提升,约每秒200+次
- 时间:50min

总结

  • 题目偏难且灵活,有两三道题有思路但无法完成,感觉就差临门一脚了。等官方WP
  • 得PWN者得天下
  • 身为Win逆向手居然靠Crypto输出...要好好反思自己的方向知识水平了
标签: writeup 强网杯 总结
最后更新:2018年7月6日

Chernobyl

这个人很懒,什么都没留下

点赞
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据。

COPYRIGHT © 2021 tinytracer.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang