ctfshow_pwn练习
栈溢出
pwn_035
正式开始栈溢出了,先来一个最最最最简单的吧
首先使用checksec
查保护:
32位程序,开启了堆栈不可执行保护。首先运行一下:
发现他会打开根目录下的文件,但是并不对其进行输出。这里使用ida进行反编译:
发现,程序读取/ctfshow_flag
文件后存入flag
变量中,但不打印,然后打印字符串,进入验证argv[1]
的值,但是程序中并没有给定输入argv
数组的功能,然后根据argv[1]
的值输出不同的字符,其中,当argc >= 1
时,会进入ctfshow函数中,进入观察:
发现使用strcpy
函数将argv的值复制给dest变量中。
漏洞很明显,是由于strcpy
函数未验证源字符串大小造成的栈溢出漏洞。这里的dest
接收0x68
大小的字符。
这里的dest相对ebp的偏移量为0x6c
.
那么argv
的值应该怎么控制呢,重新审计,发现原来该程序是通过命令行来接受参数的,这里给出chat的解释:
那么就好控制了,我们只需要输入大于0x6c的值即可造成栈溢出漏洞。但是造成栈溢出的目的是为了读取flag,程序中已经读取了flag,应该如何使其输出出来呢。重新审计发现:
1 | fgets(flag, 64, stream); |
这个函数没见过,给chat跑一下:
通过chat的解释以及菜鸟教程-signal函数,我们知道了,当该函数发生非法访问存储器,如访问不存在的内存单元时,就会调用sigsegv_handler
函数,我们跟进该函数看一下:
1 | void __noreturn sigsegv_handler() |
他就会打印出flag。所以当我们造成栈溢出漏洞时,其实就相当于非法访问存储器,自然便会调用函数打印flag。所以我们只需要输出>0x6c
个字节的内容即可获取flag。我们使用peda生成108字节的字符:
然后输入:
成功读取到本地flag。
pwn_036
存在后门函数,如何利用?
本地运行,并使用checksec
查一下保护:
程序存在输入,并且栈可执行
1 | Arch: i386-32-little ✅ 32位程序,EIP 只有4字节,易于控制 |
接下来我们使用ida打开:
main函数:
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
ctfshow函数:
1 | char *ctfshow() |
ctfshow函数中使用gets函数来读取s,标准的栈溢出漏洞。
我们将断点下在0x08048619
处
esp
的地址为0xffffd550
,ebp
的地址为0xffffd588
,s
相对于ebp
的索引为ebp+0x28
,所以这里s
相对ebp
的偏移量为0x28
。
接着找到存在getflag
函数:
地址为:0x08048586
所以我们的思路就是溢出到getflag
函数处即可。
编写exp
1 | #!/usr/bin/env python3 |
成功获取到flag:
pwn_037
32位的 system(“/bin/sh”) 后门函数给你
执行➕checksec:
开启了栈不可执行保护。放入ida中进行分析:
反编译后的main函数、logo函数以及ctfshow函数
发现漏洞点应该在ctfshow函数中,因为这里预定义的buf数组的大小为14,而read允许读入的字节大小为0x32 = 50
,所以这里存在栈溢出漏洞。
继续分析,发现存在system后门函数backdor:
backdoor函数地址:0x08048521
接下来我们计算偏移,buf相对于ebp的偏移为0x12
。就下来我们编写exp
1 | #!/usr/bin/env python3 |
成功拿到本地shell
pwn_038
64位的 system(“/bin/sh”) 后门函数给你
执行加checksec
与上题一样,输入然后推出,且仅开启了堆栈不可执行保护,不一样的是,本次的是64位程序。使用ida打开分析。
反编译,直接转到ctfshow函数中
read栈溢出漏洞。并且存在后门地址backdoor,地址0x0400657
计算偏移量为0x0a
,这里需要注意的是,64位程序距离返回地址有8个字节。
注意,这里是64位程序,与32位程序不同的是,这里我们需要考虑到堆栈平衡的情况:
堆栈平衡:64位系统需要保持一个栈平衡,需要找栈lea的地址或者该函数结束即retn的地址,当我们在堆栈中进行堆栈的操作的时候,一定要保证在ret这条指令之前,esp指向的是我们压入栈中的地址,函数执行到ret执行之前,堆栈栈顶的地址一定要是call指令的下一条地址。
仿照上例,编写exp
1 | #!/usr/bin/env python3 |
pwn_039
运行+checksec,观察:
只开启堆栈不可执行保护,使用ida反编译,找到漏洞点
read函数的栈溢出漏洞,试寻找后门函数。在hint函数中找到system函数以及/bin/sh
字符,但是并没有构成后门函数,所以我们这里需要构造system('/bin/sh')
。
找到/bin/sh
的地址:
接下来我们找到system@plt的地址:
最后,我们需要计算可溢出字符串的偏移:
为0x12 + 4
编写exp
1 | #!/usr/bin/env python3 |
pwn_040
运行+checksec,可以看到只开启了NX保护
IDA反编译查看
read函数存在溢出,且存在system函数,查找是否存在/bin/sh
字符串
计算偏移:
偏移量为0x10
编写exp
1 | #!/usr/bin/env python3 |
pwn_041
使用checksec查保护并运行,获得基本信息,32位程序,仅开启NX保护。
使用ida反编译
存在read函数栈溢出,并且存在system
函数,但不存在/bin/sh
字符。
原本准备在.bss段中写入/bin/sh\x00
,来构造system('/bin/sh')
,但是并没有找到可用的.bss段,继续审计代码,发现存在sh
字符串。
这里不得不提/bin/sh
与sh
之间的区别:
sh
是通过系统环境变量来启动一个名为sh的shell环境。而/bin/sh
则是linux系统中默认的shell环境。
接下来计算偏移为0x12
编写exp
1 | #!/usr/bin/env python3 |