逆向心法修炼之道Flare-on 5Th WriteUP

逆向心法修炼之道

Minesweeper Championship Registration

提示

解题方法

  1. 下载附件文件。
  2. 密码“infected”解压缩,获得jar文件。
  3. 使用jd-gui进行反编译获得如下代码:
  4. 从反编译后的代码中可以看到需要的Flag(“GoldenTicket2018@flare-on.com”),输入正确后提示如下:

如果输入不正确会提示如下:

告诉你下一年再来参与吧。

Ultimate Minesweeper

提示

解题方法

  1. 下载附件文件。
  2. 密码“infected”解压缩,获得exe文件。
  3. 试运行程序如下:

从运行结果看这道题是一到排雷题,每行为30个,共30行,共900个占位,其中有897个为雷区,也就是说只有三个地方为非雷区。

  1. 用IDA检测程序为net程序。

  1. 使用dnspy打开程序MainForm类的SquareRevealedCallback方法,
// Token: 0x0600000C RID: 12 RVA: 0x00002348 File Offset: 0x00000548
        private void SquareRevealedCallback(uint column, uint row)
        {
            if (this.MineField.BombRevealed)   //这里判断是否为雷区
            {
                this.stopwatch.Stop();
                Application.DoEvents();
                Thread.Sleep(1000);
                new FailurePopup().ShowDialog();
                Application.Exit();
            }
            this.RevealedCells.Add(row * MainForm.VALLOC_NODE_LIMIT + column);
            if (this.MineField.TotalUnrevealedEmptySquares == 0)
            {
                this.stopwatch.Stop();
                Application.DoEvents();
                Thread.Sleep(1000);
                new SuccessPopup(this.GetKey(this.RevealedCells)).ShowDialog();
                Application.Exit();
            }
        }
  1. 查看BombRevealed的实现如下:
public bool BombRevealed
        {
            get
            {
                int num = 0;
                while ((long)num < (long)((ulong)this.Size))
                {
                    int num2 = 0;
                    while ((long)num2 < (long)((ulong)this.Size))
                    {
                        if (this.MinesPresent[num2, num] && this.MinesVisible[num2, num]) //这里不能让返回true,MinesPresent数组标识雷的分布,MinesVisible标识雷的显示,则此题可以通过在启动时修改MinesVisible数组的值全为1(显示)即可看到雷的分布。
                        {
                            return true;
                        }
                        num2++;
                    }
                    num++;
                }
                return false;
            }
        }
  1. 显示的雷区数据如下:

  1. 重新运行程序,点击三个8的地方即可弹出显示Flag的对话框如下:

FLEGGO

提示

解题方法

  1. 下载附件文件。
  2. 密码“infected”解压缩,获得一个文件夹其中包含了多个文件,大小相同。
  3. 拿出一个试运行如下:
H:\flare-on2018\03-FLEGGO\FLEGGO>1BpnGjHOT7h5vvZsV4vISSb60Xj3pX5G.exe

What is the password?

fsdfsd

Go step on a brick!
  1. IDA反编译程序,查看主函数如下:
int __cdecl main(int argc, const char **argv, const char **envp)

{

  ……

  if ( sub_401050() )

  {

    sub_401510((const char *)L"What is the password?\n");

    sub_4014C0((const char *)L"%15ls", &v4, 16);// input password!

    if ( checkWithDefaultPassword((const unsigned __int16 *)&v4) )// chek with default password

    {

      Decrypt_data(&v4);   //decrypt data

      if ( sub_401100() )     //write to file

      {

        sub_401510((const char *)L"Everything is awesome!\n");

        sub_401510((const char *)L"%s => %s\n", encode_png_name, KeyPart);

        result = (unsigned __int16)word_4043CA;

      }

      else

      {

        sub_401510((const char *)L"Oh look a rainbow.\n");

        result = -1;

      }

    }

    else

    {

      sub_401510((const char *)L"Go step on a brick!\n");

      result = -1;

    }

  }

  else

  {

    sub_401510((const char *)L"I super hate you right now.\n");

    result = -1;

  }

  return result;

}
  1. 进入到checkWithDefaultPassword函数即可看到默认要输入的密码如下:
BOOL __thiscall checkWithDefaultPassword(const unsigned __int16 *this)

{

  int v1; // eax

  BOOL result; // eax

  int v3; // kr00_4

v1 = wcscmp(this, L”IronManSucks”);     //这里有个密码,输入这个会多出Oh, hello Batman提示,还是密码无效,说明这个密码是不正确的。

  if ( v1 )

    v1 = -(v1 < 0) | 1;

  if ( v1 )

  {

    v3 = wcscmp(this, (const unsigned __int16 *)password); //看来这里就是默认密码的地方了

    if ( v3 )

      result = (-(v3 < 0) | 1) == 0;

    else

      result = 1;

  }

  else

  {

    sub_401510((const char *)L"Oh, hello Batman...\n");

    result = 0;

  }

  return result;

}
  1. 查看password的赋值位置,发现是从BRICK资源中获得的。
const void *sub_401050()

{

  const void *result; // eax



  result = sub_401000();

  if ( result )

  {

    memcpy(password, result, 0x8150u);

    result = (const void *)1;

  }

  return result;

}



LPVOID sub_401000()

{

  HRSRC v0; // eax

  HRSRC v1; // edi

  HGLOBAL v3; // eax

  LPVOID v4; // esi



  v0 = FindResourceW(0, (LPCWSTR)0x65, L"BRICK");

  v1 = v0;

  if ( !v0 )

    return 0;

  v3 = LoadResource(0, v0);

  if ( !v3 )

    return 0;

  v4 = LockResource(v3);

  if ( SizeofResource(0, v1) != 33104 )

    v4 = 0;

  return v4;

}

 

  1. 解密数据的部分
int __thiscall sub_4010B0(void *this)

{

  int v1; // esi



  v1 = (int)this;

  sub_401080(0x20u, (int)encode_png_name, 0x85);

  sub_401080(0xAu, (int)KeyPart, 0x1A);

  return sub_401660((int)&filelen, v1, Dst, (int)&filelen);

}



signed int __usercall sub_401080@<eax>(unsigned int len@<edx>, int key@<ecx>, char xorkey)

{

  unsigned int v3; // eax

  int v4; // esi

  char v5; // cl



  v3 = 0;

  v4 = key;

  if ( len )

  {

    do

    {

      v5 = *(_BYTE *)(v3 + v4);

      if ( v5 )

        *(_BYTE *)(v3 + v4) = xorkey ^ v5;    //这里将key进行异或操作

      ++v3;

    }

    while ( v3 < len );

  }

  return 1;

}

 

  1. 分析相应的赋值数据结构总结如下:

  1. 编写脚本如下:

  1. 运行脚本获得flag
FLEGGO>python ./GetFlag.py

mor3_awes0m3_th4n_an_awes0me_p0ssum@flare-on.com

binstall

提示

解题方法

  • 下载附件文件。
  • 密码“infected”解压缩,获得exe文件。
  • 题目提示此程序可能有害,建议在安装有firefox的虚拟机中运行,说明了程序依赖的环境。
  • 用IDA检测程序为net程序。
  • 用dnspy打开发现使用了ConfuserEx 1.0的混淆。

  • 使用de4dot对程序进行反混淆处理。

  • 处理之后用dnspy打开查看发现代码如下:

  • 分析主函数如下:
private static void Main()
    {
        Class5.smethod_7();
        //根据FireFox中的配置文件获取浏览器文件路径 %APPDATA%/MICROS~1\INTERN~1\BROWSE~1.DLL
        string text = Environment.ExpandEnvironmentVariables(<Module>.GetStringFromValue<string>(2599456470u));
        //从内部数据中释放文件
        Class5.ExtractToFile(text);
        StringBuilder stringBuilder = new StringBuilder(260);
        Class5.GetShortPathName(text, stringBuilder, stringBuilder.Capacity);
        //写入启动加载项目
        //HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\LoadAppInit_DLLs = 1
        //HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\RequireSignedAppInit_DLLs = 0
        //HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs = @"C:\Users\PUBLIC~1\AppData\Roaming\MICROS~1\INTERN~1\BROWSE~1.DLL"
        Class5.SetLoadValueInReg(stringBuilder.ToString());
    }
  • dll文件中检查dll注入进程是否为firefox.exe。

  • 下载加密的配置文件com/raw/hvaru8NU,解密配置文件。
  • 根据配置信息,当访问*flare-on.com时,进行在线的js注入(代码进行了简单的混淆)。
{

         "fg_blacklist": ["*ocsp*.*", "*telemetry.mozilla.org*", "*safebrowsing.google.com*", "*services.mozilla.com*"],

         "injects": [{

                   "content": [{

                            "code": "function readIn",

                            "after": "",

                            "before": "function cp(p){if(model.passwordEntered=!1,10===p.length&&123==(16^p.charCodeAt(0))&&p.charCodeAt(1)<<2==228&&p.charCodeAt(2)+44===142&&p.charCodeAt(3)>>3==14&&p.charCodeAt(4)===parseInt(function(){var h=Array.prototype.slice.call(arguments),k=h.shift();return h.reverse().map(function(m,W){return String.fromCharCode(m-k-24-W)}).join(\"\")}(50,124)+4..toString(36).toLowerCase(),31)&&p.charCodeAt(5)-109==-22&&64==(p.charCodeAt(3)<<4&255)&&5*p.charCodeAt(6)===parseInt(function(){var n=Array.prototype.slice.call(arguments),M=n.shift();return n.reverse().map(function(r,U){return String.fromCharCode(r-M-16-U)}).join(\"\")}(22,107)+9..toString(36).toLowerCase(),19)&&p.charCodeAt(7)+14===\"xyz\".charCodeAt(1)&&3*(6*(p.charCodeAt(8)-50)+14)==17+parseInt(function(){var l=Array.prototype.slice.call(arguments),f=l.shift();return l.reverse().map(function(O,o){return String.fromCharCode(O-f-30-o)}).join(\"\")}(14,93)+6..toString(36).toLowerCase(),8)-1+12&&3+(p.charCodeAt(9)+88-1)/2===p.charCodeAt(0))model.root=1,model.password=p;else{model.password=\"\";var $err=$(function(){var Q=Array.prototype.slice.call(arguments),r=Q.shift();return Q.reverse().map(function(A,B){return String.fromCharCode(A-r-23-B)}).join(\"\")}(35,124,179,165,159,118)+12..toString(36).toLowerCase().split(\"\").map(function(w){return String.fromCharCode(w.charCodeAt()+-39)}).join(\"\")+function(){var S=Array.prototype.slice.call(arguments),t=S.shift();return S.reverse().map(function(K,I){return String.fromCharCode(K-t-8-I)}).join(\"\")}(43,172,158,152,98)+14..toString(36).toLowerCase().split(\"\").map(function(p){return String.fromCharCode(p.charCodeAt()+-39)}).join(\"\")).attr(function(){var k=Array.prototype.slice.call(arguments),m=k.shift();return k.reverse().map(function(N,G){return String.fromCharCode(N-m-41-G)}).join(\"\")}(29,179,169)+388..toString(36).toLowerCase()+function(){var j=Array.prototype.slice.call(arguments),p=j.shift();return j.reverse().map(function(D,w){return String.fromCharCode(D-p-61-w)}).join(\"\")}(63,239),12..toString(36).toLowerCase()+function(){var C=Array.prototype.slice.call(arguments),A=C.shift();return C.reverse().map(function(Q,s){return String.fromCharCode(Q-A-0-s)}).join(\"\")}(21,129)+18..toString(36).toLowerCase()).text(function(){var H=Array.prototype.slice.call(arguments),N=H.shift();return H.reverse().map(function(S,m){return String.fromCharCode(S-N-30-m)}).join(\"\")}(12,164,164,111,77,102,160,157)+(0x647e0f7a957f0).toString(36).toLowerCase()+23..toString(36).toLowerCase()+function(){var d=Array.prototype.slice.call(arguments),C=d.shift();return d.reverse().map(function(p,M){return String.fromCharCode(p-C-18-M)}).join(\"\")}(9,135,126,130,59)+786..toString(36).toLowerCase()+function(){var h=Array.prototype.slice.call(arguments),l=h.shift();return h.reverse().map(function(e,v){return String.fromCharCode(e-l-61-v)}).join(\"\")}(20,183,195));$(function(){var u=Array.prototype.slice.call(arguments),n=u.shift();return u.reverse().map(function(b,p){return String.fromCharCode(b-n-47-p)}).join(\"\")}(28,186,175,110)+13..toString(36).toLowerCase()+29..toString(36).toLowerCase().split(\"\").map(function(m){return String.fromCharCode(m.charCodeAt()+-71)}).join(\"\")+function(){var d=Array.prototype.slice.call(arguments),F=d.shift();return d.reverse().map(function(S,u){return String.fromCharCode(S-F-10-u)}).join(\"\")}(8,121,130,124,137)+896..toString(36).toLowerCase()).append($err)}view.addCmd()}"

                   }, {

                            "code": "changeDir( val, tab, $input );",

                            "after": "else if(val.substr(0, 2) === 'su') view.askPassword(); else if(model.passwordEntered) {cp($input.val())}",

                            "before": ""

                   }, {

                            "code": "} else if( model.dirList[dir] ) {",

                            "after": "",

                            "before": "} else if ( dir === (function(){var Q=Array.prototype.slice.call(arguments),f=Q.shift();return Q.reverse().map(function(M,m){return String.fromCharCode(M-f-50-m)}).join('')})(57,214)+(14).toString(36).toLowerCase()+(function(){var B=Array.prototype.slice.call(arguments),N=B.shift();return B.reverse().map(function(q,J){return String.fromCharCode(q-N-36-J)}).join('')})(59,216) && model.root === 1) {model.prevDir = model.curDir;model.curDir = (function(){var Y=Array.prototype.slice.call(arguments),e=Y.shift();return Y.reverse().map(function(g,p){return String.fromCharCode(g-e-63-p)}).join('')})(36,174)+(14).toString(36).toLowerCase()+(function(){var k=Array.prototype.slice.call(arguments),S=k.shift();return k.reverse().map(function(E,C){return String.fromCharCode(E-S-33-C)}).join('')})(29,183);view.addCmd();"

                   }, {

                            "code": "var rendered = Mustache.render( $( template ).filter( '#' + tmplt ).html(), vars );",

                            "after": "if (model.root === 1)rendered = rendered.replace('user', 'root').replace('$', '#');",

                            "before": ""

                   }],

                   "path": "/js/controller.js",

                   "host": "*flare-on.com"

         }, {

                   "content": [{

                            "code": "prevDir: '~',",

                            "after": "root : -1, password : '', passwordEntered : false,",

                            "before": ""

                   }],

                   "path": "/js/model.js",

                   "host": "*flare-on.com"

         }, {

                   "content": [{

                            "code": "function lsDir() {",

                            "after": "",

                            "before": "function askPassword(){model.curIndex++,model.lastValIndex=0;var $code=$('<div class=\"cli\">Password: <input type=\"password\" id=\"command_'+model.curIndex+'\"></input></div>');model.passwordEntered=!0,$(\"#cmd-window\").append($code),$(\"#command_\"+model.curIndex).focus(),$(\"#command_\"+model.curIndex).select()}\tfunction de(instr){for(var zzzzz,z=model.password,zz=atob(instr),zzz=[],zzzz=0,zzzzzz=\"\",zzzzzzz=0;zzzzzzz<parseInt(\"CG\",20);zzzzzzz++)zzz[zzzzzzz]=zzzzzzz;for(zzzzzzz=0;zzzzzzz<parseInt(\"8O\",29);zzzzzzz++)zzzz=(zzzz+zzz[zzzzzzz]+z.charCodeAt(zzzzzzz%z.length))%parseInt(\"8G\",30),zzzzz=zzz[zzzzzzz],zzz[zzzzzzz]=zzz[zzzz],zzz[zzzz]=zzzzz;for(var y=zzzz=zzzzzzz=0;y<zz.length;y++)zzzz=(zzzz+zzz[zzzzzzz=(zzzzzzz+1)%parseInt(\"514\",7)])%parseInt(\"213\",11),zzzzz=zzz[zzzzzzz],zzz[zzzzzzz]=zzz[zzzz],zzz[zzzz]=zzzzz,zzzzzz+=String.fromCharCode(zz.charCodeAt(y)^zzz[(zzz[zzzzzzz]+zzz[zzzz])%parseInt(\"D9\",19)]);return zzzzzz}"

                   }, {

                            "code": "view.printOut( 'home_list' );",

                            "after": "else if (d === (27).toString(36).toLowerCase().split('').map(function(A){return String.fromCharCode(A.charCodeAt()+(-39))}).join('')+(function(){var E=Array.prototype.slice.call(arguments),O=E.shift();return E.reverse().map(function(s,j){return String.fromCharCode(s-O-52-j)}).join('')})(7,160)+(34).toString(36).toLowerCase()) {$( '#cmd-window' ).append( de((function(){var A=Array.prototype.slice.call(arguments),f=A.shift();return A.reverse().map(function(E,v){return String.fromCharCode(E-f-22-v)}).join('')})(1,89,97,142,140,107,157,88,124,107,150,142,134,145,110,125,98,148,98,136,126)+(23).toString(36).toLowerCase().split('').map(function(S){return String.fromCharCode(S.charCodeAt()+(-39))}).join('')+(16201).toString(36).toLowerCase()+(1286).toString(36).toLowerCase().split('').map(function(v){return String.fromCharCode(v.charCodeAt()+(-39))}).join('')+(10).toString(36).toLowerCase().split('').map(function(p){return String.fromCharCode(p.charCodeAt()+(-13))}).join('')+(function(){var V=Array.prototype.slice.call(arguments),P=V.shift();return V.reverse().map(function(i,f){return String.fromCharCode(i-P-11-f)}).join('')})(59,171,202,183,197,149,166,148,129,184,145,176,149,174,183)+(2151800446).toString(36).toLowerCase()+(515).toString(36).toLowerCase().split('').map(function(Z){return String.fromCharCode(Z.charCodeAt()+(-13))}).join('')+(30).toString(36).toLowerCase().split('').map(function(G){return String.fromCharCode(G.charCodeAt()+(-39))}).join('')+(24).toString(36).toLowerCase()+(28).toString(36).toLowerCase().split('').map(function(W){return String.fromCharCode(W.charCodeAt()+(-39))}).join('')+(3).toString(36).toLowerCase()+(1209).toString(36).toLowerCase().split('').map(function(u){return String.fromCharCode(u.charCodeAt()+(-39))}).join('')+(13).toString(36).toLowerCase().split('').map(function(U){return String.fromCharCode(U.charCodeAt()+(-13))}).join('')+(652).toString(36).toLowerCase()+(16).toString(36).toLowerCase().split('').map(function(l){return String.fromCharCode(l.charCodeAt()+(-13))}).join('')+(function(){var D=Array.prototype.slice.call(arguments),R=D.shift();return D.reverse().map(function(L,H){return String.fromCharCode(L-R-50-H)}).join('')})(36,159,216,151,203,175,206,210,138,180,195,136,166,155)) );view.addCmd();}",

                            "before": ""

                   }, {

                            "code": "addCmd : addCmd,",

                            "after": "askPassword : askPassword,",

                            "before": ""

                   }],

                   "path": "/js/view.js",

                   "host": "*flare-on.com"

         }]

}
  • 注入代码的主要功能是给flare-on.com的MVC(Model/View/Control)框架添加功能代码。
    1. 执行命令su。
    2. 通过调用View层的askPassword函数,获取用户输入密码。
    3. 调用cp比较输入密码是否正确(k9btBW7k2y),密码正确时设置password为正确的密码。
    4. 执行“cd Key”命令及进行解密(base64 + rc4)。
    5. 执行ls命令显示Flag。

web2.0

提示

解题方法

  • 下载附件文件。
  • 密码“infected”解压缩,获得html、main.js、test.wasm三个文件。
  • html的代码如下:

  • 对html的代码分析发现其中调用了main.js文件,main.js关键代码如下:
let instance = null;

……

fetch("test.wasm").then(response =>                                                           

  response.arrayBuffer()

).then(bytes =>

  WebAssembly.instantiate(bytes, {                                  //实例化

    env: {

      /*

       * WASMCEPTION libc.a relies on the symbols for FPU,

       * but we don't really need them...

       **/

      __eqtf2: function() {},

      __multf3: function() {},

      __unordtf2: function() {},

      __addtf3: function() {},

      __eqtf2: function() {},

      __multf3: function() {},

      __subtf3: function() {},

      __netf2: function() {},

      __fixunstfsi: function() {},

      __floatunsitf: function() {},

      __fixtfsi: function() {},

      __floatsitf: function() {},

      __extenddftf2: function() {},



      /* trampoline to our js syscall handlelr */

      __syscall0: function __syscall0(n) { return syscall(instance, n, []); },

      __syscall1: function __syscall1(n, a) { return syscall(instance, n, [a]); },

      __syscall2: function __syscall2(n, a, b) { return syscall(instance, n, [a, b]); },

      __syscall3: function __syscall3(n, a, b, c) { return syscall(instance, n, [a, b, c]); },

      __syscall4: function __syscall4(n, a, b, c, d) { return syscall(instance, n, [a, b, c, d]); },

      __syscall5: function __syscall5(n, a, b, c, d, e) { return syscall(instance, n, [a, b, c, d, e]); },

      __syscall6: function __syscall6(n, a, b, c, d, e, f) { return syscall(instance, n, [a, b, c, d, e, f]); },



      putc_js: function (c) {

        c = String.fromCharCode(c);

        if (c == "\n") {

          console.log(wasm_stdout);

          wasm_stdout  = "";

        } else {

          wasm_stdout += c;

        }

      }

    }

  })

).then(results => {

    instance = results.instance;



    let a = new Uint8Array([

        0xE4, 0x47, 0x30, 0x10, 0x61, 0x24, 0x52, 0x21, 0x86, 0x40, 0xAD, 0xC1, 0xA0, 0xB4, 0x50, 0x22, 0xD0, 0x75, 0x32, 0x48, 0x24, 0x86, 0xE3, 0x48, 0xA1, 0x85, 0x36, 0x6D, 0xCC, 0x33, 0x7B, 0x6E, 0x93, 0x7F, 0x73, 0x61, 0xA0, 0xF6, 0x86, 0xEA, 0x55, 0x48, 0x2A, 0xB3, 0xFF, 0x6F, 0x91, 0x90, 0xA1, 0x93, 0x70, 0x7A, 0x06, 0x2A, 0x6A, 0x66, 0x64, 0xCA, 0x94, 0x20, 0x4C, 0x10, 0x61, 0x53, 0x77, 0x72, 0x42, 0xE9, 0x8C, 0x30, 0x2D, 0xF3, 0x6F, 0x6F, 0xB1, 0x91, 0x65, 0x24, 0x0A, 0x14, 0x21, 0x42, 0xA3, 0xEF, 0x6F, 0x55, 0x97, 0xD6



        //0xB6, 0xFF, 0x65, 0xC3, 0xED, 0x7E, 0xA4, 0x00,

        //                     0x61, 0xD3, 0xFF, 0x72, 0x36, 0x02, 0x67, 0x91,

        //0xD2, 0xD5, 0xC8, 0xA7, 0xE0, 0x6E

    ]);



    let b = new Uint8Array(new TextEncoder().encode(getParameterByName("q")));           //编码输入的参数



    let pa = wasm_alloc(instance, 0x200);

    wasm_write(instance, pa, a);



    let pb = wasm_alloc(instance, 0x200);

    wasm_write(instance, pb, b);



    if (instance.exports.Match(pa, a.byteLength, pb, b.byteLength) == 1) {      //验证输入的参数

        // PARTY POPPER

        document.getElementById("container").innerText = "🎉";

    } else {

        // PILE OF POO

        document.getElementById("container").innerText = "💩";

    }

});

 

  • 红色标注的地方是关键内容,搭建服务器,利用浏览器调试wasm代码,可以找到关键的地方。

  • 发现输入的字符串和正确的字符串进行比较,这个程序有个bug,就是在比较完后才统一返回结果,而不是比较一位发现不相同就返回。经过调试就可以发现flag为“wasm_rulez_js_droolz@flare-on.com”。
  • 当然也可以通过调试分析WASM的虚拟机代码结构,相对也比较简单,从而编写如下脚本获得Flag。
code =        [0xE4, 0x47, 0x30, 0x10, 0x61, 0x24, 0x52, 0x21, 0x86, 0x40, 0xAD, 0xC1, 0xA0, 0xB4, 0x50,

                    0x22, 0xD0, 0x75, 0x32, 0x48, 0x24, 0x86, 0xE3, 0x48, 0xA1, 0x85, 0x36, 0x6D, 0xCC, 0x33,

                    0x7B, 0x6E, 0x93, 0x7F, 0x73, 0x61, 0xA0, 0xF6, 0x86, 0xEA, 0x55, 0x48, 0x2A, 0xB3, 0xFF,

                    0x6F, 0x91, 0x90, 0xA1, 0x93, 0x70, 0x7A, 0x06, 0x2A, 0x6A, 0x66, 0x64, 0xCA, 0x94, 0x20,

                    0x4C, 0x10, 0x61, 0x53, 0x77, 0x72, 0x42, 0xE9, 0x8C, 0x30, 0x2D, 0xF3, 0x6F, 0x6F, 0xB1,

                    0x91, 0x65, 0x24, 0x0A, 0x14, 0x21, 0x42, 0xA3, 0xEF, 0x6F, 0x55, 0x97, 0xD6]



index = 0

flag = ""



while  index < 88:

         vcode = code[index] & 15

         if vcode == 0:

                   flag += chr(code[index+1] & 0xFF)

                   index += 2

         elif vcode == 1:

                   flag += chr((code[index+1] ^ 0xFF) & 0xFF)

                   index += 2

         elif vcode == 2:

                   flag += chr((code[index+1] ^ code[index+2]) & 0xFF)

                   index += 3

         elif vcode == 3:

                   flag += chr((code[index+1] & code[index+2]) & 0xFF)

                   index += 3

         elif vcode == 4:

                   flag += chr((code[index+1] | code[index+2]) & 0xFF)

                   index += 3

         elif vcode == 5:

                   flag += chr((code[index+1] + code[index+2]) & 0xFF)

                   index += 3

         elif vcode == 6:

                   flag += chr((code[index+2] - code[index+1]) & 0xFF)

                   index += 3



print "Flag is : " + flag
  • 运行脚本如下:
$ python ./getFlag.py

Flag is : wasm_rulez_js_droolz@flare-on.com

magic

提示

解题方法

  • 下载附件文件。
  • 密码“infected”解压缩,获得magic文件。
  • 利用file命令查看文件类型。
$ file magic

magic: 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]=0d9c0c6c6a7f6b7189ce4758d112c25e48effe87, stripped
  • 程序为64位linux x86-64可执行程序。
  • 查看主函数关键代码:

  • 查看VerifyInput_402DCF函数关键代码如下。

  • 根据代码可以分析出如下的数据结构。
struct check_block_config

{

       qword *encode_check_code;             //加密的输入检查代码

       qword code_len;                               //代码长度

       qword data_offset;                            //校验的数据偏移

       qword data_len;                                //校验的数据长度

       qword data_offset_at_template;          //数据在模板中的位置

       qword *decode_xor_key;                   //解密代码的key

       char encode_data[0x100];                  //最终的校验值

} check_code[32]
  • 通过调试分析发现如下结论。
    1. template为:“Ah, there is nothing like the hot winds of Hell blowing in your face.“。
    2. template被分成32组,分组校验。
    3. encode_data保存最终校验的值。
    4. 解密后的验证函数有7中,分别为斐波那契数列,crc32,base64,数组变换+xor_swap+xor,字符异或,字符相等,字符偏移。
    5. 每当输入key正确之后,将key与保存的数据进行异或解密。
    6. 更新原始程序的配置数据结构(666次)。
    7. 最终flag需要使用666个key与保存的数据进行异或解密。
  • 了解了执行原理之后,就可以编写如下代码进行自动解密获得所有的输入key。

  • 将所有的key进行异或操作获得最终的flag。

  • 运行脚本,获得的Flag如下:

wom

提示

解题思路

  • 下载附件文件。
  • 密码“infected”解压缩,获得exe文件。
  • 这个文件为一个windows下的可执行文件,查看主函数如下:

  • 这里加载的内容记作s0.dll,其功能如下:
    1. 加载crackme.dll。
    2. 查找预先设置的opcode(0xDEEDEEB),劫持WorldOfWarcraft的执行流程到crackme.dll的hijack_10001220(查找crackme.dll中设置的opcode 0xFACEFACE定位该函数)。
    3. Hook NtDeviceIoControlFile函数指定功能:IOCTL_AFD_BIND,IOCTL_AFD_CONNECT,IOCTL_AFD_RECV,IOCTL_AFD_SET_CONTEXT,IOCTL_AFD_GET_INFO。

 

  • crackme.dll的功能。
    1. 初始化网络操作。
    2. 接受用户输入数据。
    3. 执行connect -> NtDeviceIoControlFile -> IOCTL_AFD_CONNECT。
    4. 解密flag数据并输出。
  • 通过分析connect_10003018执行如下脚本获取flag。

  • 运行脚本获取Flag为“P0rt_Kn0ck1ng_0n_he4v3ns_d00r@flare-on.com”。

Doogie Hacker

提示

解题方法

  • 下载附件文件。
  • 密码“infected”解压缩,获得bin文件。
  • 使用file命令查看文件类型。
$ file doogie.bin

doogie.bin: DOS/MBR boot sector
  • 从分析的结果应该是个MBR的程序,用虚拟机加载运行如下:

  • 这里需要输入密码,通过双机调试发现使用了两组Key进行数据解密,第一组为提示中的日期,第二组为用户输入的password, 这个password是需要破解的。解密算法采用的是按照key的长度进行分组异或,通过测试确认最终key的长度为17,使用如下脚本破解password为“ioperateonmalware”。

  • 输入密码后显示的ASCII art 如下,即为Flag(‘R3_PhD@flare-on.com’)。

leet editr

提示

解题方法

  • 下载附件文件。
  • 密码“infected”解压缩,获得exe文件。
  • 通过file命令查看文件类型。
$ file leet_editr.exe

leet_editr.exe: PE32 executable (GUI) Intel 80386, for MS Windows
  • 发现为32位windows 程序。使用IDA打开查看一下主函数。
  • 程序为每一段数据分配独立的内存空间,并将内存属性设置为PAGE_NOACCESS
  • 增加向量化异常处理函数。

  • 执行main shellcode,触发STATUS_ACCESS_VIOLATION异常,将对应字节码内存设置为PAGE_EXECUTE_READWRITE解密相应的字节码。

  • 执行解密后的字节码触发STATUS_SINGLE_STEP异常,再次加密相应的字节码。(防止通过运行dump恢复程序代码)。
  • 配置IScriptModule结构。

  • ExecuteStatement_3B19F0代码功能。

  • Invoke _3B1B30根据返回值,执行特定函数的功能代码。

  • 6段shellcode通过xor 0xfe进行解密。
    • 主shellcode功能(对应代码长度0x3c5):初始化,配置脚本运行环境,设置相关参数(ScriptModule),运行解密后的脚本。
    • 其他的shellcode分别负责:定位模块,定位函数等功能。
  • 通过如下代码解密获得crouching_vbs_hidden_title.asm。

  • crouching_vbs_hidden_title.asm的内容如下:

  • crouching_vbs_hidden_title.asm功能代码如下:

  • 针对crouching_vbs_hidden_title.asm的main函数进行分析,解密数据需要用的KEY包含两部分:ascii(textin) + title,根据约束条件很容易找到textin和title的正确值。title提示包含在其中一段主要负责加载运行vbs的shellcode中(对应代码长度0x3c5),内容为:If I were to title this piece, it would be ‘A_FLARE_f0r_th3_Dr4m4t1(C)’,

textin包含在crouching_vbs_hidden_title.asm中,内容为:

  • 程序运行环境检测代码PetMeLikeATurtle如下:

  • 直接patch原始的文件运行。

  • 输入正确的textin和title执行gimmeThatSweetSweetCrazyLove函数解密flag。

  • 转换成文本为’scr1pt1ng_sl4ck1ng_and_h4ck1ng@flare-on.com‘。

golf

提示

解题方法

  • 下载附件文件。
  • 密码“infected”解压缩,获得exe文件。
  • 运行程序结果如下:
>golf.exe

Too bad so saddd fffffffe
  • 查看main函数,关键功能如下:

  • 程序要求输入参数长度为24个,同时释放并安装驱动sys,之后对输入的内容分成四个部分进行算法验证。
  • Fhv,sys会检测CPU环境是否开启了Intel VT功能,然后创建虚拟机(参考:https://bbs.pediy.com/thread-144656.htm)。

  • 设置虚拟机事件处理函数。

  • vmcall_handler_140003810处理应用层vmcall指令调用。

  • 应用层调用vmcall。

  • VMX_EXIT_EPT_VIOLATION调用虚拟机VM_CMD_1400023AC函数检查数据。

  • 虚拟机的功能为解析虚拟指令,检查输入数据是否正确。虚拟机实现比较复杂,但该程序的虚拟指令仅仅使用了部分功能,同时作者进行分类,降低了分析的难度,检查输入数据的代码逻辑如下:

  • 经过使用代码暴力分析获得flag为(’We4r_ur_v1s0r_w1th_Fl4R3@flare-on.com‘)。

malware skillz

提示

解题方法

  • 下载附件文件.
  • 密码“infected”解压缩,获得可执行文件exe和网络数据包文件pcap.pcap。
  • 提示中已经说明这个是一个恶意文件,所以分析需要在虚拟机中进行并关闭杀毒软件。
  • 经过IDA分析发现exe使用Delphi语言编写。

  • 查看入口函数如下:

  • 查看run_shellcode_41083C函数,关键代码如下:

  • 函数中解密shellcode,并进行调用执行。shellcode的主要功能是通过dns通道下载文件并进行解密。

修复IAT代码如下:

DNS通道获取数据如下:

  • 解密数据的算法如下

  • 解密后的数据为一个动态库,之后加载运行。通过如下代码提取DNS TXT完整的payload。

  • 解密下载模块,执行主模块的Shiny函数(PELoader)。

  • 加载主模块后,执行DllEntryPoint函数。

  • 从这里可以看到此题和去年的最后一题比较相似。MainPlugx主要初始化并加载cypt,comp,hmac,hash,rand 等6个插件。

  • 与服务器相互交换加密key(len=0x30)。

  • 查看c:\work\flareon2018\Challenge09\README.md。

  • 根据提示通过暴力破解的方法时不可行的,则通过利用smb渗透larryjohnson-pc主机。

  • 利用smb协议传输c&c数据包。

  • 使用exe加密level9.zip,之后删除原始文件,利用ftp上传加密后的文件level9.crypt到攻击者控制的服务器。
  • level9.crypt的数据如下:

  • Cryptor.exe算法(AES算法),这里需要注意的是解密程序的版本。
  • 通过如下代码解密数据获得level9.zip。

  • zip中的文件如下:

  • 利用获取的密码(really_long_password_to_prevent_cracking)解压zip文件。
  • 其中的level9.png进行了数据处理(图片隐写),使用stegsolve查看图片,获取最终flag。

 

Suspicious Floppy Disk

提示

解题方法

1      下载附件文件。

2      解压缩文件。

密码“infected”解压缩,获得软盘镜像文件suspicious_floppy_v1.0.img。

3      基础知识

  1. Bootkit发展历史简介:eEyeBootRoot、vBootkit、Stoned Bootkit、DreamBoot等。
  2. 44Mb软盘格式。

参考:https://blog.csdn.net/guzhou_diaoke/article/details/8436037

公式:floppy_addr = (36 * ch + 18 * dh + cl – 1) * 512

  1. TMP.DAT

cx = 0x2201   dh = 0

TMP_DAT_addr = (36 * 0x22 + 18 * 0 + 0x1 – 1) * 512 = 0x99000

  1. key.dat

cx = 0x2110   dh=0x01

key_dat_addr = (36 * 0x21 + 18 * 0x01 + 0x10 – 1) * 512 = 0x98a00

  • message.dat

cx = 0x2111   dh = 0x01

message_dat_addr = (36 * 0x21 + 18 * 0x01 + 0x11 – 1) * 512 = 0x98c00

4       加载mbr启动

  1. 复制mbr代码到0x600空间,执行0x662(sub_7c62)代码。
  2. 加载hook代码,hook int 0x13 中断,加载解密原始的mbr,并执行。
    1. Hook int 0x13中断。
    2. 加载原始mbr(0xa00),解密后执行原始的mbr。
  • 确定原始mbr为如下的MSWIN4.1系统代码。

https://github.com/angea/corkami/blob/master/misc/mbr/mswin41.asm

https://thestarman.pcministry.com/DOS/WinXPSD.md5deep.TXT

5      启动系统执行程序

引导启动mswin4.1系统,执行AUTOEXEC.BAT à infohelp.exe。

  1. exe 接受用户输入的数据key。
  2. 将用户输入的key写入到dat,写入长度固定为0x200。

写key.dat的软盘位置:

int 0x13,ah=3,cx=0x2110,dh=0x1
  1. 读取dat的数据输出到屏幕上;(This is not the message you are looking for.)。

读message.dat的软盘位置:

int 0x13,ah=2,cx=0x2111,dh=0x1

6      hook代码解读

  1. 写dat的操作(文件位置cx=0x2110)执行hook代码,将输入的数据复制到内核空间。
  2. 读message.dat的操作(文件位置cx=0x2111)执行hook代码,检查密码是否正确。

  1. 密码校验代码的实现(NICK RULES虚拟机),通过重写虚拟机引擎,输出操作日志。
    1. 虚拟机引擎。
    2. 虚拟机核心操作。

7       虚拟机日志分析

输入日志量比较多,分析后,可以发现其内部嵌套了另外一层虚拟机.

这里没有必要再去重新第二层虚拟机,直接在第一层基础之上,给关键操作下断点,解析第二层虚拟机的真实数据操作。

通过对比可以发现日志量经过优化后明显减少。

8       日志分析

分析日志和测试发现:

  1. 检查输入key中是否包含@,否则不进行数据校验。
  2. 对输入的数据每两位进行hash计算(即任何不同输入的计算结果都有唯一性),最终结果与程序中存储的正确值比较。
  3. 输入数据长度为30字节,包含15组正确值。
  4. 输入数据@字符之前的数据和,会影响计算比较的结果。
  5. flag的已知部分@flare-on.com。
  6. 获取sum正确的值(@字符之前数据的和),下面提供两种思路。
    1. 利用@后面的已知字符对(flare-on.com)来爆破sum值(6组),获取正确的sum值为0x55e。
    2. 计算获取正确的sum。
hash(“fl”) + sum – 0x3400 = 0xf8cd;hash(“fl”) = 0x276f,计算sum = 0x55e。

  1. 按照每两位进行爆破,在最终数据比较点下断点,若输入数据运算的hash值与程序中保存的正确hash值都匹配成功(9组),则爆破成功。
  2. 9组hash值完全匹配,既爆破成功。

注意:由于sum参与了运算,爆破过程中要通过给最终比较的两个值,同时减去当前的sum和正确的sum来保证比较结果的有效性)

9       瑕不掩瑜:BUG

由于最终的结果校验机制不完善,导致程序的密码不唯一,在输入非正确flag的情况下,程序输出结果为“Password Matched”。

但是通过分析数据,可以排除其他组答案。

结局

挑战赛共计12道题目,历时40天时间。当所有的挑战通过后会提示如下:

也就是填写领奖信息了。到这里感谢所有参与的人,同时也希望在本次的挑战赛中收获到的不仅仅是前所未知的知识,更重要的是再次对自己的挑战与超越,未来将会越来越好,期待下一年的更上一层楼。

Spread the word. Share this post!

Meet The Author

Leave Comment