现在开始争取每天都要做一道PWN题,并且难度要逐渐增大。做到每道题目都要弄懂原理,能够复现成功。争取每天都有一两道题能让自己学到新的知识,并且写下WP。
题目来源,现在主要是 BUUOJ 上的题目,以后再逐渐转到比赛题目吧。
0x1 ciscn_2019_c_1
保护机制
只开启了 NX,所以较为简单。
题目分析
题目整体流程实现了一个 加密程序,可以对我们的输入进行加密。
加密逻辑如下:
从上图中,可以看到函数结束时使用 puts() 函数直接将加密密文输出,那么也就是我们可以使用此 函数将我们需要的信息泄露出来。
此外,可以看到一个很明显的栈溢出漏洞:
1 | gets(s) |
读取用户输入时,用了 gets 函数,能够触发栈溢出漏洞,这里就是本题的 唯一漏洞点。
然后对我们的输入会进行一个加密,加密算法伪代码如下:
1 | while(1) |
利用分析
泄露地址
因为这道题存在一个 puts(s) 可以将我们的输入加密后直接输出,所以我们可以先利用这个函数将我们需要的地址给泄露出来。
程序 GOT 表如下:
此处,我们选择 puts() 函数 got 表地址泄露。
布置ROP
因为存在一个 栈溢出漏洞,并且系统并没有开启保护,
所以我们可以直接覆盖 函数 ret 地址,实现ROP攻击。此处我们使用 one_gadget 直接来布置 getshell 链。
one_gadget 链如下:
解密函数
看到这道题有一个加密算法,首先就会想到要去写一个解码算法。
但是,后面才反应过来这个 加密函数 中 记录输入 长度 的 x 是一个全局变量,且当执行完一次加密算法后,并没有使他归为0。
也就是我们可以第一次加密时 输入一个较长的明文,那么再后面我们输入 明文较短时,就可以绕过这个while 加密算法了。
那么,我们后面需要输入多大的 payload 呢?答案当然是 需要能够覆盖 到返回地址 且后面需要的ROP链的 长度,也就是 0x78。
所以 我们第一次就需要输入 0x60 的长度,且保证覆盖返回地址后,能够再次正常执行加密函数,则第一次payload为:
1 | payload = 'a' * 0x58 + p64(encrypt_addr) +’a'*0x18 |
EXP
1 | from pwn import * |
0x2 babyrop
保护机制
只开启了 NX,说明只需要使用 ROP绕过就行。
程序分析
程序总体流程,是先创建了一个随机数。然后再将随机数与我们的输入进行比较,来判断是否可以进入最后的输入函数。
比较函数如下:
从代码中,可以明显看到一个 read() 溢出。通过该溢出,我们可以修改最终的 返回值 v5。
同时,由于 read() 函数并不会对 ‘\x00’ 截断,而 strncmp() 会使用 ‘\x00’ 截断。所以我们可以绕过 strncmp() 函数。
最后进入 输入函数:
利用分析
本题的利用步骤为:
1 | 1. 使用 '\x00'绕过 strncmp() 函数; |
EXP
1 | from pwn import * |
0x3 get_started_3dsctf_2016
这道题,看着十分简单。本地也很快得到了flag 。但是当远程连接时,总是会显示链接超时。
第一个脚本就很简单的思路,修改EIP到漏洞函数。
1 | from pwn import * |
然后远程,就实践了一个平常不太会用到的技巧,就是修改一个可读可写内存保护属性为可读可写可执行,然后往该内存中部署我们的shellcode,然后跳转去执行该shellcode。这个方法需要一定的限制,首先你能部署一段较长的ROP链,使得你能够完成修改 内存保护属性,还要能写入shellcode,最后要跳到shellcode处执行。其次,你需要能够准确找到 mprotect 和 read 等函数地址。
但是该方法,在现有Windows10上 漏洞攻击我也见过,说明是比较通用的方法。
重点记录一下 mprotect函数及参数
1 | int mprotect(void *addr, size_t len, int prot); |
EXP:
1 | from pwn import * |
0x4 第五空间决赛pwn5
这道题典型的 格式化字符串漏洞,通过这道题主要是 复习一下使用格式化字符串任意读、改写操作。还有就是读取内存时,%p \ %s 和 %x 之间的区别。
%x 和 %s 是读取栈上的数据, %s 是读取栈上该数据指向的另一个数据。这里是需要自己输入一个栈上的地址,然后需要使用 %s 来读取该地址指向的数据。
这道题,解题思路利用第一个格式化字符串漏洞读取 内存的随机数,满足第一个条件即可。唯一需要注意的是 atoi() 函数是将 字符串转化为 整数,所以我们需要将读取的随机数转化为字符串输入。
1 | from pwn import * |
此外,练习一下 格式化字符串修改内存的做法吧:
1 | from pwn import * |
- 本文作者: A1ex
- 本文链接: http://yoursite.com/2020/07/29/BUUOJ-PWNWN-WP-1/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!