吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2880|回复: 6
收起左侧

[CTF] Flare-on 8 WriteUp(二)

[复制链接]
Y1rannn 发表于 2022-3-4 23:37
本帖最后由 Y1rannn 于 2022-3-4 23:40 编辑

3-Antioch

第三题咕了这么久,一方面是开学了很忙,另一方面最近在剁 mac 版的 Typora,ARM 还是不够熟悉呀,等剁好了拿出来给大家分享
如果有师傅已经剁好了 M1 Mac 的 Typora 也希望能指点一二,前两天刚把 Windows Typora 的复现,打算 Linux+x86Mac+ARM Mac 做一套大家都能用
这道题也是我比赛时做出来的最后一道题,和 docker 结合,出题挺新颖的吧

离谱,复现太麻烦了,脚本丢了重写的

截屏2022-03-01 下午10.15.39.png

解压之后是一个 tar 压缩包,里面有个 manifest 和一大堆 16 进制名字的文件夹,每个文件夹里有json、layer.tar和VERSION,看上去像 docker 文件,用 docker 直接 load 之

$ docker image load -i antioch.tar
d26c760acd6e: Loading layer  14.85kB/14.85kB
Loaded image: antioch:latest
antioch              latest    a13ffcf46cf4   7 months ago   13kB

把这个 docker 跑一下

$ docker run -it a13ffcf46cf4
AntiochOS, version 1.32 (build 1975)
Type help for help
> help
Available commands:
help: print this help
...AAARGH

这个 help 完全没有用,但是我们发现这儿是有一个 ELF 被执行了的,回到 manifest 里发现这样的一行:

"Layers":["7016b68f19aed3bb67ac4bf310defd3f7e0f7dd3ce544177c506d795f0b2acf3/layer.tar"]

把这个指向的 tar 解压,我们得到了一个可执行文件,至于其他的 layer 里面,都是一些 a.dat、b.dat ... z.dat 这样的东西, 把二进制反编译之~

截屏2022-03-01 下午10.32.17.jpg

魔怔人只会看看 f5 这样子,intro_message_decoder 其实就是一个把固定字符串解异或的函数,

截屏2022-03-01 下午10.36.22.png

用idapython 脚本直接解一下,后面几个也要解一下,不过无所谓,都是混淆字符串而已:

import idc
ori = get_bytes(0x4040c1, 38)
for i in range(38) :
  patch_byte(0x4040c1+i, ori[i]^0x8B)

没什么用的东西,进入程序输出的提示而已,但是我们也可以借此推断 4019F0 这个函数就是对 linux syscall write 的调用,

0x401340 是 quit, 401360 是 help, 还有 consult 和 approch,分别流向 consult func 和 askquestion。

Approch func。

离谱,由于 IDA 的 lumina 服务器,这里直接把 flag_check 的函数名给我了.. 不过我们假装没有看到这个函数名继续分析, 额,这东西并不是 flag_check

截屏2022-03-02 上午7.18.19.png

而 dword_402260是一个 CRC32 的 Table,不贴图了,由此基本可以判断这是一个 CRC32 函数.

位于 401AF0 的函数很明显是一个转换十进制的函数,我们还是回到 approach 的主逻辑里去

截屏2022-03-02 上午7.21.43.jpg

这一部分的意图很明显,就是 v3 指向 40200C,然后数组里的数逐个和 v2 比对,一共 30 个, v3 是一个 DWORD*类型的指针,这样看来两个比对的 CRC32 中间还有两个 DWORD,我们创造一个结构体看看

截屏2022-03-02 下午2.59.00.jpg

每个元素是两个 CRC32+一个 uint_32,整个函数会问三个问题:name、quest 和 color,其中 name 要和各个 layer 的 json 里的“author name”匹配,也就是上面这些 CRC32 估计都是名字的 CRC32, 需要注意的是,这个数组是从 0x402000 开始的,上面一部分也属于它

截屏2022-03-02 下午3.05.49.jpg

quest 没有发现判断逻辑,我们暂时忽略,去看下面的 color,

首先关注第一行 v7 的来源,其实v0 就是刚刚找到名字对应 CRC32 的下标,然后我们要找一个“color”,使它的 CRC32 和对应的 CRC32 对应,我们随便尝试一个

这里用的 1c5d28... 这个 layer 作测试:

{"architecture":"amd64","author":"Roger the Shrubber","config":{"AttachStderr":false,"AttachStdin":false,"AttachStdout":false,"Cmd":null,"Domainname":"","Entrypoint":null,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Hostname":"","Image":"","Labels":null,"OnBuild":null,"OpenStdin":false,"StdinOnce":false,"Tty":false,"User":"","Volumes":null,"WorkingDir":""},"container_config":{"AttachStderr":false,"AttachStdin":false,"AttachStdout":false,"Cmd":["/bin/sh","-c","#(nop) ADD multi:a08ee5be09d5524b13fb93561f476c5975fbd1f54e526380a25253d0c6a5a425 in / "],"Domainname":"","Entrypoint":null,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Hostname":"","Image":"","Labels":null,"OnBuild":null,"OpenStdin":false,"StdinOnce":false,"Tty":false,"User":"","Volumes":null,"WorkingDir":""},"created":"1975-04-03T12:00:00.000000000Z","docker_version":"20.10.2","id":"1c5d28d6564aed0316526e8bb2d79a436b45530d2493967c8083fea2b2e518ce","os":"linux"}

Roger the Shurbber 的 CRC32 是0xf16ca8c5 (btw, 用作脚本的时候 Python2 的处理真的比 Python3 舒服,如果 IDA 能把这个也 Hook 掉就好了)

截屏2022-03-02 下午3.15.54.jpg

令我惊讶的是,没有符合这个 CRC32 的结构体,但是这个输入确实是能通过 check 的,我们还是得回头看看名字。

动调一波,问题出在了小小的\n上:程序 CRC 的内容需要有换行符:重新试一下

Python>zlib.crc32(b"Roger the Shurbber\n")
0xd9285c04

???还是没有???

于是我换了另一个名字,另一个名字毫无问题的出现在了 CRC32 表里面,回头一看,好家伙,是Shrubber而不是Shurbber,晕,死在敲错字母上,这个故事告诉我们务必要复制粘贴

于是找一下这个名字(Shrubber)对应的颜色, 这个颜色的 CRC32 是 0x24D235

写个脚本跑一下颜色名字

import zlib
Colors = ["AliceBlue", ... "Yellow"]
for i in Colors :
    i += "\n"
    if zlib.crc32( i.encode(encoding="utf-8") ) == 0x24D235 :
        print(i)
# tomato     

截屏2022-03-02 下午3.44.44.jpg

然后它会给一个序号,也就是结构体里的第三个值。之后 Approach 结束

我推测这个值代表了 layer 的层数,然后这些 layer 按层数一层一层叠起来之后,consult 输出的东西就是有意义的了,那第一步就是把这些名字和对应的 layer 层数都拿出来

先一一对应颜色,这里被迫用了 Python2

import os
import json
import zlib
Colors = [
"AliceBlue", "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", "BlanchedAlmond", "Blue", 
"BlueViolet", "Brown", "BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral", "CornflowerBlue", "Cornsilk", 
"Crimson", "Cyan", "DarkBlue", "DarkCyan", "DarkGoldenRod", "DarkGray", "DarkGreen", "DarkKhaki", "DarkMagenta", 
"DarkOliveGreen", "DarkOrange", "DarkOrchid", "DarkRed", "DarkSalmon", "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray", 
"DarkTurquoise", "DarkViolet", "DeepPink", "DeepSkyBlue", "DimGray", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen", "Fuchsia", 
"Gainsboro", "GhostWhite", "Gold", "GoldenRod", "Gray", "Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", "Indigo", "Ivory", 
"Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon", "LightBlue", "LightCoral", "LightCyan", "LightGoldenRodYellow", "LightGray", 
"LightGreen", "LightPink", "LightSalmon", "LightSeaGreen", "LightSkyBlue", "LightSlateGray", "LightSteelBlue", "LightYellow", "Lime", "LimeGreen", 
"Linen", "Magenta", "Maroon", "MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple", "MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", 
"MediumTurquoise", "MediumVioletRed", "MidnightBlue", "MintCream", "MistyRose", "Moccasin", "NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", 
"OrangeRed", "Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed", "PapayaWhip", "PeachPuff", "Peru", "Pink", "Plum", "PowderBlue", 
"Purple", "Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown", "SeaGreen", "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue", 
"SlateGray", "Snow", "SpringGreen", "SteelBlue", "Tan", "Teal", "Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke", "Yellow"]
ColorsC = {}
nodes = [
  [ 3046348201, 464890665, 14 ],
  [ 1593692235, 1065642184, 18 ],
  [ 3974989264, -2100150968, 2 ],
  [ 3629421076, 4665061, 29 ],
  [ 741278285, -912236374, 12 ],
  [ 25842226, 2413109, 13 ],
  [ 1924696627, -2124978669, 20 ],
  [ 1732510946, 1365893417, 11 ],
  [ 813331381, -446635714, 28 ],
  [ 323389188, 593028265, 21 ],
  [ 2499168027, -701228461, 5 ],
  [ 3986804597, -1157983771, 24 ],
  [ 3148616269, -1500027875, 25 ],
  [ 4144489667, -283617725, 7 ],
  [ 3607255407, 2042792213, 10 ],
  [ 2258700360, 1494257628, 1 ],
  [ 3594539804, -281157144, 19 ],
  [ 2070306227, -1549204560, 3 ],
  [ 2870157772, -286397737, 4 ],
  [ 1331717848, -1668662009, 17 ],
  [ 627066826, 1082506910, 9 ],
  [ 1070145235, 932530633, 8 ],
  [ 2753867748, -276360377, 27 ],
  [ 1426653658, 33352811, 16 ],
  [ 279092781, -413116758, 22 ],
  [ 1456195679, 896473704, 15 ],
  [ 2162156454, -1660242634, 30 ],
  [ 3864515809, -1259733712, 23 ],
  [ 732029396, -1100556008, 26 ],
  [ 2100496539, 1740764549, 6 ]
]
for i in range(len(Colors)) :
    ColorsC[zlib.crc32(Colors[i]+"\n")] = Colors[i]
print(ColorsC)
for i in range(len(nodes)) :
    try :
        nodes[i][1] = ColorsC[nodes[i][1]]
    except :
        print "NOT FOUND", i
print(nodes)

这个颜色是从 CSS 的颜色库里当的,第 5、10、21 三个颜色没找到, 换了两个库表之后知道缺的是 Mint、Transparent 和 Periwinkle

再把名字替换:

for root, dir, file in os.walk(".") :
    file = root + "/" + 'json'
    try :
        f = open(file)
        name = json.load(f)['author']
    except :
        continue
    hsh = zlib.crc32((name+"\n").encode(encoding='utf-8'))
    for i in range(len(nodes)) :
        if nodes[i][0] == hsh :
            nodes[i][0] = name
print(nodes)
---
[
  ['Bridge Keeper', 'Indigo', 14],
  ['Sir Lancelot', 'Blue', 18], 
  ['Sir Bors', 'Coral', 2], 
  ['Black Knight', 'Black', 29], 
  ['Chicken of Bristol', 'Mint', 12], 
  ['Roger the Shrubber', 'Tomato', 13], 
  ['Rabbit of Caerbannog', 'Salmon', 20], 
  ['Trojan Rabbit', 'Beige', 11], 
  ['Dinky', 'Turquoise', 28], 
  ['Sir Not-Appearing-in-this-Film', 'Transparent', 21], 
  ['Brother Maynard', 'Crimson', 5], 
  ['Inspector End Of Film', 'Gray', 24], 
  ['Sir Ector', 'Bisque', 25], 
  ['Sir Robin', 'Red', 7], 
  ['Green Knight', 'Green', 10], 
  ['Miss Islington', 'Brown', 1], 
  ['Lady of the Lake', 'Gold', 19], 
  ['Tim the Enchanter', 'Orange', 3], 
  ['Dragon of Angnor', 'Khaki', 4], 
  ['A Famous Historian', 'Pink', 17], 
  ['Squire Concorde', 'Periwinkle', 9], 
  ['Zoot', 'Tan', 8], 
  ['Dennis the Peasant', 'Orchid', 27], 
  ['Legendary Black Beast of Argh', 'Silver', 16], 
  ['Prince Herbert', 'Wheat', 22], 
  ['Sir Gawain', 'Azure', 15],
  ['Sir Gallahad', 'Yellow', 30], 
  ['King Arthur', 'Purple', 23], 
  ['Squire Patsy', 'Chartreuse', 26], 
  ['Sir Bedevere', 'Teal', 6]
]

这样我们就得到了每层对应的 layer,请忽略我上面的 N^2 替换,数量级太小懒得好好写.

这样我们按着刚才的思路回去看看 consult 到底对这些 dat 文件干了什么。

把 xmm_402240 作为 Table 然后用 dat 中值异或作为下标,然后打印,大概是这么个过程。

那我们按顺序尝试一个个运行一下

import os
from pwn import *
import json
import zlib
import tarfile
nodes = [
  ['Bridge Keeper', 'Indigo', 14],
  ['Sir Lancelot', 'Blue', 18], 
  ['Sir Bors', 'Coral', 2], 
  ['Black Knight', 'Black', 29], 
  ['Chicken of Bristol', 'Mint', 12], 
  ['Roger the Shrubber', 'Tomato', 13], 
  ['Rabbit of Caerbannog', 'Salmon', 20], 
  ['Trojan Rabbit', 'Beige', 11], 
  ['Dinky', 'Turquoise', 28], 
  ['Sir Not-Appearing-in-this-Film', 'Transparent', 21], 
  ['Brother Maynard', 'Crimson', 5], 
  ['Inspector End Of Film', 'Gray', 24], 
  ['Sir Ector', 'Bisque', 25], 
  ['Sir Robin', 'Red', 7], 
  ['Green Knight', 'Green', 10], 
  ['Miss Islington', 'Brown', 1], 
  ['Lady of the Lake', 'Gold', 19], 
  ['Tim the Enchanter', 'Orange', 3], 
  ['Dragon of Angnor', 'Khaki', 4], 
  ['A Famous Historian', 'Pink', 17], 
  ['Squire Concorde', 'Periwinkle', 9], 
  ['Zoot', 'Tan', 8], 
  ['Dennis the Peasant', 'Orchid', 27], 
  ['Legendary Black Beast of Argh', 'Silver', 16], 
  ['Prince Herbert', 'Wheat', 22], 
  ['Sir Gawain', 'Azure', 15],
  ['Sir Gallahad', 'Yellow', 30], 
  ['King Arthur', 'Purple', 23], 
  ['Squire Patsy', 'Chartreuse', 26], 
  ['Sir Bedevere', 'Teal', 6]
]

nodes.sort(key = lambda i:i[2])
p = process("./temp/AntiochOS")
for i in range(len(nodes)) :
    for root, dir, file in os.walk(".") :
        file = root + "/json"
        try :
            f = open(file)
            name = json.load(f)['author']
        except :
            continue
        if name == nodes[i][0] :
            fp = tarfile.open(root+"/layer.tar", "r")
            file_names = fp.getnames()
            for file_name in file_names:
                fp.extract(file_name, "./temp")
            p.recvuntil(">")
            p.sendline("consult")
            log.info(str(nodes[i][2]) + nodes[i][0])
p.interactive()
p.sendline("quit")

跑完之后再 consult 就有 flag 了

...AAARGH

> consult
Consult the Book of Armaments!
...............
...............
...............
...............
...............
...............
...............
...............
...............
....______.....
...|..____|....
...|.|__.......
...|..__|......
...|.|.........
...|_|.........
...............
...............
...._..........
...(_).........
...._..........
...|.|.........
...|.|.........
...|_|.........
...............
...............
...............
...............
...__...__.....
...\.\././.....
....\.V./......
.....\_/.......
...............
...............
...............
...............
.....___.......
..../._.\......
...|..__/......
....\___|......
...............
...............
...............
...............
....______.....
...|______|....
...............
...............
...............
...............
...._____......
...|_..._|.....
.....|.|.......
.....|.|.......
...._|.|_......
...|_____|.....
...............
...............
...............
...............
....___........
.../.__|.......
...\__.\.......
...|___/.......
...............
...............
...............
...............
....______.....
...|______|....
...............
...............
...............
...............
...._____......
...|..__.\.....
...|.|__).|....
...|.._../.....
...|.|.\.\.....
...|_|..\_\....
...............
...............
...._..........
...(_).........
...._..........
...|.|.........
...|.|.........
...|_|.........
...............
...............
...............
...............
.....__._......
..../._`.|.....
...|.(_|.|.....
....\__,.|.....
.....__/.|.....
....|___/......
...._..........
...|.|.........
...|.|__.......
...|.'_.\......
...|.|.|.|.....
...|_|.|_|.....
...............
...............
...._..........
...|.|.........
...|.|_........
...|.__|.......
...|.|_........
....\__|.......
...............
...............
...............
...............
....______.....
...|______|....
...............
...............
...............
...............
.....____......
..../.__.\.....
...|.|..|.|....
...|.|..|.|....
...|.|__|.|....
....\____/.....
...............
...............
...............
...............
...._..._......
...|.|.|.|.....
...|.|_|.|.....
....\__,_|.....
...............
...............
...._..........
...|.|.........
...|.|_........
...|.__|.......
...|.|_........
....\__|.......
...............
...............
...............
......____.....
...../.__.\....
...././._`.|...
...|.|.(_|.|...
....\.\__,_|...
.....\____/....
...............
.....__........
..../._|.......
...|.|_........
...|.._|.......
...|.|.........
...|_|.........
...............
...............
...._..........
...|.|.........
...|.|.........
...|.|.........
...|.|.........
...|_|.........
...............
...............
...............
...............
.....__._......
..../._`.|.....
...|.(_|.|.....
....\__,_|.....
...............
...............
...............
...............
...._.__.......
...|.'__|......
...|.|.........
...|_|.........
...............
...............
...............
...............
.....___.......
..../._.\......
...|..__/......
....\___|......
...............
...............
...............
...............
....______.....
...|______|....
...............
...............
...............
...............
...............
...............
.....___.......
..../._.\......
...|.(_).|.....
....\___/......
...............
...............
...............
...............
...._.__.......
...|.'_.\......
...|.|.|.|.....
...|_|.|_|.....
...............
...............
...............
...............
...............
...............
...._..........
...(_).........
...............
...............
...............
...............
.....___.......
..../.__|......
...|.(__.......
....\___|......
...............
...............
...............
...............
.....___.......
..../._.\......
...|.(_).|.....
....\___/......
...............
...............
...............
...............
...._.__.___...
...|.'_.`._.\..
...|.|.|.|.|.|.
...|_|.|_|.|_|.
...............
...............
...............
...............
...............
...............
...............
...............
...............

免费评分

参与人数 1威望 +1 吾爱币 +20 热心值 +1 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

也就一般般 发表于 2022-3-5 01:44
谢谢大佬分享
cnstrong 发表于 2022-3-5 08:17
sheron888 发表于 2022-3-5 08:38
大王叫我来巡你 发表于 2022-3-5 10:45

谢谢大佬分享
zwtstc 发表于 2022-3-5 11:16
学到了感谢分享
 楼主| Y1rannn 发表于 2022-3-23 10:23
太离谱了, 咕咕咕了真不能全怪我, 我离校期间电脑都扔学校了, 长春突然封城回不去了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-25 02:19

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表