CTF

二进制分析实战第五章(1)

Posted by Kody Black on September 11, 2023

第五章 Linux二进制分析

第一题:分析payload文件

$ file payload
payload: ASCII text

$ head payload 
H4sIABzY61gAA+xaD3RTVZq/Sf+lFJIof1r+2aenKKh0klJKi4MmJaUvWrTSFlgR0jRN20iadpKX
UljXgROKjbUOKuOfWWfFnTlzZs/ZXTln9nTRcTHYERhnZ5c/R2RGV1lFTAFH/DNYoZD9vvvubd57
bcBl1ln3bL6e9Hvf9+733e/+v+/en0dqId80WYAWLVqI3LpooUXJgUpKFy6yEOsCy6KSRQtLLQsW
EExdWkIEyzceGVA4JLmDgkCaA92XTXel9/9H6ftVNcv0Ot2orCe3E5RiJhuVbUw/fH3SxkbKSS78
v47MJtkgZynS2YhNxYeZa84NLF0G/DLhV66X5XK9TcVnsXSc6xQ8S1UCm4o/M5moOCHCqB3Geny2
rD0+u1HFD7I4junVdnpmN8zshll6zglPr1eXL5P96pm+npWLcwdL51CkR6r9UGrGZ8O1zN+1NhUv
ZelKNXb3gl02+fpkZnwFyy9VvQgsfs55O3zH72sqK/2Ov3m+3xcId8/vLi+bX1ZaHOooLqExmVna
6rsbaHpejwKLeQqR+wC+n/ePA3n/duKu2kNvL175+MxD7z75W8GC76aSZLv1xgSdkGnLRV0+/KbD
7+UPnnhwadWbZ459b/Wsl/o/NZ468olxo3P9wOXK3Qe/a8fRmwhvcTVdl0J/UDe+nzMp9M4U+n9J
oX8jhT5HP77+ZIr0JWT8+NvI+OnvTpG+NoV/Qwr9Vyn0b6bQkxTl+ixF+p+m0N+qx743k+wWGlX6
# 从上述结果可以看出该文件为base64加密过的

$ base64 -d payload > decode_payload

$ file decode_payload 
decode_payload: gzip compressed data, last modified: Mon Apr 10 19:08:12 2017, from Unix
# 该文件是被压缩文件,尝试用tar解压

$ tar xvzf decode_payload
ctf
67b8601

目前得到两个文件,ctf和67b8601,首先分析ctf

$ file ctf
ctf: 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]=29aeb60bcee44b50d1db3a56911bd1de93cd2030, stripped
$ ./ctf
./ctf: error while loading shared libraries: lib5ae9b7f.so: cannot open shared object file: No such file or directory
$ ldd ./ctf
        linux-vdso.so.1 =>  (0x00007ffdc0bb9000)
        lib5ae9b7f.so => not found
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f355e381000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f355e16b000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f355dda1000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f355da98000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f355e703000)

目前可以确定ctf为可执行文件,但是缺少库lib5ae9b7f.so无法执行

$ file 67b8601
67b8601: PC bitmap, Windows 3.x format, 512 x 512 x 24

$ head 67b8601
# 中间有如下内容:
__gmon_start___init_fini_ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalize_Jv_RegisterClasses_ZSt19__throw_logic_errorPKc_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERmmmemcpy__stack_chk_fail_Z11rc4_encryptP11rc4_state_tPhi_Z11rc4_encryptP11rc4_state_tRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmalloc_Z11rc4_decryptP11rc4_state_tPhi_Z11rc4_decryptP11rc4_state_tRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE_Z6ui4_ini@�t)Lq��X�@te_tPhilibstdc++.so.6libc.so.6_edata__bss_start_endGLIBC_2.14GLIBC_2.4GLIBC_2.2.5GLIBCXX_3.4GLIBCXX_3.4.21 

$ xxd 67b8601 | head
00000000: 424d 3800 0c00 0000 0000 3600 0000 2800  BM8.......6...(.
00000010: 0000 0002 0000 0002 0000 0100 1800 0000  ................
00000020: 0000 0200 0c00 c01e 0000 c01e 0000 0000  ................
00000030: 0000 0000 7f45 4c46 0201 0100 0000 0000  .....ELF........
00000040: 0000 0000 0300 3e00 0100 0000 7009 0000  ......>.....p...
00000050: 0000 0000 4000 0000 0000 0000 7821 0000  ....@.......x!..
00000060: 0000 0000 0000 0000 4000 3800 0700 4000  ........@.8...@.
00000070: 1b00 1a00 0100 0000 0500 0000 0000 0000  ................
00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000090: 0000 0000 f40e 0000 0000 0000 f40e 0000  ................
# 说明67b8601也是一个可执行文件
# 提取其中的ELF头部
# 可以看到是从0x34开始的,即52,提取64个字节
$ dd skip=52 count=64 if=67b8601 of=file_head bs=1
64+0 records in
64+0 records out
64 bytes copied, 0.0040406 s, 15.8 kB/s
$ readelf -h file_head 
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x970
  Start of program headers:          64 (bytes into file)
  Start of section headers:          8568 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         7
  Size of section headers:           64 (bytes)
  Number of section headers:         27
  Section header string table index: 26
# 文件共有27个节,每个节有64字节,共计1728个字节,节头开始于8568字节处,故文件大小为10296比特
$ dd skip=52 count=10296 if=67b8601 of=newfile bs=1
10296+0 records in
10296+0 records out
10296 bytes (10 kB, 10 KiB) copied, 0.0511744 s, 201 kB/s
$ file newfile 
newfile: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=5279389c64af3477ccfdf6d3293e404fd9933817, stripped
# 可以看出该文件是一个动态链接库文件
# 考虑到ctf文件缺少动态链接库lib5ae9b7f.so,怀疑即为该文件
$ mv newfile lib5ae9b7f.so
$ export LD_LIBRARY_PATH=`pwd`
$ ./ctf
$ echo $?
1

通过上述的操作,ctf成功执行,但是错误返回,需要进一步逆向

放入ida pro后,main函数部分如下:

  if ( a1 <= 1 )
  {
    if ( dword_6020B4 )
      __printf_chk(1LL, "DEBUG: argv[1] = %s", a2[1]);
LABEL_3:
    v4 = 1;
    goto LABEL_4;
  }
  v3 = a2[1];
  __printf_chk(1LL, "checking '%s'\n", v3);
  if ( strcmp(v3, "show_me_the_flag") )
    goto LABEL_3;

意味着需要函数执行时添加参数show_me_the_flag

$ ./ctf show_me_the_flag
checking 'show_me_the_flag'
ok

还是得不到flag,进一步分析

16944420148901694442014355.png

如图,输出ok后,程序从&unk_40117B获取了name,并对其进行了解密,从63行来看,name是一个环境变量,如果没有设置,程序则会返回。之后,由从&unk_401183获取了v19,同样进行了解密,最后判断了v6和v19是否相等。

接下来,使用gdb进行动态分析,定位到63行对应的汇编代码为mov rdi, [rsp+218h+name]执行这步后进行系统调用call _getenv,因此在这一步设置断点。

gdb-peda$ file ctf
Reading symbols from ctf...(no debugging symbols found)...done.
gdb-peda$ export LD_LIBRARY_PATH=`pwd`
Undefined command: "export".  Try "help".
gdb-peda$ set env  LD_LIBRARY_PATH=`pwd`
gdb-peda$ b 0x400D07
[----------------------------------registers-----------------------------------]
RAX: 0x7fffffffde40 --> 0x454d5353455547 ('GUESSME')
RBX: 0x7fffffffe3a5 ("show_me_the_flag")
RCX: 0x454d5353 ('SSME')
RDX: 0x7 
RSI: 0x53455547 ('GUES')
RDI: 0x7fffffffde40 --> 0x454d5353455547 ('GUESSME')

可以知道,环境变量的名称为GUESSME。进一步需要知道应该设置的值是多少。

前面图中的69行对比了获取到的环境变量内容和需要的内容,其对应的汇编代码如下:

.text:0000000000400DA2 48 8D 84 24 90 00 00 00       lea     rax, [rsp+218h+var_188]
.text:0000000000400DAA 48 39 C7                      cmp     rdi, rax
.text:0000000000400DAD 74 05                         jz      short loc_400DB4
.text:0000000000400DAD

因此,在gdb中调试,添加环境变量GUESSME后在0x400DAA处设置断点,结果如下

[----------------------------------registers-----------------------------------]
RAX: 0x7fffffffde40 --> 0x15 
RBX: 0x7fffffffefa7 --> 0x5f434c0064636261 ('abcd')
RCX: 0x0 
RDX: 0x15 
RSI: 0x6150a0 ("Crackers Don't Matter")
RDI: 0x6150a0 ("Crackers Don't Matter")

因此,环境变量GUESSME=”Crackers Don’t Matter”

$ export GUESSME="Crackers Don't Matter"
$ ./ctf show_me_the_flag
checking 'show_me_the_flag'
ok
flag = 84b34c124b2ba5ca224af8e33b077e9e

得到flag为84b34c124b2ba5ca224af8e33b077e9e。

补充:

在书中,作者使用了多种工具分析了该文件:

  • 使用ldd查看文件的依赖情况:ldd -v [filename]

  • 使用xxd查看文件字节内容(可以使用xxd工具的-c选项修改每行显示的字节数)

  • 使用dd修改二进制文件

  • 使用readelf分析文件

  • 使用nm解析符号

    作者对lib5ae9b7f.so文件进行了额外的分析

    $ nm lib5ae9b7f.so
    nm: lib5ae9b7f.so: no symbols
    $ nm -D lib5ae9b7f.so
    0000000000202058 B __bss_start
                     w __cxa_finalize
    ......
    0000000000000c60 T _Z11rc4_decryptP11rc4_state_tPhi
    0000000000000c70 T _Z11rc4_decryptP11rc4_state_tRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
    0000000000000b40 T _Z11rc4_encryptP11rc4_state_tPhi
    0000000000000bc0 T _Z11rc4_encryptP11rc4_state_tRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
    0000000000000cb0 T _Z8rc4_initP11rc4_state_tPhi
                     U _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERmm
                     U _ZSt19__throw_logic_errorPKc
    $ nm -D --demangle lib5ae9b7f.so
    0000000000202058 B __bss_start
                     w __cxa_finalize
    ......
    0000000000000c60 T rc4_decrypt(rc4_state_t*, unsigned char*, int)
    0000000000000c70 T rc4_decrypt(rc4_state_t*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)
    0000000000000b40 T rc4_encrypt(rc4_state_t*, unsigned char*, int)
    0000000000000bc0 T rc4_encrypt(rc4_state_t*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)
    0000000000000cb0 T rc4_init(rc4_state_t*, unsigned char*, int)
                     U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long)
                     U std::__throw_logic_error(char const*)
    
  • 使用strings查看字符串

  • 使用strace和ltrace跟踪系统调用和库文件调用

    $ strace ./ctf show_me_the_flag
    $ ltrace -i -C ./ctf show_me_the_flag
    # 书中在这里通过ltrace的结果知道了环境变量名为GUESSME
    
  • 使用objdump检查指令集的行为

    # 输出.rodta节的内容
    $ objdump -s --section .rodata ctf
    # 反编译ctf
    $ objdump -d ctf