Flare-On 2018 writeup(上)

栏目: 数据库 · 发布时间: 6年前

内容简介:重构输出得到(28, 7),(7, 20),(24, 28)三个坐标点,依次点击显示flag

Flare-On 2018 writeup(上)

Ultimate Minesweeper

donet写的扫雷程序,找到正确的安全位置点击,雷区map的布置藏在下面的代码中

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

重构输出得到(28, 7),(7, 20),(24, 28)三个坐标点,依次点击显示flag

mine = []
vtypes = [-896,-639,-270]
for i in range(30):
    mine.append([])
    for j in range(30):
        flag = True
        r = i + 1
        c = j + 1
        if ~((r * 30) + c) in vtypes:
            flag = False
            print 'x',j,'y',i

Flare-On 2018 writeup(上)

FLEGGO

解压得到48个程序,模式一模一样,可以通过脚本批量取出各个程序的key,输入正确的key后,echo几个字符并得到一张乐高图片

Flare-On 2018 writeup(上)

import os
from subprocess import *

output = ''
pngtxt = ''

for dirpath,dirnames,filenames in os.walk('FLEGGO'):
    for file in filenames:
        pathname = os.path.join(dirpath,file)
        if pathname[-4:] == '.exe':
            txt = open(pathname,'rb').read()
            head = txt.find('\x42\x00\x52\x00', 6500) + 14
            tail = txt.find('\x00\x00', head)
            pw = txt[head:tail:2]
            output = output + pathname + '\t' + pw + '\n'
            p = Popen(pathname,stdin=PIPE,stdout=PIPE)
            p.stdin.write(pw + '\n')
            p.stdin.flush()
            p.stdout.readline()
            p.stdout.readline() 
            pngtxt = pngtxt + p.stdout.readline() + '\n'
open('res.txt','w+').write(output)

对图片根据内容进行标号,然后将得到的字符按图片标号顺序连接即flag

Flare-On 2018 writeup(上)

pngdat = []
for i in range(48):
    pngdat.append(open('png\\%02d.png'%(i+1),'rb').read())
pngarr = pngtxt.split('\n')
for p in pngarr:
    pinfo = p.split(' ')
    pngd = open('FLEGGO\\%s'%(pinfo[0]),'rb').read()
    print str(pngdat.index(pngd)) + '\t' + str(pinfo[1])

mor3_awes0m3_th4n_an_awes0me_p0ssum@flare-on.com

binstall

donet程序,会删除浏览器缓存,修改注册表,然后释放browserassist.dll文件

Flare-On 2018 writeup(上)

这个dll文件会下载了一段加密的数据,解密后得到一个js文件

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

通过cp()函数中的判断式推出密码为k9btBW7k2y,根据密码调用js中的de()函数得到flag

function cp(p) { //get password
    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, console.log(p) ;
    else {
        ……省略一万字
}

function de(instr) { //de code flag
    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
}

根据js中的等式推测出password= k9btBW7k2y,然后执行de(..)函数

Flare-On 2018 writeup(上)

web 2.0

wasm,可以由chrome调试

github下载wabt将wasm转换为wat文件,S字节码,非常类似JVM字节码时刻都在入栈、出栈。

编写watHelper脚本解析函数块,思路是记录指令操作的栈影响,然后还原出代码(遇到function call出入栈数量要根据函数类型决定)

watHelper部分代码如下

Flare-On 2018 writeup(上) Flare-On 2018 writeup(上)

分析后的函数关键位置下bp即可偷flag字节

Flare-On 2018 writeup(上) Flare-On 2018 writeup(上)

Magic

Flare-On 2018 writeup(上) 666轮checkkey通过后可以得到flag

sub_4037BF在每轮通过后改变自身程序,改变decoder和分段check函数

Flare-On 2018 writeup(上)

由decoder[33]将一轮的key分33段检查,每段的检查函数需要pFunc ^ pFunXorArr解密,并且每一轮decoder的内容、pFunc、pFunXorArr内存区的内容都将被改变

Flare-On 2018 writeup(上) getkey程序将magic当前轮的decoder和funcArr、funcXorArr加载在本地然后进行爆破(每个片段最大为3个Ascii)

Flare-On 2018 writeup(上) 爆破流程

Flare-On 2018 writeup(上) 在call ram前对stack进行清空,否则有些函数内未对所有局部变量初始化会造成和源程序执行的结果不同

Flare-On 2018 writeup(上) pwntools进行多轮爆破

Flare-On 2018 writeup(上) mag!iC_mUshr00ms_maY_h4ve_g!ven_uS_Santa_ClaUs@flare-on.com

WOW

Flare-On 2018 writeup(上)

程序xor和alloc载入dll资源

然后修改cs: 33h执行载入的x64 dll中的api,由于经过x86和x64的来回切换需要使用windbg调试

Flare-On 2018 writeup(上)

来到s0.dll,由于不是正常的loadlibrary加载的,所以全局偏移实际是文件偏移载入内存的并不是以PE描述偏移载入,导致直接运行会因为访问越界的全局量而奔溃

Flare-On 2018 writeup(上)

意味着使用到全局变量的地方crackme_dll,crack_len需要断点修改实际地址

函数会再次alloc并加载crackme.dll,x86 dll,通过结束前覆盖return stack执行到crackme中的函数

Flare-On 2018 writeup(上)

crackme.dll中的主要逻辑利用了socket通讯获取flag,但crackme本身并没藏有flag,回到s0.dll

Flare-On 2018 writeup(上)

s0中hook了crackme的socket driver

Flare-On 2018 writeup(上) 关键函数是被hook的相关函数

重构flag脚本

t_6b40 = [0x0F,0x57,0x61,0x77,0x0B,0xFA,0xB5,0xD1,0x81,0x99,0xAC,0xA7,0x90,0x58,0x1A,0x52,0x0C,0xA0,0x08,0x2D,0xED,0xD5,0x6D,0xE7,0xE0,0xF2,0xBC,0xE9,0xF2]
t_6bb8 = [0x5F,0x68,0x44,0x62,0x23,0xBA,0x21,0x54,0x33,0x73,0x04,0x65,0x50,0x97,0x72,0x26,0x01,0xC4,0xCD,0x11,0xB6,0x0B,0xD6,0xF9,0x58,0x76,0x7E,0x65,0x69]
counter = 0

def printArr(arr):
    output = ''
    for c in arr:
        output = output + chr(c)
    print output

for magicnum in t_6b40:
    if magicnum == t_6b40[counter]:
        for i in range(counter+1, 29):
            t_6b40[i] = t_6b40[i] ^ magicnum
    t_6bb8[counter] = t_6bb8[counter] ^ t_6b40[counter]
    counter = counter + 1
    print ''
    printArr(t_6b40)
    printArr(t_6bb8)

P0rt_Kn0ck1ng_0n_he4v3ns_d00r@flare-on.com

Doogie Hacker

得到一段mbr程序,bootloader, 16bit 668p加载到ida

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

大体是密文表和取现行时间异或,再和密文异或

Flare-On 2018 writeup(上) 时间在bin中提示1990.02.06,题目中还出现了16岁的时间概念因此对该时间可疑

Flare-On 2018 writeup(上)

使用不同时间异或后,密文只剩一轮异或加密,计算重合指数,确认1990.02.06时间,并且确认密文长度为17

Flare-On 2018 writeup(上)

然后假设了key中存在特殊串@flare-on.com,只需要猜测串在key的位置,对密文解密看效果,所有可能性都为乱码,排除key中存在特殊串

再假设明文中存在@flare-on.com,会得到部分的key,部分key在key中的位置也可以求得,只需要补足4位key,先不管4位key,使用部分key解出部分明文依然所有可能性都是乱码

Flare-On 2018 writeup(上) Flare-On 2018 writeup(上)

17个密文为一行进行统计发现每列都有2个字符频次极高

假设出现频次极高的字符对应明文为空格可以推的可能的key

qwh}jyteonuatoyj}

ioperal}wvmylware

进行上下组合

key: ioperateonmalware

Flare-On 2018 writeup(上)

R3_PhD@flare-on.com

leet editr

Flare-On 2018 writeup(上)

程序开始分配多个堆块并设成不可访问

Flare-On 2018 writeup(上)

分配了VEH然后执行堆块代码发生异常,由于程序有多个反调试的地方,使用od调试

大概就是在运行堆块时触发异常,通过VEH解码shellcode,从而分段解密vbs

Flare-On 2018 writeup(上)

程序解密后可以找到If I were to title this piece, it would be ‘A_FLARE_f0r_th3_Dr4m4t1(C)’将是最后的title

Flare-On 2018 writeup(上)

该函数对数据分段解密,并且周期轮换使用了xor、rc4组合的三种加密方法,bp拿到所有的解密段

Flare-On 2018 writeup(上) Flare-On 2018 writeup(上) Flare-On 2018 writeup(上)

包含一张FLARE Ascii图片、网页和vbs脚本

Flare-On 2018 writeup(上) Flare-On 2018 writeup(上)

脚本运行oh(hai(createtextfile(xx,xx)),xx)),

Flare-On 2018 writeup(上)

先通过程序invoke解RC4得到BASE64编码数据,在用vbs自身BASE64,RC4解出反调试代码

vbs invoke部分可以参考github项目wine-stable

Flare-On 2018 writeup(上) Flare-On 2018 writeup(上)

程序最后调用gimme…love(key),然后对key取md5(去除空白符等),以md5为RC4的key再解密得到最后的明文

key由ascii + title得到,分别是上面提到的FLARE图案和函数解密后的title

Flare-On 2018 writeup(上) Flare-On 2018 writeup(上)

scr1pt1ng_sl4ck1ng_and_h4ck1ng@flare-on.com

glof

Flare-On 2018 writeup(上)

程序是一个驱动加载器,输入flag作为程序参数

一开始会检查一些启动环境,释放出fhv.sys进行加载,然后调用keyCheck分4段检查key

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

大致是想通过调用vmcall,触发驱动中的某个函数,将check函数加载到申请页面进行校验

将打开CPU VT并进入OS测试模式进行运行,系统奔溃,虚拟机运行一样奔溃

分析fhv.sys参考 https://github.com/Laureline001/lolo

Flare-On 2018 writeup(上)

驱动加载后检查了OS、CPU是否支持VT,然后启动VMX

Flare-On 2018 writeup(上)

客户机寄存器和虚拟机寄存器交换数据,存在非一一对应的,同时用于vmcall传递参数

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

不同的vmcall取得不同数据后再xor 0xe2

跟入找到ring3加载器对应的vmcall,看出对内存释放了一定的数据,dump出来

Flare-On 2018 writeup(上)

IDA无法解析,非合法指令

Flare-On 2018 writeup(上)

驱动捕捉了异常指令

Flare-On 2018 writeup(上)

在驱动中重新解析了指令,意味着一套自定义的CPU指令解析

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

脚本分析后得到合法代码

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

Flare-On 2018 writeup(上)

化简片段后得到4段key Flare-On 2018 writeup(上)

We4r_ur_v1s0r_w1th_Fl4R3@flare-on.com


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First Python(中文版)

Head First Python(中文版)

巴里(Barry.P.) / 林琪 等 / 中国电力出版社 / 2012-3-1 / 68.00元

你想过可以通过一本书就学会Python吗?《Head First Python(中文版)》超越枯燥的语法和甩法手册,通过一种独特的方法教你学习这种语言。你会迅速掌握Python的基础知识,然后转向持久存储、异常处理、Web开发、SQLite、数据加工和lGoogle App Engine。你还将学习如何为Android编写移动应用,这都要归功于Python为你赋予的强大能力。本书会提供充分并且完备......一起来看看 《Head First Python(中文版)》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具