首页
社区
课程
招聘
[原创]一道带ptrace反调试的CTF逆向题目分析
发表于: 2019-4-30 15:53 8454

[原创]一道带ptrace反调试的CTF逆向题目分析

2019-4-30 15:53
8454

这是刚结束的ångstromCTF 2019的最后一道逆向题目,日常处理Windows逆向比较多,第一次遇到Linux的反调试,写个笔记记录一下做题过程。

拖入IDA分析,发现代码很明显被压缩或者加密; strings查看字符串发现UPX字样

看样子应该是被UPX加壳了,但是upx -d 并不能脱壳;类比Windows下UPX壳可能存在的一些操作,猜测可能是upx的一些壳特征被修改,导致不能正常脱壳。

但是,我不擅长Linux手动脱壳和ELFwen文件upx壳的修复,所尝试直接动态分析。gdb 加载直接运行,程序出现崩溃,猜测可能是存在反调试;程序单独运行,然后gdb,附加依然不成功:

看到应该存在ptrace反调试。google了一波ptrace反调试后,知道了大概原理,但是解题依然没有思路。

尝试从内存中dump运行起来的ELF文件。

内存中搜索可能存在的ELF文件

可以发现在0x00007ffff7ff2001处存在一个ELF文件此处内存通过mmap得到,猜测此处应该是UPX壳脱壳后的部分。

dump此处内存

gdb-peda$ dump binary memory 1.bin 0x00007ffff7ff2000 0x00007ffff7ffe000

将dump的内存载入IDA分析

可以大致看到程序执行流程,但是没有了got表

可以看到,在程序入口处有ptrace反调试,并且ptrace的调用是通过syscall实现的,不是通过调用库函数

flag检查

通过以上分析可知,如果可以在flag与内存内容对比的时候下断点,就可以从内存中直接获取到flag。那么接下来的问题就是bypass ptrace。

利用上述方法四,catch syscall ptrace,然后修改返回值rax的值;之后单步执行到flag校验处,从内存中获取flag即可,不再赘述。

平时调试Linux程序比较少,对Linux的反调试更不了解,通过着一道题目学到不少东西。

$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.95 Copyright (C) 1996-2018 the UPX Team. All Rights Reserved. $
upx: bugger: NotPackedException: not packed by UPX
Unpacked 0 files.
warning: process 3891 is already traced by process 3792
ptrace: Operation not permitted.
/home/pwn/3891: No such file or directory.
gdb-peda$ find ELF
Searching for 'ELF' in: None ranges
Found 27 results, display max 27 items:
      libc : 0x7ffff79df001 (rex.RB)
      libc : 0x7ffff7b7103f (rex.RB)
    bugger : 0x7ffff7dc0001 --> 0x10102464c45 
    bugger : 0x7ffff7dc0111 --> 0x300010102464c45 
ld-2.23.so : 0x7ffff7dc1001 (rex.RB)
ld-2.23.so : 0x7ffff7dc69a2 (rex.RB)
(省略了部分)
ld-2.23.so : 0x7ffff7de2bd7 (rex.RB)
ld-2.23.so : 0x7ffff7de38b1 (rex.RB)
    [vdso] : 0x7ffff7ff0001 (rex.RB)
    mapped : 0x7ffff7ff2001 --> 0x10102464c45 
gdb-peda$ vmmap 
Start              End                Perm    Name
0x00007ffff79df000 0x00007ffff7b9f000 r-xp    /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7b9f000 0x00007ffff7d9f000 ---p    /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7d9f000 0x00007ffff7da3000 r--p    /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7da3000 0x00007ffff7da5000 rw-p    /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7da5000 0x00007ffff7da9000 rw-p    mapped
0x00007ffff7dc0000 0x00007ffff7dc1000 r--p    /home/pwn/Desktop/angstromctf/re/5/bugger
0x00007ffff7dc1000 0x00007ffff7de7000 r-xp    /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7de7000 0x00007ffff7fe6000 ---p    mapped
0x00007ffff7fe6000 0x00007ffff7fe7000 r--p    /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7fe7000 0x00007ffff7fe8000 rw-p    /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7fe8000 0x00007ffff7fe9000 rw-p    mapped
0x00007ffff7fea000 0x00007ffff7fed000 rw-p    mapped
0x00007ffff7fed000 0x00007ffff7ff0000 r--p    [vvar]
0x00007ffff7ff0000 0x00007ffff7ff2000 r-xp    [vdso]
0x00007ffff7ff2000 0x00007ffff7ff3000 r--p    mapped
0x00007ffff7ff3000 0x00007ffff7ffc000 r-xp    mapped
0x00007ffff7ffc000 0x00007ffff7ffe000 r--p    mapped
0x00007ffff7ffe000 0x00007ffff8020000 rw-p    [heap]
0x00007ffffffde000 0x00007ffffffff000 rw-p    [stack]
0xffffffffff600000 0xffffffffff601000 r-xp    [vsyscall]
  sub_9503();
  sub_1030(sub_96EF, 0LL);
  sub_1080("Hey, dude! Please enter the flag: ");
  sub_10A0(&v5, 500LL, qword_C380);
  if ( (unsigned int)sub_956F(&v5) )
  {
    v0 = "Cool.";
    sub_1050("Cool.");
  }
  else
  {
    v0 = "Idiot.";
    sub_1050("Idiot.");
  }
LOAD:0000000000009503 sub_9503        proc near               ; CODE XREF: sub_9812+1F↓p
LOAD:0000000000009503                 push    rbp
LOAD:0000000000009504                 mov     rbp, rsp
LOAD:0000000000009507                 mov     eax, 65h ; 'e'
LOAD:000000000000950C                 mov     edi, 0          ; request
LOAD:0000000000009511                 mov     esi, 0          ; pid
LOAD:0000000000009516                 mov     edx, 0          ; addr
LOAD:000000000000951B                 syscall                 ; LINUX - sys_ptrace
;检查ptrace返回值
LOAD:000000000000951D                 test    eax, eax
LOAD:000000000000951F                 jz      short loc_953A
LOAD:0000000000009521                 lea     rdi, aNoDebuggersIdi ; "No debuggers. Idiot."
LOAD:0000000000009528                 call    sub_1050
;ptrace检测到调试后向0地址写入数据,从而导致异常
LOAD:000000000000952D                 mov     eax, 0
LOAD:0000000000009532                 mov     dword ptr [rax], 0 
;OAD:0000000000009538                 jmp     short loc_956C
LOAD:000000000000953A ; ---------------------------------------------------------------------------
LOAD:000000000000953A
LOAD:000000000000953A loc_953A:                               ; CODE XREF: sub_9503+1C↑j
LOAD:000000000000953A                 mov     eax, 65h ; 'e'
LOAD:000000000000953F                 mov     edi, 0          ; request
LOAD:0000000000009544                 mov     esi, 0          ; pid
LOAD:0000000000009549                 mov     edx, 0          ; addr
LOAD:000000000000954E                 syscall                 ; LINUX - sys_ptrace
LOAD:0000000000009550                 cmp     eax, 0FFFFFFFFh
LOAD:0000000000009553                 jz      short loc_956C
LOAD:0000000000009555                 lea     rdi, aStillNoDebugge ; "Still no debuggers. Idiot."
LOAD:000000000000955C                 call    sub_1050
;ptrace检测到调试后向0地址写入数据,从而导致异常
LOAD:0000000000009561                 mov     eax, 0
LOAD:0000000000009566                 mov     dword ptr [rax], 1
LOAD:000000000000956C
LOAD:000000000000956C loc_956C:                               ; CODE XREF: sub_9503+35↑j
LOAD:000000000000956C                                         ; sub_9503+50↑j
LOAD:000000000000956C                 nop
LOAD:000000000000956D                 pop     rbp
LOAD:000000000000956E                 retn
LOAD:000000000000956E sub_9503        endp
  //虽然没有got表,但是可以猜测此处是读取文件
  v1 = sub_10F0((__int64)"/proc/self/exe", (__int64)"rb");
  sub_10E0(v1, 0LL, 2LL);
  v2 = sub_10C0(v1);
  sub_10E0(v1, 0LL, 0LL);
  sub_1060(v1);
  v10 = 1;
  v3 = v2 - 1639;
  v4 = (char *)qword_CD68;
  //对读取到的文件内容进行处理
  sub_8DF9(qword_CD68, v2 - 1639, v13, 64LL);
  sub_1535(v4, v2 - 1639);
  for ( i = 0; i <= 63; ++i )
  {
     //检查flag开头是否为"actf{not_an_idiot._"
    if ( (unsigned int)sub_1090("actf{not_an_idiot._", v9, 19LL) )
      LOBYTE(v10) = 0;
    //检查flag是否以'}'结尾
    if ( asc_A119[0] != *(_BYTE *)(v9 + 147) )
      LOBYTE(v10) = 0;
    //flag内容与处理后的文件内容进行对比
    sub_1100(&v12, "%02x", (unsigned __int8)v13[i]);
    v3 = 2 * i + 19LL + v9;
    v4 = &v12;
    if ( (unsigned int)sub_1090(&v12, v3, 2LL) )
      v10 = 0;
    else
      v10 &= 1u;
  }

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2019-6-21 11:53 被QuietBar编辑 ,原因:
上传的附件:
收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 6832
活跃值: (1637)
能力值: ( LV5,RANK:67 )
在线值:
发帖
回帖
粉丝
2
我看别人的wp,确实是要修复UPX的一些特征然后脱壳。那个人说是通用的UPX修复手段,不会
2019-5-5 17:12
0
雪    币: 6832
活跃值: (1637)
能力值: ( LV5,RANK:67 )
在线值:
发帖
回帖
粉丝
3
https://kmh.zone/writeups/angstromctf-2019/bugger.html
2019-5-5 17:16
0
游客
登录 | 注册 方可回帖
返回
//