-
-
[原创] 看雪CTF2018-第十二题-破解之道writeup
-
2018-7-10 15:33 3137
-
目录
0x00 初步分析程序
0x01 确定校验算法逻辑
0x02 枚举搜索合适解
0x03 最终脚本
0x00 初步分析程序
程序是64位的exe,运行程序,根据提示可知校验的输入是作为命令行参数传入,尝试输入AAAAA,会返回"registration failed"的提示:
strings搜索找到一个类似的,应该是对字符串进行了加密。
IDA打开,找到对应的地方:
从而确定调用(校验)的函数check。
0x01 确定校验算法逻辑
跳过前面的一些初始化赋值操作,来到第一处校验---校验输入长度必须等于30:
然后进入第二处校验,这里对每个输入进行了FNV-1(64bits)的哈希操作,得到的哈希值和‘9’的哈希值进行比较,统计输入中包含9的个数,要求9的个数必须大于等于3:
然后来到第三处校验,同样是使用了FNV-1(64bits)的哈希,对输入的前9个字符分别哈希和特定字符的哈希比较,这里通过脚本穷举,可以得到结果为KXCTF2018:
来到第四处校验,这里对整个输入进行FNV-1(64bits)的哈希并和固定值比较,为了方便调试,先修改逻辑,跳过这部分:
来到第五处校验,这里调用了findch函数搜索输入(从第10位开始)中9所在的位置,从而以9为分界符对输入进行分割:
之后使用了FNV-1(32bits)算法对kernel32.dll(通过动态调试可知)的api函数进行逐个哈希,这里其实是一种对系统关键api进行哈希的保护动作。搜索匹配的哈希值,这里我通过dumpbin.exe导出了kernel32.dll的所有api进行枚举(脚本及方法见最后),找到匹配哈希值的api,为LoadLibraryA:
然后对从输入读取的dll名字调用LoadLibraryA加载:
之后调用GetProcAddress从对应dll基址处加载从输入读取的api名字,并调用该api函数,如果返回值是负数,则最终注册成功:
0x02 枚举搜索合适解
从刚刚整理的校验逻辑可以构造输入:
(1)满足30个字符长度,只含数字字母;
(2)开头为KXCTF2018
(3)之后为“9[5个字符长度的dll名称]9[调用的api函数名称]9”
(4)构造的输入的FNV-1(64bits)哈希==0x4F8075587499C0FF
其中,dll必须是系统环境变量包含的dll,一般在C:/Windows/SysWOW64或者C:/Windows/System32目录下,写个脚本获取5个字符长度的所有dll名称(这里有个坑,dll名字必须转大写输入,考虑到拼接时后面的.DLL也使用了大写),dump出所有api函数,进行爆破,其中api函数的长度需等于13(30-len("KXCTF2018")-1-5-1-1)。
0x03 最终脚本
获取kernel32.dll的所有API函数:
cd C:/Windows/SysWOW64 (for %i in (kernel32.dll) do dumpbin -exports %i) > out.txt findstr /X ".*[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F].*[a-zA-Z_]$" out.txt > out1.txt findstr /V "@ {content}nbsp;\. : characteristics" out1.txt > api.txt # notepad++ 正则替换^.*[0-9A-F]{8} ([a-zA-Z_0-9]+)$为($1)
# coding:utf-8 # author:sherllyyang00@gmail.com import string table=string.digits+string.letters def fnv64(data): hash_ = 0xCBF29CE484222325 for b in data: hash_ ^= ord(b) hash_ &= 0xffffffffffffffff hash_ *= 0x100000001b3 hash_ &= 0xffffffffffffffff return hash_ def fnv32(data): hash_ = 0x811C9DC5 for b in data: hash_ ^= ord(b) hash_ &= 0xffffffff hash_ *= 0x1000193 hash_ &= 0xffffffff return hash_ def crack(check): for d in table: hash_ = fnv64(d) if hash_ == check: print 'Found input[i]:',d return d def findapi(api,check): hash_ = fnv32(api) if hash_ == check: print "Found api(%x): "%check+api def crack_all(data,check): hash_ = fnv64(data) if hash_ == check: print 'Found flag:',data print crack(check=0xAF63B44C8601A894) #9 t="" t+=crack(check=0xAF64064C860233EA) t+=crack(check=0xAF64154C86024D67) t+=crack(check=0xAF63FE4C86022652) t+=crack(check=0xAF64094C86023903) t+=crack(check=0xAF63FB4C86022139) t+=crack(check=0xAF63AF4C8601A015) t+=crack(check=0xAF63AD4C86019CAF) t+=crack(check=0xAF63AC4C86019AFC) t+=crack(check=0xAF63B54C8601AA47) print "input[0:9]: "+t # KXCTF2018 # api.txt包含了ntdll.dll gdi32.dll kernel32.dll user32.dll的导出api f=open("api.txt","rb") for api in f.readlines(): findapi(api.strip(),check=0x53B2070F) #LoadLibraryA findapi(api.strip(),check=0xE463DA3C) #GetModuleHandleA findapi(api.strip(),check=0xF8F45725) #GetProcAddress f.close() # f=open("wintrust2.txt","rb") # for api in f.readlines(): # findapi(api.strip(),check=0x348B1518) #SoftpubCleanup def dll_get(): import os # dll_all.txt包含了所有系统环境变量下的dll名称 f=open("dll_all.txt","rb") dll_name="" for dll in f.readlines(): dll=dll.strip() if len(dll)==5+4: dll_name+=dll+" " print dll_name # os.chdir("C:\Windows\System32") os.chdir("C:\Windows\SysWOW64") os.system("(for %%i in (%s) do dumpbin -exports %%i) > F:\Desktop\dll_name.txt"%dll_name) os.chdir("F:\Desktop") os.system("findstr /X \".*[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F].*[a-zA-Z_]$\" dll_name.txt > dll_name2.txt") os.system("findstr /V \"@ $ \. : characteris.tics\" dll_name2.txt > dll_name3.txt") # 使用notepad++正则替换^.*[0-9A-F]{8} ([a-zA-Z_0-9]+)$为($1) def crack_dll(): dll_name=['aadtb', 'aclui', 'adsnt', 'aepic', 'atl71', 'atmfd', 'authz', 'cdprt', 'Clipc', 'cmifw', 'cmlua', 'coml2', 'd3d10', 'd3d11', 'D3D12', 'd3dim', 'dcomp', 'ddraw', 'dmime', 'dmocx', 'dpapi', 'dpnet', 'dsdmo', 'dsreg', 'dssec', 'dui70', 'duser', 'dxva2', 'esent', 'fdBth', 'fdPnp', 'fdWCN', 'fdWSD', 'fmifs', 'fwcfg', 'gcdef', 'gdi32', 'glu32', 'gpapi', 'hgcpl', 'hlink', 'icm32', 'icmui', 'icuin', 'icuuc', 'idndl', 'ifmon', 'imapi', 'imm32', 'InkEd', 'input', 'iprop', 'mfc40', 'mfc42', 'MFC71', 'mfsvr', 'mfvfw', 'mlang', 'mmres', 'msafd', 'mscms', 'msctf', 'msdmo', 'msdrm', 'msIso', 'mssph', 'mssvp', 'msutb', 'MSWB7', 'msyuv', 'mtxdm', 'mtxex', 'netid', 'nlmgp', 'Nlsdl', 'ntdll', 'nvapi', 'NvFBC', 'NvIFR', 'ole32', 'pcaui', 'pcwum', 'pdhui', 'pku2u', 'psapi', 'qedit', 'Query', 'qwave', 'rnr20', 'sbeio', 'scksp', 'slwga', 'spbcd', 'spinf', 'spnet', 'spopk', 'spwmp', 'tapi3', 'TSpkg', 'twext', 'tzres', 'ucmhc', 'uicom', 'untfs', 'uReFS', 'usbui', 'usp10', 'uxlib', 'Vault', 'vfnet', 'vfnws', 'webio', 'werui', 'winml', 'winmm', 'wmidx', 'wmpps', 'wow32', 'wpcap', 'WPDSp', 'wshrm', 'wuapi', 'wwapi', 'xwreg'] f=open("F:\Desktop\dll_name3.txt","rb") import subprocess for api in f.readlines(): for dll in dll_name: if len(api.strip())==13: api = api.strip() flag="KXCTF20189%s9%s9"%(dll.upper(),api) crack_all(flag,check=0x4F8075587499C0FF) # dll_get() crack_dll() # KXCTF20189NTDLL9DbgUiContinue9
flag:KXCTF20189NTDLL9DbgUiContinue9
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课