• pwn学习笔记


    PWN学习笔记——初稿

    注明:本篇学习笔记是入门学习pwn时的随笔,所以不具有任何参考价值 ,仅作为对学习路线回顾参考的笔记以及入门纪念。

    使用 Kali Linux , 称霸局域网 ![doge]


    调试,调试!

    Ida中的静态调试显示的函数和输出之间的距离,有时候会因为各种原因而显示错误,需要用pwndbg动态调试观察一下。淦,gdb显示的地址有时候也不对

    IDA基本操作 (静态调试)

    shift + F12

    space

    F5

    ctrl + F

    Pwndbg基本操作(动态调试)

    Pwndbg + 文件名  进入对某个文件的调试

    r 运行

    b + 地址/函数  设置断点

    checksec + 文件名  查看保护措施

    stack + 数字  查看栈段

    vmmap' 显示虚拟内存的的空间分布(观察读写的权 限是否有冲突-w与x不同时出现

    plt 查看文件里的plt表项

    x + 地址 显示该地址的内容和地址

    got 查看got中保存的函数数量及其字节、数据等信息

    disass + 地址 反汇编地址的数据,进而查看其汇编代码或plt

    c 继续执行程序,直到遇到断点/程序中断

    start 开始执行程序,会停到main函数;如果没有main函数,则会停到程 序的入口

    s 附近

    backtrace 显示函数调用栈段的状态

    return 快速回到mian函数


    求求了,用用py吧

    (context.arch = “amd64”)  调整攻击环境 

    shellcode.sh()

    print(xxx)  更清楚地查看shellcode

    print(asm(xxx))  查看shellcode的机器码

    获取shellcode : 1.shellstore 2.pwntools – shellcraft.sh() (后面就是方法) 

    Print(asm(shellcode.(amd64.)sh()))

     


    嘿嘿嘿·,脚本(介绍一下大致模板,最简单的那种啊,别误会)

    vim exp.py

    from pwn import *

    (context.arch = "amd64")

    io = process("本地文件路径") //与本地文件交互

    OR  

    io = remote("IP", 端口 )

    io.recvline() //接受程序给的文件

    payload = b'”x”(字节型的数据) + p32(劫持程序的地址) //将一个整数的地址转化成字节型的数据 32位的 ebp占4个字节,64位的·ebp占8个字节
    io.send(payload) //发送数据  

    OR  

    io.sendline(payload) //发送一行数据,相当于在数据末尾加/n;

    io.interactive()   //交互
    from pwn import *

    (context.arch = "amd64")

    io = process("本地文件路径") //与本地文件交互

    OR  

    io = remote("IP", 端口 )

    io.recvline() //接受程序给的文件

    asm(shellcode.(amd64.)sh()) //获取shellcode的机器码    

    payload = asm( shellcode.(amd64.)sh()),lhust( 112, b’A ) /*补充字节流(这里就是A )到112 */ + p32( 劫持程序的地址(可以是全局变量的地址) )

    io.send(payload) //发送数据  

    OR  

    io.sendline(payload) //发送一行数据,相当于在数据末尾加/n;

    io.interactive()   //交互

    还有很多呐!

     


    呐,shellcode注意啥啊

    bss默认可执行,因此我们可以通过全局变量向其输入shellcode

    gets 漏洞

    未初始化的全局变量保存在bss里

     


    不会算数,py来救

    使用python计算栈段之间的距离

    0x….(高地址) – 0x…(低地址)

    >>>十进制数

    Hex(十进制)

    >>>十六进制

     


    保护措施

    1-NX 栈不可执行

    2-ASLR 让函数的栈、共享连接库、堆段进行地址随机化,

    0 – 未打开;1 – 部分随机化;2 – 全部随机化

    关闭ASLR – “echo 0 > /proc/sys/kernel/randomize_va_space”

    3-Canary(金丝雀) 在调用一个函数,刚创建栈帧时,首先把一个值(canary)放在低地址空间里,在销毁 函数时,先检查这个值(canary)是否发生改变,如果值改变,就会其强行将程序退出

    4-Pie 编译时打开开关,随机化elf文件映像(text,bss。data)

     


    程序进不去怎么办

    修改文件权限

    #!/bin/sh

    gcc -fno-stack-protector -z execstack -no-pie -g -o re2stack ret2stack.c

    -fno-stack-protector 关闭canary,使栈溢出首先可行

    -z execstack  打开栈的可执行权限

    -no-pie  关闭pie

    -g  带上调试信息,便于观看(一定要带着re2stack.c)

    -o  输出文件名


    请问字节是啥

    8比特 – 1 字节

    每4比特可以直接写成一个16进制的值,

    每两个16进制数就是1个字节


    ROP!!!

    没有连续的代码,但是通过一段一段的这个函数中包含的代码片段,达到相同的执行效果,即模拟程序的执行

    其中思想的不同:没有一步到位的地址一次覆盖到tet,调用shell(即调用shell攻击目标,无法通过一个地址一次,所以需要,自己将程序中的指令组合起来,起到shell的作用)

    我们所需要的为eaxebx…赋值的代码本来就存在,但是不连续,我们需要把他们组成一个链式结构(gadget),所以需要溢出很长的一段数据,把这些调成想要的格式,使其能够连续工作,并使其最后一条指令为ret。

    对于系统调用,要在所有以ret结尾的代码中,找出个代码片段,它们的作用分别是pop eax、pop ebx、pop ecx、pop edx,pop一个寄存器的指令可以将数值直接写到栈上

    PS:系统调用 —— 本质上只是一段函数,X86使用中断进行系统调用,第一个栈帧是main函数的栈帧,在main函数之前执行的所有函数都是没有栈帧的


    ret2syscall

    因为需要执行大量代码段,故通过局部变量溢出, 组合一些gadget执行大量的代码片段,故将从ret开始的一大段栈空间,覆盖成gadget地址和对应的参数,此时,在main函数返回时,就会返回到已经被覆盖掉的,现在是ret的地址, 并执行指令

    (ret把当前栈顶的值pop到eip)ret等效于pop eip

    ROP

    ROP1 

    get ­­­­­­­­­­­­­­­­­­­­--binary 文件名 -- only “ pop | ret 要寻找的指令|管道符 grep xx 把输入参数中含有xx的命令显示出来

    Ret = pop xxx 即把xxx弹出到eip 

    Xor 清空寄存器

    下面是示例!

    ret2syscall02ret2syscall01

    Int 0x80 ( eax = 0xb , ebx = …, ecx = 0,edx = 0 )进行系统调用( int – 中断指令 ),通过寄存器传参,来确定要调用哪一个函数。在执行int 0x80 这个汇编代码对应的机器码时,要确保四个寄存器都已经存储了对应的函数所需要的参数,即0xb这一个系统调用号对应的sys_execve() 对应的内核里的函数的调用号,而0xb 在这里·也带代表了那个函数

    下面使用pwntools便捷获取/bin/sh的地址

    pwntools

    使用next传入生成器

    pwntools1

    最后一层是要输入的垃圾数据,倒数第三行是要给

    倒数第二层输入的数据,以此类推

    ret2ssystem

     


    动态链接 

    当我们使用file命令去查看一些文件的属性时,下面两点也会被显示出来:

    动态链接:gcc -fno-pie -o dytest xxx.py   dynamically link

    静态链接:gcc -fno-poe --static -o statest xxx.py   statically link

    本块主要讨论动态链接

    动态链接相关结构

    动态链接结构

    dynamic section 为操作系统描述了整个动态链接的完整内容

    提供动态链接相关信息

    link_map 保存进程载入的动态链接库的链表

    dl_runtime_resolve 解析第一次在动态链接的函数的真实地址

    装载器中用于解析动态链接库中函数的实际地址的函数

    got  全局的符号、变量地址

    got.plt 全局的函数地址

     

    动态占用内存小(其库函数占用少)

     

    动态链接过程

    ldd 文件名 查看文件用到的所有动态链接库

    动态链接

    下面分流程分析

    过程1

    text —— 代码节;foo@olt —— foo是自己写的函数;plt是代码段中存放函数真实地址的一个节; PLT0(PLT最开始的两段指令)

    因为foo是个动态链接库中的代码,所以call foo,并不能直接跳转到它自己代码段里的foo函数,只能去代码段中的plt节,而每个被调用的动态链接库中的函数都会在其中创立一个表项,

     

    1、call foo@plt 进程首次调用 foo

    2、jmp *(foo@GOT) 跳转到 .plt 中的 foo 表项,plt 中的代码立即跳转到.got.plt 中记录的地址

    3、push 由于进程是第一次调用 foo,故.got.plt 中记录的地址是 foo@plt+1

    4、jmp 回到 .plt 是,解析 foo 的实际地址

    5、push *(GOT+4) 跳转到 .plt 头部,为 dl_runtime_resolve 函数传参

    6、push *(GOT+4) 跳转到 .plt 头部,为 dl_runtime_resolve 函数传参

    过程2

    7、call_fix_up dl_runtime_resolve 函数解析 foo 的真正地址填入 .got.plt 中

    8、ret 0xc 此后 .got.plt 中保存的是 foo 的真实地址

    过程3

    9、call foo@plt 系统第二次调用foo

    10、jum *(foo@GOT)  直接自 .got.plt 跳转到 foo 的真实地址,没有了第一次的解析地址过程

    ok,接下来展示完整流程

    完整


    IDA的细节

    init 用作初始化的一个节,记录了初始化代码

    plt 存放函数真实地址的一个节

    got 存放数据的节


    ret2libc

    往往依赖于rop所需要的各种gadget创造执行shellcode的环境,但其目标是返回libc里的system函数这一类可以为我们提供一个shell的函数

     

  • 相关阅读:
    delphi编程来记录QQ的聊天记录
    delphi编程模拟发送QQ2008消息!
    C++学习 破冰之旅
    C++ 宏和预编译 预编译头
    C++头文件讲解
    EXTJS将树拖拽到PANEL,drag tree drop into panel 实例
    JS数组声明技巧、数组动态添加元素
    JS二维数组的定义
    EXTJS 按钮添加右键
    提高SQL执行效率的几点建议
  • 原文地址:https://www.cnblogs.com/socialbiao/p/15669045.html
Copyright © 2020-2023  润新知