bugku pwn
pwn2
- checksec发现什么保护都没有,拖进ida看看.
main函数1
2
3
4
5
6
7
8
9
10
11
12int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+0h] [rbp-30h]
memset(&s, 0, 0x30uLL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
puts("say something?");
read(0, &s, 0x100uLL);
puts("oh,that's so boring!");
return 0;
}
get_shell_函数:
1 | int get_shell_() |
应该是让返回地址覆盖成getshell地址,
gdb看一下偏移
1 | gdb |
rbp前四位为bAA1,算一下偏移
到rbp偏移为48,向上8字节是父函数rbp,所以偏移56覆盖到返回地址,get_shell_地址为
exp如下:
1 | from pwn import * |
pwn4
- checksec跑一下,并没有什么壳或保护.
ida64位打开一下,虽然有一个read函数,可以输入30字节,10字节的缓冲区可以制造溢出.但是没有系统函数可以调用.shift+f12
查看有没有可疑字符串,然后在字符串上按x
查看引用他的地方,找到了一个system函数.1
2
3
4int sub_400751()
{
return system("ok~you find me,but you can't get my shell'");
}
但是system函数里面的字符串并不是我们想要的'/bin/sh'
,尝试用ROPgadget去搜索,命令为ROPgadget --binary pwn4 --string '/bin/sh'
,搜索无果。。。再回到IDA中检测字符串
1 | .data:0000000000601100 00000022 C 4985y9y()DY)*YFG8yas08d976s08d7$0 |
发现了一个
$0
,$0
在linux中为为shell或shell脚本的名称。system()
会调用fork()
产生子进程,由子进程来调用/bin/sh -c string
来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。所以如果将$0
作为system
的参数,能达到传入'/bin/sh'
一样的效果。有了
system
函数和$0
作为参数,就可以进行溢出了。还有要注意的就是64位程序和32位程序的传参方式不一样,32位的函数调用使用栈传参,64位的函数调用使用寄存器传参,分别用
rdi
、rsi
、rdx
、rcx
、r8
、r9
来传递参数(参数个数小于7的时候)。
我们利用ROPgadget
工具进行查找,得到pop rdi ; ret
和$0
的地址,system的地址直接在IDA中查看.
1 | ROPgadget --binary pwn4 --only 'pop|ret' |
首先先填充缓冲区,大小为0x10,然后覆盖rbp,8个字节,传入pop rdi;ret的地址和$0,将栈中$0的地址弹出,存入rdi作为参数,在传入system地址进行调用。
下面是脚本:
1 | from pwn import * |