首页
论坛
专栏
课程

[原创] 看雪CTF2018-第十二题-破解之道writeup

sherlly
4
2018-7-10 15:33 673

目录

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



[防守篇]2018看雪.TSRC CTF 挑战赛(团队赛)11月1日征题开启!

上传的附件:
最新回复 (0)
返回