Closed fengjian closed 3 years ago
I've tried your script a dozen times and can't reproduce. Could you share a recording where this happens?
I can share a record. but I don't have any NetDisk storage.
test2.py
from pandare import Panda, blocking
import os.path
import capstone
from colorama import Fore, Back, Style
md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64)
panda = Panda(generic="x86_64")
panda.enable_memcb()
panda.load_plugin("syscalls2")
panda.load_plugin("hooks")
libc = {
"__libc_malloc": 0x97070,
"malloc": 0x97070,
"__libc_free": 0x97950,
"cfree": 0x97950,
"free": 0x97950
}
shared_lib_addr_space = 0x7ffff0000000
libc_baseaddr = 0x7ffff79e4000
malloc_count = 0
free_count = 0
target_proc = "uaf"
pc_cache_set = set()
free_cache_set = set()
def print_line():
print(f"{Fore.GREEN}"+"-"*80+Style.RESET_ALL)
def uaf_exec_hook(cpu, tb, h):
procname = panda.get_process_name(cpu)
if procname == target_proc:
print(f"{Fore.RED}[hook] UAF exec")
print_line()
code = panda.virtual_memory_read(cpu, tb.pc, tb.size)
for i in md.disasm(code, tb.pc):
print(f"0x{i.address:x}:{Fore.YELLOW}\t{i.mnemonic}\t{i.op_str}"+Style.RESET_ALL)
print_line()
pass
@panda.cb_virt_mem_after_write(procname="uaf")
def virt_mem_after_write(cpu, pc, addr, size, buf):
if pc < shared_lib_addr_space:
for cache in free_cache_set:
if addr == cache + 24:
evil_addr = panda.virtual_memory_read(cpu, addr, size, 'int')
asid = panda.current_asid(cpu)
panda.hook(evil_addr, enabled=True, kernel=False, asid=asid)(uaf_exec_hook)
print(f"[hook] UAF mem write addr: {Fore.GREEN}0x{addr:x}{Style.RESET_ALL}, value: {Fore.RED}0x{evil_addr:x}"+Style.RESET_ALL)
return
def call_return_hook(cpu, tb, h):
procname = panda.get_process_name(cpu)
if procname == target_proc:
ret = panda.arch.get_return_value(cpu)
print(f"[hook] proc:{procname} malloc ret: {Fore.GREEN}0x{ret:x}"+Style.RESET_ALL)
if ret in free_cache_set:
print(f"[hook] proc:{procname} UAF in {Fore.RED}0x{ret:x}"+Style.RESET_ALL)
def libc_malloc_hook(cpu, tb, h):
global malloc_count
procname = panda.get_process_name(cpu)
if procname == target_proc:
sp = panda.current_sp(cpu)
retaddr = panda.arch.get_return_address(cpu)
size = panda.arch.get_arg(cpu, 0)
print(f"[hook] proc:{procname} malloc: call_addr:0x{retaddr:x} arg0:{size}")
if retaddr < shared_lib_addr_space:
if retaddr not in pc_cache_set:
pc_cache_set.add(retaddr)
asid = panda.current_asid(cpu)
panda.hook(retaddr, enabled=True, kernel=False, asid=asid)(call_return_hook)
malloc_count += 1
def libc_free_hook(cpu, tb, h):
global free_count
procname = panda.get_process_name(cpu)
if procname == target_proc:
sp = panda.current_sp(cpu)
retaddr = panda.arch.get_return_address(cpu)
addr = panda.arch.get_arg(cpu, 0)
free_cache_set.add(addr)
print(f"[hook] proc:{procname} free: call_addr:0x{retaddr:x} arg0:{Fore.GREEN}0x{addr:x}"+Style.RESET_ALL)
if retaddr < shared_lib_addr_space:
free_count += 1
@panda.ppp("proc_start_linux","on_rec_auxv")
def rec_auxv(cpu, tb, av):
procname = panda.get_process_name(cpu)
if procname == "uaf":
asid = panda.current_asid(cpu)
panda.hook(libc["malloc"]+libc_baseaddr, enabled=True, kernel=False, asid=asid)(libc_malloc_hook)
panda.hook(libc["free"]+libc_baseaddr, enabled=True, kernel=False, asid=asid)(libc_free_hook)
print(f"[hook] started proc {procname} {av.phdr:x} {av.entry:x}")
@blocking
def run_cmd():
# First revert to root snapshot, then type a command via serial
panda.revert_sync("root")
panda.copy_to_guest("/root/.panda/target")
print(panda.run_serial_cmd("uname -a"))
print(panda.run_serial_cmd("cp /root/target/uaf /tmp/uaf && chmod +x /tmp/uaf"))
print(panda.run_serial_cmd("/tmp/uaf"))
print("Finding cat in cat's memory map:")
maps = panda.run_serial_cmd("cat /proc/self/maps")
for line in maps.split("\n"):
if 'cat' in line:
print(line)
panda.end_analysis()
panda.queue_async(run_cmd)
panda.run()
print(malloc_count)
print(free_count)
not work occasionally
[PYPANDA] mount: /root/target: WARNING: device write-protected, mounted read-only.
Linux ubuntu 4.15.0-72-generic #81-Ubuntu SMP Tue Nov 26 12:20:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
p1 malloc addr: 0x555555756260
hello world
free p1: hello world again
p2 malloc addr: 0x555555756260
p1 origin addr: 0x555555756260
call p1: whoami
root
Finding cat in cat's memory map:
555555554000-55555555c000 r-xp 00000000 08:01 19 /bin/cat
55555575b000-55555575c000 r--p 00007000 08:01 19 /bin/cat
55555575c000-55555575d000 rw-p 00008000 08:01 19 /bin/cat
0
0
repeated calls
[hook] started proc uaf 555555554040 555555554660
[hook] started proc uaf 555555554040 555555554660
[hook] proc:uaf malloc: call_addr:0x5555555547b2 arg0:16
[hook] proc:uaf malloc: call_addr:0x5555555547b2 arg0:16
[hook] proc:uaf malloc ret: 0x555555756260
[hook] proc:uaf malloc: call_addr:0x7ffff7a6218c arg0:4096
[hook] proc:uaf malloc: call_addr:0x7ffff7a6218c arg0:4096
[hook] proc:uaf free: call_addr:0x555555554800 arg0:0x555555756260
[hook] proc:uaf free: call_addr:0x555555554800 arg0:0x555555756260
[hook] proc:uaf malloc: call_addr:0x55555555481e arg0:16
[hook] proc:uaf malloc: call_addr:0x55555555481e arg0:16
[hook] proc:uaf malloc ret: 0x555555756260
[hook] proc:uaf UAF in 0x555555756260
[hook] UAF mem write addr: 0x555555756278, value: 0x55555555476a
[hook] UAF exec
repeated calls and Segmentation fault
[hook] started proc uaf 555555554040 555555554660
[hook] started proc uaf 555555554040 555555554660
[hook] proc:uaf malloc: call_addr:0x5555555547b2 arg0:16
[hook] proc:uaf malloc: call_addr:0x5555555547b2 arg0:16
[hook] proc:uaf malloc ret: 0x555555756260
[hook] proc:uaf malloc: call_addr:0x7ffff7a6218c arg0:4096
[hook] proc:uaf malloc: call_addr:0x7ffff7a6218c arg0:4096
[hook] proc:uaf free: call_addr:0x555555554800 arg0:0x555555756260
[hook] proc:uaf free: call_addr:0x555555554800 arg0:0x555555756260
[hook] proc:uaf malloc: call_addr:0x55555555481e arg0:16
[hook] proc:uaf malloc: call_addr:0x55555555481e arg0:16
[hook] proc:uaf malloc ret: 0x555555756260
[hook] proc:uaf UAF in 0x555555756260
[hook] UAF mem write addr: 0x555555756278, value: 0x55555555476a
[hook] UAF exec
--------------------------------------------------------------------------------
0x55555555476a: push rbp
0x55555555476b: mov rbp, rsp
0x55555555476e: sub rsp, 0x10
0x555555554772: mov qword ptr [rbp - 8], rdi
0x555555554776: mov rax, qword ptr [rbp - 8]
0x55555555477a: mov rdi, rax
0x55555555477d: call 0x555555554620
--------------------------------------------------------------------------------
p1 malloc addr: 0x555555756260
hello world
free p1: hello world again
p2 malloc addr: 0x555555756260
p1 origin addr: 0x555555756260
call p1: whoami
root
Finding cat in cat's memory map:
555555554000-55555555c000 r-xp 00000000 08:01 19 /bin/cat
55555575b000-55555575c000 r--p 00007000 08:01 19 /bin/cat
55555575c000-55555575d000 rw-p 00008000 08:01 19 /bin/cat
Segmentation fault (core dumped)
[2507790.571593] python[28518]: segfault at 2a70b38 ip 0000000002a70b38 sp 00007fff7d0eb9e8 error 15
[2518189.800371] python[29315]: segfault at 1eb2ba8 ip 0000000001eb2ba8 sp 00007ffdc3582998 error 15
[2518215.395536] python[29324]: segfault at 12d5ba8 ip 00000000012d5ba8 sp 00007fff7e7ef758 error 15
[2598383.266256] python[24997]: segfault at e9bba8 ip 0000000000e9bba8 sp 00007fff7e38f9a8 error 15
Hi @fengjian,
I wrote up a PR #958 that should address some of the issues here. Specifically it allows for specifying offsets into libraries directly.
e.g.
@panda.hook_symbol("libc-", 0x1234)
def hook_random_lib_offset(cpu,tb,h):
pass
I'm really unsure why you would be seeing a segfault. Could you consider providing a stack trace from GDB?
Re: recording we can set up some other way of transferring it. Feel free to shoot me an email at the email on my profile.
Hi, @lacraig2 I've tried the PR #958 and lastest image
The bug still exists, let me share a recording.
REPOSITORY TAG IMAGE ID CREATED SIZE
pandare/pandadev latest d6731925401d 34 hours ago 4.99GB
repeated calls: I've tried a dozen times and can't reproduce if use panda.run_replay. but the bug still exists if use panda.run.
The hook not working occasionally, I have a recording about this.
I think disable PANDA_CB_BEFORE_TCG_CODEGEN is incorrect if use panda.run.
@panda.ppp("proc_start_linux","on_rec_auxv")
def rec_auxv(cpu, tb, av):
procname = panda.get_process_name(cpu)
print(f"started proc {procname} pc:0x{tb.pc:x}")
if procname == "uaf":
asid = panda.current_asid(cpu)
panda.hook(libc["malloc"]+libc_baseaddr, enabled=True, kernel=False, asid=asid)(libc_malloc_hook)
panda.hook(libc["free"]+libc_baseaddr, enabled=True, kernel=False, asid=asid)(libc_free_hook)
print(f"[hook] started proc {procname} pc:0x{tb.pc:x} {av.phdr:x} {av.entry:x}")
started proc uaf
[hook] started proc uaf pc: 0x7ffff7dd6090 555555554040 555555554660
started proc uaf
[hook] started proc uaf pc: 0x7ffff7dd60ca 555555554040 555555554660
[hook] proc:uaf malloc: call_addr:0x5555555547b2 arg0:16
[hook] proc:uaf malloc: call_addr:0x5555555547b2 arg0:16
[hook] proc:uaf malloc ret: 0x555555756260
[hook] proc:uaf malloc: call_addr:0x7ffff7a6218c arg0:4096
[hook] proc:uaf malloc: call_addr:0x7ffff7a6218c arg0:4096
[hook] proc:uaf free: call_addr:0x555555554800 arg0:0x555555756260
[hook] proc:uaf free: call_addr:0x555555554800 arg0:0x555555756260
[hook] proc:uaf malloc: call_addr:0x55555555481e arg0:16
[hook] proc:uaf malloc: call_addr:0x55555555481e arg0:16
[hook] proc:uaf malloc ret: 0x555555756260
[hook] proc:uaf UAF in 0x555555756260
[hook] UAF mem write addr: 0x555555756278, value: 0x55555555476a
[hook] UAF exec
started proc mkdir pc: 0x7ffff7dd6090
started proc mount pc: 0x7ffff7dd6090
started proc mount pc: 0x7ffff7dd60ca
started proc modprobe pc: 0x7ffff7dd6090
started proc cp pc: 0x7ffff7dd6090
started proc sh pc: 0x7ffff7dd6090
[PYPANDA] mount: /root/target.ro: WARNING: device write-protected, mounted read-only.
started proc ln pc: 0x7ffff7dd6090
started proc uname pc: 0x7ffff7dd6090
Linux ubuntu 4.15.0-72-generic #81-Ubuntu SMP Tue Nov 26 12:20:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
started proc readlink pc: 0x7ffff7dd6090
started proc cp pc: 0x7ffff7dd6090
started proc cdrom_id pc: 0x7ffff7dd6090
started proc cdrom_id pc: 0x7ffff7dd6098