附件链接

https://adworld.xctf.org.cn/media/file/task/554e0986d6db4c19b...

第一步:执行

使用file查看这个文件:

./re: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=c8d273ed1363a1878f348d6c506048f2354849d0, not stripped

显示是32位的程序,动态链接
使用readelf检查:

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048550
  Start of program headers:          52 (bytes into file)
  Start of section headers:          4452 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         30
  Section header string table index: 27

显示是EXEC类,我突然想到一个问题:这和DYN类型有什么区别呢?在stackoverflow上找到了一些文章:
https://stackoverflow.com/questions/61553723/whats-the-difference-between-statically-linked-and-not-a-dynamic-executable
在执行时,报错:required file not found
或许是解释器的问题?它需要linux-ld.so.2,我的电脑上没有,我的第一反应是:建一个软连接文件(后来证明这是个非常愚蠢的想法),但是执行时提示我library corrupt,可能是我没有32位的库吗?

我甚至有一个想法:或许这个文件不是32位的,是64位的呢?但是用hexedit之后,readelf时一些数据变得非常离谱,排除了这种可能

我使用ldd查看文件依赖时,却报错:not a dynamic linked file
啊?不是写的好好的吗?你告诉我这不是动态链接?
在stackoverflow上,有人说是缺少32位库
https://stackoverflow.com/questions/16807560/ldd-doesnt-work-on-dynamically-linked-binary
先是在pacman.conf中允许multilib,然后又下载lib32-glibc,本来以为安装好了,但仔细一看发现竟然报错了:

error: failed to commit transaction (conflicting files)
lib32-glibc: /usr/lib/ld-linux.so.2 exists in filesystem
Errors occurred, no packages were upgraded.

好吧,原来是我自己刚才建立的软链接搞的鬼!删除之后就装好了
ldd正常运行:

linux-gate.so.1 (0xecd00000)
        libc.so.6 => /usr/lib32/libc.so.6 (0xeca8d000)
        /lib/ld-linux.so.2 => /usr/lib/ld-linux.so.2 (0xecd02000)

程序也能执行了,只是...

Welcome to cyber malware control software.
Currently tracking 1041969716 bots worldwide
Fatal glibc error: malloc.c:2599 (sysmalloc): assertion failed: (old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)
Aborted (core dumped)

从“能执行”到“正确执行”

使用valgrind检测程序:

==2585== Memcheck, a memory error detector
==2585== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==2585== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==2585== Command: ./re.bk
==2585== 
Welcome to cyber malware control software.
Currently tracking 1389691921 bots worldwide
==2585== Invalid write of size 4
==2585==    at 0x40510D3: wcscpy (vg_replace_strmem.c:2211)
==2585==    by 0x80486A5: decrypt (in /test/re.bk)
==2585==    by 0x8048724: authenticate (in /test/re.bk)
==2585==    by 0x80487D4: main (in /test/re.bk)
==2585==  Address 0x42c745c is 36 bytes inside a block of size 39 alloc'd
==2585==    at 0x4042623: malloc (vg_replace_malloc.c:446)
==2585==    by 0x8048693: decrypt (in /test/re.bk)
==2585==    by 0x8048724: authenticate (in /test/re.bk)
==2585==    by 0x80487D4: main (in /test/re.bk)
==2585== 

提示我们出错在wcscpy函数,但真正有问题的可能是前面的malloc部分
再粘贴一下ida反编译:

  • main
int __cdecl main(int argc, const char **argv, const char **envp)
{
  setlocale(6, &unk_8048BE4);
  banner();
  prompt_authentication();
  authenticate();
  return 0;
}

前面三个函数都是没用的,只看authenticate

  • anthenticate

    int authenticate()
    {
    int v1[8192]; // [esp+1Ch] [ebp-800Ch] BYREF
    int v2; // [esp+801Ch] [ebp-Ch]
    
    v2 = decrypt(&unk_8048AA8, &unk_8048A90);        //这两个参数应该是data和key
    if ( fgetws(v1, 0x2000, stdin) )                //输入,比较。所以我们的flag应该就是解密后的内容
    {
      v1[wcslen(v1) - 1] = 0;
      if ( !wcscmp(v1, v2) )
        wprintf(&unk_8048B44);
      else
        wprintf(&unk_8048BA4);
    }
    return free(v2);
    }
  • decrypt
int __cdecl decrypt(int a1, int a2)
{
  int v2; // eax
  int v4; // [esp+1Ch] [ebp-1Ch]
  int i; // [esp+20h] [ebp-18h]
  int v6; // [esp+24h] [ebp-14h]
  int v7; // [esp+28h] [ebp-10h]
  int v8; // [esp+2Ch] [ebp-Ch]

  v6 = wcslen(a1);
  v7 = wcslen(a2);
  v2 = wcslen(a1);        //从这里我们大致能确定a1是data, a2是key, 
  v8 = malloc(v2 + 1);    //给解密数据分配空间,额外多一位,或许是需要结束符?
  wcscpy(v8, a1);
  while ( v4 < v6 )
  {
    for ( i = 0; i < v7 && v4 < v6; ++i )
      *(_DWORD *)(v8 + 4 * v4++) -= *(_DWORD *)(a2 + 4 * i);    // 每个wchar都被当作一个int来处理
  }
  return v8;
}

我们可以看到分配空间的部分为 malloc( len(a1) + 1 ), 有没有可能是分配的空间不够,导致堆溢出呢?
先来看看wchar在内存中具体是怎么存储的:

.rodata:08048AA8 unk_8048AA8     db  3Ah ; :             ; DATA XREF: authenticate+11↑o
.rodata:08048AA9                 db  14h
.rodata:08048AAA                 db    0
.rodata:08048AAB                 db    0
.rodata:08048AAC                 db  36h ; 6
.rodata:08048AAD                 db  14h
.rodata:08048AAE                 db    0
.rodata:08048AAF                 db    0
.rodata:08048AB0                 db  37h ; 7
.rodata:08048AB1                 db  14h
.rodata:08048AB2                 db    0
.rodata:08048AB3                 db    0
.rodata:08048AB4                 db  3Bh ; ;
.rodata:08048AB5                 db  14h
.rodata:08048AB6                 db    0
.rodata:08048AB7                 db    0
.rodata:08048AB8                 db  80h
.rodata:08048AB9                 db  14h
.rodata:08048ABA                 db    0
.rodata:08048ABB                 db    0
.rodata:08048ABC                 db  7Ah ; z
.rodata:08048ABD                 db  14h
.rodata:08048ABE                 db    0
.rodata:08048ABF                 db    0

我们发现前两个字节是有数据的,紧跟两个空字节。也就是说,这个程序中实际上每个wchar是占用4个字符的。
会不会是应该malloc(len(a1)+4)而不是malloc(len(a1)+1)呢?这里用到工具hexedit,通过Ctrl-s可以进行连续字节的搜索。我们objdump后定位到相关的指令码,修改后执行,遗憾的是,仍然报错。
再来仔细地看看malloc(v2+1), v2=wcslen(a1), 这个wcslen返回的具体是什么值呢?通过查阅资料可知,返回的是wchar字符个数而不是真正需要的内存,所以分配的空间是远远不够的,+4也不够!如果只修改1字节数据的话,我们就把它修改成最大的7f试试
即将:

 8048684:    e8 97 fe ff ff           call   8048520 <wcslen@plt>
 8048689:    83 c0 01                 add    $0x1,%eax
 804868c:    89 04 24                 mov    %eax,(%esp)
 804868f:    e8 4c fe ff ff           call   80484e0 <malloc@plt>

修改为

 8048684:    e8 97 fe ff ff           call   8048520 <wcslen@plt>
 8048689:    83 c0 7f                 add    $0x7f,%eax
 804868c:    89 04 24                 mov    %eax,(%esp)
 804868f:    e8 4c fe ff ff           call   80484e0 <malloc@plt>

幸运的是,这次我们成功了!执行不再报错,提示我们输入:

Welcome to cyber malware control software.
Currently tracking 218702664 bots worldwide
Please enter authentication details:

找到明文

但我们当然是不会傻傻地给他输入的,直接上gdb,打断点,找到返回的明文:

0x804cfe0:      57 '9'  0 '\000'        0 '\000'        0 '\000'        52 '4'  0 '\000'        0 '\000'        0 '\000'
0x804cfe8:      52 '4'  0 '\000'        0 '\000'        0 '\000'        55 '7'  0 '\000'        0 '\000'        0 '\000'
0x804cff0:      123 '{' 0 '\000'        0 '\000'        0 '\000'        121 'y' 0 '\000'        0 '\000'        0 '\000'
0x804cff8:      111 'o' 0 '\000'        0 '\000'        0 '\000'        117 'u' 0 '\000'        0 '\000'        0 '\000'
0x804d000:      95 '_'  0 '\000'        0 '\000'        0 '\000'        97 'a'  0 '\000'        0 '\000'        0 '\000'
0x804d008:      114 'r' 0 '\000'        0 '\000'        0 '\000'        101 'e' 0 '\000'        0 '\000'        0 '\000'
0x804d010:      95 '_'  0 '\000'        0 '\000'        0 '\000'        97 'a'  0 '\000'        0 '\000'        0 '\000'
0x804d018:      110 'n' 0 '\000'        0 '\000'        0 '\000'        95 '_'  0 '\000'        0 '\000'        0 '\000'
0x804d020:      105 'i' 0 '\000'        0 '\000'        0 '\000'        110 'n' 0 '\000'        0 '\000'        0 '\000'
0x804d028:      116 't' 0 '\000'        0 '\000'        0 '\000'        101 'e' 0 '\000'        0 '\000'        0 '\000'
0x804d030:      114 'r' 0 '\000'        0 '\000'        0 '\000'        110 'n' 0 '\000'        0 '\000'        0 '\000'
0x804d038:      97 'a'  0 '\000'        0 '\000'        0 '\000'        116 't' 0 '\000'        0 '\000'        0 '\000'
0x804d040:      105 'i' 0 '\000'        0 '\000'        0 '\000'        111 'o' 0 '\000'        0 '\000'        0 '\000'
0x804d048:      110 'n' 0 '\000'        0 '\000'        0 '\000'        97 'a'  0 '\000'        0 '\000'        0 '\000'
0x804d050:      108 'l' 0 '\000'        0 '\000'        0 '\000'        95 '_'  0 '\000'        0 '\000'        0 '\000'
0x804d058:      109 'm' 0 '\000'        0 '\000'        0 '\000'        121 'y' 0 '\000'        0 '\000'        0 '\000'
0x804d060:      115 's' 0 '\000'        0 '\000'        0 '\000'        116 't' 0 '\000'        0 '\000'        0 '\000'
0x804d068:      101 'e' 0 '\000'        0 '\000'        0 '\000'        114 'r' 0 '\000'        0 '\000'        0 '\000'
0x804d070:      121 'y' 0 '\000'        0 '\000'        0 '\000'        125 '}' 0 '\000'        0 '\000'        0 '\000'

这就是我们的flag!


StupidMagpie
6 声望0 粉丝