CTF-SHOW 刷题记录
CTF SHOW
pwn35~110
pwn35(数组溢出)
数组溢出,输入一个超长字符串即可
pwn36(后门函数直接得到flag)
看准了这个ctfshow函数
这里使用了gets函数读取s数组,且此程序没有栈溢出保护,故在这里可以进行栈溢出攻击。
同时题目提示有后门函数
查看这个get_flag函数
1 | fgets函数:char* fgets(char *restrict str, int size , FILE* restrict stream) |
所以我们需要做的是
- 将ctfshow函数的返回地址填充为get_flag函数的返回地址
查看get_flag函数的地址
为0x08048586
整体思路为:
(当然还有一截previous ebp),所以距离返回地址的长度为0x28+4
exp
1 | from pwn import * |
pwn37(32位后门函数获得shell)
总的来说和上道题大差不差,init清空缓冲区,logo和puts打印信息。只有ctfshow是挺关键的
buf数组长14,读入了0x32长的数据,故可以实现栈溢出
题目提示有后门函数,故我们只需要找到后门函数的额起始地址即可
故后门函数地址为 0x08048521
exp
1 | from pwn import * |
【*】pwn38(64位后门函数获得shell)
题目可以说是完全一样,但是题目说是64位系统。放进checksec里看看就好了
注意32位和64位的区别。首先context要设置一下,然后注意寄存器和地址都是八个字节
找到后门函数地址
0x400657?
exp
1 | from pwn import * |
结果出来是错的,为什么
这是因为64位系统还需要处理**堆栈平衡**
当我们在堆栈进行堆栈的操作的时候,一定要保证在ret这条指令之前,esp指向的是我们压入栈中的地址,函数执行到ret执行之前,堆栈栈顶的地址一定要是call指令的下一个地址
因此我们还需要找一个地址: lev 的地址或者该函数结束的地址(即 retn 的地址)
可以看到
lev的地址:0x40065b
retn的地址:0x+40066d
特别注意:构造 payload 时将该地址放在该函数开始地址之前
exp2.0
1 | lev_addr = 0x40065b |
pwn39(32位后门函数system与参数分离)
还是我们喜闻乐见的32位ret2text
只不过这里的后门不是函数,而是
这里将/bin/sh
和system
函数分开了
/bin/sh的地址:0x08048750
system()的地址:0x080483A0
这张图是便于习惯的,真实的情况如下图
这里从ctfshow函数跳转到了system函数
我们要做的是将返回地址覆盖为system函数,并将参数1填充上/bin/sh字符串的起始位置。(注意这里的参数不能是/bin/sh整个字符串,因为字符串本身被硬编码为rodata节中,要传递只能通过地址)
偏移量是:12h + 4
这个exit可以是任意地址,如0xdeadbeef(64bit)
exp
1 | from pwn import * |
pwn40(64位后门函数与参数分离(ROP))
发现是64位系统。两者差异如下:
- x86
- 使用栈来传递参数
- 使用eax存放返回值
- x64
- 前6个参数依次存放于rdi、rsi、rdx、rcx、r8、r9寄存器中
- 第7个以后的参数存放于栈中
所以我们这里需要控制rdi的值
利用ROP
1 | ROPgadget --binary pwn --only "pop|ret" |
我们使用pop rdi;ret即可,地址为 0x4007e3
ret的地址为:0x4004fe
exp
1 | from pwn import * |
pwn41(32位sh替换/bin/sh)
正如题目所说,没有/bin/sh了,但是又system函数和 ”echo flag“字符串,以及“sh”字符串
一般情况下,sh和/bin/sh是等效的
- system(“/bin/sh”):在Linux和类Unix系统中,/bin/sh通常是一个符号链接,指向系统默认的shell程序(如Bash或Shell)。因此,使用system(“/bin/sh”)会启动指定的shell程序并在新的子进程中执行。这种方式可以确保使用系统默认的shell程序执行命令,因为/bin/sh链接通常指向默认shell的可执行文件
- system(“sh”):使用system(“sh”)会直接启动一个名为sh的shell程序,并在新的子进程中执行。这种方式假设系统的环境变量$PATH已经配置了能够找到sh可执行文件的路径,否则可能会导致找不到sh而执行失败。
所以还是一样的,只是把/bin/sh字符串换成sh而已
system函数位置:0x080483D0
sh字符串位置:0x080487BA
exp
1 | from pwn import * |
pwn42(64位/sh替换/bin/sh(ROP))
和上道题的漏洞一样,不过是64位系统
偏移量:0xa
system函数地址:0x400560
sh字符串位置:0x400872
pop_rdi_ret地址:0x400843
ret地址:0x40053e
exp
1 | from pwn import * |
pwn43(32位不提供后门函数参数)
32位系统
gets函数导致栈溢出
查看后门函数
这次的后门函数似乎有点复杂
首先v0作为种子,值为time(0)
接着v3为v0作为种子的随机数
然后需要输入一个数:v2
如果v2和生成的随机数相同,则进入system函数
破解随机数是下策
我们找到一段可写区域
实际上这在bss段,其中还有一个buf2数组
我们可以在这里写入/bin/sh
exp
1 | from pwn import * |
pwn44(64位不提供后门函数参数)
漏洞原理和上道题一样,只不过换成了64位系统
找到一块可读写区域,位于bss段
将字符串的起始位置定位:0x602048
system函数:0x400520
gets函数:0x400530
pop_rdi_ret:0x4007f3
ret:0x4004fe
exp
1 | from pwn import * |
p64(pop_rdi_ret_addr) + p64(bin_sh_addr) + p64(ret_addr)
这一块在传递参数
Pwn45(32位无后门函数)
103的长度读了200的数据,也是栈溢出
不过这次没有后门函数了。怎么办呢?