3-Antioch
第三题咕了这么久,一方面是开学了很忙,另一方面最近在剁 mac 版的 Typora,ARM 还是不够熟悉呀,等剁好了拿出来给大家分享
如果有师傅已经剁好了 M1 Mac 的 Typora 也希望能指点一二,前两天刚把 Windows Typora 的复现,打算 Linux+x86Mac+ARM Mac 做一套大家都能用
这道题也是我比赛时做出来的最后一道题,和 docker 结合,出题挺新颖的吧
离谱,复现太麻烦了,脚本丢了重写的
解压之后是一个 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 这样的东西, 把二进制反编译之~
魔怔人只会看看 f5 这样子,intro_message_decoder 其实就是一个把固定字符串解异或的函数,
用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
而 dword_402260是一个 CRC32 的 Table,不贴图了,由此基本可以判断这是一个 CRC32 函数.
位于 401AF0 的函数很明显是一个转换十进制的函数,我们还是回到 approach 的主逻辑里去
这一部分的意图很明显,就是 v3 指向 40200C,然后数组里的数逐个和 v2 比对,一共 30 个, v3 是一个 DWORD*类型的指针,这样看来两个比对的 CRC32 中间还有两个 DWORD,我们创造一个结构体看看
每个元素是两个 CRC32+一个 uint_32,整个函数会问三个问题:name、quest 和 color,其中 name 要和各个 layer 的 json 里的“author name”匹配,也就是上面这些 CRC32 估计都是名字的 CRC32, 需要注意的是,这个数组是从 0x402000 开始的,上面一部分也属于它
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 掉就好了)
令我惊讶的是,没有符合这个 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
然后它会给一个序号,也就是结构体里的第三个值。之后 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./......
.....\_/.......
...............
...............
...............
...............
.....___.......
..../._.\......
...|..__/......
....\___|......
...............
...............
...............
...............
....______.....
...|______|....
...............
...............
...............
...............
...._____......
...|_..._|.....
.....|.|.......
.....|.|.......
...._|.|_......
...|_____|.....
...............
...............
...............
...............
....___........
.../.__|.......
...\__.\.......
...|___/.......
...............
...............
...............
...............
....______.....
...|______|....
...............
...............
...............
...............
...._____......
...|..__.\.....
...|.|__).|....
...|.._../.....
...|.|.\.\.....
...|_|..\_\....
...............
...............
...._..........
...(_).........
...._..........
...|.|.........
...|.|.........
...|_|.........
...............
...............
...............
...............
.....__._......
..../._`.|.....
...|.(_|.|.....
....\__,.|.....
.....__/.|.....
....|___/......
...._..........
...|.|.........
...|.|__.......
...|.'_.\......
...|.|.|.|.....
...|_|.|_|.....
...............
...............
...._..........
...|.|.........
...|.|_........
...|.__|.......
...|.|_........
....\__|.......
...............
...............
...............
...............
....______.....
...|______|....
...............
...............
...............
...............
.....____......
..../.__.\.....
...|.|..|.|....
...|.|..|.|....
...|.|__|.|....
....\____/.....
...............
...............
...............
...............
...._..._......
...|.|.|.|.....
...|.|_|.|.....
....\__,_|.....
...............
...............
...._..........
...|.|.........
...|.|_........
...|.__|.......
...|.|_........
....\__|.......
...............
...............
...............
......____.....
...../.__.\....
...././._`.|...
...|.|.(_|.|...
....\.\__,_|...
.....\____/....
...............
.....__........
..../._|.......
...|.|_........
...|.._|.......
...|.|.........
...|_|.........
...............
...............
...._..........
...|.|.........
...|.|.........
...|.|.........
...|.|.........
...|_|.........
...............
...............
...............
...............
.....__._......
..../._`.|.....
...|.(_|.|.....
....\__,_|.....
...............
...............
...............
...............
...._.__.......
...|.'__|......
...|.|.........
...|_|.........
...............
...............
...............
...............
.....___.......
..../._.\......
...|..__/......
....\___|......
...............
...............
...............
...............
....______.....
...|______|....
...............
...............
...............
...............
...............
...............
.....___.......
..../._.\......
...|.(_).|.....
....\___/......
...............
...............
...............
...............
...._.__.......
...|.'_.\......
...|.|.|.|.....
...|_|.|_|.....
...............
...............
...............
...............
...............
...............
...._..........
...(_).........
...............
...............
...............
...............
.....___.......
..../.__|......
...|.(__.......
....\___|......
...............
...............
...............
...............
.....___.......
..../._.\......
...|.(_).|.....
....\___/......
...............
...............
...............
...............
...._.__.___...
...|.'_.`._.\..
...|.|.|.|.|.|.
...|_|.|_|.|_|.
...............
...............
...............
...............
...............
...............
...............
...............
...............