站点图标 Wankko Ree's Blog

CISCN 2022 S15 华中赛区 WriteUp

Misc

数据流中的秘密3[二血]

拿到题目,是个流量包。

打开大致看一遍,有一堆安卓相关的东东,如sdcardscrcpy、手机型号等。

于是右键解析为ADB CS,在2号数据流里面发现一个rar包,被拆成了0x10000+0x10000+0xb575三个包,然后前两个包又有两个分包。

数据流前4字节是固定标识DATA,4~8字节是小端序数据长度,8字节以后是数据。

提取五条数据流合并得到完整的rar文件,发现需要密码。

看14号数据流发现00 00 00 01 67头,结合scrcpy可猜测是h264视频数据。

从文件头开始提取出文件(因为h264容错性很牛逼,所以没完全正确提取也问题不大)。打开发现是四张图片来回滚动。

拼合得到一个二维码。

用工具扫码得到一串文本695c630e-523c-4098-8ff8-0bac8f8b22d7,用来当密码打开压缩包,发现确实是压缩包密码。

解压得到一个图片和一个几乎空的.git索引。

图片文件尾有一段base32

写个脚本解码。

a = "KRUGKIDXNBSWK3BA4KAI3YUARXRIBDHCQGROFANE4KA2HYUARXRIDIXCQGROFAEN4KAI3YUARTRIDIPCQCG6FAEM4KAI3YUBUHRIBDHCQGROFANC4KAIZYUBULRIBDPCQGROFAEM4KAI3YUBULRIDIPCQCG6FAEM4KA2FYUARXRIDJHCQCG6FANB4KA2HYUARTRIDJHCQGROFAEN4KAI3YUARXRIDIXCQGROFANE4KA2JYUARXRIDJHCQGROFAEM4KA2JYUBUTRIDIPCQCG6FANB4KAI3YUBUTRIDIXCQGSOFAND4KA2DYUARXRIDJHCQCGOFAEN4KA2FYUBUHRIDIXCQCGOFANC4KAIZYUBULRIDIPCQGROFAEN4KAI3YUBUHRIBDPCQCG6FANB4KAIZYUARXRIDIXCQCG6FANB4KAI3YUARTRIDIXCQGROFANE4KAIZYUBUHRIDIXCQGROFANC4KA2HYUARTRIDIXCQCGOFANB4KAI3YUBUTRIDIPCQCGOFANB4KAIZYUBULRIDIPCQCG6FANC4KAI3YUARXRIDIXCQGROFANC4KA2FYUBUTRIDIPCQCG6FANC4KA2DYUBUPRIDJHCQCG6FAND4KAIZYUBULRIBDPCQCGOFAEN4KA2FYUARXRIBDHCQGROFANC4KAI3YUARTRIDIXCQCG6FAEM4KAI3YUARXRIDIXCQGQ6FAEN4KA2HYUBUTRIDIXCQGR6FANC4KA2FYUBUTRIDIPCQCGOFANC4KA2DYUBULRIBDPCQGROFANDOR2XE3TTFQQG433UNBUW4ZZANFZSAZLWMVZCA3TFO4XA===="
from base64 import b32decode
print(b32decode(a).decode())

得到如下文本:

The wheel ‍‍‌⁢⁤⁣‍⁢⁢‍‍‌⁡‍‌‍⁡‌⁢⁢‌⁢‍⁢‌‍⁢⁡‍‌⁢‍⁤‍⁡⁣‌⁤⁢‍‍‍⁢⁢⁤⁤‍⁤⁢‌⁤⁤⁡‍⁡‍⁤⁢⁤⁣⁡‍⁤‌‍⁢⁡⁢‌⁢‌⁢⁡⁢‍‍⁡‍‍⁡‌‍⁢‍⁡‍‌⁢⁢⁤‌⁡⁢⁢⁢⁣‌⁢‌⁡‍⁤⁡‌⁡‌⁢⁡‍⁢‍‍⁢⁢⁢⁢⁤⁡‍⁢⁡⁣⁤‍⁣‌⁢‍‌‍⁢‍‌⁢⁢‍‌⁢‍‌‍‍⁢⁡‍⁣⁤⁢⁣⁢⁢⁤⁡‌⁢⁡⁢‍⁢⁣turns, nothing is ever new.

其中含有不可见字符。

去看.git索引,有个指向github.com/KuroLabs/stegcloak的源,还有个密码just4fun

打开stegcloak发现是个文本隐写工具,用上面的密码解上面的含不可见字符的文本,得到flag。

flag{487745369bbcd1e2d663b9fd136d01d0}

Crypto

NumberGame3

拿到题目,发现三组n, e, c

n1:12671827609071157026977398418260127577729239910356059636353714138256023623770344437013038456629652805253619484243190436122472172086809006270535958920503788271745182898308583012315393657937467583278528574109842696210193482837553369816110424840884683667932711439417044144625891738594098963618068866281205254024287936360981926173192169919836661589685119695804443529730259703940744061684219737502099455504322939948562185702662485642366411258841082322583213825076942399375712892608077960687636100621655314604756871227708407963698548718981737143081639214928707030543449473132959887760171345393471397998907576088643495456531
e1:65537
c1:5268497051283009363591890965286255308367378505062739645805302950184343652292967525985407935922935972883557494557593439711003227737116083417992112594428400382187113609935251268634230537282408994938066541612999550555591607744019286392765549844400176442415480559773688439693874264657925123598756193286897112566420847480601040372338338442932524410598834393630019038536173336696498743879160879377504894526001205060753543289059104874467150194596404490638065573974570258671195173327475871936431769234701590572816592485898568463143587137721883610069616008902637316459660001435171054741347142470208082183171637233299493273737
n2:18090800828995898324812976370950614944724424095669490324214928162454640462382724191043785592350299626782376411935499259428970532102686361824967300649916495702138825182857737210486173137998811993244590794690070307872074705348982970060304389842338043432383690934814892283936018142382990267868341375956549210694354065317328612440672169232803362481090661368782599819926970968509827001203936933692777821117679448168400620234261164018167404541446201828349880887526076468982840569645753428057937172715073817332736878737709704495317549386111938639861221307607948775421897063976457107356574428602380790814162110473018856344871
e2:4097
c2:2326267610355516153575986453727161366266816656017644910981028690283132055217271939475840618294311986463011398892570340626131158223217558335139831985973737748812636360601010312490160903427322848411507157238373313053959092326875136396134997877757316339153327290508806645882428114647041522287934007579220769189583249469879165078254248922442084985860374461188259818592181294686890335242981199427715392978546977718475462727987012437677290341463732660152302257234030751774759466703002189003437204934438026047163828083902584763527752033035438078609950665211243112982373167722458975172667665849715372158378299319548194854914
n3:14016899139767071357961567514373780608355222973882916699129907806456201886114368147540489514960479836424236595826190295819765979835270500889626994048655508134450908075698567925938340322498944878806273261377551132596295484579752118097281084614987064680928168918147910522922020462762688924459558896249968804885885853885632349539590507675397376494346489972596290270168847103345561743327300964196811506510943971437325302822974593782292850499524055338033832053610217461760698628614971171144300450574522839157187874548994036357212297166759231255765155759405207408315314182166142015547345744054533749334516820850300569790673
e3:1048577
c3:1507157402302225700443994264641838312753363380677759942918832857396550216927941389943122383728949792984913155517202501504817319345830153748955731880333992875210194306712098593166605310784068299411946792264365247471197716329666415403718297430110977954951479772565341847358286252098930408452594561104228639615640815799731581302607522977457874347224189202268831547055389518214072278766864028489294466057175201908756749666131546163372443691718757198229262989973810951064160488114367967684657242385568733678188829354802025582496625272334309487028498614869964712744826603931510547381997149345221530469380732265014466170524

尝试gcd一下几个n,发现n1n2n2n3有公约数,所以那肯定三个np就能出来了,然后反推q就能正常解rsa了。

n1=12671827609071157026977398418260127577729239910356059636353714138256023623770344437013038456629652805253619484243190436122472172086809006270535958920503788271745182898308583012315393657937467583278528574109842696210193482837553369816110424840884683667932711439417044144625891738594098963618068866281205254024287936360981926173192169919836661589685119695804443529730259703940744061684219737502099455504322939948562185702662485642366411258841082322583213825076942399375712892608077960687636100621655314604756871227708407963698548718981737143081639214928707030543449473132959887760171345393471397998907576088643495456531
e1=65537
c1=5268497051283009363591890965286255308367378505062739645805302950184343652292967525985407935922935972883557494557593439711003227737116083417992112594428400382187113609935251268634230537282408994938066541612999550555591607744019286392765549844400176442415480559773688439693874264657925123598756193286897112566420847480601040372338338442932524410598834393630019038536173336696498743879160879377504894526001205060753543289059104874467150194596404490638065573974570258671195173327475871936431769234701590572816592485898568463143587137721883610069616008902637316459660001435171054741347142470208082183171637233299493273737
n2=18090800828995898324812976370950614944724424095669490324214928162454640462382724191043785592350299626782376411935499259428970532102686361824967300649916495702138825182857737210486173137998811993244590794690070307872074705348982970060304389842338043432383690934814892283936018142382990267868341375956549210694354065317328612440672169232803362481090661368782599819926970968509827001203936933692777821117679448168400620234261164018167404541446201828349880887526076468982840569645753428057937172715073817332736878737709704495317549386111938639861221307607948775421897063976457107356574428602380790814162110473018856344871
e2=4097
c2=2326267610355516153575986453727161366266816656017644910981028690283132055217271939475840618294311986463011398892570340626131158223217558335139831985973737748812636360601010312490160903427322848411507157238373313053959092326875136396134997877757316339153327290508806645882428114647041522287934007579220769189583249469879165078254248922442084985860374461188259818592181294686890335242981199427715392978546977718475462727987012437677290341463732660152302257234030751774759466703002189003437204934438026047163828083902584763527752033035438078609950665211243112982373167722458975172667665849715372158378299319548194854914
n3=14016899139767071357961567514373780608355222973882916699129907806456201886114368147540489514960479836424236595826190295819765979835270500889626994048655508134450908075698567925938340322498944878806273261377551132596295484579752118097281084614987064680928168918147910522922020462762688924459558896249968804885885853885632349539590507675397376494346489972596290270168847103345561743327300964196811506510943971437325302822974593782292850499524055338033832053610217461760698628614971171144300450574522839157187874548994036357212297166759231255765155759405207408315314182166142015547345744054533749334516820850300569790673
e3=1048577
c3=1507157402302225700443994264641838312753363380677759942918832857396550216927941389943122383728949792984913155517202501504817319345830153748955731880333992875210194306712098593166605310784068299411946792264365247471197716329666415403718297430110977954951479772565341847358286252098930408452594561104228639615640815799731581302607522977457874347224189202268831547055389518214072278766864028489294466057175201908756749666131546163372443691718757198229262989973810951064160488114367967684657242385568733678188829354802025582496625272334309487028498614869964712744826603931510547381997149345221530469380732265014466170524

from gmpy2 import gcd, invert, powmod
from Crypto.Util.number import long_to_bytes

p = gcd(n1, n2)
# print p
q = n1 / p
# print q

phi = (p - 1) * (q - 1)
d = invert(e1, phi)
print long_to_bytes(powmod(c1, d, n1))

q = n2 / p
phi = (p - 1) * (q - 1)
d = invert(e2, phi)
print long_to_bytes(powmod(c2, d, n2))

p = gcd(n2, n3)
# print p
q = n3 / p
phi = (p - 1) * (q - 1)
d = invert(e3, phi)
print long_to_bytes(powmod(c3, d, n3))
# flag{fb72574404901f5a37f88431b42b4872}

flag{fb72574404901f5a37f88431b42b4872}

Reverse

crackme2_apk1

jadx打开,很容易看出调用链check -> encodecheck判断flag长度和头尾,然后encode后和目标数组比较就完事。

然后看encode函数,是个按字节加密的,没有前后影响的情况,那就直接每字节爆破就完事。

package com.example.hooktest.hook

import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.log.loggerI
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit

@InjectYukiHookWithXposed
class Main : IYukiHookXposedInit {
    override fun onHook() = YukiHookAPI.encase {
        loadApp("com.example.CrackMe2") {
            "$packageName.MainActivity".hook {
                injectMember {
                    method {
                        name = "onCreate"
                    }
                    afterHook {
                        val target = charArrayOf(
                            '\u00cd',
                            'R',
                            't',
                            'z',
                            30.toChar(),
                            '\b',
                            '\b',
                            '\u00e0',
                            'W',
                            ';',
                            24.toChar(),
                            '\u0099',
                            '\u00af',
                            '=',
                            29.toChar(),
                            '\u0094',
                            21.toChar(),
                            '%',
                            'g',
                            '[',
                            'd',
                            'S',
                            31.toChar(),
                            ';',
                            '\u00dc',
                            '\u00a2',
                            'F',
                            '6',
                            '\u00d3',
                            '\u00fd',
                            '\u00be',
                            '3'
                        )
                        val encode = method {
                            name="encode"
                        }.get(instance)
                        var flag = byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
                        var i = 0
                        while (i < 32) {
                            val rst = (encode.call(String(flag), "happygame") as String).toCharArray()
                            if (rst[i] == target[i]) {
                                loggerI(msg = flag[i].toString())
                                i++
                                continue
                            } else {
                                flag[i] = (flag[i] + 1).toByte()
                            }
                        }
                        loggerI(msg = String(flag))
                    }
                }
            }
        }
    }
}

flag{2fd3d38b20b7bae1f6ed0d70a7df345e}

meikyu2[一血]

打开题目的main.py,看着感觉像是读取地图然后输入线路走迷宫的题。

其中地图标识分别有START, END, WALL, ROAD,尝试读取地图,发现大小是10201,所以应该是101*101的图。

with open('data', 'rb') as f:
    data = f.read()
map_ = list(data)
cipher = list(b'suta-to')
print(len(map_))  # 101 * 101

尝试按101*101输出,可以猜测START=83, END=69, WALL=35, ROAD=32

with open('data', 'rb') as f:
    data = f.read()
map_ = list(data)
cipher = list(b'suta-to')
print(len(map_))  # 101 * 101
for i, ch in enumerate(map_):
    if i % 101 == 0:
        print()
    map_[i] = ch ^ cipher[i % len(cipher)]
    print(map_[i], end=' ')
print()
# # START 83, END 69, WALL 35, ROAD 32

那就写个dfs去搜路径就完事。

def dfs(x, y, lx, ly):
    if map_[x * 101 + y] == 69:
        return True, ""
    if x + 1 < 101 and map_[(x + 1) * 101 + y] != 35 and x + 1 != lx:
        rst, road = dfs(x+1, y, x, y)
        if rst:
            return True, "下"+road
    if x - 1 >= 0 and map_[(x - 1) * 101 + y] != 35 and x - 1 != lx:
        rst, road = dfs(x-1, y, x, y)
        if rst:
            return True, "上"+road
    if y + 1 < 101 and map_[x * 101 + y + 1] != 35 and y + 1 != ly:
        rst, road = dfs(x, y+1, x, y)
        if rst:
            return True, "右"+road
    if y - 1 >= 0 and map_[x * 101 + y - 1] != 35 and y - 1 != ly:
        rst, road = dfs(x, y-1, x, y)
        if rst:
            return True, "左"+road
    return False, ""

with open('data', 'rb') as f:
    data = f.read()
map_ = list(data)
cipher = list(b'suta-to')
print(len(map_))  # 101 * 101
for i, ch in enumerate(map_):
    if i % 101 == 0:
        print()
    map_[i] = ch ^ cipher[i % len(cipher)]
    print(map_[i], end=' ')
print()
# # START 83, END 69, WALL 35, ROAD 32
print(dfs(1, 0, 0, 0))

然后现在就是路径格式应该是长啥样的问题了,先去看了下mylib.pyd文件,看了好久没找到什么头绪,后来在util.dll里面的run_decoded_map_0函数发现了解析路径的逻辑。

那就把上面的路径用wsad替换一下,然后md5一波(main.py文件里面有写flag格式)交一下看看,结果真就是flag。

from hashlib import md5

def dfs(x, y, lx, ly):
    if map_[x * 101 + y] == 69:
        return True, ""
    if x + 1 < 101 and map_[(x + 1) * 101 + y] != 35 and x + 1 != lx:
        rst, road = dfs(x+1, y, x, y)
        if rst:
            return True, "s"+road
    if x - 1 >= 0 and map_[(x - 1) * 101 + y] != 35 and x - 1 != lx:
        rst, road = dfs(x-1, y, x, y)
        if rst:
            return True, "w"+road
    if y + 1 < 101 and map_[x * 101 + y + 1] != 35 and y + 1 != ly:
        rst, road = dfs(x, y+1, x, y)
        if rst:
            return True, "d"+road
    if y - 1 >= 0 and map_[x * 101 + y - 1] != 35 and y - 1 != ly:
        rst, road = dfs(x, y-1, x, y)
        if rst:
            return True, "a"+road
    return False, ""

with open('data', 'rb') as f:
    data = f.read()
map_ = list(data)
cipher = list(b'suta-to')
print(len(map_))  # 101 * 101
for i, ch in enumerate(map_):
    if i % 101 == 0:
        print()
    map_[i] = ch ^ cipher[i % len(cipher)]
    print(map_[i], end=' ')
print()
# # START 83, END 69, WALL 35, ROAD 32
print(dfs(1, 0, 0, 0))
print(f"flag{{{md5(dfs(1, 0, 0, 0)[1].encode()).hexdigest()}}}")

flag{3f48672b213770d9de5c3d50369840a3}


The End
退出移动版