『hijack_libc_got』劫持libc的got表getshell
0x00 前言
在glibc2.34或更高版本,没有了hook用来劫持,所以一般会用IO之类的路子来劫持。如果条件允许,还可以考虑劫持劫持libc的got表来getshell。libc一般是partial relro,所以got表可写。但准确来说,接下来的PoC,其实针对的是劫持.got.plt段执行one gadget而设计的。劫持libcgot的技术还可以结合context的gadget实现rop,后面再深入研究。
0x01 PoC
1 |
|
0x02 分析
puts函数的跟进
PoC最后执行了一个puts函数,并且直接_exit,没法劫持exit_hook。我们去IDA翻一翻puts函数都干了些什么。
发现它调用了j_strlen函数,我们跟进看看。
继续跟进
发现最后来到了.got.plt段。这是一个可读可写的段,所以我们可以通过劫持这个strlen的内容为one gadget,让程序执行到puts的时候,调用的是ogg,从而getshell。
.got.plt段函数的规律
这里我们可以发现一个规律:
不难发现这些函数大部分都指向.plt.sec段,并且命名都有j_
开头。那么在实际做题的时候思路就很清晰了,我们可以去找我们要劫持的函数会不会调用到这样命名的函数,有的话就有机会通过劫持got表getshell。
劫持strlen后无法getshell
PoC中我并没有直接将strlen劫持为ogg,因为直接劫持是没办法getshell的。下面用一道其他题目的调试过程来展示这一点。
我们先来看ogg:
PoC中我们选择的是0xebc88,也就是说我们要让rsi和rdx都为NULL的情况下,这个ogg才能正常getshell。但是我们运行脚本会发现程序炸了,调试观察看住的地方,发现此时rdx并不为零。
那么我们就要想办法使rdx为0。当然这里调整ogg条件的方法不止一种,毕竟ogg不止这一个,还可以通过调栈的方法满足条件,这个具体视题目条件而定。
调整寄存器状态满足ogg条件
回到这里,其实PoC的情况和上述情况差不多,也是rdx不为0导致的程序出错。解决思路是,找到形如mov rdx , rsi; call xxx
这样的gadget,将其地址写入到strlen的got中,然后在xxx的got表中写入ogg地址。我们用ropper -f libc.so.6 -search "mov rdx, rsi"
找一下gadget。
发现有两条符合的gadget,但是上面那个gadget会导致rsi被改变为2,所以不能用。所以我们将0xb1788的gadget写到strlen的got中。在IDA中查看一下0x28670处,发现是memset的.plt.sec,因此我们只要将memset的got表改为ogg即可。顺带一提,下面那个gadget是explicit_bzero
函数中的。
于是就有了PoC那样的劫持步骤。
总结一下:
- 泄露libc地址
- 劫持
strlen
的got表,写入explicit_bzero
的gadget - 劫持
memset
的got表,写入one gadget - 执行puts函数getshell
实际题目中,我们要劫持的函数不一定是puts函数,可以是stack_chk_fail
或者其他的,只要调用了got表函数,能满足ogg条件,都能劫持。甚至为了满足ogg条件,可以凑一条调用链出来。